From 9d21dbe82b9b7dc64991309fec6e6d56db2e4440 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 25 May 2026 10:31:23 -0700 Subject: [PATCH] improve: bandpass skirt width in Hz, not bins (consistent across selections) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The playback bandpass transition was freqPerBin*10 wide, and freqPerBin depends on the FFT size, which is derived from the selection length — so the same frequency band got a sharper or softer filter depending on how long a region you selected. Set the skirt to ~20% of the passband (capped at 100 Hz), floored at 3 FFT bins so it stays smooth at coarse resolution. Now a given band sounds the same regardless of selection duration. Co-Authored-By: Claude Opus 4.7 --- src/audio.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/audio.c b/src/audio.c index 33f3a99..f600b11 100644 --- a/src/audio.c +++ b/src/audio.c @@ -136,14 +136,23 @@ static void ApplyBandpassFilterFFT(float* samples, int numSamples, int sampleRat FFT(fftInput, fftOutput, fftSize, false); float freqPerBin = (float)sampleRate / fftSize; + + // Transition (skirt) width in Hz: ~20% of the passband, capped at 100 Hz, + // with a floor of 3 FFT bins so it stays smooth at coarse resolution. + // Previously the skirt was tied to bin width alone (freqPerBin * 10), so the + // FFT size — and thus the filter's sharpness — changed with the selection + // length: the same band sounded different depending on how much you boxed. + float bandwidthHz = freqHigh - freqLow; + float transitionHz = fmaxf(fminf(bandwidthHz * 0.2f, 100.0f), freqPerBin * 3.0f); + for (int bin = 0; bin < fftSize / 2 + 1; bin++) { float frequency = bin * freqPerBin; float attenuation = 1.0f; if (frequency < freqLow) { - float dist = (freqLow - frequency) / (freqPerBin * 10.0f); + float dist = (freqLow - frequency) / transitionHz; attenuation = 1.0f / (1.0f + dist * dist * dist); } else if (frequency > freqHigh) { - float dist = (frequency - freqHigh) / (freqPerBin * 10.0f); + float dist = (frequency - freqHigh) / transitionHz; attenuation = 1.0f / (1.0f + dist * dist * dist); } fftOutput[bin] *= attenuation;