when decoding ADPCM data, don't step over multiple samples at a time (or else the decode state is corrupt)

This commit is contained in:
Anthony Pesch 2017-05-08 01:17:29 -04:00
parent 80b103760a
commit 4b8f969307
2 changed files with 111 additions and 93 deletions

View File

@ -26,6 +26,7 @@ DEFINE_AGGREGATE_COUNTER(aica_samples);
#define AICA_NUM_CHANNELS 64
#define AICA_FNS_BITS 10
#define AICA_STEP_SAMPLE (1 << AICA_FNS_BITS)
#define AICA_OFFSET_POS(s) (s >> AICA_FNS_BITS)
#define AICA_OFFSET_FRAC(s) (s & ((1 << AICA_FNS_BITS) - 1))
@ -384,7 +385,7 @@ static void aica_rtc_timer(void *data) {
static uint32_t aica_channel_step(struct aica_channel *ch) {
/* by default, step the stream a single sample at a time */
uint32_t step = 1 << AICA_FNS_BITS;
uint32_t step = AICA_STEP_SAMPLE;
/* FNS represents the fractional portion of a step, used to linearly
interpolate between samples */
@ -419,6 +420,7 @@ static void aica_channel_start(struct aica *aica, struct aica_channel *ch) {
uint32_t start_addr = (ch->data->SA_hi << 16) | ch->data->SA_lo;
ch->active = 1;
ch->looped = 0;
ch->base = &aica->wave_ram[start_addr];
ch->step = aica_channel_step(ch);
ch->offset = 0;
@ -456,61 +458,70 @@ static int32_t aica_channel_update(struct aica *aica, struct aica_channel *ch) {
CHECK_NOTNULL(ch->base);
uint32_t pos = AICA_OFFSET_POS(ch->offset);
uint32_t frac = AICA_OFFSET_FRAC(ch->offset);
/* the data returned is a signed 16-bit PCM data, but signed 32-bit values are
used intermediately to avoid dealing with overflows until the end */
int32_t next_sample = 0;
int32_t next_quant = 0;
switch (ch->data->PCMS) {
/* 16-bit signed PCM */
case 0: {
next_sample = *(int16_t *)&ch->base[pos << 1];
} break;
/* note, a step may skip more than one sample. for ADPCM channels at least,
each of these intermediate samples must be processed due to its delta-
based decoding */
uint32_t next_offset = ch->offset + ch->step;
uint32_t next_pos = AICA_OFFSET_POS(next_offset);
uint32_t next_frac = AICA_OFFSET_FRAC(next_offset);
uint32_t pos = AICA_OFFSET_POS(ch->offset);
/* 8-bit signed PCM */
case 1: {
next_sample = *(int8_t *)&ch->base[pos] << 8;
} break;
while (pos < next_pos) {
switch (ch->data->PCMS) {
case AICA_PCM_S16: {
next_sample = *(int16_t *)&ch->base[pos << 1];
} break;
/* 4-bit ADPCM */
case 2:
case 3: {
int shift = (pos & 1) << 2;
int32_t data = (ch->base[pos >> 1] >> shift) & 0xf;
aica_decode_adpcm(data, ch->prev_sample, ch->prev_quant, &next_sample,
&next_quant);
} break;
case AICA_PCM_S8: {
next_sample = *(int8_t *)&ch->base[pos] << 8;
} break;
default:
LOG_WARNING("Unsupported PCMS %d", ch->data->PCMS);
break;
case AICA_ADPCM:
case AICA_ADPCM_STREAM: {
int shift = (pos & 1) << 2;
int32_t data = (ch->base[pos >> 1] >> shift) & 0xf;
aica_decode_adpcm(data, ch->prev_sample, ch->prev_quant, &next_sample,
&next_quant);
} break;
default:
LOG_WARNING("Unsupported PCMS %d", ch->data->PCMS);
break;
}
ch->prev_sample = next_sample;
ch->prev_quant = next_quant;
pos++;
}
/* interpolate sample */
int32_t result = ch->prev_sample * ((1 << AICA_FNS_BITS) - frac);
result += next_sample * frac;
result >>= AICA_FNS_BITS;
ch->offset = next_offset;
/* step forward */
ch->offset += ch->step;
ch->prev_sample = next_sample;
ch->prev_quant = next_quant;
/* interpolate sample */
int32_t result = ch->prev_sample * (AICA_STEP_SAMPLE - next_frac);
result += next_sample * next_frac;
result >>= AICA_FNS_BITS;
/* check if the current position in the sound source has passed the loop end
position */
if (pos > ch->data->LEA) {
if (ch->data->LPCTL) {
/* restart channel at LSA */
LOG_AICA("aica_channel_step %d restart", ch - aica->channels);
ch->offset = ch->data->LSA << AICA_FNS_BITS;
ch->prev_sample = 0;
ch->prev_quant = ADPCM_QUANT_MIN;
ch->looped = 1;
} else {
aica_channel_stop(aica, ch);
if (next_pos > ch->data->LEA) {
switch (ch->data->LPCTL) {
case AICA_LOOP_NONE: {
aica_channel_stop(aica, ch);
} break;
case AICA_LOOP_FORWARD: {
/* restart channel at LSA */
LOG_AICA("aica_channel_step %d restart", ch - aica->channels);
ch->looped = 1;
ch->offset = ch->data->LSA << AICA_FNS_BITS;
ch->prev_sample = 0;
ch->prev_quant = ADPCM_QUANT_MIN;
} break;
}
}

View File

@ -3,7 +3,7 @@
#include <stdint.h>
// interrupts
/* interrupts */
enum {
AICA_INT_INTON,
AICA_INT_RES1,
@ -19,13 +19,20 @@ enum {
NUM_AICA_INT,
};
// audio modes
#define AICA_MODE_16BIT 0
#define AICA_MODE_8BIT 1
#define AICA_MODE_ADPCM 3
enum {
AICA_PCM_S16,
AICA_PCM_S8,
AICA_ADPCM,
AICA_ADPCM_STREAM,
};
enum {
AICA_LOOP_NONE,
AICA_LOOP_FORWARD,
};
struct channel_data {
// 0x0
/* 0x0 */
uint32_t SA_hi : 7;
uint32_t PCMS : 2;
uint32_t LPCTL : 1;
@ -35,26 +42,26 @@ struct channel_data {
uint32_t KYONEX : 1;
uint32_t : 16;
// 0x4
/* 0x4 */
uint32_t SA_lo : 16;
uint32_t : 16;
// 0x8
/* 0x8 */
uint32_t LSA : 16;
uint32_t : 16;
// 0xc
/* 0xc */
uint32_t LEA : 16;
uint32_t : 16;
// 0x10
/* 0x10 */
uint32_t AR : 5;
uint32_t : 1;
uint32_t D1R : 5;
uint32_t D2R : 5;
uint32_t : 16;
// 0x14
/* 0x14 */
uint32_t RR : 5;
uint32_t DL : 5;
uint32_t KRS : 4;
@ -62,14 +69,14 @@ struct channel_data {
uint32_t : 1;
uint32_t : 16;
// 0x18
/* 0x18 */
uint32_t FNS : 10;
uint32_t : 1;
uint32_t OCT : 4;
uint32_t : 1;
uint32_t : 16;
// 0x1c
/* 0x1c */
uint32_t ALFOS : 3;
uint32_t ALFOWS : 2;
uint32_t PLFOS : 3;
@ -78,58 +85,58 @@ struct channel_data {
uint32_t LFORE : 1;
uint32_t : 16;
// 0x20
/* 0x20 */
uint32_t ISEL : 4;
uint32_t IMXL : 4;
uint32_t : 8;
uint32_t : 16;
// 0x24
/* 0x24 */
uint32_t DIPAN : 5;
uint32_t : 3;
uint32_t DISDL : 4;
uint32_t : 4;
uint32_t : 16;
// 0x28
/* 0x28 */
uint32_t Q : 5;
uint32_t : 3;
uint32_t TL : 8;
uint32_t : 16;
// 0x2c
/* 0x2c */
uint32_t FLV0 : 13;
uint32_t : 3;
uint32_t : 16;
// 0x30
/* 0x30 */
uint32_t FLV1 : 13;
uint32_t : 3;
uint32_t : 16;
// 0x34
/* 0x34 */
uint32_t FLV2 : 13;
uint32_t : 3;
uint32_t : 16;
// 0x38
/* 0x38 */
uint32_t FLV3 : 13;
uint32_t : 3;
uint32_t : 16;
// 0x3c
/* 0x3c */
uint32_t FLV4 : 13;
uint32_t : 3;
uint32_t : 16;
// 0x40
/* 0x40 */
uint32_t FD1R : 5;
uint32_t : 3;
uint32_t FAR : 5;
uint32_t : 3;
uint32_t : 16;
// 0x44
/* 0x44 */
uint32_t FRR : 5;
uint32_t : 3;
uint32_t FD2R : 5;
@ -138,7 +145,7 @@ struct channel_data {
};
struct common_data {
// 0x0
/* 0x0 */
uint32_t MVOL : 4;
uint32_t VER : 4;
uint32_t DAC18B : 1;
@ -147,14 +154,14 @@ struct common_data {
uint32_t MONO : 1;
uint32_t : 16;
// 0x4
/* 0x4 */
uint32_t RBP : 12;
uint32_t : 1;
uint32_t RBL : 2;
uint32_t TESTB0 : 1;
uint32_t : 16;
// 0x8
/* 0x8 */
uint32_t MIBUF : 8;
uint32_t MIEMP : 1;
uint32_t MIFUL : 1;
@ -164,27 +171,27 @@ struct common_data {
uint32_t : 3;
uint32_t : 16;
// 0xc
/* 0xc */
uint32_t MOBUF : 8;
uint32_t MSLC : 6;
uint32_t AFSEL : 1;
uint32_t : 1;
uint32_t : 16;
// 0x10
/* 0x10 */
uint32_t EG : 13;
uint32_t SGC : 2;
uint32_t LP : 1;
uint32_t : 16;
// 0x14
/* 0x14 */
uint32_t CA : 16;
uint32_t : 16;
// 0x18
/* 0x18 */
uint8_t padding0[0x68];
// 0x80
/* 0x80 */
uint32_t MRWINH : 4;
uint32_t T : 1;
uint32_t TSCD : 3;
@ -192,106 +199,106 @@ struct common_data {
uint32_t DMEA_hi : 7;
uint32_t : 16;
// 0x84
/* 0x84 */
uint32_t : 2;
uint32_t DMEA_lo : 14;
uint32_t : 16;
// 0x88
/* 0x88 */
uint32_t : 2;
uint32_t DRGA : 13;
uint32_t DGATE : 1;
uint32_t : 16;
// 0x8c
/* 0x8c */
uint32_t DEXE : 1;
uint32_t : 1;
uint32_t DLG : 13;
uint32_t DDIR : 1;
uint32_t : 16;
// 0x90
/* 0x90 */
uint32_t TIMA : 8;
uint32_t TACTL : 3;
uint32_t : 5;
uint32_t : 16;
// 0x94
/* 0x94 */
uint32_t TIMB : 8;
uint32_t TBCTL : 3;
uint32_t : 5;
uint32_t : 16;
// 0x98
/* 0x98 */
uint32_t TIMC : 8;
uint32_t TCCTL : 3;
uint32_t : 5;
uint32_t : 16;
// 0x9c
/* 0x9c */
uint32_t SCIEB : 11;
uint32_t : 5;
uint32_t : 16;
// 0xa0
/* 0xa0 */
uint32_t SCIPD : 11;
uint32_t : 5;
uint32_t : 16;
// 0xa4
/* 0xa4 */
uint32_t SCIRE : 11;
uint32_t : 5;
uint32_t : 16;
// 0xa8
/* 0xa8 */
uint32_t SCILV0 : 8;
uint32_t : 8;
uint32_t : 16;
// 0xac
/* 0xac */
uint32_t SCILV1 : 8;
uint32_t : 8;
uint32_t : 16;
// 0xb0
/* 0xb0 */
uint32_t SCILV2 : 8;
uint32_t : 8;
uint32_t : 16;
// 0xb4
/* 0xb4 */
uint32_t MCIEB : 11;
uint32_t : 5;
uint32_t : 16;
// 0xb8
/* 0xb8 */
uint32_t MCIPD : 11;
uint32_t : 5;
uint32_t : 16;
// 0xbc
/* 0xbc */
uint32_t MCIRE : 11;
uint32_t : 5;
uint32_t : 16;
// 0xc0
/* 0xc0 */
uint8_t padding1[0x340];
// 0x400
/* 0x400 */
uint32_t ARMRST : 1;
uint32_t : 7;
uint32_t VREG : 2;
uint32_t : 6;
uint32_t : 16;
// 0x404
/* 0x404 */
uint8_t padding2[0xfc];
// 0x500
/* 0x500 */
uint32_t L : 8;
uint32_t : 8;
uint32_t : 16;
// 0x504
/* 0x504 */
uint32_t M : 8;
uint32_t RP : 1;
uint32_t : 7;