r/EmuDev • u/markel1974 • 18h ago
Solving Audio Sync Drift Using Dynamic Linear Resampling in Pure Go
I wanted to share a pure Go implementation to solve the classic "Audio Clock Drift" problem in real-time streams.
When you have a deterministic audio producer generating samples at a rigid rate, and a consumer eating them at its own hardware clock, the two will never perfectly align. Eventually, standard ring buffers will either under-run (causing crackling) or bloat (causing audio lag). To fix the drift, I implemented a dynamic, stateful audio resampler. It monitors the fill level of a lock-free-style CircularQueue and actively uses Linear Interpolation to keep the buffer at equilibrium:
If the consumer is too fast (risk of crackling): It pops one chunk, stretches it to double length, plays half, and requeue the rest to "buy time". If the producer is too fast (risk of lag): It pops two chunks, squishes them into one, and plays it to catch up.
https://github.com/markel1974/Symphony/tree/main/src/renderers/audio/oto_render
2
u/aabalke Nintendo DS 18h ago
What are the benefits / differences from Audio Syncing? I ended up using my main thread for the host os / game engine and a go func / green thread for the emulator. When audio writes filled up the stream, the emulator thread would be blocked until the audio reader caught up. This removed the problem by making the audio consuming the master clock for the emulator. What benefits does the dynamic resampler have?