mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-15 02:57:38 +01:00
Highly improved Game.com ADPCM decoding algorithm
This commit is contained in:
parent
5682f3b9cc
commit
8a5af7ccdb
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user