all repos — mgba @ d3fa698c81eb372f9ab9e6843c8d571e6383a5de

mGBA Game Boy Advance Emulator

GB Audio: Begin rewrite of frame counting
Jeffrey Pfau jeffrey@endrift.com
Sat, 06 Feb 2016 01:00:17 -0800
commit

d3fa698c81eb372f9ab9e6843c8d571e6383a5de

parent

385059c63ab64ada69f328d744342f6a86f497e4

3 files changed, 114 insertions(+), 119 deletions(-)

jump to
M src/gb/audio.csrc/gb/audio.c

@@ -9,9 +9,9 @@ #include "core/sync.h"

#include "gb/gb.h" #include "gb/io.h" -#define SWEEP_CYCLES (DMG_LR35902_FREQUENCY >> 7) +#define FRAME_CYCLES (DMG_LR35902_FREQUENCY >> 9) -static const int CLOCKS_PER_FRAME = 0x1000; +static const int CLOCKS_PER_BLIP_FRAME = 0x1000; static const unsigned BLIP_BUFFER_SIZE = 0x4000; static void _writeDuty(struct GBAudioEnvelope* envelope, uint8_t value);

@@ -50,11 +50,13 @@ audio->nextCh1 = 0;

audio->nextCh2 = 0; audio->nextCh3 = 0; audio->nextCh4 = 0; - audio->ch1 = (struct GBAudioChannel1) { .envelope = { .nextStep = INT_MAX }, .nextSweep = INT_MAX }; - audio->ch2 = (struct GBAudioChannel2) { .envelope = { .nextStep = INT_MAX } }; + audio->ch1 = (struct GBAudioChannel1) { }; + audio->ch2 = (struct GBAudioChannel2) { }; audio->ch3 = (struct GBAudioChannel3) { .bank = 0 }; - audio->ch4 = (struct GBAudioChannel4) { .envelope = { .nextStep = INT_MAX } }; + audio->ch4 = (struct GBAudioChannel4) { }; audio->eventDiff = 0; + audio->nextFrame = 0; + audio->frame = 0; audio->nextSample = 0; audio->sampleInterval = 128; audio->volumeRight = 0;

