diff --git a/include/mgba/internal/gb/audio.h b/include/mgba/internal/gb/audio.h index 3e2d4c2f8..ffcc71744 100644 --- a/include/mgba/internal/gb/audio.h +++ b/include/mgba/internal/gb/audio.h @@ -197,7 +197,6 @@ struct GBAudio { struct mTimingEvent frameEvent; struct mTimingEvent ch3Event; struct mTimingEvent ch3Fade; - struct mTimingEvent ch4Event; struct mTimingEvent sampleEvent; bool enable; @@ -240,7 +239,6 @@ void GBAudioWriteNR52(struct GBAudio* audio, uint8_t); void GBAudioRun(struct GBAudio* audio, int32_t timestamp); void GBAudioUpdateFrame(struct GBAudio* audio); -void GBAudioUpdateChannel4(struct GBAudio* audio); void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right); diff --git a/src/gb/audio.c b/src/gb/audio.c index e65bd106a..a44f6e12a 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -83,10 +83,6 @@ void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAu audio->ch3Fade.name = "GB Audio Channel 3 Memory"; audio->ch3Fade.callback = _fadeChannel3; audio->ch3Fade.priority = 0x14; - audio->ch4Event.context = audio; - audio->ch4Event.name = "GB Audio Channel 4"; - audio->ch4Event.callback = NULL; // This is pending removal, so calling it will crash - audio->ch4Event.priority = 0x15; audio->sampleEvent.context = audio; audio->sampleEvent.name = "GB Audio Sample"; audio->sampleEvent.callback = _sample; @@ -102,7 +98,6 @@ void GBAudioReset(struct GBAudio* audio) { mTimingDeschedule(audio->timing, &audio->frameEvent); mTimingDeschedule(audio->timing, &audio->ch3Event); mTimingDeschedule(audio->timing, &audio->ch3Fade); - mTimingDeschedule(audio->timing, &audio->ch4Event); mTimingDeschedule(audio->timing, &audio->sampleEvent); if (audio->style != GB_AUDIO_GBA) { mTimingSchedule(audio->timing, &audio->sampleEvent, 0); @@ -335,13 +330,13 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) { } void GBAudioWriteNR41(struct GBAudio* audio, uint8_t value) { - GBAudioUpdateChannel4(audio); + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); _writeDuty(&audio->ch4.envelope, value); audio->ch4.length = 64 - audio->ch4.envelope.length; } void GBAudioWriteNR42(struct GBAudio* audio, uint8_t value) { - GBAudioUpdateChannel4(audio); + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); if (!_writeEnvelope(&audio->ch4.envelope, value, audio->style)) { audio->playingCh4 = false; *audio->nr52 &= ~0x0008; @@ -349,14 +344,14 @@ void GBAudioWriteNR42(struct GBAudio* audio, uint8_t value) { } void GBAudioWriteNR43(struct GBAudio* audio, uint8_t value) { - GBAudioUpdateChannel4(audio); + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); audio->ch4.ratio = GBAudioRegisterNoiseFeedbackGetRatio(value); audio->ch4.frequency = GBAudioRegisterNoiseFeedbackGetFrequency(value); audio->ch4.power = GBAudioRegisterNoiseFeedbackGetPower(value); } void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { - GBAudioUpdateChannel4(audio); + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); bool wasStop = audio->ch4.stop; audio->ch4.stop = GBAudioRegisterNoiseControlGetStop(value); if (!wasStop && audio->ch4.stop && audio->ch4.length && !(audio->frame & 1)) { @@ -379,7 +374,7 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { --audio->ch4.length; } } - if (audio->playingCh4 && audio->ch4.envelope.dead != 2) { + if (audio->playingCh4) { audio->ch4.lastEvent = mTimingCurrentTime(audio->timing); } } @@ -498,6 +493,24 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp) { audio->ch2.lastUpdate += diff * period; _updateSquareSample(&audio->ch2); } + if (audio->playingCh4) { + int32_t cycles = audio->ch4.ratio ? 2 * audio->ch4.ratio : 1; + cycles <<= audio->ch4.frequency; + cycles *= 8 * audio->timingFactor; + + int32_t last = 0; + int32_t diff = timestamp - audio->ch4.lastEvent; + for (; last + cycles <= diff; last += cycles) { + int lsb = audio->ch4.lfsr & 1; + audio->ch4.sample = lsb * audio->ch4.envelope.currentVolume; + ++audio->ch4.nSamples; + audio->ch4.samples += audio->ch4.sample; + audio->ch4.lfsr >>= 1; + audio->ch4.lfsr ^= (lsb * 0x60) << (audio->ch4.power ? 0 : 8); + } + + audio->ch4.lastEvent += last; + } } void GBAudioUpdateFrame(struct GBAudio* audio) { @@ -555,7 +568,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) { if (audio->ch4.length && audio->ch4.stop) { --audio->ch4.length; if (audio->ch4.length == 0) { - GBAudioUpdateChannel4(audio); audio->playingCh4 = 0; *audio->nr52 &= ~0x0008; } @@ -581,7 +593,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) { if (audio->playingCh4 && !audio->ch4.envelope.dead) { --audio->ch4.envelope.nextStep; if (audio->ch4.envelope.nextStep == 0) { - GBAudioUpdateChannel4(audio); int8_t sample = audio->ch4.sample; _updateEnvelope(&audio->ch4.envelope); audio->ch4.sample = (sample > 0) * audio->ch4.envelope.currentVolume; @@ -595,31 +606,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) { } } -void GBAudioUpdateChannel4(struct GBAudio* audio) { - struct GBAudioNoiseChannel* ch = &audio->ch4; - if (ch->envelope.dead == 2 || !audio->playingCh4) { - return; - } - - int32_t cycles = ch->ratio ? 2 * ch->ratio : 1; - cycles <<= ch->frequency; - cycles *= 8 * audio->timingFactor; - - uint32_t last = 0; - uint32_t now = mTimingCurrentTime(audio->timing) - ch->lastEvent; - - for (; last + cycles <= now; last += cycles) { - int lsb = ch->lfsr & 1; - ch->sample = lsb * ch->envelope.currentVolume; - ++ch->nSamples; - ch->samples += ch->sample; - ch->lfsr >>= 1; - ch->lfsr ^= (lsb * 0x60) << (ch->power ? 0 : 8); - } - - ch->lastEvent += last; -} - void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) { GBAudioRun(audio, mTimingCurrentTime(audio->timing)); int dcOffset = audio->style == GB_AUDIO_GBA ? 0 : -0x8; @@ -660,7 +646,6 @@ void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) { sampleRight <<= 3; if (!audio->forceDisableCh[3]) { - GBAudioUpdateChannel4(audio); int16_t sample = audio->style == GB_AUDIO_GBA ? (audio->ch4.sample << 3) : _coalesceNoiseChannel(&audio->ch4); if (audio->ch4Left) { sampleLeft += sample; diff --git a/src/gb/io.c b/src/gb/io.c index a948403ec..973ff43f7 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -628,7 +628,7 @@ uint8_t GBIORead(struct GB* gb, unsigned address) { if (gb->model < GB_MODEL_CGB) { mLOG(GB_IO, GAME_ERROR, "Reading from CGB register FF%02X in DMG mode", address); } else if (gb->audio.enable) { - GBAudioUpdateChannel4(&gb->audio); + GBAudioRun(&gb->audio, mTimingCurrentTime(gb->audio.timing)); return (gb->audio.ch3.sample) | (gb->audio.ch4.sample << 4); } break;