From 35cf01a1631497967cae40147dfcafd64fbcf5c2 Mon Sep 17 00:00:00 2001 From: hariel1985 Date: Wed, 25 Mar 2026 22:57:28 +0100 Subject: [PATCH] v1.3.2: Log-spaced auto makeup gain for musical accuracy Auto makeup now evaluates at log-spaced frequencies (equal weight per octave) instead of linear. Fixes over-compensation on high shelf boosts where 5k-22kHz dominated the calculation despite having little musical energy. Co-Authored-By: Claude Opus 4.6 (1M context) --- CMakeLists.txt | 2 +- Source/FIREngine.cpp | 37 +++++++++++++++++++++++++++++-------- Source/PluginEditor.h | 2 +- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a6532e..d3d3cbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.22) -project(InstaLPEQ VERSION 1.3.0) +project(InstaLPEQ VERSION 1.3.2) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/Source/FIREngine.cpp b/Source/FIREngine.cpp index f45aec8..f40c937 100644 --- a/Source/FIREngine.cpp +++ b/Source/FIREngine.cpp @@ -192,20 +192,41 @@ juce::AudioBuffer FIREngine::generateFIR (const std::vector& band // Extract actual magnitude from FFT result // Format: [DC_real, Nyquist_real, bin1_real, bin1_imag, bin2_real, bin2_imag, ...] + // Evaluate at log-spaced frequencies (equal weight per octave) + // This matches musical content much better than linear spacing + // (linear gives 77% weight to 5k-22k where music has little energy) + const int numPoints = 512; double powerSum = 0.0; - int count = 0; + double binRes = sr / (double) fftSize; // Hz per bin - for (int i = 1; i < fftSize / 2; ++i) + for (int p = 0; p < numPoints; ++p) { - float re = analysisBuf[i * 2]; - float im = analysisBuf[i * 2 + 1]; - powerSum += (double) (re * re + im * im); - count++; + // Log-spaced 20 Hz — 20 kHz + double freq = 20.0 * std::pow (1000.0, (double) p / (double) (numPoints - 1)); + + // Interpolate magnitude from FFT bins + double binFloat = freq / binRes; + int bin = (int) binFloat; + double frac = binFloat - (double) bin; + + if (bin < 1 || bin >= fftSize / 2 - 1) + continue; + + float re0 = analysisBuf[bin * 2]; + float im0 = analysisBuf[bin * 2 + 1]; + float re1 = analysisBuf[(bin + 1) * 2]; + float im1 = analysisBuf[(bin + 1) * 2 + 1]; + + double mag0 = std::sqrt ((double) (re0 * re0 + im0 * im0)); + double mag1 = std::sqrt ((double) (re1 * re1 + im1 * im1)); + double mag = mag0 * (1.0 - frac) + mag1 * frac; + + powerSum += mag * mag; } - if (count > 0) + if (numPoints > 0) { - double avgPower = powerSum / (double) count; + double avgPower = powerSum / (double) numPoints; float rmsGain = (float) std::sqrt (avgPower); float makeupDb = -20.0f * std::log10 (std::max (rmsGain, 1e-10f)); autoMakeupDb.store (makeupDb); diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 7cca99c..65acb4d 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -44,7 +44,7 @@ private: NodeParameterPanel nodePanel; juce::Label titleLabel { {}, "INSTALPEQ" }; - juce::Label versionLabel { {}, "v1.3.0" }; + juce::Label versionLabel { {}, "v1.3.2" }; juce::ToggleButton bypassToggle; juce::Label bypassLabel { {}, "BYPASS" };