summaryrefslogtreecommitdiff
path: root/src/audio/audio.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio/audio.cc')
-rw-r--r--src/audio/audio.cc79
1 files changed, 54 insertions, 25 deletions
diff --git a/src/audio/audio.cc b/src/audio/audio.cc
index 2d667bc..d3880f0 100644
--- a/src/audio/audio.cc
+++ b/src/audio/audio.cc
@@ -125,44 +125,73 @@ void audio_render_ahead(float music_time, float dt) {
break;
}
- // Determine how much we can actually render
- // Render the smaller of: desired chunk size OR available space
- const int actual_samples =
- (available_space < chunk_samples) ? available_space : chunk_samples;
- const int actual_frames = actual_samples / RING_BUFFER_CHANNELS;
+ // Get direct write pointer from ring buffer
+ int available_for_write = 0;
+ float* write_ptr = g_ring_buffer.get_write_region(&available_for_write);
- // Allocate temporary buffer (stereo)
- float* temp_buffer = new float[actual_samples];
+ if (available_for_write == 0) {
+ break; // Buffer full, wait for consumption
+ }
- // Render audio from synth (advances synth state incrementally)
- synth_render(temp_buffer, actual_frames);
+ // Clamp to desired chunk size
+ const int actual_samples =
+ (available_for_write < chunk_samples) ? available_for_write
+ : chunk_samples;
+ const int actual_frames = actual_samples / RING_BUFFER_CHANNELS;
- // Write to ring buffer
- const int written = g_ring_buffer.write(temp_buffer, actual_samples);
+ // Render directly to ring buffer (NO COPY, NO ALLOCATION)
+ synth_render(write_ptr, actual_frames);
- // If partial write, save remaining samples to pending buffer
- if (written < actual_samples) {
- const int remaining = actual_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;
- }
+ // Apply clipping in-place (Phase 2: ensure samples stay in [-1.0, 1.0])
+ for (int i = 0; i < actual_samples; ++i) {
+ if (write_ptr[i] > 1.0f)
+ write_ptr[i] = 1.0f;
+ if (write_ptr[i] < -1.0f)
+ write_ptr[i] = -1.0f;
}
- // Notify backend of frames rendered (count frames sent to synth)
+ // Commit written data atomically
+ g_ring_buffer.commit_write(actual_samples);
+
+ // Notify backend of frames rendered
#if !defined(STRIP_ALL)
if (g_audio_backend != nullptr) {
g_audio_backend->on_frames_rendered(actual_frames);
}
#endif
- delete[] temp_buffer;
+ // Handle wrap-around: if we wanted more samples but ring wrapped,
+ // get a second region and render remaining chunk
+ if (actual_samples < chunk_samples) {
+ int second_avail = 0;
+ float* second_ptr = g_ring_buffer.get_write_region(&second_avail);
+ if (second_avail > 0) {
+ const int remaining_samples = chunk_samples - actual_samples;
+ const int second_samples =
+ (second_avail < remaining_samples) ? second_avail
+ : remaining_samples;
+ const int second_frames = second_samples / RING_BUFFER_CHANNELS;
- // If we couldn't write everything, stop and retry next frame
- if (written < actual_samples)
- break;
+ synth_render(second_ptr, second_frames);
+
+ // Apply clipping to wrap-around region
+ for (int i = 0; i < second_samples; ++i) {
+ if (second_ptr[i] > 1.0f)
+ second_ptr[i] = 1.0f;
+ if (second_ptr[i] < -1.0f)
+ second_ptr[i] = -1.0f;
+ }
+
+ g_ring_buffer.commit_write(second_samples);
+
+ // Notify backend of additional frames
+#if !defined(STRIP_ALL)
+ if (g_audio_backend != nullptr) {
+ g_audio_backend->on_frames_rendered(second_frames);
+ }
+#endif
+ }
+ }
}
}