all repos — mgba @ 7652fe9f7ae13b4e3d5b29e0ebf869d7503b22cc

mGBA Game Boy Advance Emulator

GB Audio: Fix serializing sweep time
Vicki Pfau vi@endrift.com
Mon, 10 Aug 2020 18:11:54 -0700
commit

7652fe9f7ae13b4e3d5b29e0ebf869d7503b22cc

parent

717ede4b94e49a70ca2a8512e6851c4b2db99c69

4 files changed, 40 insertions(+), 18 deletions(-)

jump to
M CHANGESCHANGES

@@ -10,6 +10,7 @@ - ARM: Fix ALU reading PC after shifting

- ARM: Fix STR storing PC after address calculation - GB: Partially fix timing for skipped BIOS - GB Audio: Fix initial sweep state + - GB Audio: Fix serializing sweep time - GB MBC: Fix MBC1 mode changing behavior - GB Video: Fix state after skipping BIOS (fixes mgba.io/i/1715 and mgba.io/i/1716) - GBA: Fix timing advancing too quickly in rare cases
M include/mgba/internal/gb/serialize.hinclude/mgba/internal/gb/serialize.h

@@ -59,7 +59,9 @@ * | bits 10 - 20: Shadow frequency register

* | bits 21 - 31: Reserved * | 0x0004C - 0x0004F: Next frame * | 0x00050 - 0x00053: Next channel 3 fade - * | 0x00054 - 0x00057: Reserved + * | 0x00054 - 0x00057: Sweep state + * | bits 0 - 2: Timesteps + * | bits 3 - 31: Reserved * | 0x00058 - 0x0005B: Next event * 0x0005C - 0x0006B: Audio channel 2 state * | 0x0005C - 0x0005F: Envelepe timing

@@ -87,22 +89,23 @@ * | 0x000A4: Channel 1 envelope state

* | bits 0 - 3: Current volume * | bits 4 - 5: Is dead? * | bit 6: Is high? +* | bit 7: Reserved * | 0x000A5: Channel 2 envelope state * | bits 0 - 3: Current volume * | bits 4 - 5: Is dead? * | bit 6: Is high? -* | bits 7: Reserved +* | bit 7: Reserved * | 0x000A6: Channel 4 envelope state * | bits 0 - 3: Current volume * | bits 4 - 5: Is dead? - * | bit 6: Is high? -* | bits 7: Reserved + * | bits 6 - 7: Current frame (continued) * | 0x000A7: Miscellaneous audio flags - * | bits 0 - 3: Current frame - * | bit 4: Is channel 1 sweep enabled? - * | bit 5: Has channel 1 sweep occurred? - * | bit 6: Is channel 3's memory readable? - * | bit 7: Reserved + * | bit 0: Current frame (continuation) + * | bit 1: Is channel 1 sweep enabled? + * | bit 2: Has channel 1 sweep occurred? + * | bit 3: Is channel 3's memory readable? + * | bit 4: Skip frame + * | bits 5 - 7: Reserved * | 0x000A8 - 0x000AB: Left capacitor charge * | 0x000AC - 0x000AF: Right capacitor charge * | 0x000B0 - 0x000B3: Next sample

@@ -203,12 +206,16 @@ DECL_BITS(GBSerializedAudioEnvelope, Length, 0, 7);

