Merge pull request #382 from bnnm/txtp-akb-at3

txtp akb at3
This commit is contained in:
Christopher Snowhill 2019-03-30 00:59:26 -07:00 committed by GitHub
commit b62357c832
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 103 additions and 15 deletions

View File

@ -294,7 +294,9 @@ in foobar's preferences):
If your player isn't picking tags make sure vgmstream is detecting the song 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 (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 ## Supported codec types

View File

@ -38,8 +38,9 @@ def print_help(appname):
print("Options:\n" print("Options:\n"
" -r: find recursive (writes files to current dir, with dir in TXTP)\n" " -r: find recursive (writes files to current dir, with dir in TXTP)\n"
" -c (name): set path to CLI (default: test.exe)\n" " -c (name): set path to CLI (default: test.exe)\n"
" -n (name): use (name)_(subsong).txtp format\n" " -n (name): use (name).txtp, that can be formatted using:\n"
" You can put '{filename}' somewhere to get it substituted by the base name\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" " -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" " -d (dir): add dir in TXTP (if the file will reside in a subdir)\n"
" -m: create mini-txtp\n" " -m: create mini-txtp\n"
@ -437,14 +438,21 @@ class TxtpMaker(object):
if (pos != -1 and pos > 1): if (pos != -1 and pos > 1):
fname_base = fname_base[:pos] fname_base = fname_base[:pos]
internal_name = self.stream_name
txt = cfg.base_name txt = cfg.base_name
txt = txt.replace("{filename}",fname_base) txt = txt.replace("{filename}",fname_base)
txt = txt.replace("{subsong}",index)
txt = txt.replace("{internal-name}",internal_name)
outname = "{}".format(txt)
else: else:
txt = fname_path txt = fname_path
pos = txt.rfind(".") #remove ext pos = txt.rfind(".") #remove ext
if (pos != -1 and pos > 1): if (pos != -1 and pos > 1):
txt = txt[:pos] txt = txt[:pos]
outname = "{}".format(txt) outname = "{}".format(txt)
if index != "": if index != "":
outname += "_" + index outname += "_" + index

View File

@ -134,6 +134,12 @@ music_Home.ps3.scd#c1~3
``` ```
Doesn't change the final number of channels though, just mutes non-selected channels. 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 ### Custom play settings
**`#l(loops)`**, **`#f(fade)`**, **`#d(fade-delay)`**, **`#i(ignore loop)`**, **`#F(ignore fade)`**, **`#E(end-to-end loop)`** **`#l(loops)`**, **`#f(fade)`**, **`#d(fade-delay)`**, **`#i(ignore loop)`**, **`#F(ignore fade)`**, **`#E(end-to-end loop)`**

View File

@ -291,6 +291,7 @@ void free_ffmpeg(ffmpeg_codec_data *data);
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples); void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data); 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_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); ffmpeg_codec_data * init_ffmpeg_switch_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);

View File

@ -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 */ /* 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) { static void convert_audio_pcm16(sample_t *outbuf, const uint8_t *inbuf, int fullSampleCount, int bitsPerSample, int floatingPoint) {
int s; int s;
@ -656,6 +675,8 @@ end:
/* convert native sample format into PCM16 outbuf */ /* convert native sample format into PCM16 outbuf */
samplesReadNow = bytesRead / (bytesPerSample * channels); samplesReadNow = bytesRead / (bytesPerSample * channels);
convert_audio_pcm16(outbuf, data->sampleBuffer, samplesReadNow * channels, data->bitsPerSample, data->floatingPoint); 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 */ /* clean buffer when requested more samples than possible */
if (endOfAudio && samplesReadNow < samples_to_do) { 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 */ 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 #endif

View File

@ -50,7 +50,9 @@ void render_vgmstream_layered(sample_t * outbuf, int32_t sample_count, VGMSTREAM
} }
samples_written += samples_to_do; 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 */ //vgmstream->samples_into_block = 0; /* handled in each layer */
} }
} }

