2008-05-06 05:35:37 +02:00
|
|
|
#include "coding.h"
|
2008-02-13 15:31:21 +01:00
|
|
|
#include "../util.h"
|
|
|
|
|
|
|
|
|
2018-08-03 00:46:36 +02:00
|
|
|
/* Nintendo GC Disc TracK streaming ADPCM (similar to CD-XA) */
|
|
|
|
void decode_ngc_dtk(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
|
|
|
off_t frame_offset;
|
|
|
|
int i, frames_in, sample_count = 0;
|
|
|
|
size_t bytes_per_frame, samples_per_frame;
|
|
|
|
uint8_t coef_index, shift_factor;
|
2008-02-13 15:31:21 +01:00
|
|
|
int32_t hist1 = stream->adpcm_history1_32;
|
|
|
|
int32_t hist2 = stream->adpcm_history2_32;
|
|
|
|
|
|
|
|
|
2018-08-03 00:46:36 +02:00
|
|
|
/* external interleave (fixed size), stereo */
|
|
|
|
bytes_per_frame = 0x20;
|
|
|
|
samples_per_frame = 28;
|
|
|
|
frames_in = first_sample / samples_per_frame;
|
|
|
|
first_sample = first_sample % samples_per_frame;
|
|
|
|
|
|
|
|
/* parse frame L/R header (repeated at 0x03/04) */
|
|
|
|
frame_offset = stream->offset + bytes_per_frame*frames_in;
|
|
|
|
coef_index = ((uint8_t)read_8bit(frame_offset+channel,stream->streamfile) >> 4) & 0xf;
|
|
|
|
shift_factor = ((uint8_t)read_8bit(frame_offset+channel,stream->streamfile) >> 0) & 0xf;
|
|
|
|
/* rare but happens, also repeated headers don't match (ex. Ikaruga (GC) SONG02.adp) */
|
|
|
|
VGM_ASSERT_ONCE(coef_index > 4 || shift_factor > 12, "DTK: incorrect coefs/shift at %lx\n", frame_offset);
|
2008-02-13 15:31:21 +01:00
|
|
|
|
2018-08-03 00:46:36 +02:00
|
|
|
/* decode nibbles */
|
|
|
|
for (i = first_sample; i < first_sample+samples_to_do; i++) {
|
|
|
|
int32_t hist = 0, new_sample;
|
|
|
|
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x04+i,stream->streamfile);
|
2008-02-13 15:31:21 +01:00
|
|
|
|
2018-08-03 00:46:36 +02:00
|
|
|
/* apply XA filters << 6 */
|
|
|
|
switch(coef_index) {
|
2008-02-13 15:31:21 +01:00
|
|
|
case 0:
|
2018-08-03 00:46:36 +02:00
|
|
|
hist = 0; // (hist1 * 0) - (hist2 * 0);
|
2008-02-13 15:31:21 +01:00
|
|
|
break;
|
|
|
|
case 1:
|
2018-08-03 00:46:36 +02:00
|
|
|
hist = (hist1 * 60); // - (hist2 * 0);
|
2008-02-13 15:31:21 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2018-08-03 00:46:36 +02:00
|
|
|
hist = (hist1 * 115) - (hist2 * 52);
|
2008-02-13 15:31:21 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
2018-08-03 00:46:36 +02:00
|
|
|
hist = (hist1 * 98) - (hist2 * 55);
|
2008-02-13 15:31:21 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-08-03 00:46:36 +02:00
|
|
|
hist = (hist + 32) >> 6;
|
2008-02-13 15:31:21 +01:00
|
|
|
if (hist > 0x1fffff) hist = 0x1fffff;
|
|
|
|
if (hist < -0x200000) hist = -0x200000;
|
|
|
|
|
2018-08-03 00:46:36 +02:00
|
|
|
new_sample = (channel==0) ? /* L=low nibble first */
|
|
|
|
get_low_nibble_signed(nibbles) :
|
|
|
|
get_high_nibble_signed(nibbles);
|
|
|
|
new_sample = (new_sample << 12) >> shift_factor;
|
|
|
|
new_sample = (new_sample << 6) + hist;
|
2008-02-13 15:31:21 +01:00
|
|
|
|
2018-08-03 00:46:36 +02:00
|
|
|
hist2 = hist1;
|
|
|
|
hist1 = new_sample;
|
2008-02-13 15:31:21 +01:00
|
|
|
|
2018-08-03 00:46:36 +02:00
|
|
|
outbuf[sample_count] = clamp16(new_sample >> 6);
|
|
|
|
sample_count += channelspacing;
|
2008-02-13 15:31:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
stream->adpcm_history1_32 = hist1;
|
|
|
|
stream->adpcm_history2_32 = hist2;
|
|
|
|
}
|