769f2f5702
sceAudioOutputPannedBlocking() occupies the calling thread for the full duration of the chunk it just submitted. That was fine while PCM chunks came out of a fully-resident buffer (a near-instant memcpy), but now that they're read from the asset on demand, that same read happens in between output calls on the same thread - any read slower than a memcpy opens a real gap in the hardware channel, heard as crackle. Split the single feeder thread in two: a reader thread that does all PCM I/O (seek/read, loop-wrap, fade prep) ahead of playback into a small 3-slot queue, and a player thread that only pulls ready chunks off the queue and outputs them. This overlaps I/O with hardware playback instead of serializing them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>