View File

@ -192,7 +192,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
off_t start_offset, material_offset, extradata_offset; off_t start_offset, material_offset, extradata_offset;
size_t material_size, extradata_size, stream_size; 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; int total_subsongs, target_subsong = streamFile->stream_index;
/* check extensions */ /* check extensions */
@ -237,7 +237,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
material_size = read_16bitLE(material_offset+0x04,streamFile); material_size = read_16bitLE(material_offset+0x04,streamFile);
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile); sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile);
stream_size = read_32bitLE(material_offset+0x08,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_start = read_32bitLE(material_offset+0x10,streamFile);
loop_end = read_32bitLE(material_offset+0x14,streamFile); loop_end = read_32bitLE(material_offset+0x14,streamFile);
@ -263,6 +263,17 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_AKB; vgmstream->meta_type = meta_AKB;
switch (codec) { 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)] */ case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */
vgmstream->coding_type = coding_MSADPCM; vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
@ -323,7 +334,6 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
} }
#endif #endif
case 0x01: /* PCM16LE */
default: default:
goto fail; goto fail;
} }

View File

@ -608,6 +608,21 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
ffmpeg_set_skip_samples(ffmpeg_data, fact_sample_skip); 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 */ /* RIFF loop/sample values are absolute (with skip samples), adjust */
if (loop_flag) { if (loop_flag) {
loop_start_smpl -= (int32_t)ffmpeg_data->skipSamples; loop_start_smpl -= (int32_t)ffmpeg_data->skipSamples;

View File

@ -285,7 +285,7 @@ static void apply_config(VGMSTREAM *vgmstream, txtp_entry *current) {
for (ch = 0; ch < vgmstream->channels; ch++) { for (ch = 0; ch < vgmstream->channels; ch++) {
if (!((current->channel_mask >> ch) & 1)) { if (!((current->channel_mask >> ch) & 1)) {
txtp_mix_data mix = {0}; txtp_mix_data mix = {0};
mix.ch_dst = ch; mix.ch_dst = ch + 1;
mix.vol = 0.0f; mix.vol = 0.0f;
add_mixing(current, &mix, MIX_VOLUME); 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); 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}; txtp_mix_data mix = {0};
nm = get_mask(config, &mix.mask); nm = get_mask(config, &mix.mask);
@ -930,7 +931,9 @@ static int add_filename(txtp_header * txtp, char *filename, int is_default) {
} }
else { else {
//;VGM_LOG("TXTP: unknown command\n"); //;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;
} }
} }
} }

View File

@ -468,6 +468,7 @@ void mixing_push_add(VGMSTREAM* vgmstream, int ch_dst, int ch_src, double volume
mix.ch_src = ch_src; mix.ch_src = ch_src;
mix.vol = volume; mix.vol = volume;
//;VGM_LOG("MIX: add %i+%i*%f\n", ch_dst,ch_src,volume);
add_mixing(vgmstream, &mix); 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.ch_dst = ch_dst;
mix.vol = volume; mix.vol = volume;
//;VGM_LOG("MIX: volume %i*%f\n", ch_dst,volume);
add_mixing(vgmstream, &mix); 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 */ /* 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); add_mixing(vgmstream, &mix);
} }

View File

@ -1205,6 +1205,9 @@ typedef struct {
int64_t skipSamples; // number of start samples that will be skipped (encoder delay), for looping adjustments int64_t skipSamples; // number of start samples that will be skipped (encoder delay), for looping adjustments
int streamCount; // number of FFmpeg audio streams int streamCount; // number of FFmpeg audio streams
int channel_remap_set;
int channel_remap[32]; /* map of channel > new position */
/*** internal state ***/ /*** internal state ***/
// Intermediate byte buffer // Intermediate byte buffer
uint8_t *sampleBuffer; uint8_t *sampleBuffer;