From ea634ad4730b820d8e11f8d10e425173b743a3e4 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 22:25:44 +0100 Subject: [PATCH] Add 3DS IMA for BCSTM and fix old IMA regression (HWAS/SWAV/SAD/AUD/etc) Standard IMA algorithm was changed for BCSTM, subtly altering regular IMA's waveforms (not too audible). Now this 3DS variation is separate. --- src/coding/coding.h | 1 + src/coding/ima_decoder.c | 32 +++++++++++++++++++++++++++----- src/formats.c | 1 + src/meta/bcstm.c | 2 +- src/vgmstream.c | 9 +++++++++ src/vgmstream.h | 1 + 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index e31dc1d3..98cde6df 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -22,6 +22,7 @@ void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first); void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index b6f8b25a..2be5c5c1 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -41,8 +41,8 @@ static const int IMA_IndexTable[16] = }; -/* Alt IMA */ -static void ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { +/* 3DS IMA (Mario Golf, Mario Tennis; maybe other Camelot games) */ +static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; //"original" ima nibble expansion @@ -64,7 +64,7 @@ static void ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int if (*step_index > 88) *step_index=88; } -/* Microsoft's IMA (most common) */ +/* Standard IMA (most common) */ static void ms_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; @@ -86,7 +86,7 @@ static void ms_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, i if (*step_index > 88) *step_index=88; } -/* Apple's MS IMA variation. Exactly the same except it uses 16b history (probably more sensitive to overflow/sign extend) */ +/* Apple's IMA variation. Exactly the same except it uses 16b history (probably more sensitive to overflow/sign extend) */ static void ms_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int16_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; @@ -472,7 +472,29 @@ void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, off_t byte_offset = stream->offset + i/2; int nibble_shift = (i&1?4:0); //low nibble order - ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //external interleave + + //no header + + for (i=first_sample,sample_count=0; ioffset + i/2; + int nibble_shift = (i&1?4:0); //low nibble order + + n3ds_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } diff --git a/src/formats.c b/src/formats.c index 889a2c42..e734f446 100644 --- a/src/formats.c +++ b/src/formats.c @@ -442,6 +442,7 @@ static const coding_info coding_info_list[] = { {coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"}, {coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"}, {coding_IMA, "IMA 4-bit ADPCM"}, + {coding_3DS_IMA, "3DS IMA 4-bit ADPCM"}, {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, {coding_RAD_IMA, "Radical 4-bit IMA ADPCM"}, {coding_RAD_IMA_mono, "Radical 4-bit IMA ADPCM (mono)"}, diff --git a/src/meta/bcstm.c b/src/meta/bcstm.c index 399e1f59..2d8c8365 100644 --- a/src/meta/bcstm.c +++ b/src/meta/bcstm.c @@ -75,7 +75,7 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) { if (seek_offset == 0) goto fail; if ((uint32_t)read_32bitBE(seek_offset, streamFile) != 0x5345454B) { /* "SEEK" If this header doesn't exist, assuming that the file is IMA */ ima = 1; - coding_type = coding_IMA_int; + coding_type = coding_3DS_IMA; } else coding_type = coding_NGC_DSP; diff --git a/src/vgmstream.c b/src/vgmstream.c index ec1a0a3b..b3e736fb 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1026,6 +1026,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { return 1; case coding_IMA_int: case coding_DVI_IMA_int: + case coding_3DS_IMA: case coding_AICA: return 2; case coding_NGC_AFC: @@ -1211,6 +1212,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_IMA_int: case coding_DVI_IMA: case coding_DVI_IMA_int: + case coding_3DS_IMA: case coding_AICA: return 1; case coding_APPLE_IMA4: @@ -1627,6 +1629,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_3DS_IMA: + for (chan=0;chanchannels;chan++) { + decode_3ds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; case coding_APPLE_IMA4: for (chan=0;chanchannels;chan++) { decode_apple_ima4(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, diff --git a/src/vgmstream.h b/src/vgmstream.h index a1917cdb..8e5b277f 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -135,6 +135,7 @@ typedef enum { coding_REF_IMA, /* Reflections IMA ADPCM */ coding_AWC_IMA, /* Rockstar AWC IMA ADPCM */ coding_UBI_IMA, /* Ubisoft IMA ADPCM */ + coding_3DS_IMA, /* 3DS IMA ADPCM */ coding_MSADPCM, /* Microsoft ADPCM */ coding_WS, /* Westwood Studios VBR ADPCM */