summaryrefslogtreecommitdiff
path: root/src/audio/wav_dump_backend.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-07 10:46:43 +0100
committerskal <pascal.massimino@gmail.com>2026-02-07 10:46:43 +0100
commit0f79b532c886f338ab80d506d4b06048e1784056 (patch)
tree28639cc355c91e294ced1dd1d3491b822c3e45b8 /src/audio/wav_dump_backend.cc
parent858f9d5e765bfc8f8f13b38fa0fab790139a0740 (diff)
refactor(audio): Remove tempo logic from WavDumpBackend
Fixed design flaw where WavDumpBackend had hardcoded tempo curves duplicating logic from main.cc. Backend should be passive and just write audio data, not implement simulation logic. Changes: - WavDumpBackend.start() is now non-blocking (was blocking simulation loop) - Added write_audio() method for passive audio writing - Removed all tempo scaling logic from backend (lines 62-97) - Removed tracker_update() and audio_render_ahead() calls from backend - Removed set_duration() (no longer needed, frontend controls duration) Frontend (main.cc): - Added WAV dump mode loop that drives simulation with its own tempo logic - Reads from ring buffer and calls wav_backend.write_audio() - Tempo logic stays in one place (no duplication) - Added ring_buffer.h include for AudioRingBuffer access Test (test_wav_dump.cc): - Updated to use frontend-driven approach - Test manually drives simulation loop - Calls write_audio() after each frame - Verifies passive backend behavior Design: - Backend: Passive file writer (init/start/write_audio/shutdown) - Frontend: Active simulation driver (tempo, tracker, rendering) - Zero duplication of tempo/simulation logic - Clean separation of concerns All 27 tests pass. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/audio/wav_dump_backend.cc')
-rw-r--r--src/audio/wav_dump_backend.cc111
1 files changed, 23 insertions, 88 deletions
diff --git a/src/audio/wav_dump_backend.cc b/src/audio/wav_dump_backend.cc
index 9fa13f5..eda835c 100644
--- a/src/audio/wav_dump_backend.cc
+++ b/src/audio/wav_dump_backend.cc
@@ -5,10 +5,6 @@
#if !defined(STRIP_ALL)
-#include "audio.h"
-#include "ring_buffer.h"
-#include "synth.h"
-#include "tracker.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -16,7 +12,7 @@
WavDumpBackend::WavDumpBackend()
: wav_file_(nullptr), samples_written_(0),
output_filename_("audio_dump.wav"), is_active_(false),
- duration_sec_(60.0f) {
+ duration_sec_(0.0f) {
sample_buffer_.resize(kBufferSize);
}
@@ -28,10 +24,6 @@ void WavDumpBackend::set_output_file(const char* filename) {
output_filename_ = filename;
}
-void WavDumpBackend::set_duration(float seconds) {
- duration_sec_ = seconds;
-}
-
void WavDumpBackend::init() {
// Open WAV file for writing
wav_file_ = fopen(output_filename_, "wb");
@@ -49,90 +41,29 @@ void WavDumpBackend::init() {
void WavDumpBackend::start() {
is_active_ = true;
- printf("WAV dump started, rendering audio...\n");
-
- // Render audio in small chunks with tracker updates
- // This matches the seek logic in main.cc
- const float update_dt = 1.0f / 60.0f; // 60Hz update rate (matches main loop)
- const int frames_per_update = (int)(kSampleRate * update_dt); // ~533 frames
- const int samples_per_update =
- frames_per_update * 2; // Stereo: 2 samples per frame
- const int total_updates = (int)(duration_sec_ / update_dt);
-
- // Music time tracking
- float music_time = 0.0f;
- float tempo_scale = 1.0f;
- float physical_time = 0.0f;
-
- // Get ring buffer for reading
- AudioRingBuffer* ring_buffer = audio_get_ring_buffer();
-
- // Temporary buffer for each update chunk (stereo)
- std::vector<float> chunk_buffer(samples_per_update);
-
- for (int update_count = 0; update_count < total_updates; ++update_count) {
- // Update tempo scaling (matches main.cc phases)
- if (physical_time < 10.0f) {
- tempo_scale = 1.0f;
- } else if (physical_time < 15.0f) {
- const float progress = (physical_time - 10.0f) / 5.0f;
- tempo_scale = 1.0f + progress * 1.0f; // 1.0 → 2.0
- } else if (physical_time < 20.0f) {
- tempo_scale = 1.0f;
- } else if (physical_time < 25.0f) {
- const float progress = (physical_time - 20.0f) / 5.0f;
- tempo_scale = 1.0f - progress * 0.5f; // 1.0 → 0.5
- } else {
- tempo_scale = 1.0f;
- }
-
- // Advance music time
- music_time += update_dt * tempo_scale;
- physical_time += update_dt;
-
- // Update tracker (triggers patterns)
- tracker_update(music_time);
-
- // Fill ring buffer with upcoming audio
- audio_render_ahead(music_time, update_dt);
-
- // Read from ring buffer (same as audio callback would do)
- if (ring_buffer != nullptr) {
- ring_buffer->read(chunk_buffer.data(), samples_per_update);
- }
-
- // Convert float to int16 and write to WAV (stereo interleaved)
- for (int i = 0; i < samples_per_update; ++i) {
- float sample = chunk_buffer[i];
- if (sample > 1.0f)
- sample = 1.0f;
- if (sample < -1.0f)
- sample = -1.0f;
+ printf("WAV dump started (passive mode - frontend drives rendering)\n");
+}
- const int16_t sample_i16 = (int16_t)(sample * 32767.0f);
- fwrite(&sample_i16, sizeof(int16_t), 1, wav_file_);
- }
+void WavDumpBackend::write_audio(const float* samples, int num_samples) {
+ if (!is_active_ || wav_file_ == nullptr) {
+ return;
+ }
- samples_written_ += samples_per_update;
+ // Convert float samples to int16 and write to WAV
+ for (int i = 0; i < num_samples; ++i) {
+ float sample = samples[i];
- // Progress indicator
- if (update_count % 60 == 0) {
- printf(" Rendering: %.1fs / %.1fs (music: %.1fs, tempo: %.2fx)\r",
- physical_time, duration_sec_, music_time, tempo_scale);
- fflush(stdout);
- }
+ // Clamp to [-1.0, 1.0]
+ if (sample > 1.0f)
+ sample = 1.0f;
+ if (sample < -1.0f)
+ sample = -1.0f;
- // Call frame rendering hook (pass frames, not samples)
- on_frames_rendered(frames_per_update);
+ const int16_t sample_i16 = (int16_t)(sample * 32767.0f);
+ fwrite(&sample_i16, sizeof(int16_t), 1, wav_file_);
}
- printf(
- "\nWAV dump complete: %zu samples (%.2f seconds stereo, %.2f music "
- "time)\n",
- samples_written_, (float)samples_written_ / (kSampleRate * 2),
- music_time);
-
- is_active_ = false;
+ samples_written_ += num_samples;
}
void WavDumpBackend::shutdown() {
@@ -142,8 +73,12 @@ void WavDumpBackend::shutdown() {
fclose(wav_file_);
wav_file_ = nullptr;
- printf("WAV file written: %s\n", output_filename_);
+ const float duration_sec = (float)samples_written_ / (kSampleRate * 2);
+ printf("WAV file written: %s (%.2f seconds, %zu samples)\n",
+ output_filename_, duration_sec, samples_written_);
}
+
+ is_active_ = false;
}
void WavDumpBackend::write_wav_header(FILE* file, uint32_t num_samples) {