From 76a8f4da2bb4fc4ef10a64eae5d3da0d7846c73f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 31 May 2022 22:45:00 -0700 Subject: [PATCH] GB Audio: Migrate channel 3 into GBRunAudio --- include/mgba/internal/gb/audio.h | 5 +- include/mgba/internal/gb/serialize.h | 4 +- include/mgba/internal/gba/serialize.h | 4 +- src/gb/audio.c | 182 ++++++++++++-------------- src/gb/io.c | 2 + src/gba/audio.c | 2 + 6 files changed, 91 insertions(+), 108 deletions(-) diff --git a/include/mgba/internal/gb/audio.h b/include/mgba/internal/gb/audio.h index ffcc71744..93c76d997 100644 --- a/include/mgba/internal/gb/audio.h +++ b/include/mgba/internal/gb/audio.h @@ -113,6 +113,7 @@ struct GBAudioWaveChannel { bool bank; bool enable; + int8_t sample; unsigned length; int volume; @@ -125,7 +126,7 @@ struct GBAudioWaveChannel { uint32_t wavedata32[8]; uint8_t wavedata8[16]; }; - int8_t sample; + int32_t nextUpdate; }; struct GBAudioNoiseChannel { @@ -195,8 +196,6 @@ struct GBAudio { enum GBAudioStyle style; struct mTimingEvent frameEvent; - struct mTimingEvent ch3Event; - struct mTimingEvent ch3Fade; struct mTimingEvent sampleEvent; bool enable; diff --git a/include/mgba/internal/gb/serialize.h b/include/mgba/internal/gb/serialize.h index 6043cc919..11bdf7dc3 100644 --- a/include/mgba/internal/gb/serialize.h +++ b/include/mgba/internal/gb/serialize.h @@ -59,7 +59,7 @@ mLOG_DECLARE_CATEGORY(GB_STATE); * | bits 21 - 23: Duty index * | bits 24 - 31: Reserved * | 0x0004C - 0x0004F: Next frame - * | 0x00050 - 0x00053: Next channel 3 fade + * | 0x00050 - 0x00053: Reserved * | 0x00054 - 0x00057: Sweep state * | bits 0 - 2: Timesteps * | bits 3 - 31: Reserved @@ -220,7 +220,7 @@ struct GBSerializedPSGState { struct { GBSerializedAudioEnvelope envelope; int32_t nextFrame; - int32_t nextCh3Fade; + int32_t reserved; GBSerializedAudioSweep sweep; uint32_t lastUpdate; } ch1; diff --git a/include/mgba/internal/gba/serialize.h b/include/mgba/internal/gba/serialize.h index b25b3aec0..364563195 100644 --- a/include/mgba/internal/gba/serialize.h +++ b/include/mgba/internal/gba/serialize.h @@ -42,7 +42,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE); * | bits 21 - 23: Duty index * | bits 24 - 31: Reserved * | 0x00134 - 0x00137: Next frame - * | 0x00138 - 0x0013B: Next channel 3 fade + * | 0x00138 - 0x0013B: Reserved * | 0x0013C - 0x0013F: Sweep state * | bits 0 - 2: Timesteps * | bits 3 - 7: Reserved @@ -60,7 +60,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE); * | 0x00154 - 0x00173: Wave banks * | 0x00174 - 0x00175: Remaining length * | 0x00176 - 0x00177: Reserved - * | 0x00178 - 0x0017B: Last update + * | 0x00178 - 0x0017B: Next event * 0x0017C - 0x0018B: Audio channel 4 state * | 0x0017C - 0x0017F: Linear feedback shift register state * | 0x00180 - 0x00183: Envelepe timing diff --git a/src/gb/audio.c b/src/gb/audio.c index a44f6e12a..9051a3c5d 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -39,8 +39,6 @@ static void _updateSquareSample(struct GBAudioSquareChannel* ch); static int16_t _coalesceNoiseChannel(struct GBAudioNoiseChannel* ch); static void _updateFrame(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 _sample(struct mTiming* timing, void* user, uint32_t cyclesLate); static const int _squareChannelDuty[4][8] = { @@ -75,14 +73,6 @@ void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAu audio->frameEvent.name = "GB Audio Frame Sequencer"; audio->frameEvent.callback = _updateFrame; audio->frameEvent.priority = 0x10; - audio->ch3Event.context = audio; - audio->ch3Event.name = "GB Audio Channel 3"; - audio->ch3Event.callback = _updateChannel3; - audio->ch3Event.priority = 0x13; - audio->ch3Fade.context = audio; - audio->ch3Fade.name = "GB Audio Channel 3 Memory"; - audio->ch3Fade.callback = _fadeChannel3; - audio->ch3Fade.priority = 0x14; audio->sampleEvent.context = audio; audio->sampleEvent.name = "GB Audio Sample"; audio->sampleEvent.callback = _sample; @@ -96,8 +86,6 @@ void GBAudioDeinit(struct GBAudio* audio) { void GBAudioReset(struct GBAudio* audio) { mTimingDeschedule(audio->timing, &audio->frameEvent); - mTimingDeschedule(audio->timing, &audio->ch3Event); - mTimingDeschedule(audio->timing, &audio->ch3Fade); mTimingDeschedule(audio->timing, &audio->sampleEvent); if (audio->style != GB_AUDIO_GBA) { mTimingSchedule(audio->timing, &audio->sampleEvent, 0); @@ -261,28 +249,32 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) { } void GBAudioWriteNR30(struct GBAudio* audio, uint8_t value) { + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); audio->ch3.enable = GBAudioRegisterBankGetEnable(value); if (!audio->ch3.enable) { - mTimingDeschedule(audio->timing, &audio->ch3Event); audio->playingCh3 = false; *audio->nr52 &= ~0x0004; } } void GBAudioWriteNR31(struct GBAudio* audio, uint8_t value) { + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); audio->ch3.length = 256 - value; } void GBAudioWriteNR32(struct GBAudio* audio, uint8_t value) { + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); audio->ch3.volume = GBAudioRegisterBankVolumeGetVolumeGB(value); } void GBAudioWriteNR33(struct GBAudio* audio, uint8_t value) { + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); audio->ch3.rate &= 0x700; audio->ch3.rate |= GBAudioRegisterControlGetRate(value); } void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) { + GBAudioRun(audio, mTimingCurrentTime(audio->timing)); audio->ch3.rate &= 0xFF; audio->ch3.rate |= GBAudioRegisterControlGetRate(value << 8); bool wasStop = audio->ch3.stop; @@ -318,12 +310,10 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) { audio->ch3.sample = 0; } } - mTimingDeschedule(audio->timing, &audio->ch3Fade); - mTimingDeschedule(audio->timing, &audio->ch3Event); if (audio->playingCh3) { audio->ch3.readable = audio->style != GB_AUDIO_DMG; // TODO: Where does this cycle delay come from? - mTimingSchedule(audio->timing, &audio->ch3Event, audio->timingFactor * (4 + 2 * (2048 - audio->ch3.rate))); + audio->ch3.nextUpdate = mTimingCurrentTime(audio->timing) + (6 + 2 * (2048 - audio->ch3.rate)) * audio->timingFactor; } *audio->nr52 &= ~0x0004; *audio->nr52 |= audio->playingCh3 << 2; @@ -493,6 +483,78 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp) { audio->ch2.lastUpdate += diff * period; _updateSquareSample(&audio->ch2); } + if (audio->playingCh3) { + int cycles = 2 * (2048 - audio->ch3.rate) * audio->timingFactor; + int32_t diff = timestamp - audio->ch3.nextUpdate; + if (diff >= 0) { + diff = (diff / cycles) + 1; + int volume; + switch (audio->ch3.volume) { + case 0: + volume = 4; + break; + case 1: + volume = 0; + break; + case 2: + volume = 1; + break; + default: + case 3: + volume = 2; + break; + } + int start = 7; + int end = 0; + int mask = 0x1F; + int iter; + switch (audio->style) { + case GB_AUDIO_DMG: + default: + audio->ch3.window += diff; + audio->ch3.window &= 0x1F; + audio->ch3.sample = audio->ch3.wavedata8[audio->ch3.window >> 1]; + if (!(audio->ch3.window & 1)) { + audio->ch3.sample >>= 4; + } + audio->ch3.sample &= 0xF; + break; + case GB_AUDIO_GBA: + if (audio->ch3.size) { + mask = 0x3F; + } else if (audio->ch3.bank) { + end = 4; + } else { + start = 3; + } + for (iter = 0; iter < (diff & mask); ++iter) { + uint32_t bitsCarry = audio->ch3.wavedata32[end] & 0x000000F0; + uint32_t bits; + int i; + for (i = start; i >= end; --i) { + bits = audio->ch3.wavedata32[i] & 0x000000F0; + audio->ch3.wavedata32[i] = ((audio->ch3.wavedata32[i] & 0x0F0F0F0F) << 4) | ((audio->ch3.wavedata32[i] & 0xF0F0F000) >> 12); + audio->ch3.wavedata32[i] |= bitsCarry << 20; + bitsCarry = bits; + } + audio->ch3.sample = bitsCarry >> 4; + } + break; + } + if (audio->ch3.volume > 3) { + audio->ch3.sample += audio->ch3.sample << 1; + } + audio->ch3.sample >>= volume; + audio->ch3.nextUpdate += diff * cycles; + audio->ch3.readable = true; + } + if (audio->style == GB_AUDIO_DMG && audio->ch3.readable) { + diff = timestamp - audio->ch3.nextUpdate + cycles; + if (diff >= 4) { + audio->ch3.readable = false; + } + } + } if (audio->playingCh4) { int32_t cycles = audio->ch4.ratio ? 2 * audio->ch4.ratio : 1; cycles <<= audio->ch4.frequency; @@ -559,7 +621,6 @@ void GBAudioUpdateFrame(struct GBAudio* audio) { if (audio->ch3.length && audio->ch3.stop) { --audio->ch3.length; if (audio->ch3.length == 0) { - mTimingDeschedule(audio->timing, &audio->ch3Event); audio->playingCh3 = 0; *audio->nr52 &= ~0x0004; } @@ -828,80 +889,6 @@ static bool _updateSweep(struct GBAudioSquareChannel* ch, bool initial) { return true; } -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) { - case 0: - volume = 4; - break; - case 1: - volume = 0; - break; - case 2: - volume = 1; - break; - default: - case 3: - volume = 2; - break; - } - int start; - int end; - switch (audio->style) { - case GB_AUDIO_DMG: - default: - ++ch->window; - ch->window &= 0x1F; - ch->sample = ch->wavedata8[ch->window >> 1]; - if (!(ch->window & 1)) { - ch->sample >>= 4; - } - ch->sample &= 0xF; - break; - case GB_AUDIO_GBA: - if (ch->size) { - start = 7; - end = 0; - } else if (ch->bank) { - start = 7; - end = 4; - } else { - start = 3; - end = 0; - } - uint32_t bitsCarry = ch->wavedata32[end] & 0x000000F0; - uint32_t bits; - for (i = start; i >= end; --i) { - bits = ch->wavedata32[i] & 0x000000F0; - ch->wavedata32[i] = ((ch->wavedata32[i] & 0x0F0F0F0F) << 4) | ((ch->wavedata32[i] & 0xF0F0F000) >> 12); - ch->wavedata32[i] |= bitsCarry << 20; - bitsCarry = bits; - } - ch->sample = bitsCarry >> 4; - break; - } - if (ch->volume > 3) { - ch->sample += ch->sample << 1; - } - ch->sample >>= volume; - audio->ch3.readable = true; - if (audio->style == GB_AUDIO_DMG) { - mTimingDeschedule(audio->timing, &audio->ch3Fade); - mTimingSchedule(timing, &audio->ch3Fade, 4 - 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; -} - void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGState* state, uint32_t* flagsOut) { uint32_t flags = 0; uint32_t sweep = 0; @@ -937,8 +924,7 @@ void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGStat flags = GBSerializedAudioFlagsSetCh3Readable(flags, audio->ch3.readable); memcpy(state->ch3.wavebanks, audio->ch3.wavedata32, sizeof(state->ch3.wavebanks)); STORE_16LE(audio->ch3.length, 0, &state->ch3.length); - STORE_32LE(audio->ch3Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch3.nextEvent); - STORE_32LE(audio->ch3Fade.when - mTimingCurrentTime(audio->timing), 0, &state->ch1.nextCh3Fade); + STORE_32LE(audio->ch3.nextUpdate - mTimingCurrentTime(audio->timing), 0, &state->ch3.nextEvent); flags = GBSerializedAudioFlagsSetCh4Volume(flags, audio->ch4.envelope.currentVolume); flags = GBSerializedAudioFlagsSetCh4Dead(flags, audio->ch4.envelope.dead); @@ -1009,14 +995,8 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt // 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(when, 0, &state->ch3.nextEvent); - if (audio->playingCh3) { - mTimingSchedule(audio->timing, &audio->ch3Event, when); - } - LOAD_32LE(when, 0, &state->ch1.nextCh3Fade); - if (audio->ch3.readable && audio->style == GB_AUDIO_DMG) { - mTimingSchedule(audio->timing, &audio->ch3Fade, when); - } + LOAD_32LE(audio->ch3.nextUpdate, 0, &state->ch3.nextEvent); + audio->ch3.nextUpdate += mTimingCurrentTime(audio->timing); LOAD_32LE(ch4Flags, 0, &state->ch4.envelope); audio->ch4.envelope.currentVolume = GBSerializedAudioFlagsGetCh4Volume(flags); diff --git a/src/gb/io.c b/src/gb/io.c index 973ff43f7..d03171bb4 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -403,6 +403,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { case GB_REG_WAVE_D: case GB_REG_WAVE_E: case GB_REG_WAVE_F: + GBAudioRun(&gb->audio, mTimingCurrentTime(gb->audio.timing)); if (!gb->audio.playingCh3 || gb->audio.style != GB_AUDIO_DMG) { gb->audio.ch3.wavedata8[address - GB_REG_WAVE_0] = value; } else if(gb->audio.ch3.readable) { @@ -607,6 +608,7 @@ uint8_t GBIORead(struct GB* gb, unsigned address) { case GB_REG_WAVE_E: case GB_REG_WAVE_F: if (gb->audio.playingCh3) { + GBAudioRun(&gb->audio, mTimingCurrentTime(gb->audio.timing)); if (gb->audio.ch3.readable || gb->audio.style != GB_AUDIO_DMG) { return gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1]; } else { diff --git a/src/gba/audio.c b/src/gba/audio.c index fc264349f..4f3cfe3de 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -229,6 +229,7 @@ void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) { bank = 1; } + GBAudioRun(&audio->psg, mTimingCurrentTime(audio->psg.timing)); audio->psg.ch3.wavedata32[address | (bank * 4)] = value; } @@ -241,6 +242,7 @@ uint32_t GBAAudioReadWaveRAM(struct GBAAudio* audio, int address) { bank = 1; } + GBAudioRun(&audio->psg, mTimingCurrentTime(audio->psg.timing)); return audio->psg.ch3.wavedata32[address | (bank * 4)]; }