diff --git a/CHANGES b/CHANGES index 5a2ba5b37..b3a0c01e3 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,7 @@ Bugfixes: - DS GX: Properly mask address for slot 2 4x4-texel textures - DS Slot-1: Emulate initial SPI command delay - DS: Fix exposed CPU frequencies and audio timing + - DS Audio: Fix audio sampling slightly too quickly Misc: - DS: Set boot complete bit in RAM on boot (fixes mgba.io/i/576, mgba.io/i/580, mgba.io/i/586) - DS Memory: Ensure DS9 I/O is 8-byte aligned diff --git a/include/mgba/internal/ds/audio.h b/include/mgba/internal/ds/audio.h index c568f3835..3162b7d5f 100644 --- a/include/mgba/internal/ds/audio.h +++ b/include/mgba/internal/ds/audio.h @@ -80,6 +80,7 @@ struct DSAudio { unsigned sampleRate; int32_t sampleInterval; + unsigned sampleDrift; bool forceDisableCh[16]; int bias; diff --git a/src/ds/audio.c b/src/ds/audio.c index 062d98e8b..fe30aa0a4 100644 --- a/src/ds/audio.c +++ b/src/ds/audio.c @@ -86,6 +86,7 @@ void DSAudioReset(struct DSAudio* audio) { mTimingSchedule(&audio->p->ds7.timing, &audio->sampleEvent, 0); audio->sampleRate = 0x8000; audio->sampleInterval = DS_ARM7TDMI_FREQUENCY / audio->sampleRate; + audio->sampleDrift = 0; int ch; for (ch = 0; ch < 16; ++ch) { @@ -325,6 +326,12 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { int16_t sampleLeft = _applyBias(audio, audio->sampleLeft); int16_t sampleRight = _applyBias(audio, audio->sampleRight); + audio->sampleDrift += DS_ARM7TDMI_FREQUENCY % audio->sampleRate; + + if (audio->sampleDrift >= audio->sampleRate) { + ++audio->sampleInterval; + } + mCoreSyncLockAudio(audio->p->sync); unsigned produced; if ((size_t) blip_samples_avail(audio->left) < audio->samples) { @@ -351,4 +358,9 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { audio->p->stream->postAudioBuffer(audio->p->stream, audio->left, audio->right); } mTimingSchedule(timing, &audio->sampleEvent, audio->sampleInterval - cyclesLate); + + if (audio->sampleDrift >= audio->sampleRate) { + --audio->sampleInterval; + audio->sampleDrift -= audio->sampleRate; + } }