From 63bc8043abdb256b220e36db29578ca269cde6e7 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 9 Oct 2022 20:29:10 +0200 Subject: [PATCH] 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: