GB Audio: Convert audio to mTiming
@@ -35,11 +35,14 @@ static bool _updateSweep(struct GBAudioSquareChannel* sweep, bool initial);
static void _updateSquareSample(struct GBAudioSquareChannel* ch); static int32_t _updateSquareChannel(struct GBAudioSquareChannel* ch); -static int32_t _updateWaveChannel(struct GBAudioWaveChannel* ch, enum GBAudioStyle style); -static int32_t _updateNoiseChannel(struct GBAudioNoiseChannel* ch); -static void _sample(struct GBAudio* audio, int32_t cycles); -static void _scheduleEvent(struct GBAudio* audio); +static void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate); +static void _updateChannel1(struct mTiming* timing, void* user, uint32_t cyclesLate); +static void _updateChannel2(struct mTiming* timing, void* user, uint32_t cyclesLate); +static void _updateChannel3(struct mTiming* timing, void* user, uint32_t cyclesLate); +static void _fadeChannel3(struct mTiming* timing, void* user, uint32_t cyclesLate); +static void _updateChannel4(struct mTiming* timing, void* user, uint32_t cyclesLate); +static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate); void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAudioStyle style) { audio->samples = samples;@@ -56,6 +59,33 @@ audio->forceDisableCh[3] = false;
audio->masterVolume = GB_AUDIO_VOLUME_MAX; audio->nr52 = nr52; audio->style = style; + if (style == GB_AUDIO_GBA) { + audio->timingFactor = 4; + } else { + audio->timingFactor = 1; + } + + audio->frameEvent.context = audio; + audio->frameEvent.name = "GB Audio Frame Sequencer"; + audio->frameEvent.callback = _updateFrame; + audio->ch1Event.context = audio; + audio->ch1Event.name = "GB Audio Channel 1"; + audio->ch1Event.callback = _updateChannel1; + audio->ch2Event.context = audio; + audio->ch2Event.name = "GB Audio Channel 2"; + audio->ch2Event.callback = _updateChannel2; + audio->ch3Event.context = audio; + audio->ch3Event.name = "GB Audio Channel 3"; + audio->ch3Event.callback = _updateChannel3; + audio->ch3Fade.context = audio; + audio->ch3Fade.name = "GB Audio Channel 3 Memory"; + audio->ch3Fade.callback = _fadeChannel3; + audio->ch4Event.context = audio; + audio->ch4Event.name = "GB Audio Channel 4"; + audio->ch4Event.callback = _updateChannel4; + audio->sampleEvent.context = audio; + audio->sampleEvent.name = "GB Audio Sample"; + audio->sampleEvent.callback = _sample; } void GBAudioDeinit(struct GBAudio* audio) {@@ -64,12 +94,17 @@ blip_delete(audio->right);
} void GBAudioReset(struct GBAudio* audio) { - audio->nextEvent = 0; - audio->nextCh1 = 0; - audio->nextCh2 = 0; - audio->nextCh3 = 0; - audio->fadeCh3 = 0; - audio->nextCh4 = 0; + mTimingDeschedule(audio->timing, &audio->frameEvent); + mTimingDeschedule(audio->timing, &audio->ch1Event); + mTimingDeschedule(audio->timing, &audio->ch2Event); + mTimingDeschedule(audio->timing, &audio->ch3Event); + mTimingDeschedule(audio->timing, &audio->ch3Fade); + mTimingDeschedule(audio->timing, &audio->ch4Event); + mTimingDeschedule(audio->timing, &audio->sampleEvent); + mTimingSchedule(audio->timing, &audio->frameEvent, 0); + if (audio->style != GB_AUDIO_GBA) { + mTimingSchedule(audio->timing, &audio->sampleEvent, 0); + } audio->ch1 = (struct GBAudioSquareChannel) { .envelope = { .dead = 2 } }; audio->ch2 = (struct GBAudioSquareChannel) { .envelope = { .dead = 2 } }; audio->ch3 = (struct GBAudioWaveChannel) { .bank = 0 };@@ -91,10 +126,7 @@ audio->ch3.wavedata8[13] = 0xFF;
audio->ch3.wavedata8[14] = 0x00; audio->ch3.wavedata8[15] = 0xFF; audio->ch4 = (struct GBAudioNoiseChannel) { .envelope = { .dead = 2 } }; - audio->eventDiff = 0; - audio->nextFrame = 0; audio->frame = 0; - audio->nextSample = 0; audio->sampleInterval = 128; audio->lastLeft = 0; audio->lastRight = 0;@@ -126,6 +158,7 @@ }
void GBAudioWriteNR10(struct GBAudio* audio, uint8_t value) { if (!_writeSweep(&audio->ch1.sweep, value)) { + mTimingDeschedule(audio->timing, &audio->ch1Event); audio->playingCh1 = false; *audio->nr52 &= ~0x0001; }@@ -138,6 +171,7 @@ }
void GBAudioWriteNR12(struct GBAudio* audio, uint8_t value) { if (!_writeEnvelope(&audio->ch1.envelope, value)) { + mTimingDeschedule(audio->timing, &audio->ch1Event); audio->playingCh1 = false; *audio->nr52 &= ~0x0001; }@@ -156,20 +190,17 @@ audio->ch1.control.stop = GBAudioRegisterControlGetStop(value << 8);
if (!wasStop && audio->ch1.control.stop && audio->ch1.control.length && !(audio->frame & 1)) { --audio->ch1.control.length; if (audio->ch1.control.length == 0) { + mTimingDeschedule(audio->timing, &audio->ch1Event); audio->playingCh1 = false; } } if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh1 = _resetEnvelope(&audio->ch1.envelope); - if (audio->nextEvent == INT_MAX) { - audio->eventDiff = 0; - } if (audio->playingCh1) { audio->ch1.control.hi = 0; _updateSquareSample(&audio->ch1); } - audio->nextCh1 = audio->eventDiff; audio->ch1.sweep.realFrequency = audio->ch1.control.frequency; _resetSweep(&audio->ch1.sweep);@@ -182,7 +213,10 @@ if (audio->ch1.control.stop && !(audio->frame & 1)) {
--audio->ch1.control.length; } } - _scheduleEvent(audio); + mTimingDeschedule(audio->timing, &audio->ch1Event); + if (audio->playingCh1 && audio->ch1.envelope.dead != 2) { + mTimingSchedule(audio->timing, &audio->ch1Event, 0); + } } *audio->nr52 &= ~0x0001; *audio->nr52 |= audio->playingCh1;@@ -195,6 +229,7 @@ }
void GBAudioWriteNR22(struct GBAudio* audio, uint8_t value) { if (!_writeEnvelope(&audio->ch2.envelope, value)) { + mTimingDeschedule(audio->timing, &audio->ch2Event); audio->playingCh2 = false; *audio->nr52 &= ~0x0002; }@@ -213,15 +248,13 @@ audio->ch2.control.stop = GBAudioRegisterControlGetStop(value << 8);
if (!wasStop && audio->ch2.control.stop && audio->ch2.control.length && !(audio->frame & 1)) { --audio->ch2.control.length; if (audio->ch2.control.length == 0) { + mTimingDeschedule(audio->timing, &audio->ch2Event); audio->playingCh2 = false; } } if (GBAudioRegisterControlIsRestart(value << 8)) { audio->playingCh2 = _resetEnvelope(&audio->ch2.envelope); - if (audio->nextEvent == INT_MAX) { - audio->eventDiff = 0; - } if (audio->playingCh2) { audio->ch2.control.hi = 0; _updateSquareSample(&audio->ch2);@@ -233,8 +266,10 @@ if (audio->ch2.control.stop && !(audio->frame & 1)) {
--audio->ch2.control.length; } } - audio->nextCh2 = audio->eventDiff; - _scheduleEvent(audio); + mTimingDeschedule(audio->timing, &audio->ch2Event); + if (audio->playingCh2 && audio->ch2.envelope.dead != 2) { + mTimingSchedule(audio->timing, &audio->ch2Event, 0); + } } *audio->nr52 &= ~0x0002; *audio->nr52 |= audio->playingCh2 << 1;@@ -294,14 +329,11 @@ }
} audio->ch3.window = 0; } + mTimingDeschedule(audio->timing, &audio->ch3Event); if (audio->playingCh3) { - if (audio->nextEvent == INT_MAX) { - audio->eventDiff = 0; - } audio->ch3.readable = audio->style != GB_AUDIO_DMG; - _scheduleEvent(audio); // TODO: Where does this cycle delay come from? - audio->nextCh3 = audio->eventDiff + audio->nextEvent + 4 + 2 * (2048 - audio->ch3.rate); + mTimingSchedule(audio->timing, &audio->ch3Event, audio->timingFactor * 4 + 2 * (2048 - audio->ch3.rate)); } *audio->nr52 &= ~0x0004; *audio->nr52 |= audio->playingCh3 << 2;@@ -314,6 +346,7 @@ }
void GBAudioWriteNR42(struct GBAudio* audio, uint8_t value) { if (!_writeEnvelope(&audio->ch4.envelope, value)) { + mTimingDeschedule(audio->timing, &audio->ch4Event); audio->playingCh4 = false; *audio->nr52 &= ~0x0008; }@@ -331,6 +364,7 @@ audio->ch4.stop = GBAudioRegisterNoiseControlGetStop(value);
if (!wasStop && audio->ch4.stop && audio->ch4.length && !(audio->frame & 1)) { --audio->ch4.length; if (audio->ch4.length == 0) { + mTimingDeschedule(audio->timing, &audio->ch4Event); audio->playingCh4 = false; } }@@ -342,17 +376,16 @@ audio->ch4.lfsr = 0x40;
} else { audio->ch4.lfsr = 0x4000; } - if (audio->nextEvent == INT_MAX) { - audio->eventDiff = 0; - } - audio->nextCh4 = audio->eventDiff; if (!audio->ch4.length) { audio->ch4.length = 64; if (audio->ch4.stop && !(audio->frame & 1)) { --audio->ch4.length; } } - _scheduleEvent(audio); + mTimingDeschedule(audio->timing, &audio->ch4Event); + if (audio->playingCh4 && audio->ch4.envelope.dead != 2) { + mTimingSchedule(audio->timing, &audio->ch4Event, 0); + } } *audio->nr52 &= ~0x0008; *audio->nr52 |= audio->playingCh4 << 3;@@ -438,170 +471,105 @@ audio->frame = 7;
} } -int32_t GBAudioProcessEvents(struct GBAudio* audio, int32_t cycles) { - if (audio->nextEvent == INT_MAX) { - return INT_MAX; - } - audio->nextEvent -= cycles; - 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 && frame == 7) { - --audio->ch1.envelope.nextStep; - if (audio->ch1.envelope.nextStep == 0) { - _updateEnvelope(&audio->ch1.envelope); - _updateSquareSample(&audio->ch1); - } - } +void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate) { + struct GBAudio* audio = user; - if (audio->ch1.sweep.enable && (frame & 3) == 2) { - --audio->ch1.sweep.step; - if (audio->ch1.sweep.step == 0) { - audio->playingCh1 = _updateSweep(&audio->ch1, false); - } - } + int frame = (audio->frame + 1) & 7; + audio->frame = frame; - if (audio->ch1.envelope.dead != 2) { - if (audio->nextCh1 <= 0) { - audio->nextCh1 += _updateSquareChannel(&audio->ch1); - } - if (audio->nextCh1 < audio->nextEvent) { - audio->nextEvent = audio->nextCh1; - } - } + switch (frame) { + case 2: + case 6: + if (audio->ch1.sweep.enable) { + --audio->ch1.sweep.step; + if (audio->ch1.sweep.step == 0) { + audio->playingCh1 = _updateSweep(&audio->ch1, false); + *audio->nr52 &= ~0x0001; + *audio->nr52 |= audio->playingCh1; } - - if (audio->ch1.control.length && audio->ch1.control.stop && !(frame & 1)) { - --audio->ch1.control.length; - if (audio->ch1.control.length == 0) { - audio->playingCh1 = 0; - } + } + // Fall through + case 0: + case 4: + if (audio->ch1.control.length && audio->ch1.control.stop) { + --audio->ch1.control.length; + if (audio->ch1.control.length == 0) { + mTimingDeschedule(timing, &audio->ch1Event); + audio->playingCh1 = 0; + *audio->nr52 &= ~0x0001; } - - if (audio->playingCh2) { - audio->nextCh2 -= audio->eventDiff; - if (!audio->ch2.envelope.dead && frame == 7) { - --audio->ch2.envelope.nextStep; - if (audio->ch2.envelope.nextStep == 0) { - _updateEnvelope(&audio->ch2.envelope); - _updateSquareSample(&audio->ch2); - } - } + } - if (audio->ch2.envelope.dead != 2) { - if (audio->nextCh2 <= 0) { - audio->nextCh2 += _updateSquareChannel(&audio->ch2); - } - if (audio->nextCh2 < audio->nextEvent) { - audio->nextEvent = audio->nextCh2; - } - } + if (audio->ch2.control.length && audio->ch2.control.stop) { + --audio->ch2.control.length; + if (audio->ch2.control.length == 0) { + mTimingDeschedule(timing, &audio->ch2Event); + audio->playingCh2 = 0; + *audio->nr52 &= ~0x0002; } + } - if (audio->ch2.control.length && audio->ch2.control.stop && !(frame & 1)) { - --audio->ch2.control.length; - if (audio->ch2.control.length == 0) { - audio->playingCh2 = 0; - } + if (audio->ch3.length && audio->ch3.stop) { + --audio->ch3.length; + if (audio->ch3.length == 0) { + mTimingDeschedule(timing, &audio->ch3Event); + audio->playingCh3 = 0; + *audio->nr52 &= ~0x0004; } + } - if (audio->playingCh3) { - audio->nextCh3 -= audio->eventDiff; - audio->fadeCh3 -= audio->eventDiff; - if (audio->fadeCh3 <= 0) { - audio->ch3.readable = false; - audio->fadeCh3 = INT_MAX; - } - if (audio->nextCh3 <= 0) { - if (audio->style == GB_AUDIO_DMG) { - audio->fadeCh3 = audio->nextCh3 + 2; - } - audio->nextCh3 += _updateWaveChannel(&audio->ch3, audio->style); - audio->ch3.readable = true; - } - if (audio->fadeCh3 < audio->nextEvent) { - audio->nextEvent = audio->fadeCh3; - } - if (audio->nextCh3 < audio->nextEvent) { - audio->nextEvent = audio->nextCh3; - } + if (audio->ch4.length && audio->ch4.stop) { + --audio->ch4.length; + if (audio->ch4.length == 0) { + mTimingDeschedule(timing, &audio->ch4Event); + audio->playingCh4 = 0; + *audio->nr52 &= ~0x0008; } - - if (audio->ch3.length && audio->ch3.stop && !(frame & 1)) { - --audio->ch3.length; - if (audio->ch3.length == 0) { - audio->playingCh3 = 0; + } + break; + case 7: + if (audio->playingCh1 && !audio->ch1.envelope.dead) { + --audio->ch1.envelope.nextStep; + if (audio->ch1.envelope.nextStep == 0) { + _updateEnvelope(&audio->ch1.envelope); + if (audio->ch1.envelope.dead == 2) { + mTimingDeschedule(timing, &audio->ch1Event); } + _updateSquareSample(&audio->ch1); } + } - if (audio->playingCh4) { - audio->nextCh4 -= audio->eventDiff; - if (!audio->ch4.envelope.dead && frame == 7) { - --audio->ch4.envelope.nextStep; - if (audio->ch4.envelope.nextStep == 0) { - int8_t sample = (audio->ch4.sample >> 7) * 0x8; - _updateEnvelope(&audio->ch4.envelope); - audio->ch4.sample = sample * audio->ch4.envelope.currentVolume; - } + if (audio->playingCh2 && !audio->ch2.envelope.dead) { + --audio->ch2.envelope.nextStep; + if (audio->ch2.envelope.nextStep == 0) { + _updateEnvelope(&audio->ch2.envelope); + if (audio->ch2.envelope.dead == 2) { + mTimingDeschedule(timing, &audio->ch2Event); } + _updateSquareSample(&audio->ch1); } + } - if (audio->ch4.length && audio->ch4.stop && !(frame & 1)) { - --audio->ch4.length; - if (audio->ch4.length == 0) { - audio->playingCh4 = 0; + if (audio->playingCh4 && !audio->ch4.envelope.dead) { + --audio->ch4.envelope.nextStep; + if (audio->ch4.envelope.nextStep == 0) { + int8_t sample = (audio->ch4.sample >> 7) * 0x8; + _updateEnvelope(&audio->ch4.envelope); + if (audio->ch4.envelope.dead == 2) { + mTimingDeschedule(timing, &audio->ch4Event); } + audio->ch4.sample = sample * audio->ch4.envelope.currentVolume; } } + break; + } - *audio->nr52 &= ~0x000F; - *audio->nr52 |= audio->playingCh1; - *audio->nr52 |= audio->playingCh2 << 1; - *audio->nr52 |= audio->playingCh3 << 2; - *audio->nr52 |= audio->playingCh4 << 3; - - if (audio->p) { - audio->nextSample -= audio->eventDiff; - if (audio->nextSample <= 0) { - _sample(audio, audio->sampleInterval); - audio->nextSample += audio->sampleInterval; - } - - if (audio->nextSample < audio->nextEvent) { - audio->nextEvent = audio->nextSample; - } - } - audio->eventDiff = 0; - } - return audio->nextEvent; + mTimingSchedule(timing, &audio->frameEvent, audio->timingFactor * FRAME_CYCLES - cyclesLate); } void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) { int sampleLeft = 0; int sampleRight = 0; - - if (audio->ch4.envelope.dead != 2) { - while (audio->nextCh4 <= 0) { - audio->nextCh4 += _updateNoiseChannel(&audio->ch4); - } - if (audio->nextCh4 < audio->nextEvent) { - audio->nextEvent = audio->nextCh4; - } - } if (audio->playingCh1 && !audio->forceDisableCh[0]) { if (audio->ch1Left) {@@ -647,7 +615,8 @@ *left = sampleLeft * (1 + audio->volumeLeft);
*right = sampleRight * (1 + audio->volumeRight); } -void _sample(struct GBAudio* audio, int32_t cycles) { +static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { + struct GBAudio* audio = user; int16_t sampleLeft = 0; int16_t sampleRight = 0; GBAudioSamplePSG(audio, &sampleLeft, &sampleRight);@@ -661,7 +630,7 @@ blip_add_delta(audio->left, audio->clock, sampleLeft - audio->lastLeft);
blip_add_delta(audio->right, audio->clock, sampleRight - audio->lastRight); audio->lastLeft = sampleLeft; audio->lastRight = sampleRight; - audio->clock += cycles; + audio->clock += audio->sampleInterval; if (audio->clock >= CLOCKS_PER_BLIP_FRAME) { blip_end_frame(audio->left, audio->clock); blip_end_frame(audio->right, audio->clock);@@ -678,6 +647,7 @@
if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) { audio->p->stream->postAudioBuffer(audio->p->stream, audio->left, audio->right); } + mTimingSchedule(timing, &audio->sampleEvent, audio->sampleInterval * audio->timingFactor - cyclesLate); } bool _resetEnvelope(struct GBAudioEnvelope* envelope) {@@ -722,7 +692,7 @@ envelope->direction = GBAudioRegisterSweepGetDirection(value);
envelope->initialVolume = GBAudioRegisterSweepGetInitialVolume(value); _updateEnvelopeDead(envelope); envelope->nextStep = envelope->stepTime; - return envelope->initialVolume || envelope->direction; + return (envelope->initialVolume || envelope->direction) && envelope->dead != 2; } static void _updateSquareSample(struct GBAudioSquareChannel* ch) {@@ -806,7 +776,23 @@ ch->sweep.step = ch->sweep.time;
return true; } -static int32_t _updateWaveChannel(struct GBAudioWaveChannel* ch, enum GBAudioStyle style) { +static void _updateChannel1(struct mTiming* timing, void* user, uint32_t cyclesLate) { + struct GBAudio* audio = user; + struct GBAudioSquareChannel* ch = &audio->ch1; + int cycles = _updateSquareChannel(ch); + mTimingSchedule(timing, &audio->ch1Event, audio->timingFactor * cycles - cyclesLate); +} + +static void _updateChannel2(struct mTiming* timing, void* user, uint32_t cyclesLate) { + struct GBAudio* audio = user; + struct GBAudioSquareChannel* ch = &audio->ch2; + int cycles = _updateSquareChannel(ch); + mTimingSchedule(timing, &audio->ch2Event, audio->timingFactor * cycles - cyclesLate); +} + +static void _updateChannel3(struct mTiming* timing, void* user, uint32_t cyclesLate) { + struct GBAudio* audio = user; + struct GBAudioWaveChannel* ch = &audio->ch3; int i; int volume; switch (ch->volume) {@@ -826,9 +812,9 @@ default:
volume = 3; break; } - switch (style) { - int start; - int end; + int start; + int end; + switch (audio->style) { case GB_AUDIO_DMG: default: ++ch->window;@@ -863,29 +849,32 @@ break;
} ch->sample -= 8; ch->sample *= volume * 4; - return 2 * (2048 - ch->rate); + audio->ch3.readable = true; + if (audio->style == GB_AUDIO_DMG) { + mTimingSchedule(timing, &audio->ch3Fade, 2 - cyclesLate); + } + int cycles = 2 * (2048 - ch->rate); + mTimingSchedule(timing, &audio->ch3Event, audio->timingFactor * cycles - cyclesLate); +} +static void _fadeChannel3(struct mTiming* timing, void* user, uint32_t cyclesLate) { + UNUSED(timing); + UNUSED(cyclesLate); + struct GBAudio* audio = user; + audio->ch3.readable = false; } -static int32_t _updateNoiseChannel(struct GBAudioNoiseChannel* ch) { +static void _updateChannel4(struct mTiming* timing, void* user, uint32_t cyclesLate) { + struct GBAudio* audio = user; + struct GBAudioNoiseChannel* ch = &audio->ch4; int lsb = ch->lfsr & 1; ch->sample = lsb * 0x10 - 0x8; ch->sample *= ch->envelope.currentVolume; ch->lfsr >>= 1; ch->lfsr ^= (lsb * 0x60) << (ch->power ? 0 : 8); - int timing = ch->ratio ? 2 * ch->ratio : 1; - timing <<= ch->frequency; - timing *= 8; - return timing; -} - -void _scheduleEvent(struct GBAudio* audio) { - // TODO: Don't need p - if (audio->p) { - audio->nextEvent = audio->p->cpu->cycles >> audio->p->doubleSpeed; - audio->p->cpu->nextEvent = audio->p->cpu->cycles; - } else { - audio->nextEvent = 0; - } + int cycles = ch->ratio ? 2 * ch->ratio : 1; + cycles <<= ch->frequency; + cycles *= 8; + mTimingSchedule(timing, &audio->ch4Event, audio->timingFactor * cycles - cyclesLate); } void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGState* state, uint32_t* flagsOut) {@@ -905,8 +894,6 @@ ch1Flags = GBSerializedAudioEnvelopeSetLength(ch1Flags, audio->ch1.control.length);
ch1Flags = GBSerializedAudioEnvelopeSetNextStep(ch1Flags, audio->ch1.envelope.nextStep); ch1Flags = GBSerializedAudioEnvelopeSetFrequency(ch1Flags, audio->ch1.sweep.realFrequency); STORE_32LE(ch1Flags, 0, &state->ch1.envelope); - STORE_32LE(audio->nextFrame, 0, &state->ch1.nextFrame); - STORE_32LE(audio->nextCh1, 0, &state->ch1.nextEvent); flags = GBSerializedAudioFlagsSetCh2Volume(flags, audio->ch2.envelope.currentVolume); flags = GBSerializedAudioFlagsSetCh2Dead(flags, audio->ch2.envelope.dead);@@ -914,12 +901,9 @@ flags = GBSerializedAudioFlagsSetCh2Hi(flags, audio->ch2.control.hi);
ch2Flags = GBSerializedAudioEnvelopeSetLength(ch2Flags, audio->ch2.control.length); ch2Flags = GBSerializedAudioEnvelopeSetNextStep(ch2Flags, audio->ch2.envelope.nextStep); STORE_32LE(ch2Flags, 0, &state->ch2.envelope); - STORE_32LE(audio->nextCh2, 0, &state->ch2.nextEvent); memcpy(state->ch3.wavebanks, audio->ch3.wavedata32, sizeof(state->ch3.wavebanks)); STORE_16LE(audio->ch3.length, 0, &state->ch3.length); - STORE_32LE(audio->nextCh3, 0, &state->ch3.nextEvent); - STORE_32LE(audio->fadeCh3, 0, &state->ch1.nextCh3Fade); flags = GBSerializedAudioFlagsSetCh4Volume(flags, audio->ch4.envelope.currentVolume); flags = GBSerializedAudioFlagsSetCh4Dead(flags, audio->ch4.envelope.dead);@@ -927,7 +911,6 @@ STORE_32LE(audio->ch4.lfsr, 0, &state->ch4.lfsr);
ch4Flags = GBSerializedAudioEnvelopeSetLength(ch4Flags, audio->ch4.length); ch4Flags = GBSerializedAudioEnvelopeSetNextStep(ch4Flags, audio->ch4.envelope.nextStep); STORE_32LE(ch4Flags, 0, &state->ch4.envelope); - STORE_32LE(audio->nextCh4, 0, &state->ch4.nextEvent); STORE_32LE(flags, 0, flagsOut); }@@ -954,8 +937,6 @@ audio->ch1.sweep.occurred = GBSerializedAudioFlagsGetCh1SweepOccurred(flags);
audio->ch1.control.length = GBSerializedAudioEnvelopeGetLength(ch1Flags); audio->ch1.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch1Flags); audio->ch1.sweep.realFrequency = GBSerializedAudioEnvelopeGetFrequency(ch1Flags); - LOAD_32LE(audio->nextFrame, 0, &state->ch1.nextFrame); - LOAD_32LE(audio->nextCh1, 0, &state->ch1.nextEvent); LOAD_32LE(ch2Flags, 0, &state->ch2.envelope); audio->ch2.envelope.currentVolume = GBSerializedAudioFlagsGetCh2Volume(flags);@@ -963,14 +944,11 @@ audio->ch2.envelope.dead = GBSerializedAudioFlagsGetCh2Dead(flags);
audio->ch2.control.hi = GBSerializedAudioFlagsGetCh2Hi(flags); audio->ch2.control.length = GBSerializedAudioEnvelopeGetLength(ch2Flags); audio->ch2.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch2Flags); - LOAD_32LE(audio->nextCh2, 0, &state->ch2.nextEvent); audio->ch3.readable = GBSerializedAudioFlagsGetCh3Readable(flags); // TODO: Big endian? memcpy(audio->ch3.wavedata32, state->ch3.wavebanks, sizeof(audio->ch3.wavedata32)); LOAD_16LE(audio->ch3.length, 0, &state->ch3.length); - LOAD_32LE(audio->nextCh3, 0, &state->ch3.nextEvent); - LOAD_32LE(audio->fadeCh3, 0, &state->ch1.nextCh3Fade); LOAD_32LE(ch4Flags, 0, &state->ch4.envelope); audio->ch4.envelope.currentVolume = GBSerializedAudioFlagsGetCh4Volume(flags);@@ -978,21 +956,12 @@ audio->ch4.envelope.dead = GBSerializedAudioFlagsGetCh4Dead(flags);
audio->ch4.length = GBSerializedAudioEnvelopeGetLength(ch4Flags); audio->ch4.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch4Flags); LOAD_32LE(audio->ch4.lfsr, 0, &state->ch4.lfsr); - LOAD_32LE(audio->nextCh4, 0, &state->ch4.nextEvent); } void GBAudioSerialize(const struct GBAudio* audio, struct GBSerializedState* state) { GBAudioPSGSerialize(audio, &state->audio.psg, &state->audio.flags); - - STORE_32LE(audio->nextEvent, 0, &state->audio.nextEvent); - STORE_32LE(audio->eventDiff, 0, &state->audio.eventDiff); - STORE_32LE(audio->nextSample, 0, &state->audio.nextSample); } void GBAudioDeserialize(struct GBAudio* audio, const struct GBSerializedState* state) { GBAudioPSGDeserialize(audio, &state->audio.psg, &state->audio.flags); - - LOAD_32LE(audio->nextEvent, 0, &state->audio.nextEvent); - LOAD_32LE(audio->eventDiff, 0, &state->audio.eventDiff); - LOAD_32LE(audio->nextSample, 0, &state->audio.nextSample); }
@@ -8,6 +8,7 @@ #define GB_AUDIO_H
#include "util/common.h" +#include "core/timing.h" #include "third-party/blip_buf/blip_buf.h" DECL_BITFIELD(GBAudioRegisterDuty, uint8_t);@@ -147,6 +148,8 @@ };
struct GBAudio { struct GB* p; + struct mTiming* timing; + unsigned timingFactor; struct GBAudioSquareChannel ch1; struct GBAudioSquareChannel ch2; struct GBAudioWaveChannel ch3;@@ -176,20 +179,18 @@ bool playingCh3;
bool playingCh4; uint8_t* nr52; - int32_t nextEvent; - int32_t eventDiff; - int32_t nextFrame; int frame; - int32_t nextSample; int32_t sampleInterval; enum GBAudioStyle style; - int32_t nextCh1; - int32_t nextCh2; - int32_t nextCh3; - int32_t fadeCh3; - int32_t nextCh4; + struct mTimingEvent frameEvent; + struct mTimingEvent ch1Event; + struct mTimingEvent ch2Event; + struct mTimingEvent ch3Event; + struct mTimingEvent ch3Fade; + struct mTimingEvent ch4Event; + struct mTimingEvent sampleEvent; bool enable; size_t samples;@@ -229,7 +230,6 @@ void GBAudioWriteNR50(struct GBAudio* audio, uint8_t);
void GBAudioWriteNR51(struct GBAudio* audio, uint8_t); void GBAudioWriteNR52(struct GBAudio* audio, uint8_t); -int32_t GBAudioProcessEvents(struct GBAudio* audio, int32_t cycles); void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right); struct GBSerializedPSGState;
@@ -84,6 +84,7 @@ gb->coreCallbacks = NULL;
gb->stream = NULL; mTimingInit(&gb->timing, &gb->cpu->cycles, &gb->cpu->nextEvent); + gb->audio.timing = &gb->timing; } static void GBDeinit(struct mCPUComponent* component) {@@ -530,7 +531,6 @@ struct GB* gb = (struct GB*) cpu->master;
do { int32_t cycles = cpu->cycles; int32_t nextEvent; - int32_t testEvent; cpu->cycles = 0; cpu->nextEvent = INT_MAX;@@ -548,14 +548,6 @@ }
mTimingTick(&gb->timing, cycles); nextEvent = cpu->nextEvent; - - testEvent = GBAudioProcessEvents(&gb->audio, cycles >> gb->doubleSpeed); - if (testEvent != INT_MAX) { - testEvent <<= gb->doubleSpeed; - if (testEvent < nextEvent) { - nextEvent = testEvent; - } - } cpu->nextEvent = nextEvent;@@ -596,6 +588,7 @@ mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X\n", cpu->pc, cpu->bus);
} if (gb->memory.io[REG_KEY1] & 1) { gb->doubleSpeed ^= 1; + gb->audio.timingFactor = gb->doubleSpeed + 1; gb->memory.io[REG_KEY1] = 0; gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7; } else if (cpu->bus) {
@@ -177,6 +177,7 @@ LOAD_32LE(flags, 0, &state->cpu.flags);
gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags); gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags); gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags); + gb->audio.timingFactor = gb->doubleSpeed + 1; LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles); LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
@@ -33,8 +33,9 @@ #ifdef __BIG_ENDIAN__
++nr52; #endif GBAudioInit(&audio->psg, 0, nr52, GB_AUDIO_GBA); + audio->psg.timing = &audio->p->timing; + audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY; audio->samples = samples; - audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY; // Guess too large; we hang producing extra samples if we guess too low blip_set_rates(audio->psg.left, GBA_ARM7TDMI_FREQUENCY, 96000); blip_set_rates(audio->psg.right, GBA_ARM7TDMI_FREQUENCY, 96000);@@ -96,13 +97,6 @@ audio->nextEvent -= cycles;
audio->eventDiff += cycles; while (audio->nextEvent <= 0) { audio->nextEvent = INT_MAX; - if (audio->enable) { - audio->nextEvent = GBAudioProcessEvents(&audio->psg, audio->eventDiff / 4); - if (audio->nextEvent != INT_MAX) { - audio->nextEvent *= 4; - } - } - audio->nextSample -= audio->eventDiff; if (audio->nextSample <= 0) { _sample(audio);