From 6899cc35addc43acb04bb04bcb60e88cb66ab1de Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 15 Feb 2026 11:52:14 +0100 Subject: fix(audio): eliminate startup delay with automatic buffer pre-fill Added audio_get_required_prefill_time() to query ring buffer lookahead (400ms) and audio_is_prefilled() to check buffer state. audio_start() now warns if buffer under-filled. Replaced hardcoded 100ms pre-fill with automatic target-based pre-fill in main.cc and test_demo.cc. Co-Authored-By: Claude Sonnet 4.5 --- src/app/main.cc | 4 ++-- src/app/test_demo.cc | 4 ++-- src/audio/audio.cc | 24 ++++++++++++++++++++++++ src/audio/audio.h | 6 ++++++ 4 files changed, 34 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/app/main.cc b/src/app/main.cc index 90e3015..03434a0 100644 --- a/src/app/main.cc +++ b/src/app/main.cc @@ -198,8 +198,8 @@ int main(int argc, char** argv) { } #endif /* !defined(STRIP_ALL) */ - // Pre-fill using same pattern as main loop (100ms) - fill_audio_buffer(0.1f, 0.0); + // Pre-fill ring buffer to target lookahead (prevents startup delay) + fill_audio_buffer(audio_get_required_prefill_time(), 0.0); audio_start(); g_last_audio_time = audio_get_playback_time(); // Initialize after start diff --git a/src/app/test_demo.cc b/src/app/test_demo.cc index 39dbcba..f45916a 100644 --- a/src/app/test_demo.cc +++ b/src/app/test_demo.cc @@ -286,8 +286,8 @@ int main(int argc, char** argv) { audio_render_ahead(g_music_time, audio_dt * g_tempo_scale); }; - // Pre-fill using same pattern as main loop (100ms) - fill_audio_buffer(0.1f, 0.0); + // Pre-fill ring buffer to target lookahead (prevents startup delay) + fill_audio_buffer(audio_get_required_prefill_time(), 0.0); audio_start(); g_last_audio_time = audio_get_playback_time(); diff --git a/src/audio/audio.cc b/src/audio/audio.cc index d044b00..aaadd5a 100644 --- a/src/audio/audio.cc +++ b/src/audio/audio.cc @@ -57,11 +57,35 @@ void audio_init() { g_audio_backend->init(); } +float audio_get_required_prefill_time() { + return (float)RING_BUFFER_LOOKAHEAD_MS / 1000.0f; +} + +bool audio_is_prefilled() { + const int buffered = g_ring_buffer.available_read(); + const float buffered_time = + (float)buffered / (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS); + const float required = audio_get_required_prefill_time(); + return buffered_time >= (required - 0.001f); // 1ms tolerance +} + void audio_start() { if (g_audio_backend == nullptr) { printf("Cannot start: audio not initialized.\n"); return; } + +#if !defined(STRIP_ALL) + if (!audio_is_prefilled()) { + const int buffered = g_ring_buffer.available_read(); + const float buffered_ms = + (float)buffered / (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS) * + 1000.0f; + printf("WARNING: Audio buffer not pre-filled (%.1fms < %.1fms)\n", + buffered_ms, audio_get_required_prefill_time() * 1000.0f); + } +#endif + g_audio_backend->start(); } diff --git a/src/audio/audio.h b/src/audio/audio.h index 9d521e6..beb994f 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -23,6 +23,12 @@ struct SpecHeader { void audio_init(); void audio_start(); // Starts the audio device callback +// Get required pre-fill time (matches ring buffer lookahead) +float audio_get_required_prefill_time(); + +// Check if buffer is sufficiently pre-filled +bool audio_is_prefilled(); + // Ring buffer audio rendering (main thread fills buffer) // target_fill: Target buffer fill time in seconds (default: // RING_BUFFER_LOOKAHEAD_MS/1000) -- cgit v1.2.3