#714: fix crackling audio. #1618
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Previously, the sound registers were used to synthesize fixed amount of sound after every TIC() and this was pushed to SDL. The problem with this approach was crackling if TIC() takes too long to reach 60Hz. In this fix, the sound registers are instead pushed to a ring buffer and the audio is synthesized in SDL callback, to render audio. If the ring buffer does not have enough values, the sound synthesis uses the last good values from the ring buffer, so the music slows down yes, but at least it does not crackle.
The corollary to this is that calling tic_core_tick_end(tic) is not enough during the Studio sound export; one should also call tic_core_synthesize_sound which does the job of pulling the sound registers from the tail of the ring buffer and doing the sound synthesis.
The ring buffer is kept short on purpose, because if there slight desync between the TIC() frequency and sound frequency, the TIC() frequency might run faster and delay might build up. So, the ring buffer length sets a maximum on the delay that this technique can create.
Just to note that you might want to experiment with TIC_SOUND_RINGBUF_LEN and SDL_AudioSpec.samples to get good amount of buffering, without significant delays, and not too much overhead. SDL_AudioSpec.samples controls how many times a second the callback is called and presumably there's a small overhead with each call.
This fix also btw probably fixes the complaints about the sound getting desynchronized with the video; the short ring buffer ensures that the audio can never be too much out of sync with the video.