mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-15 02:57:38 +01:00
Implement Tiger Game.com ADPCM
This commit is contained in:
parent
b2043c0e5b
commit
5106ccba68
@ -137,6 +137,9 @@ void decode_nxap(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacin
|
||||
size_t yamaha_bytes_to_samples(size_t bytes, int channels);
|
||||
size_t aska_bytes_to_samples(size_t bytes, int channels);
|
||||
|
||||
/* tgcadpcm_decoder */
|
||||
void decode_tgc(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
/* nds_procyon_decoder */
|
||||
void decode_nds_procyon(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
|
42
src/coding/tgcadpcm_decoder.c
Normal file
42
src/coding/tgcadpcm_decoder.c
Normal file
@ -0,0 +1,42 @@
|
||||
#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] =
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
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) >>
|
||||
(i & 1 ? 4 : 0)) & 0xf;
|
||||
|
||||
uint8_t slopeIndex = stream->adpcm_scale | (samp >> 1);
|
||||
|
||||
stream->adpcm_step_index = slopeTable[slopeIndex] >> 8;
|
||||
stream->adpcm_scale = slopeTable[slopeIndex] & 0xff;
|
||||
|
||||
stream->adpcm_history1_16 += (samp & 1) ?
|
||||
-stream->adpcm_step_index:
|
||||
stream->adpcm_step_index;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ static const char* extension_list[] = {
|
||||
"208",
|
||||
"2dx9",
|
||||
"2pfs",
|
||||
"4",
|
||||
"8", //txth/reserved [Gungage (PS1)]
|
||||
"800",
|
||||
"9tav",
|
||||
@ -177,6 +178,7 @@ static const char* extension_list[] = {
|
||||
"gbts",
|
||||
"gca",
|
||||
"gcm",
|
||||
"gcomadpcm",
|
||||
"gcub",
|
||||
"gcw",
|
||||
"genh",
|
||||
@ -474,6 +476,7 @@ static const char* extension_list[] = {
|
||||
"sxd3",
|
||||
|
||||
"tec",
|
||||
"tgcadpcm",
|
||||
"tgq",
|
||||
"thp",
|
||||
"tk5",
|
||||
@ -718,6 +721,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_AICA_int, "Yamaha AICA 4-bit ADPCM (mono/interleave)"},
|
||||
{coding_ASKA, "tri-Ace Aska 4-bit ADPCM"},
|
||||
{coding_NXAP, "Nex NXAP 4-bit ADPCM"},
|
||||
{coding_TGC, "Tiger Game.com 4-bit ADPCM"},
|
||||
{coding_NDS_PROCYON, "Procyon Studio Digital Sound Elements NDS 4-bit APDCM"},
|
||||
{coding_L5_555, "Level-5 0x555 4-bit ADPCM"},
|
||||
{coding_LSF, "lsf 4-bit ADPCM"},
|
||||
@ -1255,6 +1259,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_XSSB, "Artoon XSSB header"},
|
||||
{meta_XMA_UE3, "Unreal Engine XMA header"},
|
||||
{meta_FDA, "Relic FDA header"},
|
||||
{meta_TGC, "Tiger Game.com .4 header"},
|
||||
|
||||
};
|
||||
|
||||
|
@ -196,6 +196,7 @@
|
||||
<ClCompile Include="meta\mtaf.c" />
|
||||
<ClCompile Include="meta\ps2_spm.c" />
|
||||
<ClCompile Include="meta\rad.c" />
|
||||
<ClCompile Include="meta\tgc.c" />
|
||||
<ClCompile Include="meta\vs_str.c" />
|
||||
<ClCompile Include="meta\ps2_wmus.c" />
|
||||
<ClCompile Include="meta\ivag.c" />
|
||||
@ -224,6 +225,7 @@
|
||||
<ClCompile Include="plugins.c" />
|
||||
<ClCompile Include="meta\ps2_va3.c" />
|
||||
<ClCompile Include="streamfile.c" />
|
||||
<ClCompile Include="coding\tgcadpcm_decoder.c" />
|
||||
<ClCompile Include="util.c" />
|
||||
<ClCompile Include="vgmstream.c" />
|
||||
<ClCompile Include="meta\208.c" />
|
||||
|
@ -1669,5 +1669,11 @@
|
||||
<ClCompile Include="meta\xmv_valve.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\tgcadpcm_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\tgc.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -879,4 +879,6 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE *sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_fda(STREAMFILE *sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_tgc(STREAMFILE *streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
30
src/meta/tgc.c
Normal file
30
src/meta/tgc.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* Tiger Game.com ADPCM file */
|
||||
VGMSTREAM * init_vgmstream_tgc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "gcomadpcm,tgcadpcm,4"))
|
||||
goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(1, 0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 8000;
|
||||
vgmstream->num_samples = (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))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -36,6 +36,7 @@ typedef enum {
|
||||
PCM4_U = 26, /* 4-bit unsigned PCM (3rd and 4th gen games) */
|
||||
OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
|
||||
AAC = 28, /* Advanced Audio Coding (raw without .mp4) */
|
||||
TGC = 29 /* Tiger Game.com 4-bit ADPCM */
|
||||
} txth_type;
|
||||
|
||||
typedef struct {
|
||||
@ -221,6 +222,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
case PCM4: coding = coding_PCM4; break;
|
||||
case PCM4_U: coding = coding_PCM4_U; break;
|
||||
case OKI16: coding = coding_OKI16; break;
|
||||
case TGC: coding = coding_TGC; break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
@ -266,6 +268,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
case coding_IMA:
|
||||
case coding_AICA:
|
||||
case coding_APPLE_IMA4:
|
||||
case coding_TGC:
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
if (vgmstream->channels > 1)
|
||||
@ -843,6 +846,8 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
||||
else if (is_string(val,"PCM4_U")) txth->codec = PCM4_U;
|
||||
else if (is_string(val,"OKI16")) txth->codec = OKI16;
|
||||
else if (is_string(val,"AAC")) txth->codec = AAC;
|
||||
else if (is_string(val,"TGC")) txth->codec = TGC;
|
||||
else if (is_string(val,"GCOM_ADPCM")) txth->codec = TGC;
|
||||
else goto fail;
|
||||
|
||||
/* set common interleaves to simplify usage
|
||||
@ -1698,6 +1703,7 @@ static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) {
|
||||
return pcm_bytes_to_samples(bytes, txth->channels, 8);
|
||||
case PCM4:
|
||||
case PCM4_U:
|
||||
case TGC:
|
||||
return pcm_bytes_to_samples(bytes, txth->channels, 4);
|
||||
case MSADPCM:
|
||||
return msadpcm_bytes_to_samples(bytes, txth->interleave, txth->channels);
|
||||
|
@ -487,6 +487,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_xma_ue3,
|
||||
init_vgmstream_csb,
|
||||
init_vgmstream_fda,
|
||||
init_vgmstream_tgc,
|
||||
|
||||
/* 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 */
|
||||
@ -2031,6 +2032,12 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_TGC:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_tgc(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->samples_into_block,samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_NDS_PROCYON:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_nds_procyon(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
|
@ -154,6 +154,8 @@ typedef enum {
|
||||
coding_ASKA, /* Aska ADPCM */
|
||||
coding_NXAP, /* NXAP ADPCM */
|
||||
|
||||
coding_TGC, /* Tiger Game.com 4-bit ADPCM */
|
||||
|
||||
coding_NDS_PROCYON, /* Procyon Studio ADPCM */
|
||||
coding_L5_555, /* Level-5 0x555 ADPCM */
|
||||
coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/
|
||||
@ -720,7 +722,7 @@ typedef enum {
|
||||
meta_XSSB,
|
||||
meta_XMA_UE3,
|
||||
meta_FDA,
|
||||
|
||||
meta_TGC,
|
||||
} meta_t;
|
||||
|
||||
/* standard WAVEFORMATEXTENSIBLE speaker positions */
|
||||
|
Loading…
Reference in New Issue
Block a user