@@ -77,21 +79,20 @@ void GBAudioWriteNR10(struct GBAudio* audio, uint8_t value) {

audio->ch1.shift = GBAudioRegisterSquareSweepGetShift(value); audio->ch1.direction = GBAudioRegisterSquareSweepGetDirection(value); audio->ch1.time = GBAudioRegisterSquareSweepGetTime(value); - if (audio->ch1.time) { - audio->ch1.nextSweep = audio->ch1.time * SWEEP_CYCLES; - } else { - audio->ch1.nextSweep = INT_MAX; - } } void GBAudioWriteNR11(struct GBAudio* audio, uint8_t value) { _writeDuty(&audio->ch1.envelope, value); - audio->ch1.control.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch1.envelope.length)) >> 8; + audio->ch1.control.length = 64 - audio->ch1.envelope.length; } void GBAudioWriteNR12(struct GBAudio* audio, uint8_t value) { if (!_writeSweep(&audio->ch1.envelope, value)) { - audio->ch1.sample = 0; + audio->playingCh1 = false; + // TODO: Don't need p + if (audio->p) { + audio->p->memory.io[REG_NR52] &= ~0x0001; + } } }

@@ -105,26 +106,20 @@ audio->ch1.control.frequency &= 0xFF;

audio->ch1.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8); audio->ch1.control.stop = GBAudioRegisterControlGetStop(value << 8); if (GBAudioRegisterControlIsRestart(value << 8)) { - if (audio->ch1.time) { - audio->ch1.nextSweep = audio->ch1.time * SWEEP_CYCLES; - } else { - audio->ch1.nextSweep = INT_MAX; - } if (audio->nextEvent == INT_MAX) { audio->eventDiff = 0; } if (!audio->playingCh1) { audio->nextCh1 = audio->eventDiff; } - audio->playingCh1 = 1; + audio->playingCh1 = audio->ch1.envelope.initialVolume || audio->ch1.envelope.direction; audio->ch1.envelope.currentVolume = audio->ch1.envelope.initialVolume; if (audio->ch1.envelope.currentVolume > 0) { audio->ch1.envelope.dead = 0; } - if (audio->ch1.envelope.stepTime) { - audio->ch1.envelope.nextStep = audio->eventDiff; - } else { - audio->ch1.envelope.nextStep = INT_MAX; + audio->ch1.sweepStep = audio->ch1.time; + if (!audio->ch1.control.length) { + audio->ch1.control.length = 64; } audio->nextEvent = 0; }

@@ -132,12 +127,16 @@ }

void GBAudioWriteNR21(struct GBAudio* audio, uint8_t value) { _writeDuty(&audio->ch2.envelope, value); - audio->ch2.control.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch1.envelope.length)) >> 8; + audio->ch2.control.length = 64 - audio->ch2.envelope.length; } void GBAudioWriteNR22(struct GBAudio* audio, uint8_t value) { if (!_writeSweep(&audio->ch2.envelope, value)) { - audio->ch2.sample = 0; + audio->playingCh2 = false; + // TODO: Don't need p + if (audio->p) { + audio->p->memory.io[REG_NR52] &= ~0x0002; + } } }

@@ -151,7 +150,7 @@ audio->ch2.control.frequency &= 0xFF;

audio->ch2.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8); audio->ch2.control.stop = GBAudioRegisterControlGetStop(value << 8); if (GBAudioRegisterControlIsRestart(value << 8)) { - audio->playingCh2 = 1; + audio->playingCh2 = audio->ch2.envelope.initialVolume || audio->ch2.envelope.direction; audio->ch2.envelope.currentVolume = audio->ch2.envelope.initialVolume; if (audio->ch2.envelope.currentVolume > 0) { audio->ch2.envelope.dead = 0;

@@ -162,10 +161,8 @@ }

if (!audio->playingCh2) { audio->nextCh2 = audio->eventDiff; } - if (audio->ch2.envelope.stepTime) { - audio->ch2.envelope.nextStep = audio->eventDiff; - } else { - audio->ch2.envelope.nextStep = INT_MAX; + if (!audio->ch2.control.length) { + audio->ch2.control.length = 64; } audio->nextEvent = 0; }

@@ -173,14 +170,18 @@ }

void GBAudioWriteNR30(struct GBAudio* audio, uint8_t value) { audio->ch3.enable = GBAudioRegisterBankGetEnable(value); - if (audio->ch3.endTime >= 0) { - audio->playingCh3 = audio->ch3.enable; + if (!audio->ch3.enable) { + audio->playingCh3 = false; + // TODO: Don't need p + if (audio->p) { + audio->p->memory.io[REG_NR52] &= ~0x0004; + } } } void GBAudioWriteNR31(struct GBAudio* audio, uint8_t value) { audio->ch3.length = value; - audio->ch3.endTime = (DMG_LR35902_FREQUENCY * (256 - audio->ch3.length)) >> 8; + audio->ch3.lengthShadow = 256 - value; } void GBAudioWriteNR32(struct GBAudio* audio, uint8_t value) {

@@ -198,6 +199,9 @@ audio->ch3.rate |= GBAudioRegisterControlGetRate(value << 8);

audio->ch3.stop = GBAudioRegisterControlGetStop(value << 8); if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh3 = audio->ch3.enable; + if (!audio->ch3.lengthShadow) { + audio->ch3.lengthShadow = 256; + } } if (audio->playingCh3) { if (audio->nextEvent == INT_MAX) {

@@ -210,12 +214,16 @@ }

void GBAudioWriteNR41(struct GBAudio* audio, uint8_t value) { _writeDuty(&audio->ch4.envelope, value); - audio->ch4.endTime = (DMG_LR35902_FREQUENCY * (64 - audio->ch4.envelope.length)) >> 8; + audio->ch4.length = 64 - audio->ch4.envelope.length; } void GBAudioWriteNR42(struct GBAudio* audio, uint8_t value) { if (!_writeSweep(&audio->ch4.envelope, value)) { - audio->ch4.sample = 0; + audio->playingCh4 = false; + // TODO: Don't need p + if (audio->p) { + audio->p->memory.io[REG_NR52] &= ~0x0008; + } } }

@@ -228,16 +236,11 @@

void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { audio->ch4.stop = GBAudioRegisterNoiseControlGetStop(value); if (GBAudioRegisterNoiseControlIsRestart(value)) { - audio->playingCh4 = 1; + audio->playingCh4 = audio->ch4.envelope.initialVolume || audio->ch4.envelope.direction; audio->ch4.envelope.currentVolume = audio->ch4.envelope.initialVolume; if (audio->ch4.envelope.currentVolume > 0) { audio->ch4.envelope.dead = 0; } - if (audio->ch4.envelope.stepTime) { - audio->ch4.envelope.nextStep = 0; - } else { - audio->ch4.envelope.nextStep = INT_MAX; - } if (audio->ch4.power) { audio->ch4.lfsr = 0x40; } else {

@@ -248,6 +251,9 @@ audio->eventDiff = 0;

} if (!audio->playingCh4) { audio->nextCh4 = audio->eventDiff; + } + if (!audio->ch4.length) { + audio->ch4.length = 64; } audio->nextEvent = 0; }

@@ -331,28 +337,33 @@ audio->eventDiff += cycles;

while (audio->nextEvent <= 0) { audio->nextEvent = INT_MAX; if (audio->enable) { + audio->nextFrame -= audio->eventDiff; + int frame = -1; + if (audio->nextFrame <= 0) { + frame = (audio->frame + 1) & 7; + audio->frame = frame; + audio->nextFrame += FRAME_CYCLES; + if (audio->nextFrame < audio->nextEvent) { + audio->nextEvent = audio->nextFrame; + } + } + if (audio->playingCh1) { audio->nextCh1 -= audio->eventDiff; if (!audio->ch1.envelope.dead) { - if (audio->ch1.envelope.nextStep != INT_MAX) { - audio->ch1.envelope.nextStep -= audio->eventDiff; - if (audio->ch1.envelope.nextStep <= 0) { + if (frame == 7) { + --audio->ch1.envelope.nextStep; + if (audio->ch1.envelope.nextStep == 0) { int8_t sample = audio->ch1.control.hi * 0x10 - 0x8; _updateEnvelope(&audio->ch1.envelope); - if (audio->ch1.envelope.nextStep < audio->nextEvent) { - audio->nextEvent = audio->ch1.envelope.nextStep; - } audio->ch1.sample = sample * audio->ch1.envelope.currentVolume; } } - if (audio->ch1.nextSweep != INT_MAX) { - audio->ch1.nextSweep -= audio->eventDiff; - if (audio->ch1.nextSweep <= 0) { + if ((frame & 3) == 2) { + --audio->ch1.sweepStep; + if (audio->ch1.sweepStep == 0) { audio->playingCh1 = _updateSweep(&audio->ch1); - if (audio->ch1.nextSweep < audio->nextEvent) { - audio->nextEvent = audio->ch1.nextSweep; - } } } }

@@ -363,25 +374,22 @@ }

if (audio->nextCh1 < audio->nextEvent) { audio->nextEvent = audio->nextCh1; } + } - if (audio->ch1.control.stop) { - audio->ch1.control.endTime -= audio->eventDiff; - if (audio->ch1.control.endTime <= 0) { - audio->playingCh1 = 0; - } + if (audio->ch1.control.length && audio->ch1.control.stop && !(frame & 1)) { + --audio->ch1.control.length; + if (audio->ch1.control.length == 0) { + audio->playingCh1 = 0; } } if (audio->playingCh2) { audio->nextCh2 -= audio->eventDiff; - if (!audio->ch2.envelope.dead && audio->ch2.envelope.nextStep != INT_MAX) { - audio->ch2.envelope.nextStep -= audio->eventDiff; - if (audio->ch2.envelope.nextStep <= 0) { + if (!audio->ch2.envelope.dead && frame == 7) { + --audio->ch2.envelope.nextStep; + if (audio->ch2.envelope.nextStep == 0) { int8_t sample = audio->ch2.control.hi * 0x10 - 0x8; _updateEnvelope(&audio->ch2.envelope); - if (audio->ch2.envelope.nextStep < audio->nextEvent) { - audio->nextEvent = audio->ch2.envelope.nextStep; - } audio->ch2.sample = sample * audio->ch2.envelope.currentVolume; } }

@@ -392,12 +400,12 @@ }

if (audio->nextCh2 < audio->nextEvent) { audio->nextEvent = audio->nextCh2; } + } - if (audio->ch2.control.stop) { - audio->ch2.control.endTime -= audio->eventDiff; - if (audio->ch2.control.endTime <= 0) { - audio->playingCh2 = 0; - } + if (audio->ch2.control.length && audio->ch2.control.stop && !(frame & 1)) { + --audio->ch2.control.length; + if (audio->ch2.control.length == 0) { + audio->playingCh2 = 0; } }

@@ -409,25 +417,22 @@ }

if (audio->nextCh3 < audio->nextEvent) { audio->nextEvent = audio->nextCh3; } + } - if (audio->ch3.stop) { - audio->ch3.endTime -= audio->eventDiff; - if (audio->ch3.endTime <= 0) { - audio->playingCh3 = 0; - } + if (audio->ch3.lengthShadow && audio->ch3.stop && !(frame & 1)) { + --audio->ch3.lengthShadow; + if (audio->ch3.lengthShadow == 0) { + audio->playingCh3 = 0; } } if (audio->playingCh4) { audio->nextCh4 -= audio->eventDiff; - if (!audio->ch4.envelope.dead && audio->ch4.envelope.nextStep != INT_MAX) { - audio->ch4.envelope.nextStep -= audio->eventDiff; - if (audio->ch4.envelope.nextStep <= 0) { + if (!audio->ch4.envelope.dead && frame == 7) { + --audio->ch4.envelope.nextStep; + if (audio->ch4.envelope.nextStep == 0) { int8_t sample = (audio->ch4.sample >> 31) * 0x8; _updateEnvelope(&audio->ch4.envelope); - if (audio->ch4.envelope.nextStep < audio->nextEvent) { - audio->nextEvent = audio->ch4.envelope.nextStep; - } audio->ch4.sample = sample * audio->ch4.envelope.currentVolume; } }

@@ -438,12 +443,12 @@ }

if (audio->nextCh4 < audio->nextEvent) { audio->nextEvent = audio->nextCh4; } + } - if (audio->ch4.stop) { - audio->ch4.endTime -= audio->eventDiff; - if (audio->ch4.endTime <= 0) { - audio->playingCh4 = 0; - } + if (audio->ch4.length && audio->ch4.stop && !(frame & 1)) { + --audio->ch4.length; + if (audio->ch4.length == 0) { + audio->playingCh4 = 0; } } }

@@ -532,10 +537,10 @@ blip_add_delta(audio->right, audio->clock, sampleRight - audio->lastRight);

audio->lastLeft = sampleLeft; audio->lastRight = sampleRight; audio->clock += cycles; - if (audio->clock >= CLOCKS_PER_FRAME) { + if (audio->clock >= CLOCKS_PER_BLIP_FRAME) { blip_end_frame(audio->left, audio->clock); blip_end_frame(audio->right, audio->clock); - audio->clock -= CLOCKS_PER_FRAME; + audio->clock -= CLOCKS_PER_BLIP_FRAME; } } produced = blip_samples_avail(audio->left);

@@ -554,16 +559,8 @@ envelope->stepTime = GBAudioRegisterSweepGetStepTime(value);

envelope->direction = GBAudioRegisterSweepGetDirection(value); envelope->initialVolume = GBAudioRegisterSweepGetInitialVolume(value); envelope->dead = 0; - if (envelope->stepTime) { - envelope->nextStep = 0; - } else { - envelope->nextStep = INT_MAX; - if (envelope->initialVolume == 0) { - envelope->dead = 1; - return false; - } - } - return true; + envelope->nextStep = envelope->stepTime; + return envelope->initialVolume || envelope->direction; } static int32_t _updateSquareChannel(struct GBAudioSquareControl* control, int duty) {

@@ -592,13 +589,11 @@ --envelope->currentVolume;

} if (envelope->currentVolume >= 15) { envelope->currentVolume = 15; - envelope->nextStep = INT_MAX; } else if (envelope->currentVolume <= 0) { envelope->currentVolume = 0; envelope->dead = 1; - envelope->nextStep = INT_MAX; } else { - envelope->nextStep += envelope->stepTime * (DMG_LR35902_FREQUENCY >> 6); + envelope->nextStep = envelope->stepTime; } }

@@ -618,7 +613,7 @@ } else {

return false; } } - ch->nextSweep += ch->time * SWEEP_CYCLES; + ch->sweepStep = ch->time; return true; }
M src/gb/audio.hsrc/gb/audio.h

@@ -78,24 +78,22 @@ uint8_t initialVolume;

bool direction; int currentVolume; int dead; - int32_t nextStep; + uint8_t nextStep; }; struct GBAudioSquareControl { uint16_t frequency; + uint8_t length; bool stop; int hi; - int32_t nextStep; - int32_t endTime; }; struct GBAudioChannel1 { uint8_t shift; uint8_t time; + uint8_t sweepStep; bool direction; - int32_t nextSweep; - struct GBAudioEnvelope envelope; struct GBAudioSquareControl control; int8_t sample;

@@ -113,11 +111,11 @@ bool bank;

bool enable; unsigned length; + unsigned lengthShadow; uint8_t volume; uint16_t rate; bool stop; - int32_t endTime; uint32_t wavedata[8]; int8_t sample;

@@ -130,7 +128,7 @@ uint8_t ratio;

uint8_t frequency; bool power; bool stop; - int32_t endTime; + uint8_t length; uint32_t lfsr; int8_t sample;

@@ -168,6 +166,8 @@ bool playingCh4;

int32_t nextEvent; int32_t eventDiff; + int32_t nextFrame; + int frame; int32_t nextSample; int32_t sampleInterval;
M src/gba/audio.csrc/gba/audio.c

@@ -331,29 +331,29 @@

flags = GBASerializedAudioFlagsSetCh1Volume(flags, audio->psg.ch1.envelope.currentVolume); flags = GBASerializedAudioFlagsSetCh1Dead(flags, audio->psg.ch1.envelope.dead); flags = GBASerializedAudioFlagsSetCh1Hi(flags, audio->psg.ch1.control.hi); - STORE_32(audio->psg.ch1.envelope.nextStep, 0, &state->audio.ch1.envelopeNextStep); + /*STORE_32(audio->psg.ch1.envelope.nextStep, 0, &state->audio.ch1.envelopeNextStep); STORE_32(audio->psg.ch1.control.nextStep, 0, &state->audio.ch1.waveNextStep); STORE_32(audio->psg.ch1.nextSweep, 0, &state->audio.ch1.sweepNextStep); - STORE_32(audio->psg.ch1.control.endTime, 0, &state->audio.ch1.endTime); + STORE_32(audio->psg.ch1.control.endTime, 0, &state->audio.ch1.endTime);*/ STORE_32(audio->psg.nextCh1, 0, &state->audio.ch1.nextEvent); flags = GBASerializedAudioFlagsSetCh2Volume(flags, audio->psg.ch2.envelope.currentVolume); flags = GBASerializedAudioFlagsSetCh2Dead(flags, audio->psg.ch2.envelope.dead); flags = GBASerializedAudioFlagsSetCh2Hi(flags, audio->psg.ch2.control.hi); - STORE_32(audio->psg.ch2.envelope.nextStep, 0, &state->audio.ch2.envelopeNextStep); + /*STORE_32(audio->psg.ch2.envelope.nextStep, 0, &state->audio.ch2.envelopeNextStep); STORE_32(audio->psg.ch2.control.nextStep, 0, &state->audio.ch2.waveNextStep); - STORE_32(audio->psg.ch2.control.endTime, 0, &state->audio.ch2.endTime); + STORE_32(audio->psg.ch2.control.endTime, 0, &state->audio.ch2.endTime);*/ STORE_32(audio->psg.nextCh2, 0, &state->audio.ch2.nextEvent); memcpy(state->audio.ch3.wavebanks, audio->psg.ch3.wavedata, sizeof(state->audio.ch3.wavebanks)); - STORE_32(audio->psg.ch3.endTime, 0, &state->audio.ch3.endTime); + //STORE_32(audio->psg.ch3.endTime, 0, &state->audio.ch3.endTime); STORE_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent); state->audio.flags = GBASerializedAudioFlagsSetCh4Volume(flags, audio->psg.ch4.envelope.currentVolume); state->audio.flags = GBASerializedAudioFlagsSetCh4Dead(flags, audio->psg.ch4.envelope.dead); STORE_32(audio->psg.ch4.envelope.nextStep, 0, &state->audio.ch4.envelopeNextStep); STORE_32(audio->psg.ch4.lfsr, 0, &state->audio.ch4.lfsr); - STORE_32(audio->psg.ch4.endTime, 0, &state->audio.ch4.endTime); + //STORE_32(audio->psg.ch4.endTime, 0, &state->audio.ch4.endTime); STORE_32(audio->psg.nextCh4, 0, &state->audio.ch4.nextEvent); STORE_32(flags, 0, &state->audio.flags);

@@ -375,29 +375,29 @@ audio->psg.ch1.envelope.currentVolume = GBASerializedAudioFlagsGetCh1Volume(flags);

audio->psg.ch1.envelope.dead = GBASerializedAudioFlagsGetCh1Dead(flags); audio->psg.ch1.control.hi = GBASerializedAudioFlagsGetCh1Hi(flags); LOAD_32(audio->psg.ch1.envelope.nextStep, 0, &state->audio.ch1.envelopeNextStep); - LOAD_32(audio->psg.ch1.control.nextStep, 0, &state->audio.ch1.waveNextStep); + /*LOAD_32(audio->psg.ch1.control.nextStep, 0, &state->audio.ch1.waveNextStep); LOAD_32(audio->psg.ch1.nextSweep, 0, &state->audio.ch1.sweepNextStep); - LOAD_32(audio->psg.ch1.control.endTime, 0, &state->audio.ch1.endTime); + LOAD_32(audio->psg.ch1.control.endTime, 0, &state->audio.ch1.endTime);*/ LOAD_32(audio->psg.nextCh1, 0, &state->audio.ch1.nextEvent); audio->psg.ch2.envelope.currentVolume = GBASerializedAudioFlagsGetCh2Volume(flags); audio->psg.ch2.envelope.dead = GBASerializedAudioFlagsGetCh2Dead(flags); audio->psg.ch2.control.hi = GBASerializedAudioFlagsGetCh2Hi(flags); LOAD_32(audio->psg.ch2.envelope.nextStep, 0, &state->audio.ch2.envelopeNextStep); - LOAD_32(audio->psg.ch2.control.nextStep, 0, &state->audio.ch2.waveNextStep); - LOAD_32(audio->psg.ch2.control.endTime, 0, &state->audio.ch2.endTime); + /*LOAD_32(audio->psg.ch2.control.nextStep, 0, &state->audio.ch2.waveNextStep); + LOAD_32(audio->psg.ch2.control.endTime, 0, &state->audio.ch2.endTime);*/ LOAD_32(audio->psg.nextCh2, 0, &state->audio.ch2.nextEvent); // TODO: Big endian? memcpy(audio->psg.ch3.wavedata, state->audio.ch3.wavebanks, sizeof(audio->psg.ch3.wavedata)); - LOAD_32(audio->psg.ch3.endTime, 0, &state->audio.ch3.endTime); + //LOAD_32(audio->psg.ch3.endTime, 0, &state->audio.ch3.endTime); LOAD_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent); audio->psg.ch4.envelope.currentVolume = GBASerializedAudioFlagsGetCh4Volume(flags); audio->psg.ch4.envelope.dead = GBASerializedAudioFlagsGetCh4Dead(flags); LOAD_32(audio->psg.ch4.envelope.nextStep, 0, &state->audio.ch4.envelopeNextStep); LOAD_32(audio->psg.ch4.lfsr, 0, &state->audio.ch4.lfsr); - LOAD_32(audio->psg.ch4.endTime, 0, &state->audio.ch4.endTime); + //LOAD_32(audio->psg.ch4.endTime, 0, &state->audio.ch4.endTime); LOAD_32(audio->psg.nextCh4, 0, &state->audio.ch4.nextEvent); CircleBufferClear(&audio->chA.fifo);