DECL_BITS(GBSerializedAudioEnvelope, NextStep, 7, 3); DECL_BITS(GBSerializedAudioEnvelope, Frequency, 10, 11); + +DECL_BITFIELD(GBSerializedAudioSweep, uint32_t); +DECL_BITS(GBSerializedAudioSweep, Time, 0, 3); + struct GBSerializedPSGState { struct { GBSerializedAudioEnvelope envelope; int32_t nextFrame; int32_t nextCh3Fade; - int32_t reserved; + GBSerializedAudioSweep sweep; uint32_t nextEvent; } ch1; struct {
M include/mgba/internal/gba/serialize.hinclude/mgba/internal/gba/serialize.h

@@ -41,7 +41,10 @@ * | bits 7 - 9: Next step

* | bits 10 - 20: Shadow frequency register * | bits 21 - 31: Reserved * | 0x00134 - 0x00137: Next frame - * | 0x00138 - 0x0013F: Reserved + * | 0x00138 - 0x0013B: Next channel 3 fade + * | 0x0013C - 0x0013F: Sweep state + * | bits 0 - 2: Timesteps + * | bits 3 - 7: Reserved * | 0x00140 - 0x00143: Next event * 0x00144 - 0x00153: Audio channel 2 state * | 0x00144 - 0x00147: Envelepe timing

@@ -75,21 +78,23 @@ * | 0x001DC - 0x001DC: Channel 1 envelope state

* | bits 0 - 3: Current volume * | bits 4 - 5: Is dead? * | bit 6: Is high? +* | bit 7: Reserved * | 0x001DD - 0x001DD: Channel 2 envelope state * | bits 0 - 3: Current volume * | bits 4 - 5: Is dead? * | bit 6: Is high? -* | bits 7: Reserved +* | bit 7: Reserved * | 0x001DE - 0x001DE: Channel 4 envelope state * | bits 0 - 3: Current volume * | bits 4 - 5: Is dead? - * | bit 6: Is high? -* | bits 7: Reserved + * | bits 6 - 7: Current frame (continued) * | 0x001DF - 0x001DF: Miscellaneous audio flags - * | bits 0 - 3: Current frame - * | bit 4: Is channel 1 sweep enabled? - * | bit 5: Has channel 1 sweep occurred? - * | bits 6 - 7: Reserved + * | bit 0: Current frame (continuation) + * | bit 1: Is channel 1 sweep enabled? + * | bit 2: Has channel 1 sweep occurred? + * | bit 3: Is channel 3's memory readable? + * | bit 4: Skip frame + * | bits 5 - 7: Reserved * 0x001E0 - 0x001FF: Video miscellaneous state * | 0x001E0 - 0x001E3: Next event * | 0x001E4 - 0x001F7: Reserved
M src/gb/audio.csrc/gb/audio.c

@@ -964,6 +964,7 @@ }

void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGState* state, uint32_t* flagsOut) { uint32_t flags = 0; + uint32_t sweep = 0; uint32_t ch1Flags = 0; uint32_t ch2Flags = 0; uint32_t ch4Flags = 0;

@@ -980,7 +981,9 @@ flags = GBSerializedAudioFlagsSetCh1SweepOccurred(flags, audio->ch1.sweep.occurred);

ch1Flags = GBSerializedAudioEnvelopeSetLength(ch1Flags, audio->ch1.control.length); ch1Flags = GBSerializedAudioEnvelopeSetNextStep(ch1Flags, audio->ch1.envelope.nextStep); ch1Flags = GBSerializedAudioEnvelopeSetFrequency(ch1Flags, audio->ch1.sweep.realFrequency); + sweep = GBSerializedAudioSweepSetTime(sweep, audio->ch1.sweep.time & 7); STORE_32LE(ch1Flags, 0, &state->ch1.envelope); + STORE_32LE(sweep, 0, &state->ch1.sweep); STORE_32LE(audio->ch1Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch1.nextEvent); flags = GBSerializedAudioFlagsSetCh2Volume(flags, audio->ch2.envelope.currentVolume);

@@ -1011,6 +1014,7 @@ }

void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGState* state, const uint32_t* flagsIn) { uint32_t flags; + uint32_t sweep; uint32_t ch1Flags = 0; uint32_t ch2Flags = 0; uint32_t ch4Flags = 0;

@@ -1032,11 +1036,16 @@ audio->frame = GBSerializedAudioFlagsGetFrame(flags);

audio->skipFrame = GBSerializedAudioFlagsGetSkipFrame(flags); LOAD_32LE(ch1Flags, 0, &state->ch1.envelope); + LOAD_32LE(sweep, 0, &state->ch1.sweep); audio->ch1.envelope.currentVolume = GBSerializedAudioFlagsGetCh1Volume(flags); audio->ch1.envelope.dead = GBSerializedAudioFlagsGetCh1Dead(flags); audio->ch1.control.hi = GBSerializedAudioFlagsGetCh1Hi(flags); audio->ch1.sweep.enable = GBSerializedAudioFlagsGetCh1SweepEnabled(flags); audio->ch1.sweep.occurred = GBSerializedAudioFlagsGetCh1SweepOccurred(flags); + audio->ch1.sweep.time = GBSerializedAudioSweepGetTime(sweep); + if (!audio->ch1.sweep.time) { + audio->ch1.sweep.time = 8; + } audio->ch1.control.length = GBSerializedAudioEnvelopeGetLength(ch1Flags); audio->ch1.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch1Flags); audio->ch1.sweep.realFrequency = GBSerializedAudioEnvelopeGetFrequency(ch1Flags);