From a9f0174f95b577cc7f8d67023eb37d83d050c0fd Mon Sep 17 00:00:00 2001 From: skal Date: Fri, 6 Feb 2026 16:32:57 +0100 Subject: fix(audio): Scale procedural note generation for orthonormal DCT Fixed procedural notes (NOTE_*) being inaudible by adding scaling compensation in gen.cc. Root Cause: - Old non-orthonormal DCT produced values ~16x larger (no sqrt scaling) - New orthonormal DCT: output *= sqrt(1/N) or sqrt(2/N) - Procedural note generation in gen.cc now produces 16x smaller spectrograms - IDCT expects same magnitude as .spec files -> notes too quiet Solution: - Added scale_factor = sqrt(DCT_SIZE / 2) = sqrt(256) = 16 - Multiply DCT output by 16 to match old magnitude - Procedural notes now have same loudness as sample-based notes Verification: - Checked spectral_editor: does not use DCT for procedural - Checked editor tools: no procedural generation with DCT - All 23 tests pass Procedural notes should now be audible at correct volume. Co-Authored-By: Claude Sonnet 4.5 --- src/audio/gen.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/audio/gen.cc b/src/audio/gen.cc index 148fc68..5604457 100644 --- a/src/audio/gen.cc +++ b/src/audio/gen.cc @@ -69,9 +69,14 @@ std::vector generate_note_spectrogram(const NoteParams& params, float dct_chunk[DCT_SIZE]; fdct_512(pcm_chunk, dct_chunk); - // Copy to buffer + // Scale up to compensate for orthonormal normalization + // Old non-orthonormal DCT had no sqrt scaling, so output was ~sqrt(N/2) larger + // Scale factor: sqrt(DCT_SIZE / 2) = sqrt(256) = 16 + const float scale_factor = sqrtf(DCT_SIZE / 2.0f); + + // Copy to buffer with scaling for (int i = 0; i < DCT_SIZE; ++i) { - spec_data[f * DCT_SIZE + i] = dct_chunk[i]; + spec_data[f * DCT_SIZE + i] = dct_chunk[i] * scale_factor; } } -- cgit v1.2.3