diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-15 23:56:43 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-15 23:56:43 +0100 |
| commit | 5c7feffd3749ce4b355d0db6334cf39ca94d8d82 (patch) | |
| tree | 7105aea12d0367208a37777cf53b348f35a66dad /src/audio/audio.cc | |
| parent | e21127a3fc4797805d49ae2d95fc7ed6f94ac456 (diff) | |
perf(audio): smooth playback time and RMS-based peak at 60Hz
Interpolates audio playback time between callbacks using CLOCK_MONOTONIC
for smooth 60Hz updates instead of coarse 8-10Hz steps.
Replaces artificial peak decay with true RMS calculation over 50ms
window. Ring buffer computes RMS directly on internal buffer without
copies for efficiency.
All backends updated with get_callback_state() interface for time
interpolation. Tests passing (34/34).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/audio/audio.cc')
| -rw-r--r-- | src/audio/audio.cc | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/src/audio/audio.cc b/src/audio/audio.cc index a220fbb..780691a 100644 --- a/src/audio/audio.cc +++ b/src/audio/audio.cc @@ -12,6 +12,7 @@ #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" +#include <cmath> #include <stdio.h> // Global ring buffer for audio streaming @@ -228,6 +229,27 @@ void audio_render_ahead(float music_time, float dt, float target_fill) { } float audio_get_playback_time() { + // Smooth interpolation: use backend callback state if available + if (g_audio_backend != nullptr) { + double last_callback_time = 0.0; + int64_t last_callback_samples = 0; + g_audio_backend->get_callback_state(&last_callback_time, + &last_callback_samples); + + // If callback has fired, interpolate for smooth 60Hz updates + if (last_callback_time != 0.0) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + const double current_time = ts.tv_sec + ts.tv_nsec / 1e9; + const double elapsed = current_time - last_callback_time; + const float interpolated_samples = + (float)(elapsed * RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS); + const float total_samples = (float)last_callback_samples + interpolated_samples; + return total_samples / (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS); + } + } + + // Fallback: coarse ring buffer time (before first callback or no backend) const int64_t total_samples = g_ring_buffer.get_total_read(); return (float)total_samples / (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS); @@ -240,10 +262,12 @@ float audio_get_render_time() { } float audio_get_realtime_peak() { - if (g_audio_backend == nullptr) { - return 0.0f; - } - return g_audio_backend->get_realtime_peak(); + // Calculate RMS over recent time window (50ms) + const int window_ms = 50; + const int window_samples = + (window_ms * RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS) / 1000; + + return g_ring_buffer.get_past_rms(window_samples); } // Expose ring buffer for backends |
