From 63bc8043abdb256b220e36db29578ca269cde6e7 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 9 Oct 2022 20:29:10 +0200 Subject: [PATCH 1/7] Add TXTH codec "YMZ" --- doc/TXTH.md | 69 ++++++++++++++++++++++--------------- src/coding/coding.h | 2 +- src/coding/yamaha_decoder.c | 20 ++++++----- src/decode.c | 3 +- src/meta/txth.c | 11 +++++- 5 files changed, 66 insertions(+), 39 deletions(-) diff --git a/doc/TXTH.md b/doc/TXTH.md index a60f5e60..d9ae5bcd 100644 --- a/doc/TXTH.md +++ b/doc/TXTH.md @@ -74,9 +74,7 @@ as explained below, but often will use default values. Accepted codec strings: # - HEVAG Vita/PS4 ADPCM # * For some Vita/PS4 games # * Interleave is multiple of 0x10 (default) -# - XBOX Xbox IMA ADPCM (mono/stereo) -# * For many XBOX games, and some PC games -# * Special interleave is multiple of 0x24 (mono) or 0x48 (stereo) +# # - DSP|NGC_DSP Nintendo GameCube ADPCM # * For many GC/Wii/3DS/Switch games # * Interleave is multiple of 0x08 (default), often +0x1000 @@ -84,6 +82,7 @@ as explained below, but often will use default values. Accepted codec strings: # * Should set ADPCM state (hist_offset/spacing/etc) # - DTK|NGC_DTK Nintendo ADP/DTK ADPCM # * For rare GC games +# # - PCM16LE PCM 16-bit little endian # * For many games (usually on PC) # * Interleave is multiple of 0x2 (default) @@ -102,27 +101,43 @@ as explained below, but often will use default values. Accepted codec strings: # - PCM_FLOAT_LE PCM 32-bit float little endian # * For few rare games [Ikinari Maou (Switch)] # * Interleave is multiple of 0x4 (default) +# # - IMA IMA ADPCM (mono/stereo) # * For some PC games, and rarely consoles # * Special interleave is multiple of 0x1, often +0x80 # - DVI_IMA IMA ADPCM (DVI order) # * Variation with modified encoding -# - AICA Yamaha AICA ADPCM (mono/stereo) -# * For some Dreamcast games, and some arcade (Naomi) games -# * Special interleave is multiple of 0x1 -# - APPLE_IMA4 Apple Quicktime IMA ADPCM -# * For some Mac/iOS games +# - XBOX Xbox IMA ADPCM (mono/stereo) +# * For many XBOX games, and some PC games +# * Special interleave is multiple of 0x24 (mono) or 0x48 (stereo) # - MS_IMA Microsoft IMA ADPCM # * For some PC games # * Interleave (frame size) varies, often multiple of 0x100 [required] +# - APPLE_IMA4 Apple Quicktime IMA ADPCM +# * For some Mac/iOS games +# - IMA_HV High Voltage's IMA ADPCM +# * For some High Voltage Software PC games [NBA Hangtime (PC), NHL Open Ice (PC)] +# # - MSADPCM Microsoft ADPCM (mono/stereo) # * For some PC games # * Interleave (frame size) varies, often multiple of 0x100 [required] +# +# - AICA Yamaha AICA ADPCM (mono/stereo) +# * For some Dreamcast games, and some arcade (Naomi) games +# * Special interleave is multiple of 0x1 +# - YMZ Yamaha YMZ263B/YMZ280B ADPCM (mono/stereo) +# * Variation of AICA +# * For rare arcade games [VJ: Visual & Music Slap (AC)] +# - CP_YM Capcom's Yamaha ADPCM +# * For rare Saturn games [Marvel Super Heroes vs Street Fighter (SAT)] +# # - SDX2 Squareroot-delta-exact 8-bit DPCM # * For many 3DO games +# # - MPEG MPEG Audio Layer file (MP1/2/3) # * For some games (usually PC/PS3) # * May set skip_samples (MP2: around 240 or 480, MP3: around 1152) +# # - ATRAC3 Sony ATRAC3 # * For some PS2 and PS3 games # * Interleave (frame size) can be 0x60/0x98/0xC0 * channels [required] @@ -134,45 +149,45 @@ as explained below, but often will use default values. Accepted codec strings: # Stereo: 0x0118|0178|0230|02E8|03A8|0460|05D0|0748|0800 # 6/8 channels: multiple of one of the above # * Should set skip_samples (around 2048+184 but varies) +# # - XMA1 Microsoft XMA1 # * For early X360 games # - XMA2 Microsoft XMA2 # * For later X360 games -# - FFMPEG Any headered FFmpeg format -# * For uncommon games -# * May set skip_samples +# # - AC3 AC3/SPDIF # * For few PS2 games # * Should set skip_samples (around 256 but varies) -# - PCFX PC-FX ADPCM -# * For many PC-FX games -# * Interleave is multiple of 0x1, often +0x8000 -# * Sample rate may be ~31468/~15734/~10489/~7867 -# - PCM4 PCM 4-bit signed -# * For early consoles -# - PCM4_U PCM 4-bit unsigned -# * Variation with modified encoding +# - AAC Advanced Audio Coding (raw outside .mp4) +# * For some 3DS games and many iOS games +# * Should set skip_samples (typically 1024 but varies, 2112 is also common) +# - FFMPEG Any headered FFmpeg format +# * For uncommon games +# * May set skip_samples +# # - OKI16 OKI ADPCM with 16-bit output (not VOX/Dialogic 12-bit) # * For rare PS2 games [Sweet Legacy (PS2), Hooligan (PS2)] # - OKI4S OKI ADPCM with 16-bit output and adjusted tables # * For later Konami arcade games [Gitadora (AC), Metal Gear Arcade (AC)] -# - AAC Advanced Audio Coding (raw outside .mp4) -# * For some 3DS games and many iOS games -# * Should set skip_samples (typically 1024 but varies, 2112 is also common) +# - PCFX PC-FX ADPCM +# * For many PC-FX games +# * Interleave is multiple of 0x1, often +0x8000 +# * Sample rate may be ~31468/~15734/~10489/~7867 +# +# - PCM4 PCM 4-bit signed +# * For early consoles +# - PCM4_U PCM 4-bit unsigned +# * Variation with modified encoding # - TGC Tiger Game.com 4-bit ADPCM # * For Tiger Game.com games # - ASF Argonaut ASF ADPCM # * For rare Argonaut games [Croc (SAT)] # - EAXA Electronic Arts EA-XA ADPCM # * For rare EA games [Harry Potter and the Chamber of Secrets (PC)] -# - XA CD-XA ADPCM (ISO 2048 mode1/data streams without subchannels) +# - XA CD-XA ADPCM (ISO 2048 mode1 streams without subchannel data) # * For rare Saturn and PS2 games [Phantasy Star Collection (SAT), Fantavision (PS2), EA SAT videos] # - XA_EA Electronic Arts XA ADPCM variation # * For rare Saturn games [EA SAT videos] -# - CP_YM Capcom's Yamaha ADPCM -# * For rare Saturn games [Marvel Super Heroes vs Street Fighter (SAT)] -# - IMA_HV High Voltage's IMA ADPCM -# * For some High Voltage Software PC games [NBA Hangtime (PC), NHL Open Ice (PC)] codec = (codec string) ``` diff --git a/src/coding/coding.h b/src/coding/coding.h index 3621fe30..0cf10959 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -171,7 +171,7 @@ int msadpcm_check_coefs(STREAMFILE* sf, uint32_t offset); /* yamaha_decoder */ -void decode_aica(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo); +void decode_aica(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first); void decode_cp_ym(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo); void decode_aska(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, size_t frame_size); void decode_nxap(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); diff --git a/src/coding/yamaha_decoder.c b/src/coding/yamaha_decoder.c index ea66088b..18036396 100644 --- a/src/coding/yamaha_decoder.c +++ b/src/coding/yamaha_decoder.c @@ -44,12 +44,12 @@ static void yamaha_adpcmb_expand_nibble(uint8_t byte, int shift, int32_t* hist1, /* Yamaha AICA expand, slightly filtered vs "ACM" Yamaha ADPCM, same as Creative ADPCM * (some info from https://github.com/vgmrips/vgmplay, https://wiki.multimedia.cx/index.php/Creative_ADPCM) */ -static void yamaha_aica_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t* hist1, int32_t* step_size, int16_t *out_sample) { +static void yamaha_aica_expand_nibble(uint8_t byte, int shift, int32_t* hist1, int32_t* step_size, int16_t *out_sample) { int code, delta, sample; *hist1 = *hist1 * 254 / 256; /* hist filter is vital to get correct waveform but not done in many emus */ - code = ((read_8bit(byte_offset,stream->streamfile) >> nibble_shift))&0xf; + code = (byte >> shift) & 0xf; delta = (*step_size * scale_delta[code]) / 8; /* 'mul' IMA with table (not sure if part of encoder) */ sample = *hist1 + delta; @@ -108,8 +108,8 @@ static void yamaha_capcom_expand_nibble(uint8_t byte, int shift, int32_t* hist1, */ -/* Yamaha AICA ADPCM (also used in YMZ280B with high nibble first) */ -void decode_aica(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) { +/* Yamaha AICA ADPCM (also used in YMZ263B/YMZ280B with high nibble first) */ +void decode_aica(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) { int i, sample_count = 0; int16_t out_sample; int32_t hist1 = stream->adpcm_history1_16; @@ -120,14 +120,16 @@ void decode_aica(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacin if (step_size > 0x6000) step_size = 0x6000; for (i = first_sample; i < first_sample + samples_to_do; i++) { - off_t byte_offset = is_stereo ? + uint8_t byte; + off_t offset = is_stereo ? stream->offset + i : /* stereo: one nibble per channel */ stream->offset + i/2; /* mono: consecutive nibbles */ - int nibble_shift = is_stereo ? - (!(channel&1) ? 0:4) : /* even = low/L, odd = high/R */ - (!(i&1) ? 0:4); /* low nibble first */ + int shift = is_high_first ? + is_stereo ? (!(channel&1) ? 4:0) : (!(i&1) ? 4:0) : /* even = high/L, odd = low/R */ + is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low/L, odd = high/L */ - yamaha_aica_expand_nibble(stream, byte_offset, nibble_shift, &hist1, &step_size, &out_sample); + byte = read_u8(offset, stream->streamfile); + yamaha_aica_expand_nibble(byte, shift, &hist1, &step_size, &out_sample); outbuf[sample_count] = out_sample; sample_count += channelspacing; } diff --git a/src/decode.c b/src/decode.c index aec74b23..55b4bc5c 100644 --- a/src/decode.c +++ b/src/decode.c @@ -1354,10 +1354,11 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_ case coding_AICA: case coding_AICA_int: { int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_AICA); + int is_high_first = vgmstream->codec_config == 1; for (ch = 0; ch < vgmstream->channels; ch++) { decode_aica(&vgmstream->ch[ch], buffer+ch, vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, - is_stereo); + is_stereo, is_high_first); } break; } diff --git a/src/meta/txth.c b/src/meta/txth.c index c47f6471..c40714c9 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -51,6 +51,7 @@ typedef enum { IMA_HV, PCM8_SB, HEVAG, + YMZ, UNKNOWN = 99, } txth_codec_t; @@ -258,6 +259,7 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */ #endif case IMA: coding = coding_IMA; break; + case YMZ: case AICA: coding = coding_AICA; break; case MSADPCM: coding = coding_MSADPCM; break; case NGC_DSP: coding = coding_NGC_DSP; break; @@ -386,7 +388,12 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) { vgmstream->codec_config = txth.codec_mode; } - vgmstream->allow_dual_stereo = 1; /* AICA and PSX */ + if (txth.codec == YMZ) { + vgmstream->codec_config = 1; /* CONFIG_HIGH_NIBBLE */ + } + + //TODO recheck and use only for needed cases + vgmstream->allow_dual_stereo = 1; /* known to be used in: PSX, AICA, YMZ */ break; case coding_PCFX: @@ -955,6 +962,7 @@ static txth_codec_t parse_codec(txth_header* txth, const char* val) { else if (is_string(val,"MPEG")) return MPEG; else if (is_string(val,"IMA")) return IMA; else if (is_string(val,"AICA")) return AICA; + else if (is_string(val,"YMZ")) return YMZ; else if (is_string(val,"MSADPCM")) return MSADPCM; else if (is_string(val,"NGC_DSP")) return NGC_DSP; else if (is_string(val,"DSP")) return NGC_DSP; @@ -2129,6 +2137,7 @@ static int get_bytes_to_samples(txth_header* txth, uint32_t bytes) { case IMA_HV: return ima_bytes_to_samples(bytes, txth->channels); case AICA: + case YMZ: case CP_YM: return yamaha_bytes_to_samples(bytes, txth->channels); case PCFX: From 0cb5c672fe8dc96662695d0a25e737a04ab86303 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 9 Oct 2022 20:29:30 +0200 Subject: [PATCH 2/7] Lower DTK priority --- src/vgmstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vgmstream.c b/src/vgmstream.c index 58f7187e..723b50d1 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -529,7 +529,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ init_vgmstream_agsc, - init_vgmstream_dtk, init_vgmstream_rsf, init_vgmstream_ps2_wmus, init_vgmstream_mib_mih, @@ -542,6 +541,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ + init_vgmstream_dtk, init_vgmstream_mpeg, /* semi-raw MP3 */ init_vgmstream_encrypted, /* encrypted stuff */ init_vgmstream_btsnd, /* semi-headerless */ From 20902d7409c67166ed106657d5ab906d3a3e6114 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 9 Oct 2022 20:29:59 +0200 Subject: [PATCH 3/7] cleanup --- cli/vgmstream_cli.c | 2 +- src/util/m2_psb.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/vgmstream_cli.c b/cli/vgmstream_cli.c index 971d656f..93040422 100644 --- a/cli/vgmstream_cli.c +++ b/cli/vgmstream_cli.c @@ -523,7 +523,7 @@ static void replace_filename(char* dst, size_t dstsize, cli_config* cfg, VGMSTRE subsong = 0; /* for games without subsongs / bad config */ } - if (vgmstream->stream_name && vgmstream->stream_name[0] != '\0') { + if (vgmstream->stream_name[0] != '\0') { snprintf(stream_name, sizeof(stream_name), "%s", vgmstream->stream_name); clean_filename(stream_name, 1); /* clean subsong name's subdirs */ } diff --git a/src/util/m2_psb.c b/src/util/m2_psb.c index b6fabba6..26ca6960 100644 --- a/src/util/m2_psb.c +++ b/src/util/m2_psb.c @@ -788,7 +788,7 @@ int psb_node_exists(const psb_node_t* node, const char* key) { static void print_internal(psb_node_t* curr, int depth) { int i; - psb_node_t node; + psb_node_t node = { 0 }; const char* key; psb_type_t type; psb_result_t res; @@ -857,7 +857,7 @@ static void print_internal(psb_node_t* curr, int depth) { } void psb_print(psb_context_t* ctx) { - psb_node_t node; + psb_node_t node = { 0 }; psb_get_root(ctx, &node); print_internal(&node, 0); From 8665a1179ccad95d04c65bfc6ec5097618280070 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 9 Oct 2022 20:30:08 +0200 Subject: [PATCH 4/7] doc --- doc/BUILD.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/BUILD.md b/doc/BUILD.md index 319998bf..6ab69ada 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -69,10 +69,12 @@ This guide is mainly geared towards beginner devs, introducing concepts in steps Common C compiler, most development is done with this. On **Windows** you need one of these somewhere in PATH: -- MinGW-w64 (32bit version): https://sourceforge.net/projects/mingw-w64/ +- MinGW-w64 (32bit version), in any config (for example: gcc-8.1.0, i686, win32, sjlj) - Use this for easier standalone executables - - [Latest online MinGW installer](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe/download) with any config should work (for example: gcc-8.1.0, i686, win32, sjlj). + - [Sourceforce project](https://sourceforge.net/projects/mingw-w64/) + - [Latest online MinGW installer](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe/download). - Or download and unzip the [portable MinGW package](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/8.1.0/threads-win32/sjlj/i686-8.1.0-release-win32-sjlj-rt_v6-rev0.7z/download) + - Or get from [alt builds](https://github.com/niXman/mingw-builds-binaries/releases/) (may be more recent versions) - MSYS2 with the MinGW-w64_shell (32bit) package: https://msys2.github.io/ - Resulting binaries may depend on `msys*.dll`. From ebafe71889967901f789efdbc9e86dc445c6cca9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 9 Oct 2022 20:30:29 +0200 Subject: [PATCH 5/7] Add HCA key --- src/meta/hca_keys.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/meta/hca_keys.h b/src/meta/hca_keys.h index f46fe0e1..90e7b46c 100644 --- a/src/meta/hca_keys.h +++ b/src/meta/hca_keys.h @@ -1051,6 +1051,9 @@ static const hcakey_info hcakey_list[] = { // Fairy Fencer F: Refrain Chord (multi) {348693553056839375}, // 04D6CEF0656BF6CF + + // Echoes of Mana (Android) + {1090221945250803295}, // 0F213F153D026E5F }; #endif/*_HCA_KEYS_H_*/ From 75025e2f085188c4ab36ca2793377a8d9c34fa04 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 9 Oct 2022 20:31:04 +0200 Subject: [PATCH 6/7] Fix some Ogg Opus loops [Kuro no Kiseki (PC)] --- src/meta/ogg_opus.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/meta/ogg_opus.c b/src/meta/ogg_opus.c index 5d6bd1a3..e81db0cd 100644 --- a/src/meta/ogg_opus.c +++ b/src/meta/ogg_opus.c @@ -91,6 +91,13 @@ VGMSTREAM* init_vgmstream_ogg_opus(STREAMFILE* sf) { sscanf(strrchr(user_comment, '=') + 1, "%d-%d", &loop_start, &loop_end); loop_flag = 1; } + else if (strstr(user_comment,"loopstart=")==user_comment) { /* The Legend of Heroes: Kuro no Kiseki (PC) */ + loop_start= atol(strrchr(user_comment,'=')+1); + loop_flag = (loop_start >= 0); + } + else if (strstr(user_comment,"loopend=")==user_comment) { /* LoopStart pair */ + loop_end = atol(strrchr(user_comment,'=')+1); + } //;VGM_LOG("OggOpus: user_comment=%s\n", user_comment); offset += 0x04 + user_comment_size; From 7f08dbb89f49579e740d918fb821ab67853f805b Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 9 Oct 2022 21:00:52 +0200 Subject: [PATCH 7/7] Add .cads extension [Drakengard (PS2)] --- src/formats.c | 1 + src/meta/ads.c | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/formats.c b/src/formats.c index e9d95659..85d76a9a 100644 --- a/src/formats.c +++ b/src/formats.c @@ -129,6 +129,7 @@ static const char* extension_list[] = { "bvg", "bwav", + "cads", "caf", "cbd2", "ccc", //fake extension (to be removed) diff --git a/src/meta/ads.c b/src/meta/ads.c index cfed961e..4f4f6ea4 100644 --- a/src/meta/ads.c +++ b/src/meta/ads.c @@ -336,19 +336,26 @@ VGMSTREAM* init_vgmstream_ads_container(STREAMFILE* sf) { size_t subfile_size; /* checks */ - if (!check_extensions(sf, "ads")) - goto fail; - - if (read_32bitBE(0x00,sf) == 0x41445343 && /* "ADSC" */ - read_32bitBE(0x04,sf) == 0x01000000) { + if (is_id32be(0x00,sf, "ADSC")) { /* Kenka Bancho 2, Kamen Rider Hibiki/Kabuto, Shinjuku no Okami */ + if (read_u32le(0x04,sf) != 0x01) + goto fail; + + if (!check_extensions(sf, "ads")) + goto fail; + subfile_offset = 0x08; } - else if (read_32bitBE(0x00,sf) == 0x63617669 && /* "cavi" */ - read_32bitBE(0x04,sf) == 0x61207374 && /* "a st" */ - read_32bitBE(0x08,sf) == 0x7265616D) { /* "ream" */ + else if (is_id32be(0x00,sf, "cavi") && + is_id32be(0x04,sf, "a st") && + is_id32be(0x08,sf, "ream")) { /* cavia games: Drakengard 1/2, Dragon Quest Yangus, GITS: Stand Alone Complex */ subfile_offset = 0x7d8; + + /* .ads: assumed + * .cads: probable extension (found in bigfiles as LE field) */ + if (!check_extensions(sf, "ads,cads")) + goto fail; } else { goto fail;