summaryrefslogtreecommitdiff
path: root/src/audio/wav_dump_backend.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio/wav_dump_backend.cc')
-rw-r--r--src/audio/wav_dump_backend.cc139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/audio/wav_dump_backend.cc b/src/audio/wav_dump_backend.cc
new file mode 100644
index 0000000..7418a40
--- /dev/null
+++ b/src/audio/wav_dump_backend.cc
@@ -0,0 +1,139 @@
+// This file is part of the 64k demo project.
+// Implementation of WAV dump backend for debugging.
+
+#include "wav_dump_backend.h"
+
+#if !defined(STRIP_ALL)
+
+#include "synth.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+WavDumpBackend::WavDumpBackend()
+ : wav_file_(nullptr),
+ samples_written_(0),
+ output_filename_("audio_dump.wav"),
+ is_active_(false) {
+ sample_buffer_.resize(kBufferSize);
+}
+
+WavDumpBackend::~WavDumpBackend() { shutdown(); }
+
+void WavDumpBackend::set_output_file(const char* filename) {
+ output_filename_ = filename;
+}
+
+void WavDumpBackend::init() {
+ // Open WAV file for writing
+ wav_file_ = fopen(output_filename_, "wb");
+ if (wav_file_ == nullptr) {
+ fprintf(stderr, "Error: Failed to open WAV file: %s\n", output_filename_);
+ return;
+ }
+
+ // Write placeholder header (we'll update it in shutdown())
+ write_wav_header(wav_file_, 0);
+
+ samples_written_ = 0;
+ printf("WAV dump backend initialized: %s\n", output_filename_);
+}
+
+void WavDumpBackend::start() {
+ is_active_ = true;
+ printf("WAV dump started, rendering audio...\n");
+
+ // Render audio in chunks until we reach desired duration
+ // For debugging, render 60 seconds max
+ const int max_duration_sec = 60;
+ const size_t total_samples = kSampleRate * max_duration_sec;
+ const size_t total_frames = total_samples / kBufferSize;
+
+ for (size_t frame = 0; frame < total_frames; ++frame) {
+ // Render audio from synth
+ synth_render(sample_buffer_.data(), kBufferSize);
+
+ // Convert float to int16 and write to WAV
+ for (int i = 0; i < kBufferSize; ++i) {
+ // Clamp to [-1, 1] and convert to 16-bit signed
+ float sample = sample_buffer_[i];
+ if (sample > 1.0f) sample = 1.0f;
+ if (sample < -1.0f) sample = -1.0f;
+
+ const int16_t sample_i16 = (int16_t)(sample * 32767.0f);
+ fwrite(&sample_i16, sizeof(int16_t), 1, wav_file_);
+ }
+
+ samples_written_ += kBufferSize;
+
+ // Progress indicator
+ if (frame % 100 == 0) {
+ const float progress_sec = (float)samples_written_ / kSampleRate;
+ printf(" Rendering: %.1fs / %ds\r", progress_sec, max_duration_sec);
+ fflush(stdout);
+ }
+
+ // Call frame rendering hook
+ on_frames_rendered(kBufferSize);
+ }
+
+ printf("\nWAV dump complete: %zu samples (%.2f seconds)\n", samples_written_,
+ (float)samples_written_ / kSampleRate);
+
+ is_active_ = false;
+}
+
+void WavDumpBackend::shutdown() {
+ if (wav_file_ != nullptr) {
+ // Update header with final sample count
+ update_wav_header();
+ fclose(wav_file_);
+ wav_file_ = nullptr;
+
+ printf("WAV file written: %s\n", output_filename_);
+ }
+}
+
+void WavDumpBackend::write_wav_header(FILE* file, uint32_t num_samples) {
+ // WAV file header structure
+ // Reference: http://soundfile.sapp.org/doc/WaveFormat/
+
+ const uint32_t num_channels = 1; // Mono
+ const uint32_t sample_rate = kSampleRate;
+ const uint32_t bits_per_sample = 16;
+ const uint32_t byte_rate = sample_rate * num_channels * bits_per_sample / 8;
+ const uint16_t block_align = num_channels * bits_per_sample / 8;
+ const uint32_t data_size = num_samples * num_channels * bits_per_sample / 8;
+
+ // RIFF header
+ fwrite("RIFF", 1, 4, file);
+ const uint32_t chunk_size = 36 + data_size;
+ fwrite(&chunk_size, 4, 1, file);
+ fwrite("WAVE", 1, 4, file);
+
+ // fmt subchunk
+ fwrite("fmt ", 1, 4, file);
+ const uint32_t subchunk1_size = 16;
+ fwrite(&subchunk1_size, 4, 1, file);
+ const uint16_t audio_format = 1; // PCM
+ fwrite(&audio_format, 2, 1, file);
+ fwrite(&num_channels, 2, 1, file);
+ fwrite(&sample_rate, 4, 1, file);
+ fwrite(&byte_rate, 4, 1, file);
+ fwrite(&block_align, 2, 1, file);
+ fwrite(&bits_per_sample, 2, 1, file);
+
+ // data subchunk header
+ fwrite("data", 1, 4, file);
+ fwrite(&data_size, 4, 1, file);
+}
+
+void WavDumpBackend::update_wav_header() {
+ if (wav_file_ == nullptr) return;
+
+ // Seek to beginning and rewrite header with actual sample count
+ fseek(wav_file_, 0, SEEK_SET);
+ write_wav_header(wav_file_, samples_written_);
+}
+
+#endif /* !defined(STRIP_ALL) */