mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 23:10:10 +01:00
Clean DTK decoder to clarify similarities with XA
This commit is contained in:
parent
16f2474a50
commit
e1434bc432
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user