Fix multichannel/variable frame ASKA ADPCM [Resonance of Fate (PC)]

This commit is contained in:
bnnm 2020-10-17 19:00:33 +02:00
parent 6fc5e604e7
commit e325a739f8
3 changed files with 51 additions and 36 deletions

View File

@ -165,10 +165,10 @@ int msadpcm_check_coefs(STREAMFILE* sf, off_t offset);
/* yamaha_decoder */
void decode_aica(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
void decode_aska(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_aska(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, size_t frame_size);
void decode_nxap(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
size_t yamaha_bytes_to_samples(size_t bytes, int channels);
size_t aska_bytes_to_samples(size_t bytes, int channels);
size_t aska_bytes_to_samples(size_t bytes, size_t frame_size, int channels);
/* tgcadpcm_decoder */

View File

@ -19,10 +19,10 @@ static const int scale_delta[16] = {
};
/* Yamaha ADPCM-B (aka DELTA-T) expand used in YM2608/YM2610/etc (cross referenced with various sources and .so) */
static void yamaha_adpcmb_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t* hist1, int32_t* step_size, int16_t *out_sample) {
static void yamaha_adpcmb_expand_nibble(uint8_t byte, int shift, int32_t* hist1, int32_t* step_size, int16_t *out_sample) {
int code, delta, sample;
code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf;
code = (byte >> shift) & 0xf;
delta = ((((code & 0x7) * 2) + 1) * (*step_size)) >> 3; /* like 'mul' IMA */
if (code & 8)
delta = -delta;
@ -109,38 +109,47 @@ void decode_aica(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacin
/* tri-Ace Aska ADPCM, Yamaha ADPCM-B with headered frames (reversed from Android SO's .so)
* implements table with if-else/switchs too but that's too goofy */
void decode_aska(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0, num_frame;
void decode_aska(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, size_t frame_size) {
uint8_t frame[0x100] = {0}; /* known max is 0xC0 */
off_t frame_offset;
int i, sample_count = 0, frames_in;
int16_t out_sample;
int32_t hist1 = stream->adpcm_history1_32;
int step_size = stream->adpcm_step_index;
/* external interleave */
int block_samples = (0x40 - 0x04*channelspacing) * 2 / channelspacing;
num_frame = first_sample / block_samples;
int block_samples = (frame_size - 0x04*channelspacing) * 2 / channelspacing;
frames_in = first_sample / block_samples;
first_sample = first_sample % block_samples;
if (frame_size > sizeof(frame)) {
VGM_LOG_ONCE("ASKA: unknown frame size %x\n", frame_size);
return;
}
/* parse frame */
frame_offset = stream->offset + frame_size * frames_in;
read_streamfile(frame, frame_offset, frame_size, stream->streamfile); /* ignore EOF errors */
/* header (hist+step) */
if (first_sample == 0) {
off_t header_offset = stream->offset + 0x40*num_frame + 0x04*channel;
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
step_size = read_16bitLE(header_offset+0x02,stream->streamfile);
/* in most files 1st frame has step 0 but it seems ok and accounted for */
hist1 = get_s16le(frame + 0x04*channel + 0x00);
step_size = get_s16le(frame + 0x04*channel + 0x02);
/* in most files 1st frame has step 0 but it seems ok and needed for correct waveform */
//if (step_size < 0x7f) step_size = 0x7f;
//else if (step_size > 0x6000) step_size = 0x6000;
}
/* decode nibbles (layout: varies) */
/* decode nibbles (layout: one nibble per channel, low-high order, ex 6ch=10325410 32541032 ...) */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
off_t byte_offset = (channelspacing == 2) ?
(stream->offset + 0x40*num_frame + 0x04*channelspacing) + i : /* stereo: one nibble per channel */
(stream->offset + 0x40*num_frame + 0x04*channelspacing) + i/2; /* mono: consecutive nibbles */
int nibble_shift = (channelspacing == 2) ?
(!(channel&1) ? 0:4) :
(!(i&1) ? 0:4); /* even = low, odd = high */
int pos = (channelspacing == 1) ?
(0x04*channelspacing) + i/2 :
(0x04*channelspacing) + (i * 4 * channelspacing + 4*channel) / 8; /* nibble position to closest byte */
int shift = (channelspacing == 1) ? /* low first */
(!(i&1) ? 0:4) :
(!(channel&1) ? 0:4);
yamaha_adpcmb_expand_nibble(stream, byte_offset, nibble_shift, &hist1, &step_size, &out_sample);
yamaha_adpcmb_expand_nibble(frame[pos], shift, &hist1, &step_size, &out_sample);
outbuf[sample_count] = out_sample;
sample_count += channelspacing;
}
@ -150,24 +159,29 @@ void decode_aska(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacin
}
/* NXAP ADPCM, Yamaha ADPCM-B with weird headered frames */
/* NXAP ADPCM, Yamaha ADPCM-B with weird headered frames, partially rev'd from the ELF */
void decode_nxap(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count = 0, num_frame;
uint8_t frame[0x40] = {0}; /* known max is 0xC0 */
off_t frame_offset;
int i, sample_count = 0, frames_in;
int32_t hist1 = stream->adpcm_history1_32;
int step_size = stream->adpcm_step_index;
int16_t out_sample;
/* external interleave, mono */
int block_samples = (0x40 - 0x4) * 2;
num_frame = first_sample / block_samples;
size_t frame_size = 0x40;
int block_samples = (frame_size - 0x4) * 2;
frames_in = first_sample / block_samples;
first_sample = first_sample % block_samples;
/* parse frame */
frame_offset = stream->offset + frame_size * frames_in;
read_streamfile(frame, frame_offset, frame_size, stream->streamfile); /* ignore EOF errors */
/* header (hist+step) */
if (first_sample == 0) {
off_t header_offset = stream->offset + 0x40*num_frame;
hist1 = read_s16le(header_offset+0x00,stream->streamfile);
step_size = read_u16le(header_offset+0x02,stream->streamfile) >> 1; /* remove lower bit, also note unsignedness */
hist1 = get_s16le(frame + 0x00);
step_size = get_u16le(frame + 0x02) >> 1; /* remove lower bit, also note unsignedness */
if (step_size < 0x7f) step_size = 0x7f;
else if (step_size > 0x6000) step_size = 0x6000;
/* step's lower bit is hist1 sign (useless), and code doesn't seem to do anything useful with it? */
@ -175,10 +189,10 @@ void decode_nxap(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacin
/* decode nibbles (layout: all nibbles from one channel) */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
off_t byte_offset = (stream->offset + 0x40*num_frame + 0x04) + i/2;
int nibble_shift = (i&1?0:4);
int pos = 0x04 + i/2;
int shift = (i&1?0:4);
yamaha_adpcmb_expand_nibble(stream, byte_offset, nibble_shift, &hist1, &step_size, &out_sample);
yamaha_adpcmb_expand_nibble(frame[pos], shift, &hist1, &step_size, &out_sample);
outbuf[sample_count] = out_sample;
sample_count += channelspacing;
}
@ -193,8 +207,8 @@ size_t yamaha_bytes_to_samples(size_t bytes, int channels) {
return bytes * 2 / channels;
}
size_t aska_bytes_to_samples(size_t bytes, int channels) {
int block_align = 0x40;
size_t aska_bytes_to_samples(size_t bytes, size_t frame_size, int channels) {
int block_align = frame_size;
if (channels <= 0) return 0;
return (bytes / block_align) * (block_align - 0x04*channels) * 2 / channels
+ ((bytes % block_align) ? ((bytes % block_align) - 0x04*channels) * 2 / channels : 0);

View File

@ -425,7 +425,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
case coding_AICA_int:
return 2;
case coding_ASKA:
return (0x40-0x04*vgmstream->channels) * 2 / vgmstream->channels;
return (vgmstream->frame_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels;
case coding_NXAP:
return (0x40-0x04) * 2;
case coding_NDS_PROCYON:
@ -626,6 +626,7 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
case coding_AICA_int:
return 0x01;
case coding_ASKA:
return vgmstream->frame_size;
case coding_NXAP:
return 0x40;
case coding_NDS_PROCYON:
@ -1249,7 +1250,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
case coding_ASKA:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_aska(&vgmstream->ch[ch], buffer+ch,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch, vgmstream->frame_size);
}
break;
case coding_NXAP: