mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-21 02:45:52 +01:00
53 lines
1.8 KiB
C
53 lines
1.8 KiB
C
#include "coding.h"
|
|
|
|
|
|
static const int dsa_coefs[16] = {
|
|
0x0, 0x1999, 0x3333, 0x4CCC,
|
|
0x6666, 0x8000, 0x9999, 0xB333,
|
|
0xCCCC, 0xE666, 0x10000, 0x11999,
|
|
0x13333, 0x18000, 0x1CCCC, 0x21999
|
|
};
|
|
|
|
/* Decodes Ocean DSA ADPCM codec from Last Rites (PC).
|
|
* Reverse engineered from daemon1's reverse engineering. */
|
|
void decode_dsa(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
|
off_t frame_offset;
|
|
int i, frames_in, sample_count = 0;
|
|
size_t bytes_per_frame, samples_per_frame;
|
|
uint8_t header;
|
|
int shift, filter;
|
|
int32_t hist1 = stream->adpcm_history1_32;
|
|
|
|
/* external interleave (fixed size), mono */
|
|
bytes_per_frame = 0x08;
|
|
samples_per_frame = (bytes_per_frame - 0x01) * 2;
|
|
frames_in = first_sample / samples_per_frame;
|
|
first_sample = first_sample % samples_per_frame;
|
|
|
|
/* parse frame header */
|
|
frame_offset = stream->offset + bytes_per_frame*frames_in;
|
|
header = (uint8_t)read_8bit(frame_offset+0x00,stream->streamfile);
|
|
shift = 0x0c - ((header >> 4) & 0xf);
|
|
filter = dsa_coefs[header & 0xf];
|
|
|
|
/* decode nibbles */
|
|
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
|
int32_t sample;
|
|
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01 + i/2,stream->streamfile);
|
|
|
|
sample = i&1 ? /* high nibble first */
|
|
(nibbles >> 0) & 0xf :
|
|
(nibbles >> 4) & 0xf;
|
|
|
|
sample = ((int16_t)(sample << 0xC) >> shift); /* 16b sign extend + scale */
|
|
sample = sample + ((hist1 * filter) >> 0x10);
|
|
|
|
outbuf[sample_count] = (sample_t)(sample << 2);
|
|
sample_count += channelspacing;
|
|
|
|
hist1 = sample;
|
|
}
|
|
|
|
stream->adpcm_history1_32 = hist1;
|
|
}
|