mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 15:00:11 +01:00
commit
b62357c832
@ -294,7 +294,9 @@ in foobar's preferences):
|
||||
|
||||
If your player isn't picking tags make sure vgmstream is detecting the song
|
||||
(as other plugins can steal its extensions, see above), .m3u is properly
|
||||
named and that filenames inside match the song filename.
|
||||
named and that filenames inside match the song filename. For Winamp you need
|
||||
to make sure options > titles > advanced title formatting checkbox is set and
|
||||
the format defined.
|
||||
|
||||
|
||||
## Supported codec types
|
||||
|
@ -38,8 +38,9 @@ def print_help(appname):
|
||||
print("Options:\n"
|
||||
" -r: find recursive (writes files to current dir, with dir in TXTP)\n"
|
||||
" -c (name): set path to CLI (default: test.exe)\n"
|
||||
" -n (name): use (name)_(subsong).txtp format\n"
|
||||
" You can put '{filename}' somewhere to get it substituted by the base name\n"
|
||||
" -n (name): use (name).txtp, that can be formatted using:\n"
|
||||
" {filename}, {subsong}, {internal-name}\n"
|
||||
" ex. -n BGM_{subsong}, -n {subsong}__{internal-name} "
|
||||
" -z N: zero-fill subsong number (default: auto fill up to total subsongs)\n"
|
||||
" -d (dir): add dir in TXTP (if the file will reside in a subdir)\n"
|
||||
" -m: create mini-txtp\n"
|
||||
@ -437,14 +438,21 @@ class TxtpMaker(object):
|
||||
if (pos != -1 and pos > 1):
|
||||
fname_base = fname_base[:pos]
|
||||
|
||||
internal_name = self.stream_name
|
||||
|
||||
txt = cfg.base_name
|
||||
txt = txt.replace("{filename}",fname_base)
|
||||
txt = txt.replace("{subsong}",index)
|
||||
txt = txt.replace("{internal-name}",internal_name)
|
||||
|
||||
outname = "{}".format(txt)
|
||||
|
||||
else:
|
||||
txt = fname_path
|
||||
pos = txt.rfind(".") #remove ext
|
||||
if (pos != -1 and pos > 1):
|
||||
txt = txt[:pos]
|
||||
|
||||
outname = "{}".format(txt)
|
||||
if index != "":
|
||||
outname += "_" + index
|
||||
|
@ -134,6 +134,12 @@ music_Home.ps3.scd#c1~3
|
||||
```
|
||||
Doesn't change the final number of channels though, just mutes non-selected channels.
|
||||
|
||||
If you use **`C(number)`** it will remove non-selected channels (not done directly for backwards compatibility). This just a shortcut for macro `#@track` (described later):
|
||||
```
|
||||
#plays channels 3 and 4 = 2nd subsong and removes other channels
|
||||
music_Home.ps3.scd#C3 4
|
||||
```
|
||||
|
||||
|
||||
### Custom play settings
|
||||
**`#l(loops)`**, **`#f(fade)`**, **`#d(fade-delay)`**, **`#i(ignore loop)`**, **`#F(ignore fade)`**, **`#E(end-to-end loop)`**
|
||||
|
@ -291,6 +291,7 @@ void free_ffmpeg(ffmpeg_codec_data *data);
|
||||
|
||||
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
|
||||
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data);
|
||||
void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channels_remap);
|
||||
|
||||
/* ffmpeg_decoder_custom_opus.c (helper-things) */
|
||||
ffmpeg_codec_data * init_ffmpeg_switch_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
|
@ -28,6 +28,25 @@ static void g_init_ffmpeg() {
|
||||
}
|
||||
}
|
||||
|
||||
static void remap_audio(sample_t *outbuf, int sample_count, int channels, int channel_mappings[]) {
|
||||
int ch_from,ch_to,s;
|
||||
sample_t temp;
|
||||
for (s = 0; s < sample_count; s++) {
|
||||
for (ch_from = 0; ch_from < channels; ch_from++) {
|
||||
if (ch_from > 32)
|
||||
continue;
|
||||
|
||||
ch_to = channel_mappings[ch_from];
|
||||
if (ch_to < 1 || ch_to > 32 || ch_to > channels-1 || ch_from == ch_to)
|
||||
continue;
|
||||
|
||||
temp = outbuf[s*channels + ch_from];
|
||||
outbuf[s*channels + ch_from] = outbuf[s*channels + ch_to];
|
||||
outbuf[s*channels + ch_to] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* converts codec's samples (can be in any format, ex. Ogg's float32) to PCM16 */
|
||||
static void convert_audio_pcm16(sample_t *outbuf, const uint8_t *inbuf, int fullSampleCount, int bitsPerSample, int floatingPoint) {
|
||||
int s;
|
||||
@ -656,6 +675,8 @@ end:
|
||||
/* convert native sample format into PCM16 outbuf */
|
||||
samplesReadNow = bytesRead / (bytesPerSample * channels);
|
||||
convert_audio_pcm16(outbuf, data->sampleBuffer, samplesReadNow * channels, data->bitsPerSample, data->floatingPoint);
|
||||
if (data->channel_remap_set)
|
||||
remap_audio(outbuf, samplesReadNow, data->channels, data->channel_remap);
|
||||
|
||||
/* clean buffer when requested more samples than possible */
|
||||
if (endOfAudio && samplesReadNow < samples_to_do) {
|
||||
@ -814,4 +835,19 @@ uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data) {
|
||||
return (uint32_t)data->codecCtx->channel_layout; /* uint64 but there ain't so many speaker mappings */
|
||||
}
|
||||
|
||||
/* yet another hack to fix codecs that encode channels in different order and reorder on decoder
|
||||
* but FFmpeg doesn't do it automatically
|
||||
* (maybe should be done via mixing, but could clash with other stuff?) */
|
||||
void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channel_remap) {
|
||||
int i;
|
||||
|
||||
if (data->channels > 32)
|
||||
return;
|
||||
|
||||
for (i = 0; i < data->channels; i++) {
|
||||
data->channel_remap[i] = channel_remap[i];
|
||||
}
|
||||
data->channel_remap_set = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -50,7 +50,9 @@ void render_vgmstream_layered(sample_t * outbuf, int32_t sample_count, VGMSTREAM
|
||||
}
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample = data->layers[0]->current_sample; /* just in case it's used for info */
|
||||
/* needed for info (ex. for mixing) */
|
||||
vgmstream->current_sample = data->layers[0]->current_sample;
|
||||
vgmstream->loop_count = data->layers[0]->loop_count;
|
||||
//vgmstream->samples_into_block = 0; /* handled in each layer */
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, material_offset, extradata_offset;
|
||||
size_t material_size, extradata_size, stream_size;
|
||||
int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, /*num_samples,*/ loop_start, loop_end;
|
||||
int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, num_samples, loop_start, loop_end;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
/* check extensions */
|
||||
@ -237,7 +237,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
material_size = read_16bitLE(material_offset+0x04,streamFile);
|
||||
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile);
|
||||
stream_size = read_32bitLE(material_offset+0x08,streamFile);
|
||||
//num_samples = read_32bitLE(material_offset+0x0c,streamFile);
|
||||
num_samples = read_32bitLE(material_offset+0x0c,streamFile);
|
||||
|
||||
loop_start = read_32bitLE(material_offset+0x10,streamFile);
|
||||
loop_end = read_32bitLE(material_offset+0x14,streamFile);
|
||||
@ -263,6 +263,17 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
vgmstream->meta_type = meta_AKB;
|
||||
|
||||
switch (codec) {
|
||||
case 0x01: /* PCM16LE [Mobius: Final Fantasy (Android)] */
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
break;
|
||||
|
||||
|
||||
case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -323,7 +334,6 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
}
|
||||
#endif
|
||||
|
||||
case 0x01: /* PCM16LE */
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
@ -608,6 +608,21 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, fact_sample_skip);
|
||||
}
|
||||
|
||||
/* LFE channel should be reordered on decode, but FFmpeg doesn't do it automatically:
|
||||
* - 6ch: FL FR FC BL BR LFE > FL FR FC LFE BL BR
|
||||
* - 8ch: FL FR FC BL BR SL SR LFE > FL FR FC LFE BL BR SL SR
|
||||
* (ATRAC3Plus only, 5/7ch can't be encoded) */
|
||||
if (ffmpeg_data->channels == 6) {
|
||||
/* LFE BR BL > LFE BL BR > same */
|
||||
int channel_remap[] = { 0, 1, 2, 5, 5, 5, };
|
||||
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
|
||||
}
|
||||
else if (ffmpeg_data->channels == 8) {
|
||||
/* LFE BR SL SR BL > LFE BL SL SR BR > LFE BL BR SR SL > LFE BL BR SL SR > same */
|
||||
int channel_remap[] = { 0, 1, 2, 7, 7, 7, 7, 7};
|
||||
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
|
||||
}
|
||||
|
||||
/* RIFF loop/sample values are absolute (with skip samples), adjust */
|
||||
if (loop_flag) {
|
||||
loop_start_smpl -= (int32_t)ffmpeg_data->skipSamples;
|
||||
|
@ -285,7 +285,7 @@ static void apply_config(VGMSTREAM *vgmstream, txtp_entry *current) {
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
if (!((current->channel_mask >> ch) & 1)) {
|
||||
txtp_mix_data mix = {0};
|
||||
mix.ch_dst = ch;
|
||||
mix.ch_dst = ch + 1;
|
||||
mix.vol = 0.0f;
|
||||
add_mixing(current, &mix, MIX_VOLUME);
|
||||
}
|
||||
@ -880,7 +880,8 @@ static int add_filename(txtp_header * txtp, char *filename, int is_default) {
|
||||
|
||||
add_mixing(&cfg, &mix, MACRO_VOLUME);
|
||||
}
|
||||
else if (strcmp(command,"@track") == 0) {
|
||||
else if (strcmp(command,"@track") == 0 ||
|
||||
strcmp(command,"C") == 0 ) {
|
||||
txtp_mix_data mix = {0};
|
||||
|
||||
nm = get_mask(config, &mix.mask);
|
||||
@ -930,7 +931,9 @@ static int add_filename(txtp_header * txtp, char *filename, int is_default) {
|
||||
}
|
||||
else {
|
||||
//;VGM_LOG("TXTP: unknown command\n");
|
||||
break; /* end, incorrect command, or possibly a comment or double ## comment too */
|
||||
/* end, incorrect command, or possibly a comment or double ## comment too
|
||||
* (shouldn't fail for forward compatibility) */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -468,6 +468,7 @@ void mixing_push_add(VGMSTREAM* vgmstream, int ch_dst, int ch_src, double volume
|
||||
mix.ch_src = ch_src;
|
||||
mix.vol = volume;
|
||||
|
||||
//;VGM_LOG("MIX: add %i+%i*%f\n", ch_dst,ch_src,volume);
|
||||
add_mixing(vgmstream, &mix);
|
||||
}
|
||||
|
||||
@ -484,6 +485,7 @@ void mixing_push_volume(VGMSTREAM* vgmstream, int ch_dst, double volume) {
|
||||
mix.ch_dst = ch_dst;
|
||||
mix.vol = volume;
|
||||
|
||||
//;VGM_LOG("MIX: volume %i*%f\n", ch_dst,volume);
|
||||
add_mixing(vgmstream, &mix);
|
||||
}
|
||||
|
||||
@ -648,7 +650,7 @@ void mixing_push_fade(VGMSTREAM* vgmstream, int ch_dst, double vol_start, double
|
||||
/* should only modify prev if add_mixing but meh */
|
||||
}
|
||||
|
||||
//;VGM_LOG("MIX: fade: %i^%f~%f=%c@%i~%i~%i~%i\n", ch_dst, vol_start, vol_end, shape, time_pre, time_start, time_end, time_post);
|
||||
//;VGM_LOG("MIX: fade %i^%f~%f=%c@%i~%i~%i~%i\n", ch_dst, vol_start, vol_end, shape, time_pre, time_start, time_end, time_post);
|
||||
add_mixing(vgmstream, &mix);
|
||||
}
|
||||
|
||||
|
@ -1205,6 +1205,9 @@ typedef struct {
|
||||
int64_t skipSamples; // number of start samples that will be skipped (encoder delay), for looping adjustments
|
||||
int streamCount; // number of FFmpeg audio streams
|
||||
|
||||
int channel_remap_set;
|
||||
int channel_remap[32]; /* map of channel > new position */
|
||||
|
||||
/*** internal state ***/
|
||||
// Intermediate byte buffer
|
||||
uint8_t *sampleBuffer;
|
||||
|
Loading…
Reference in New Issue
Block a user