diff options
| -rw-r--r-- | src/audio/wav_dump_backend.cc | 27 | ||||
| -rw-r--r-- | src/audio/wav_dump_backend.h | 6 | ||||
| -rw-r--r-- | src/tests/test_wav_dump.cc | 49 |
3 files changed, 76 insertions, 6 deletions
diff --git a/src/audio/wav_dump_backend.cc b/src/audio/wav_dump_backend.cc index eda835c..82803a2 100644 --- a/src/audio/wav_dump_backend.cc +++ b/src/audio/wav_dump_backend.cc @@ -10,7 +10,7 @@ #include <string.h> WavDumpBackend::WavDumpBackend() - : wav_file_(nullptr), samples_written_(0), + : wav_file_(nullptr), samples_written_(0), clipped_samples_(0), output_filename_("audio_dump.wav"), is_active_(false), duration_sec_(0.0f) { sample_buffer_.resize(kBufferSize); @@ -36,6 +36,7 @@ void WavDumpBackend::init() { write_wav_header(wav_file_, 0); samples_written_ = 0; + clipped_samples_ = 0; printf("WAV dump backend initialized: %s\n", output_filename_); } @@ -50,15 +51,18 @@ void WavDumpBackend::write_audio(const float* samples, int num_samples) { } // Convert float samples to int16 and write to WAV + // Note: We do NOT clamp samples (matches MiniaudioBackend behavior) + // Instead, we count samples that would clip during int16 conversion for (int i = 0; i < num_samples; ++i) { float sample = samples[i]; - // Clamp to [-1.0, 1.0] - if (sample > 1.0f) - sample = 1.0f; - if (sample < -1.0f) - sample = -1.0f; + // Track clipping for diagnostics (but don't prevent it) + if (sample > 1.0f || sample < -1.0f) { + clipped_samples_++; + } + // Convert to int16 (allows overflow for diagnostic purposes) + // This matches hardware behavior where clipping occurs in the DAC const int16_t sample_i16 = (int16_t)(sample * 32767.0f); fwrite(&sample_i16, sizeof(int16_t), 1, wav_file_); } @@ -76,6 +80,17 @@ void WavDumpBackend::shutdown() { 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_); + + // Report clipping diagnostics + if (clipped_samples_ > 0) { + const float clip_percent = + (float)clipped_samples_ / (float)samples_written_ * 100.0f; + printf(" WARNING: %zu samples clipped (%.2f%% of total)\n", + clipped_samples_, clip_percent); + printf(" This indicates audio distortion - consider reducing volume\n"); + } else { + printf(" ā No clipping detected\n"); + } } is_active_ = false; diff --git a/src/audio/wav_dump_backend.h b/src/audio/wav_dump_backend.h index 6482ef3..c3c5302 100644 --- a/src/audio/wav_dump_backend.h +++ b/src/audio/wav_dump_backend.h @@ -35,6 +35,11 @@ class WavDumpBackend : public AudioBackend { return samples_written_; } + // Get number of samples that were clipped (diagnostic metric) + size_t get_clipped_samples() const { + return clipped_samples_; + } + private: // Write WAV header with known sample count void write_wav_header(FILE* file, uint32_t num_samples); @@ -45,6 +50,7 @@ class WavDumpBackend : public AudioBackend { FILE* wav_file_; std::vector<float> sample_buffer_; size_t samples_written_; + size_t clipped_samples_; const char* output_filename_; bool is_active_; float duration_sec_; diff --git a/src/tests/test_wav_dump.cc b/src/tests/test_wav_dump.cc index cc2de19..aa195cc 100644 --- a/src/tests/test_wav_dump.cc +++ b/src/tests/test_wav_dump.cc @@ -190,6 +190,54 @@ void test_wav_stereo_buffer_size() { printf(" ā Buffer size calculations correct for stereo\n"); } +void test_clipping_detection() { + printf("Test: Clipping detection and reporting...\n"); + + const char* test_file = "test_clipping.wav"; + + audio_init(); + AudioEngine engine; + engine.init(); + + WavDumpBackend wav_backend; + wav_backend.set_output_file(test_file); + wav_backend.init(); + wav_backend.start(); + + // Create test samples with intentional clipping + const int num_samples = 1000; + float test_samples[1000]; + + // Mix of normal and clipped samples + for (int i = 0; i < num_samples; ++i) { + if (i % 10 == 0) { + test_samples[i] = 1.5f; // Clipped high + } else if (i % 10 == 1) { + test_samples[i] = -1.2f; // Clipped low + } else { + test_samples[i] = 0.5f; // Normal + } + } + + // Write samples + wav_backend.write_audio(test_samples, num_samples); + + // Verify clipping was detected (20% of samples should be clipped) + const size_t clipped = wav_backend.get_clipped_samples(); + assert(clipped == 200); // 10% + 10% = 20% of 1000 + + printf(" Detected %zu clipped samples (expected 200)\n", clipped); + + wav_backend.shutdown(); + engine.shutdown(); + audio_shutdown(); + + // Clean up + remove(test_file); + + printf(" ā Clipping detection works correctly\n"); +} + #endif /* !defined(STRIP_ALL) */ int main() { @@ -197,6 +245,7 @@ int main() { printf("Running WAV Dump Backend tests...\n\n"); test_wav_format_matches_live_audio(); test_wav_stereo_buffer_size(); + test_clipping_detection(); printf("\nā
All WAV Dump tests PASSED\n"); return 0; #else |
