diff --git a/src/hw/aica/aica.c b/src/hw/aica/aica.c index a938d8eb..e7b5c3f6 100644 --- a/src/hw/aica/aica.c +++ b/src/hw/aica/aica.c @@ -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; } } diff --git a/src/hw/aica/aica_types.h b/src/hw/aica/aica_types.h index 39ff4932..7c1f6e5d 100644 --- a/src/hw/aica/aica_types.h +++ b/src/hw/aica/aica_types.h @@ -3,7 +3,7 @@ #include -// 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;