Clean DTK decoder to clarify similarities with XA

This commit is contained in:
bnnm 2018-08-03 00:46:36 +02:00
parent 16f2474a50
commit e1434bc432
2 changed files with 53 additions and 35 deletions

View File

@ -1,51 +1,65 @@
#include "coding.h"
#include "../util.h"
/* 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) {
int i=first_sample;
int32_t sample_count;
int framesin = first_sample/28;
uint8_t q = read_8bit(framesin*32+stream->offset+channel,stream->streamfile);
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;
int32_t hist1 = stream->adpcm_history1_32;
int32_t hist2 = stream->adpcm_history2_32;
first_sample = first_sample%28;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int sample_byte = read_8bit(framesin*32+stream->offset+4+i,stream->streamfile);
/* 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;
int32_t hist=0;
/* 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);
switch (q>>4)
{
/* 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);
/* apply XA filters << 6 */
switch(coef_index) {
case 0:
hist = 0;
hist = 0; // (hist1 * 0) - (hist2 * 0);
break;
case 1:
hist = (hist1 * 0x3c);
hist = (hist1 * 60); // - (hist2 * 0);
break;
case 2:
hist = (hist1 * 0x73) - (hist2 * 0x34);
hist = (hist1 * 115) - (hist2 * 52);
break;
case 3:
hist = (hist1 * 0x62) - (hist2 * 0x37);
hist = (hist1 * 98) - (hist2 * 55);
break;
}
hist = (hist+0x20)>>6;
hist = (hist + 32) >> 6;
if (hist > 0x1fffff) hist = 0x1fffff;
if (hist < -0x200000) hist = -0x200000;
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;
hist2 = hist1;
hist1 = new_sample;
hist1 = ((((channel==0?
get_low_nibble_signed(sample_byte):
get_high_nibble_signed(sample_byte)
) << 12) >> (q & 0xf)) << 6) + hist;
outbuf[sample_count] = clamp16(hist1 >> 6);
outbuf[sample_count] = clamp16(new_sample >> 6);
sample_count += channelspacing;
}
stream->adpcm_history1_32 = hist1;

View File

@ -2,40 +2,45 @@
#include "meta.h"
#include "../util.h"
/* DTK - headerless Nintendo DTK file [Harvest Moon - Another Wonderful Life (GC), XGRA (GC)] */
/* DTK - headerless Nintendo GC DTK file [Harvest Moon: Another Wonderful Life (GC), XGRA (GC)] */
VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset = 0;
int channel_count = 2, loop_flag = 0; /* always stereo, no loop */
off_t start_offset;
int channel_count, loop_flag;
/* checks */
/* dtk: standard [XGRA (GC)], adp: standard [Harvest Moon AWL (GC)], wav/lwav: Alien Hominid (GC) */
/* .dtk: standard [XGRA (GC)], .adp: standard [Harvest Moon AWL (GC)], .wav/lwav: Alien Hominid (GC) */
if ( !check_extensions(streamFile,"dtk,adp,wav,lwav"))
goto fail;
/* files have no header, and the ext is common, so all we can do is look for valid first frames */
if (check_extensions(streamFile,"adp,wav,lwav")) {
/* check valid frames as files have no header, and .adp/wav are common */
{
int i;
for (i = 0; i < 10; i++) { /* try a bunch of frames */
if (read_8bit(0x00 + i*0x20,streamFile) != read_8bit(0x02 + i*0x20,streamFile) ||
read_8bit(0x01 + i*0x20,streamFile) != read_8bit(0x03 + i*0x20,streamFile))
goto fail;
/* header 0x00/01 are repeated in 0x02/03 (for error correction?),
* could also test header values (upper nibble should be 0..3, and lower nibble 0..C) */
}
}
/* always stereo, no loop (since it's hardware-decoded and streamed) */
channel_count = 2;
loop_flag = 0;
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->num_samples = get_streamfile_size(streamFile) / 32 * 28;
vgmstream->sample_rate = 48000;
vgmstream->num_samples = get_streamfile_size(streamFile) / 0x20 * 28;
vgmstream->sample_rate = 48000; /* due to a GC hardware defect this may be closer to 48043 */
vgmstream->coding_type = coding_NGC_DTK;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_NGC_ADPDTK;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
@ -45,4 +50,3 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}