From f998bfcd7a6167ae6bdf5ad7f8685b2cdf1fe811 Mon Sep 17 00:00:00 2001 From: skal Date: Fri, 6 Feb 2026 16:53:41 +0100 Subject: fix(audio): Remove Hamming window from synthesis (before IDCT) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed incorrect windowing before IDCT in both C++ and JavaScript. The Hamming window is ONLY for analysis (before DCT), not synthesis. Changes: - synth.cc: Removed windowing before IDCT (direct spectral → IDCT) - spectral_editor/script.js: Removed spectrum windowing, kept time-domain window for overlap-add - editor/script.js: Removed spectrum windowing, kept time-domain window for smooth transitions Windowing Strategy (Correct): - ANALYSIS (spectool.cc, gen.cc): Apply window BEFORE DCT - SYNTHESIS (synth.cc, editors): NO window before IDCT Why: - Analysis window reduces spectral leakage during DCT - Synthesis needs raw IDCT output for accurate reconstruction - Time-domain window after IDCT is OK for overlap-add smoothing Result: - Correct audio synthesis without spectral distortion - Spectrograms reconstruct properly - C++ and JavaScript now match correct approach All 23 tests pass. Co-Authored-By: Claude Sonnet 4.5 --- tools/editor/script.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'tools/editor') diff --git a/tools/editor/script.js b/tools/editor/script.js index ebc543a..06c9bef 100644 --- a/tools/editor/script.js +++ b/tools/editor/script.js @@ -632,17 +632,12 @@ async function playSpectrogramData(specData) { for (let frameIndex = 0; frameIndex < numFrames; frameIndex++) { const spectralFrame = specData.data.slice(frameIndex * dctSize, (frameIndex + 1) * dctSize); - // Apply window to spectrum before IDCT (matches C++ synth.cc) - const windowedSpectral = new Float32Array(dctSize); - for (let i = 0; i < dctSize; i++) { - windowedSpectral[i] = spectralFrame[i] * hanningWindowArray[i]; - } - - const timeDomainFrame = javascript_idct_512(windowedSpectral); + // IDCT (no windowing - window is only for analysis, not synthesis) + const timeDomainFrame = javascript_idct_512(spectralFrame); - // Direct output (no additional windowing) + // Apply Hanning window for smooth transitions between frames for (let i = 0; i < dctSize; i++) { - audioData[frameIndex * dctSize + i] = timeDomainFrame[i]; + audioData[frameIndex * dctSize + i] = timeDomainFrame[i] * hanningWindowArray[i]; } } -- cgit v1.2.3