diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-15 16:41:08 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-15 16:41:08 +0100 |
| commit | 3a3eca975f15d1e025d6c46c6de253d2abaa7170 (patch) | |
| tree | 766b9684a4075681c571b06caae1262f30910381 /src | |
| parent | 6e7aa374b6e0e5ebda2f3525c130ce0cc1cd72cb (diff) | |
fix(audio): WAV dump drift improvements, acceptable state
WAV dump changes:
- Bypass ring buffer, render directly with synth_render()
- Frame accumulator eliminates truncation errors
- Skip pre-fill and fix seek for WAV dump mode
- Result: No glitches, -150ms drift at 64b (acceptable)
Timeline editor:
- Fix waveform tooltip position calculation
- Increase beat bar visibility (0.5 opacity)
Cleanup:
- Remove all drift debugging code from audio.cc and tracker.cc
Status: Acceptable for now, further investigation needed.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/app/main.cc | 41 | ||||
| -rw-r--r-- | src/audio/audio.cc | 17 | ||||
| -rw-r--r-- | src/audio/tracker.cc | 8 |
3 files changed, 24 insertions, 42 deletions
diff --git a/src/app/main.cc b/src/app/main.cc index 537da74..5648b90 100644 --- a/src/app/main.cc +++ b/src/app/main.cc @@ -207,7 +207,10 @@ int main(int argc, char** argv) { #endif /* !defined(STRIP_ALL) */ // Pre-fill ring buffer to target lookahead (prevents startup delay) - fill_audio_buffer(audio_get_required_prefill_time(), 0.0); + // Skip pre-fill in WAV dump mode (direct render, no ring buffer) + if (!dump_wav) { + fill_audio_buffer(audio_get_required_prefill_time(), 0.0); + } audio_start(); g_last_audio_time = audio_get_playback_time(); // Initialize after start @@ -268,37 +271,41 @@ int main(int argc, char** argv) { printf("Running WAV dump simulation (%.1fs - %.1fs)...\n", start_time, end_time); - // Seek to start time if needed + // Seek to start time if needed (advance state without rendering) if (start_time > 0.0f) { const double step = 1.0 / 60.0; for (double t = 0.0; t < start_time; t += step) { - fill_audio_buffer(step, t); - audio_render_silent((float)step); + g_audio_engine.update(g_music_time, (float)step * g_tempo_scale); + g_music_time += (float)step * g_tempo_scale; } printf("Seeked to %.1fs\n", start_time); } const float update_dt = 1.0f / 60.0f; // 60Hz update rate - const int frames_per_update = (int)(32000 * update_dt); // ~533 frames - const int samples_per_update = frames_per_update * 2; // Stereo + const int sample_rate = 32000; - AudioRingBuffer* ring_buffer = audio_get_ring_buffer(); - std::vector<float> chunk_buffer(samples_per_update); + std::vector<float> chunk_buffer(2048); // Max samples for one update double physical_time = start_time; + double frame_accumulator = 0.0; while (physical_time < end_time) { - // Update music time and tracker (using tempo logic from - // fill_audio_buffer) - fill_audio_buffer(update_dt, physical_time); + // Calculate exact frames for this update + frame_accumulator += sample_rate * update_dt; + const int frames_this_update = (int)frame_accumulator; + frame_accumulator -= frames_this_update; + const int samples_this_update = frames_this_update * 2; - // Read rendered audio from ring buffer - if (ring_buffer != nullptr) { - ring_buffer->read(chunk_buffer.data(), samples_per_update); - } + // Update tracker/audio state + g_audio_engine.update(g_music_time, update_dt * g_tempo_scale); - // Write to WAV file - wav_backend.write_audio(chunk_buffer.data(), samples_per_update); + // Render directly to buffer (bypass ring buffer) + if (frames_this_update > 0) { + synth_render(chunk_buffer.data(), frames_this_update); + wav_backend.write_audio(chunk_buffer.data(), samples_this_update); + } + // Advance music time + g_music_time += update_dt * g_tempo_scale; physical_time += update_dt; // Progress indicator every second diff --git a/src/audio/audio.cc b/src/audio/audio.cc index f5bc4ab..ba76a28 100644 --- a/src/audio/audio.cc +++ b/src/audio/audio.cc @@ -108,10 +108,6 @@ void audio_render_ahead(float music_time, float dt, float target_fill) { if (chunk_frames <= 0) return; - static int64_t g_total_render_calls = 0; - static int64_t g_total_frames_rendered = 0; - const int64_t frames_before = g_ring_buffer.get_total_written() / RING_BUFFER_CHANNELS; - // Keep rendering small chunks until buffer is full enough while (true) { // First, try to flush any pending samples from previous partial writes @@ -228,19 +224,6 @@ void audio_render_ahead(float music_time, float dt, float target_fill) { } } } - - // DEBUG: Track actual frames rendered vs expected - const int64_t frames_after = g_ring_buffer.get_total_written() / RING_BUFFER_CHANNELS; - const int64_t actual_rendered = frames_after - frames_before; - g_total_render_calls++; - g_total_frames_rendered += actual_rendered; - - if (g_total_render_calls % 600 == 0) { // Every 10 seconds at 60fps - const float expected_frames = g_total_render_calls * (float)(chunk_frames); - const float drift_ms = (expected_frames - g_total_frames_rendered) / RING_BUFFER_SAMPLE_RATE * 1000.0f; - printf("[RENDER_DRIFT] calls=%lld expect=%.1f actual=%lld drift=%.2fms\n", - g_total_render_calls, expected_frames, g_total_frames_rendered, drift_ms); - } } float audio_get_playback_time() { diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc index 00c31e9..37f0683 100644 --- a/src/audio/tracker.cc +++ b/src/audio/tracker.cc @@ -324,14 +324,6 @@ void tracker_update(float music_time_sec, float dt_music_sec) { } } - // DEBUG: Track kick/snare timing for drift investigation - if (event.sample_id == 0 || event.sample_id == 1) { // Assuming kick=0, snare=1 - const char* name = (event.sample_id == 0) ? "KICK " : "SNARE"; - const float delta_ms = (event_music_time - music_time_sec) * 1000.0f; - printf("[DRIFT] %s: music=%.4f expect=%.4f delta=%.2fms offset=%d\n", - name, music_time_sec, event_music_time, delta_ms, sample_offset); - } - trigger_note_event(event, sample_offset, volume_mult); active.next_event_idx++; } |
