From f87c75299b05203d987143dd0e6fa45f384ad788 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 23 Jul 2022 15:14:30 +0200 Subject: [PATCH] Improve s14 detection --- src/coding/g7221_decoder_lib.c | 6 ++- src/meta/s14_sss.c | 75 ++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/coding/g7221_decoder_lib.c b/src/coding/g7221_decoder_lib.c index fb5a51e9..976737ee 100644 --- a/src/coding/g7221_decoder_lib.c +++ b/src/coding/g7221_decoder_lib.c @@ -1132,6 +1132,7 @@ struct g7221_handle { /* control */ int bit_rate; int frame_size; + int test_errors; /* AES setup/state */ s14aes_handle* aes; /* state */ @@ -1179,7 +1180,7 @@ int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples * so we could avoid one extra buffer, but for clarity we'll leave as is */ /* unpack data into MLT spectrum coefs */ - res = unpack_frame(handle->bit_rate, data, handle->frame_size, &mag_shift, handle->mlt_coefs, &handle->random_value, encrypted); + res = unpack_frame(handle->bit_rate, data, handle->frame_size, &mag_shift, handle->mlt_coefs, &handle->random_value, handle->test_errors); if (res < 0) goto fail; /* convert coefs to samples using reverse (inverse) MLT */ @@ -1254,6 +1255,7 @@ int g7221_set_key(g7221_handle* handle, const uint8_t* key) { if (key == NULL) { s14aes_close(handle->aes); handle->aes = NULL; + handle->test_errors = 1; /* force? */ return 1; } @@ -1263,6 +1265,8 @@ int g7221_set_key(g7221_handle* handle, const uint8_t* key) { if (!handle->aes) goto fail; } + handle->test_errors = 1; + /* Base key is XORed probably against memdumps, as plain key would be part of the final AES key. However * roundkey is still in memdumps near AES state (~0x1310 from sbox table, that starts with 0x63,0x7c,0x77,0x7b...) * so it isn't too effective. XORing was originally done inside aes_expand_key during S14/S22 init. */ diff --git a/src/meta/s14_sss.c b/src/meta/s14_sss.c index 71b87cf0..921e4e0d 100644 --- a/src/meta/s14_sss.c +++ b/src/meta/s14_sss.c @@ -3,48 +3,45 @@ #include "../coding/coding.h" #include -/* .s14 and .sss - headerless siren14 stream (The Idolm@ster DS, Korogashi Puzzle Katamari Damacy DS) */ -VGMSTREAM * init_vgmstream_s14_sss(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +static int test_interleave(STREAMFILE* sf, int channels, int interleave); + +/* .s14/.sss - headerless siren14 stream [The Idolm@ster (DS), Korogashi Puzzle Katamari Damacy (DS), Taiko no Tatsujin DS 1/2 (DS)] */ +VGMSTREAM* init_vgmstream_s14_sss(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; off_t start_offset = 0; - int channel_count, loop_flag = 0, interleave; + int channels, loop_flag = 0, interleave; /* check extension */ - if (check_extensions(streamFile,"sss")) { - channel_count = 2; - } else if (check_extensions(streamFile,"s14")) { - channel_count = 1; //todo missing dual _0ch.s14 _1ch.s14, but dual_ext thing doesn't work properly with siren14 decoder + if (check_extensions(sf,"sss")) { + channels = 2; + } else if (check_extensions(sf,"s14")) { + channels = 1; /* may have dual _0ch.s14 + _1ch.s14, needs .txtp */ } else { goto fail; } - /* raw siren comes in 3 frame sizes, try to guess the correct one - * (should try to decode and check the error flag but it isn't currently reported) */ + /* raw siren comes in 3 frame sizes, try to guess the correct one */ { - char filename[PATH_LIMIT]; - streamFile->get_name(streamFile,filename,sizeof(filename)); - - /* horrid but I ain't losing sleep over it (besides the header is often incrusted in-code as some tracks loop) */ - if (strstr(filename,"S037")==filename || strstr(filename,"b06")==filename || /* Korogashi Puzzle Katamari Damacy */ - strstr(filename,"_48kbps")!=NULL) /* Taiko no Tatsujin DS 1/2 */ + /* horrid but ain't losing sleep over it (besides the header is often incrusted in-code as some tracks loop) + * Katamari, Taiko = 0x78/0x50, idolmaster=0x3c (usually but can be any) */ + if (test_interleave(sf, channels, 0x78)) interleave = 0x78; - else if (strstr(filename,"32700")==filename || /* Hottarake no Shima - Kanata to Nijiiro no Kagami */ - strstr(filename,"b0")==filename || strstr(filename,"puzzle")==filename || strstr(filename,"M09")==filename || /* Korogashi Puzzle Katamari Damacy */ - strstr(filename,"_32kbps")!=NULL) /* Taiko no Tatsujin DS 1/2 */ - interleave = 0x50; + else if (test_interleave(sf, channels, 0x50)) + interleave = 0x50; + else if (test_interleave(sf, channels, 0x3c)) + interleave = 0x3c; else - interleave = 0x3c; /* The Idolm@ster - Dearly Stars */ + goto fail; } - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels,loop_flag); if (!vgmstream) goto fail; - vgmstream->num_samples = get_streamfile_size(streamFile) / (interleave * channel_count) * (32000/50); - vgmstream->sample_rate = 32768; /* maybe 32700? */ + vgmstream->num_samples = get_streamfile_size(sf) / (interleave * channels) * (32000/50); + vgmstream->sample_rate = 32768; - vgmstream->meta_type = channel_count==1 ? meta_S14 : meta_SSS; + vgmstream->meta_type = channels==1 ? meta_S14 : meta_SSS; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = interleave; @@ -58,7 +55,7 @@ VGMSTREAM * init_vgmstream_s14_sss(STREAMFILE *streamFile) { #endif } - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; @@ -66,3 +63,27 @@ fail: close_vgmstream(vgmstream); return NULL; } + +/* pretty gross (should use TXTH), but codec info seems to be in hard-to-locate places/exe + * and varies per file, so for now autodetect possible types. could also check if data_size matches interleave */ +static int test_interleave(STREAMFILE* sf, int channels, int interleave) { +#ifdef VGM_USE_G7221 + int res; + g7221_codec_data* data = init_g7221(channels, interleave); + if (!data) goto fail; + + set_key_g7221(data, NULL); /* force test key */ + + /* though this is mainly for key testing, with no key can be used to test frames too */ + res = test_key_g7221(data, 0x00, sf); + if (res <= 0) goto fail; + + free_g7221(data); + return 1; +fail: + free_g7221(data); + return 0; +#else + return 0; +#endif +}