diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio/audio.cc | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/src/audio/audio.cc b/src/audio/audio.cc index de1c702..3b7b7fd 100644 --- a/src/audio/audio.cc +++ b/src/audio/audio.cc @@ -17,6 +17,12 @@ // Global ring buffer for audio streaming static AudioRingBuffer g_ring_buffer; +// Pending write buffer for partially written samples +// Maximum size: one chunk (533 frames @ 60fps = 1066 samples stereo) +#define MAX_PENDING_SAMPLES 2048 +static float g_pending_buffer[MAX_PENDING_SAMPLES]; +static int g_pending_samples = 0; // How many samples are waiting to be written + // Global backend pointer for audio abstraction static AudioBackend* g_audio_backend = nullptr; static MiniaudioBackend g_default_backend; @@ -54,6 +60,9 @@ int register_spec_asset(AssetId id) { void audio_init() { synth_init(); + // Clear pending buffer + g_pending_samples = 0; + // Use default backend if none set if (g_audio_backend == nullptr) { g_audio_backend = &g_default_backend; @@ -85,6 +94,31 @@ void audio_render_ahead(float music_time, float dt) { // Keep rendering small chunks until buffer is full enough while (true) { + // First, try to flush any pending samples from previous partial writes + if (g_pending_samples > 0) { + const int written = g_ring_buffer.write(g_pending_buffer, g_pending_samples); + + if (written > 0) { + // Some or all samples were written + // Move remaining samples to front of buffer + const int remaining = g_pending_samples - written; + if (remaining > 0) { + for (int i = 0; i < remaining; ++i) { + g_pending_buffer[i] = g_pending_buffer[written + i]; + } + } + g_pending_samples = remaining; + + // Notify backend + if (g_audio_backend != nullptr) { + g_audio_backend->on_frames_rendered(written / RING_BUFFER_CHANNELS); + } + } + + // If still have pending samples, buffer is full - wait for consumption + if (g_pending_samples > 0) break; + } + // Check current buffer state const int buffered_samples = g_ring_buffer.available_read(); const float buffered_time = @@ -93,7 +127,7 @@ void audio_render_ahead(float music_time, float dt) { // Stop if buffer is full enough if (buffered_time >= target_lookahead) break; - // Check if buffer has space for this chunk BEFORE rendering + // Check if buffer has space for this chunk const int available_space = g_ring_buffer.available_write(); if (available_space < chunk_samples) { // Buffer is too full, wait for audio callback to consume more @@ -106,17 +140,28 @@ void audio_render_ahead(float music_time, float dt) { // Render audio from synth (advances synth state incrementally) synth_render(temp_buffer, chunk_frames); - // Write to ring buffer (should succeed since we checked space) + // Write to ring buffer const int written = g_ring_buffer.write(temp_buffer, chunk_samples); - // Notify backend of frames rendered (for testing/tracking) + // If partial write, save remaining samples to pending buffer + if (written < chunk_samples) { + const int remaining = chunk_samples - written; + if (remaining <= MAX_PENDING_SAMPLES) { + for (int i = 0; i < remaining; ++i) { + g_pending_buffer[i] = temp_buffer[written + i]; + } + g_pending_samples = remaining; + } + } + + // Notify backend of frames rendered (count frames sent to synth) if (g_audio_backend != nullptr) { - g_audio_backend->on_frames_rendered(written / RING_BUFFER_CHANNELS); + g_audio_backend->on_frames_rendered(chunk_frames); } delete[] temp_buffer; - // Safety: if write failed unexpectedly, stop to avoid infinite loop + // If we couldn't write everything, stop and retry next frame if (written < chunk_samples) break; } } |
