From 8a5af7ccdbac06885a63f952a5bba6f8ce6e8f0f Mon Sep 17 00:00:00 2001 From: Simon Aarons <40786398+simontime@users.noreply.github.com> Date: Sun, 16 Aug 2020 12:28:15 +1000 Subject: [PATCH 1/7] Highly improved Game.com ADPCM decoding algorithm --- src/coding/tgcadpcm_decoder.c | 57 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/coding/tgcadpcm_decoder.c b/src/coding/tgcadpcm_decoder.c index 896a2ae0..64ed4812 100644 --- a/src/coding/tgcadpcm_decoder.c +++ b/src/coding/tgcadpcm_decoder.c @@ -1,42 +1,47 @@ #include "coding.h" /* Decodes SunPlus' ADPCM codec used on the Tiger Game.com. - * Reverse engineered from the Game.com's BIOS. */ - -static uint16_t slopeTable[64] = + * Highly improved, optimised signed 16-bit version of the algorithm. */ +static const int16_t slope_table[8][16] = { - 0x0000, 0x0100, 0x0200, 0x0400, 0x0610, 0x0810, 0x0C18, 0x1020, - 0x0100, 0x0300, 0x0508, 0x0908, 0x0D18, 0x1118, 0x1920, 0x2128, - 0x0208, 0x0508, 0x0810, 0x0E10, 0x1420, 0x1A20, 0x2628, 0x3230, - 0x0310, 0x0710, 0x0B18, 0x1318, 0x1B28, 0x2328, 0x2930, 0x4338, - 0x0418, 0x0918, 0x0E20, 0x1820, 0x2230, 0x2C30, 0x4038, 0x5438, - 0x0520, 0x0B20, 0x1128, 0x1D28, 0x2938, 0x3538, 0x4D38, 0x6F38, - 0x0628, 0x0D28, 0x1430, 0x2230, 0x3038, 0x3E38, 0x5A38, 0x7638, - 0x0730, 0x0F30, 0x1738, 0x2738, 0x3738, 0x4738, 0x6738, 0x7D38 + { 0, 0, 256, -256, 512, -512, 1024, -1024, 1536, -1536, 2048, -2048, 3072, -3072, 4096, -4096 }, + { 256, -256, 768, -768, 1280, -1280, 2304, -2304, 3328, -3328, 4352, -4352, 6400, -6400, 8448, -8448 }, + { 512, -512, 1280, -1280, 2048, -2048, 3584, -3584, 5120, -5120, 6656, -6656, 9728, -9728, 12800, -12800 }, + { 768, -768, 1792, -1792, 2816, -2816, 4864, -4864, 6912, -6912, 8960, -8960, 10496, -10496, 17152, -17152 }, + { 1024, -1024, 2304, -2304, 3584, -3584, 6144, -6144, 8704, -8704, 11264, -11264, 16384, -16384, 21504, -21504 }, + { 1280, -1280, 2816, -2816, 4352, -4352, 7424, -7424, 10496, -10496, 13568, -13568, 19712, -19712, 28416, -28416 }, + { 1536, -1536, 3328, -3328, 5120, -5120, 8704, -8704, 12288, -12288, 15872, -15872, 23040, -23040, 30208, -30208 }, + { 1792, -1792, 3840, -3840, 5888, -5888, 9984, -9984, 14080, -14080, 18176, -18176, 26368, -26368, 32000, -32000 }, +}; + +static const uint8_t next_step[8][16] = +{ + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 4 }, + { 0, 0, 0, 0, 1, 1, 1, 1, 3, 3, 3, 3, 4, 4, 5, 5 }, + { 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 5, 5, 6, 6 }, + { 2, 2, 2, 2, 3, 3, 3, 3, 5, 5, 5, 5, 6, 6, 7, 7 }, + { 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, 7, 7, 7, 7 }, + { 4, 4, 4, 4, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7 }, + { 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7 }, + { 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 } }; void decode_tgc(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do) { for (int i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count++) { - uint8_t samp = ((uint8_t)read_8bit(i/2, stream->streamfile) >> + uint8_t nibble = ((uint8_t)read_8bit(i/2, stream->streamfile) >> (i & 1 ? 4 : 0)) & 0xf; - uint8_t slopeIndex = stream->adpcm_scale | (samp >> 1); + stream->adpcm_history1_16 += slope_table[stream->adpcm_step_index][nibble]; + stream->adpcm_step_index = next_step [stream->adpcm_step_index][nibble]; - stream->adpcm_step_index = slopeTable[slopeIndex] >> 8; - stream->adpcm_scale = slopeTable[slopeIndex] & 0xff; + if (stream->adpcm_history1_16 < -32768) + stream->adpcm_history1_16 = -32768; - stream->adpcm_history1_16 += (samp & 1) ? - -stream->adpcm_step_index: - stream->adpcm_step_index; + if (stream->adpcm_history1_16 > 32767) + stream->adpcm_history1_16 = 32767; - if (stream->adpcm_history1_16 < 0) - stream->adpcm_history1_16 = 0; - - if (stream->adpcm_history1_16 > 0xff) - stream->adpcm_history1_16 = 0xff; - - outbuf[sample_count] = stream->adpcm_history1_16 * 0x100 - 0x8000; + outbuf[sample_count] = stream->adpcm_history1_16; } -} \ No newline at end of file +} From 221c50b85c873e5c00360872ca0c4bd00c9c71bf Mon Sep 17 00:00:00 2001 From: Simon Aarons <40786398+simontime@users.noreply.github.com> Date: Sun, 16 Aug 2020 12:36:59 +1000 Subject: [PATCH 2/7] Ensure int32_t for clamps --- src/coding/tgcadpcm_decoder.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coding/tgcadpcm_decoder.c b/src/coding/tgcadpcm_decoder.c index 64ed4812..100b9661 100644 --- a/src/coding/tgcadpcm_decoder.c +++ b/src/coding/tgcadpcm_decoder.c @@ -33,14 +33,14 @@ void decode_tgc(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int32_t first_samp uint8_t nibble = ((uint8_t)read_8bit(i/2, stream->streamfile) >> (i & 1 ? 4 : 0)) & 0xf; - stream->adpcm_history1_16 += slope_table[stream->adpcm_step_index][nibble]; + stream->adpcm_history1_32 += slope_table[stream->adpcm_step_index][nibble]; stream->adpcm_step_index = next_step [stream->adpcm_step_index][nibble]; - if (stream->adpcm_history1_16 < -32768) - stream->adpcm_history1_16 = -32768; + if (stream->adpcm_history1_32 < -32768) + stream->adpcm_history1_32 = -32768; - if (stream->adpcm_history1_16 > 32767) - stream->adpcm_history1_16 = 32767; + if (stream->adpcm_history1_32 > 32767) + stream->adpcm_history1_32 = 32767; outbuf[sample_count] = stream->adpcm_history1_16; } From a9100be92f8aa0b7e740fab1c3d560169c42c188 Mon Sep 17 00:00:00 2001 From: Simon Aarons <40786398+simontime@users.noreply.github.com> Date: Sun, 16 Aug 2020 13:08:29 +1000 Subject: [PATCH 3/7] Initialise sample history and step index to 0 --- src/meta/tgc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/meta/tgc.c b/src/meta/tgc.c index a865309e..bb9f2b7b 100644 --- a/src/meta/tgc.c +++ b/src/meta/tgc.c @@ -18,6 +18,9 @@ VGMSTREAM * init_vgmstream_tgc(STREAMFILE *streamFile) { vgmstream->meta_type = meta_TGC; vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_TGC; + + vgmstream->ch[0].adpcm_history1_32 = 0; + vgmstream->ch[0].adpcm_step_index = 0; if (!vgmstream_open_stream(vgmstream, streamFile, 3)) goto fail; From e04234e733256a65dea2383e4849952149a3ab21 Mon Sep 17 00:00:00 2001 From: Simon Aarons <40786398+simontime@users.noreply.github.com> Date: Sun, 16 Aug 2020 15:52:23 +1000 Subject: [PATCH 4/7] Fix offset bug --- src/coding/tgcadpcm_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coding/tgcadpcm_decoder.c b/src/coding/tgcadpcm_decoder.c index 100b9661..d5a76672 100644 --- a/src/coding/tgcadpcm_decoder.c +++ b/src/coding/tgcadpcm_decoder.c @@ -30,7 +30,7 @@ void decode_tgc(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int32_t first_samp { for (int i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count++) { - uint8_t nibble = ((uint8_t)read_8bit(i/2, stream->streamfile) >> + uint8_t nibble = ((uint8_t)read_8bit(stream->offset + i/2, stream->streamfile) >> (i & 1 ? 4 : 0)) & 0xf; stream->adpcm_history1_32 += slope_table[stream->adpcm_step_index][nibble]; From 18d461bc368f56d256642739527a91eed1a24aac Mon Sep 17 00:00:00 2001 From: Simon Aarons <40786398+simontime@users.noreply.github.com> Date: Sun, 16 Aug 2020 15:53:13 +1000 Subject: [PATCH 5/7] Remove useless lines --- src/meta/tgc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/meta/tgc.c b/src/meta/tgc.c index bb9f2b7b..ca9c4e10 100644 --- a/src/meta/tgc.c +++ b/src/meta/tgc.c @@ -16,11 +16,7 @@ VGMSTREAM * init_vgmstream_tgc(STREAMFILE *streamFile) { vgmstream->sample_rate = 8000; vgmstream->num_samples = ((uint16_t)read_16bitBE(1, streamFile) - 3) * 2; vgmstream->meta_type = meta_TGC; - vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_TGC; - - vgmstream->ch[0].adpcm_history1_32 = 0; - vgmstream->ch[0].adpcm_step_index = 0; if (!vgmstream_open_stream(vgmstream, streamFile, 3)) goto fail; From 57cd7c602946dc0fb116598c35bce6e3c89cae7a Mon Sep 17 00:00:00 2001 From: Simon Aarons <40786398+simontime@users.noreply.github.com> Date: Sun, 16 Aug 2020 22:55:23 +1000 Subject: [PATCH 6/7] Line not actually useless, future-proofing in case of reordering --- src/meta/tgc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meta/tgc.c b/src/meta/tgc.c index ca9c4e10..a865309e 100644 --- a/src/meta/tgc.c +++ b/src/meta/tgc.c @@ -16,6 +16,7 @@ VGMSTREAM * init_vgmstream_tgc(STREAMFILE *streamFile) { vgmstream->sample_rate = 8000; vgmstream->num_samples = ((uint16_t)read_16bitBE(1, streamFile) - 3) * 2; vgmstream->meta_type = meta_TGC; + vgmstream->layout_type = layout_none; vgmstream->coding_type = coding_TGC; if (!vgmstream_open_stream(vgmstream, streamFile, 3)) From ac38e353dfd6b4c14f0b071e6c25bc6c91b5ad99 Mon Sep 17 00:00:00 2001 From: Simon Aarons <40786398+simontime@users.noreply.github.com> Date: Sun, 16 Aug 2020 22:57:38 +1000 Subject: [PATCH 7/7] Use adpcm_history1_32 for consistency --- src/coding/tgcadpcm_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coding/tgcadpcm_decoder.c b/src/coding/tgcadpcm_decoder.c index d5a76672..2362e14b 100644 --- a/src/coding/tgcadpcm_decoder.c +++ b/src/coding/tgcadpcm_decoder.c @@ -42,6 +42,6 @@ void decode_tgc(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int32_t first_samp if (stream->adpcm_history1_32 > 32767) stream->adpcm_history1_32 = 32767; - outbuf[sample_count] = stream->adpcm_history1_16; + outbuf[sample_count] = (sample_t)stream->adpcm_history1_32; } }