Add Tantalus .tad decoder [House of the Dead (SAT)]

This commit is contained in:
bnnm 2021-07-23 22:30:57 +02:00
parent 2fcc3d69e4
commit 93339ba2bc
12 changed files with 157 additions and 0 deletions

View File

@ -751,6 +751,7 @@ are used in few games.
- Konami XMD 4-bit ADPCM - Konami XMD 4-bit ADPCM
- Platinum 4-bit ADPCM - Platinum 4-bit ADPCM
- Argonaut ASF 4-bit ADPCM - Argonaut ASF 4-bit ADPCM
- Tantalus 4-bit ADPCM
- Ocean DSA 4-bit ADPCM - Ocean DSA 4-bit ADPCM
- Circus XPCM ADPCM - Circus XPCM ADPCM
- Circus XPCM VQ - Circus XPCM VQ

View File

@ -224,6 +224,11 @@ void decode_dsa(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing,
void decode_xmd(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size); void decode_xmd(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size);
/* tantalus_decoder */
void decode_tantalus(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
int32_t tantalus_bytes_to_samples(size_t bytes, int channels);
/* derf_decoder */ /* derf_decoder */
void decode_derf(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_derf(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);

View File

@ -0,0 +1,63 @@
#include "coding.h"
/* Decodes Tantalus TADC ADPCM codec, used in Saturn games.
* Guessed based on other XA-style codecs values. */
void decode_tantalus(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x10] = {0};
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
int shift, filter, coef1, coef2;
int32_t hist1 = stream->adpcm_history1_32;
int32_t hist2 = stream->adpcm_history2_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x10;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
//first_sample = first_sample % samples_per_frame; /* for flat layout */
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame*frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
filter = (frame[0x00] >> 4) & 0xf; /* 0 in tested files */
shift = (frame[0x00] >> 0) & 0xf;
if (filter != 0) {
VGM_LOG_ONCE("TANTALUS: unknown filter\n");
coef1 = 64;
coef2 = 64; /* will sound horrid and hopefully reported */
}
else {
coef1 = 64;
coef2 = 0;
}
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
uint8_t nibbles = frame[0x01 + i/2];
int32_t sample;
sample = i&1 ? /* low nibble first */
get_high_nibble_signed(nibbles) :
get_low_nibble_signed(nibbles);
sample = sample << (shift + 6);
sample = (sample + (hist1 * coef1) + (hist2 * coef2)) >> 6;
outbuf[sample_count] = clamp16(sample);
sample_count += channelspacing;
hist2 = hist1;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}
int32_t tantalus_bytes_to_samples(size_t bytes, int channels) {
if (channels <= 0) return 0;
return bytes / channels / 0x10 * 30;
}

View File

@ -503,6 +503,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
return 256; /* (0x8c - 0xc) * 2 */ return 256; /* (0x8c - 0xc) * 2 */
case coding_ASF: case coding_ASF:
return 32; /* (0x11 - 0x1) * 2 */ return 32; /* (0x11 - 0x1) * 2 */
case coding_TANTALUS:
return 30; /* (0x10 - 0x01) * 2 */
case coding_DSA: case coding_DSA:
return 14; /* (0x08 - 0x1) * 2 */ return 14; /* (0x08 - 0x1) * 2 */
case coding_XMD: case coding_XMD:
@ -716,6 +718,8 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
return 0x8c; return 0x8c;
case coding_ASF: case coding_ASF:
return 0x11; return 0x11;
case coding_TANTALUS:
return 0x10;
case coding_DSA: case coding_DSA:
return 0x08; return 0x08;
case coding_XMD: case coding_XMD:
@ -1386,6 +1390,12 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
vgmstream->channels, vgmstream->samples_into_block, samples_to_do); vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
} }
break; break;
case coding_TANTALUS:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_tantalus(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
}
break;
case coding_DSA: case coding_DSA:
for (ch = 0; ch < vgmstream->channels; ch++) { for (ch = 0; ch < vgmstream->channels; ch++) {
decode_dsa(&vgmstream->ch[ch], buffer+ch, decode_dsa(&vgmstream->ch[ch], buffer+ch,

View File

@ -515,6 +515,7 @@ static const char* extension_list[] = {
"sxd2", "sxd2",
"sxd3", "sxd3",
"tad",
"tec", "tec",
"tgq", "tgq",
"thp", "thp",
@ -787,6 +788,7 @@ static const coding_info coding_info_list[] = {
{coding_MC3, "Paradigm MC3 3-bit ADPCM"}, {coding_MC3, "Paradigm MC3 3-bit ADPCM"},
{coding_FADPCM, "FMOD FADPCM 4-bit ADPCM"}, {coding_FADPCM, "FMOD FADPCM 4-bit ADPCM"},
{coding_ASF, "Argonaut ASF 4-bit ADPCM"}, {coding_ASF, "Argonaut ASF 4-bit ADPCM"},
{coding_TANTALUS, "Tantalus 4-bit ADPCM"},
{coding_DSA, "Ocean DSA 4-bit ADPCM"}, {coding_DSA, "Ocean DSA 4-bit ADPCM"},
{coding_XMD, "Konami XMD 4-bit ADPCM"}, {coding_XMD, "Konami XMD 4-bit ADPCM"},
{coding_PCFX, "PC-FX 4-bit ADPCM"}, {coding_PCFX, "PC-FX 4-bit ADPCM"},
@ -1350,6 +1352,7 @@ static const meta_info meta_info_list[] = {
{meta_IDSP_TOSE, "TOSE .IDSP header"}, {meta_IDSP_TOSE, "TOSE .IDSP header"},
{meta_DSP_KWA, "Kuju London .KWA header"}, {meta_DSP_KWA, "Kuju London .KWA header"},
{meta_OGV_3RDEYE, "3rdEye .OGV header"}, {meta_OGV_3RDEYE, "3rdEye .OGV header"},
{meta_PIFF_TPCM, "Tantalus PIFF TPCM header"},
}; };
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {

View File

@ -1201,6 +1201,10 @@
<File <File
RelativePath=".\meta\pcm_success.c" RelativePath=".\meta\pcm_success.c"
> >
</File>
<File
RelativePath=".\meta\piff_tpcm.c"
>
</File> </File>
<File <File
RelativePath=".\meta\scd_pcm.c" RelativePath=".\meta\scd_pcm.c"
@ -2354,6 +2358,10 @@
RelativePath=".\coding\tac_decoder_lib.c" RelativePath=".\coding\tac_decoder_lib.c"
> >
</File> </File>
<File
RelativePath=".\coding\tantalus_decoder.c"
>
</File>
<File <File
RelativePath=".\coding\ubi_adpcm_decoder.c" RelativePath=".\coding\ubi_adpcm_decoder.c"
> >

View File

@ -430,6 +430,7 @@
<ClCompile Include="meta\xa_xa30.c" /> <ClCompile Include="meta\xa_xa30.c" />
<ClCompile Include="meta\pcm_sre.c" /> <ClCompile Include="meta\pcm_sre.c" />
<ClCompile Include="meta\pcm_success.c" /> <ClCompile Include="meta\pcm_success.c" />
<ClCompile Include="meta\piff_tpcm.c" />
<ClCompile Include="meta\scd_pcm.c" /> <ClCompile Include="meta\scd_pcm.c" />
<ClCompile Include="meta\pona.c" /> <ClCompile Include="meta\pona.c" />
<ClCompile Include="meta\pos.c" /> <ClCompile Include="meta\pos.c" />
@ -646,6 +647,7 @@
<ClCompile Include="coding\speex_decoder.c" /> <ClCompile Include="coding\speex_decoder.c" />
<ClCompile Include="coding\tac_decoder.c" /> <ClCompile Include="coding\tac_decoder.c" />
<ClCompile Include="coding\tac_decoder_lib.c" /> <ClCompile Include="coding\tac_decoder_lib.c" />
<ClCompile Include="coding\tantalus_decoder.c" />
<ClCompile Include="coding\ubi_adpcm_decoder.c" /> <ClCompile Include="coding\ubi_adpcm_decoder.c" />
<ClCompile Include="coding\vadpcm_decoder.c" /> <ClCompile Include="coding\vadpcm_decoder.c" />
<ClCompile Include="coding\vorbis_custom_decoder.c" /> <ClCompile Include="coding\vorbis_custom_decoder.c" />

View File

@ -787,6 +787,9 @@
<ClCompile Include="meta\pcm_success.c"> <ClCompile Include="meta\pcm_success.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\piff_tpcm.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\scd_pcm.c"> <ClCompile Include="meta\scd_pcm.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1408,6 +1411,9 @@
<ClCompile Include="coding\tac_decoder.c"> <ClCompile Include="coding\tac_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="coding\tantalus_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\tac_decoder_lib.c"> <ClCompile Include="coding\tac_decoder_lib.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -951,4 +951,6 @@ VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_sspr(STREAMFILE* sf); VGMSTREAM* init_vgmstream_sspr(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_piff_tpcm(STREAMFILE* sf);
#endif /*_META_H*/ #endif /*_META_H*/

54
src/meta/piff_tpcm.c Normal file
View File

@ -0,0 +1,54 @@
#include "meta.h"
#include "../coding/coding.h"
/* PIFF TADH - from Tantalus games [House of the Dead (SAT)] */
VGMSTREAM* init_vgmstream_piff_tpcm(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset, header_offset, data_size;
int loop_flag, channels, sample_rate;
/* checks */
/* .tad: from internal filenames */
if (!check_extensions(sf, "tad"))
goto fail;
/* Tantalus also has PIFF without this */
if (!is_id32be(0x00,sf, "PIFF") || !is_id32be(0x08,sf, "TPCM") || !is_id32be(0x0c,sf, "TADH"))
goto fail;
header_offset = 0x14;
/* 0x00: 1? */
/* 0x01: 1? */
channels = read_u16le(header_offset + 0x02,sf);
sample_rate = read_s32le(header_offset + 0x04,sf);
/* 0x08+: ? (mostly fixed, maybe related to ADPCM?) */
loop_flag = 0;
if (!is_id32be(0x38,sf, "BODY"))
goto fail;
start_offset = 0x40;
data_size = read_u32le(0x3c,sf);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PIFF_TPCM;
vgmstream->sample_rate = sample_rate;
vgmstream->coding_type = coding_TANTALUS;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->num_samples = tantalus_bytes_to_samples(data_size, channels);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -525,6 +525,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_dsp_kwa, init_vgmstream_dsp_kwa,
init_vgmstream_ogv_3rdeye, init_vgmstream_ogv_3rdeye,
init_vgmstream_sspr, init_vgmstream_sspr,
init_vgmstream_piff_tpcm,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ /* 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 */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */

View File

@ -164,6 +164,7 @@ typedef enum {
coding_ASF, /* Argonaut ASF 4-bit ADPCM */ coding_ASF, /* Argonaut ASF 4-bit ADPCM */
coding_DSA, /* Ocean DSA 4-bit ADPCM */ coding_DSA, /* Ocean DSA 4-bit ADPCM */
coding_XMD, /* Konami XMD 4-bit ADPCM */ coding_XMD, /* Konami XMD 4-bit ADPCM */
coding_TANTALUS, /* Tantalus 4-bit ADPCM */
coding_PCFX, /* PC-FX 4-bit ADPCM */ coding_PCFX, /* PC-FX 4-bit ADPCM */
coding_OKI16, /* OKI 4-bit ADPCM with 16-bit output and modified expand */ coding_OKI16, /* OKI 4-bit ADPCM with 16-bit output and modified expand */
coding_OKI4S, /* OKI 4-bit ADPCM with 16-bit output and cuadruple step */ coding_OKI4S, /* OKI 4-bit ADPCM with 16-bit output and cuadruple step */
@ -752,6 +753,7 @@ typedef enum {
meta_IDSP_TOSE, meta_IDSP_TOSE,
meta_DSP_KWA, meta_DSP_KWA,
meta_OGV_3RDEYE, meta_OGV_3RDEYE,
meta_PIFF_TPCM,
} meta_t; } meta_t;
/* standard WAVEFORMATEXTENSIBLE speaker positions */ /* standard WAVEFORMATEXTENSIBLE speaker positions */