mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-06 06:34:21 +01:00
64 lines
2.1 KiB
C
64 lines
2.1 KiB
C
#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;
|
|
}
|