all repos — mgba @ 093c86c94355f296a3dfb201b30f008b1893d967

mGBA Game Boy Advance Emulator

Add channel 4 envelope, fix audio timing
Jeffrey Pfau jeffrey@endrift.com
Fri, 18 Oct 2013 09:33:07 -0700
commit

093c86c94355f296a3dfb201b30f008b1893d967

parent

a55b4dc87f31bbb4dc9629d1335270f32b00db29

2 files changed, 73 insertions(+), 5 deletions(-)

jump to
M src/gba/gba-audio.csrc/gba/gba-audio.c

@@ -9,6 +9,7 @@

const unsigned GBA_AUDIO_SAMPLES = 512; const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t); +static void _updateEnvelope(struct GBAAudioEnvelope* envelope); static int32_t _updateChannel1(struct GBAAudioChannel1* ch); static int32_t _updateChannel2(struct GBAAudioChannel2* ch); static int32_t _updateChannel3(struct GBAAudioChannel3* ch);

@@ -21,7 +22,10 @@ audio->nextCh1 = 0;

audio->nextCh2 = 0; audio->nextCh3 = 0; audio->nextCh4 = 0; + audio->ch1.envelope.nextStep = INT_MAX; + audio->ch2.envelope.nextStep = INT_MAX; audio->ch4.sample = 0; + audio->ch4.envelope.nextStep = INT_MAX; audio->eventDiff = 0; audio->nextSample = 0; audio->sampleRate = 0x8000;

@@ -48,7 +52,8 @@ }

int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) { audio->nextEvent -= cycles; - if (audio->nextEvent <= 0) { + audio->eventDiff += cycles; + while (audio->nextEvent <= 0) { audio->nextEvent = INT_MAX; audio->nextCh1 -= audio->eventDiff;

@@ -56,6 +61,30 @@ audio->nextCh2 -= audio->eventDiff;

audio->nextCh3 -= audio->eventDiff; audio->nextCh4 -= audio->eventDiff; + if (audio->ch1.envelope.nextStep != INT_MAX) { + audio->ch1.envelope.nextStep -= audio->eventDiff; + if (audio->ch1.envelope.nextStep <= 0) { + _updateEnvelope(&audio->ch1.envelope); + } + } + + if (audio->ch2.envelope.nextStep != INT_MAX) { + audio->ch2.envelope.nextStep -= audio->eventDiff; + if (audio->ch2.envelope.nextStep <= 0) { + _updateEnvelope(&audio->ch2.envelope); + } + } + + if (audio->ch4.envelope.nextStep != INT_MAX) { + audio->ch4.envelope.nextStep -= audio->eventDiff; + if (audio->ch4.envelope.nextStep <= 0) { + _updateEnvelope(&audio->ch4.envelope); + if (audio->ch4.envelope.nextStep < audio->nextEvent) { + audio->nextEvent = audio->nextCh4; + } + } + } + if ((audio->ch1Right || audio->ch1Left) && audio->nextCh1 <= 0) { audio->nextCh1 += _updateChannel1(&audio->ch1); }

@@ -84,7 +113,7 @@

if (audio->nextSample < audio->nextEvent) { audio->nextEvent = audio->nextSample; } - audio->eventDiff = audio->nextEvent; + audio->eventDiff = 0; } return audio->nextEvent; }

@@ -110,6 +139,11 @@ }

void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) { audio->ch1.envelope.packed = value; + if (audio->ch1.envelope.stepTime) { + audio->ch1.envelope.nextStep = 0; + } else { + audio->ch1.envelope.nextStep = INT_MAX; + } } void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) {

@@ -118,6 +152,11 @@ }

void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) { audio->ch2.envelope.packed = value; + if (audio->ch2.envelope.stepTime) { + audio->ch2.envelope.nextStep = 0; + } else { + audio->ch2.envelope.nextStep = INT_MAX; + } } void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) {

@@ -138,11 +177,22 @@ }

void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) { audio->ch4.envelope.packed = value; + if (audio->ch4.envelope.stepTime) { + audio->ch4.envelope.nextStep = 0; + } else { + audio->ch4.envelope.nextStep = INT_MAX; + } } void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) { audio->ch4.control.packed = value; if (audio->ch4.control.restart) { + audio->ch4.envelope.currentVolume = audio->ch4.envelope.initialVolume; + if (audio->ch4.envelope.stepTime) { + audio->ch4.envelope.nextStep = 0; + } else { + audio->ch4.envelope.nextStep = INT_MAX; + } if (audio->ch4.control.power) { audio->ch4.lfsr = 0x40; } else {

@@ -205,6 +255,23 @@ }

CircleBufferRead8(&channel->fifo, &channel->sample); } +static void _updateEnvelope(struct GBAAudioEnvelope* envelope) { + if (envelope->direction) { + ++envelope->currentVolume; + } else { + --envelope->currentVolume; + } + if (envelope->currentVolume >= 15) { + envelope->currentVolume = 15; + envelope->nextStep = INT_MAX; + } else if (envelope->currentVolume <= 0) { + envelope->currentVolume = 0; + envelope->nextStep = INT_MAX; + } else { + envelope->nextStep += envelope->stepTime * (GBA_ARM7TDMI_FREQUENCY >> 6); + } +} + static int32_t _updateChannel1(struct GBAAudioChannel1* ch) { return INT_MAX / 4; }

@@ -219,7 +286,8 @@ }

static int32_t _updateChannel4(struct GBAAudioChannel4* ch) { int lsb = ch->lfsr & 1; - ch->sample = lsb * 0xFF - 0x80; + ch->sample = lsb * 0x10 - 0x8; + ch->sample *= ch->envelope.currentVolume; ch->lfsr >>= 1; ch->lfsr ^= (lsb * 0x60) << (ch->control.power ? 0 : 8); int timing = ch->control.ratio ? 2 * ch->control.ratio : 1;
M src/platform/sdl/sdl-audio.csrc/platform/sdl/sdl-audio.c

@@ -37,12 +37,12 @@

static void _pulldownResample(struct GBASDLAudio* context) { int32_t value; if (CircleBufferRead32(&context->audio->left, &value)) { - context->currentSample.left = value << 7; + context->currentSample.left = value << 5; } else { context->currentSample.left = 0; } if (CircleBufferRead32(&context->audio->right, &value)) { - context->currentSample.right = value << 7; + context->currentSample.right = value << 5; } else { context->currentSample.right = 0; }