SoundSource / AudioHandler stopping sound output (works in simulator)

I'm having trouble with an AudioHandler in C. I've read through the discussion here: Tips and tricks for processing audio in C:

I'm writing a sound emulator for 8 bit game consoles. Right now I'm focusing on NES (NSF files)

My setup is as follows:

  1. User presses button, call from lua to c for "play_file". Which instantiates an emulator and sets a flag "playing" = true;
  2. Meanwhile in lua playdate.update() I have a call to emulator:update() (my c code). In emulator:update(), if "playing" = true, I fill a ring buffer of samples. Right now it is 500 arrays of 512 int16_t. Once the ring buffer is full, this method no-ops.
  3. emulator:update() binds a new sound source with "AudioSourceCallback" once it has a full ring buffer.
  4. The audio callbacks begin, samples are removed from the ring buffer and fed into the *left and *right arrays (256 pcm samples each) and audio plays. In the meantime, emulator:update() keeps on getting called so it can replenish the ring buffer.
  5. Eventually (after about 2 seconds) AudioSouceCallback reaches the end of the initial 500 elements of the buffer and needs to circle back to the front. When this happens audio stops playing on device, but it works in the simulator.

I've added debugging via LogToConsole statements to document where the error happens. The number of items in the buffer never drops below about 480 elements.

main.c:79:AudioSourceCallback(): Played a sample, writeIndex: 497, readIndex: 498, bufferLength: 499, audioSourceCallbackCount: 497
main.c:79:AudioSourceCallback(): Played a sample, writeIndex: 497, readIndex: 499, bufferLength: 498, audioSourceCallbackCount: 498
main.c:79:AudioSourceCallback(): Played a sample, writeIndex: 497, readIndex: 500, bufferLength: 497, audioSourceCallbackCount: 499
*****  Audio playback dies here....I think ******
main.c:79:AudioSourceCallback(): Played a sample, writeIndex: 497, readIndex: 1, bufferLength: 496, audioSourceCallbackCount: 500
main.c:79:AudioSourceCallback(): Played a sample, writeIndex: 497, readIndex: 2, bufferLength: 495, audioSourceCallbackCount: 501
main.c:79:AudioSourceCallback(): Played a sample, writeIndex: 497, readIndex: 3, bufferLength: 494, audioSourceCallbackCount: 502

If I preload the enitre track, sound works great, but it needs about 15k samples and uses like 10MB of memory (and needs about 6 seconds CPU time to load the huge buffer). In theory, I think I can get away with a buffer of about 50 items or less as the buffer length never drops below 480 on device (on simulator the buffer stays at 495 or more) in my current code.

The audio issue always seems to be when the index wraps the ring and comes back to start. This all works fine on the simulator. Any ideas as to what's going on? Do I need to free memory in the buffer slot before I overwrite it?

I'm really curious to see how this turns out, as I'm doing something very similar in my music player app, but I haven't been able to test it on hardware just yet. I personally had issues with the read/write indexes (or more specifically, the 'block count') of my ring buffer falling behind the actual state of the buffer, occasionally during playback in the Simulator. I ended up changing the variable from an int to an _Atomic int and that seemed to resolve the issue. I have no idea if that's necessary on hardware, and your issue is probably something different, anyway.