v1.2.2: Live spectrum analyzer, makeup gain, drag-and-drop signal chain

- Real-time FFT spectrum analyzer drawn behind EQ curves
- Makeup gain knob (+/- 24 dB) after limiter
- Draggable signal chain panel: reorder Master Gain / Limiter / Makeup Gain
- Chain order saved/restored with DAW session
- Scaled fonts in signal chain panel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hariel1985
2026-03-25 11:44:27 +01:00
szülő 72c7958d98
commit 9c5b5a3957
9 fájl változott, egészen pontosan 474 új sor hozzáadva és 14 régi sor törölve

Fájl megtekintése

@@ -17,6 +17,13 @@ void EQCurveDisplay::setMagnitudeResponse (const std::vector<float>& magnitudesD
repaint();
}
void EQCurveDisplay::setSpectrum (const float* data, int numBins, double sampleRate, int fftSize)
{
spectrumDb.assign (data, data + numBins);
spectrumSampleRate = sampleRate;
spectrumFftSize = fftSize;
}
void EQCurveDisplay::setSelectedBand (int index)
{
if (selectedBand != index)
@@ -93,6 +100,7 @@ void EQCurveDisplay::paint (juce::Graphics& g)
g.drawRoundedRectangle (bounds, 4.0f, 1.0f);
drawGrid (g);
drawSpectrum (g);
drawPerBandCurves (g);
drawResponseCurve (g);
drawNodes (g);
@@ -140,6 +148,55 @@ void EQCurveDisplay::drawGrid (juce::Graphics& g)
}
}
void EQCurveDisplay::drawSpectrum (juce::Graphics& g)
{
if (spectrumDb.empty())
return;
auto area = getPlotArea();
int numBins = (int) spectrumDb.size();
juce::Path specPath;
specPath.startNewSubPath (area.getX(), area.getBottom());
bool hasPoints = false;
for (float px = area.getX(); px <= area.getRight(); px += 1.5f)
{
float freq = xToFreq (px);
if (freq < 1.0f || freq > spectrumSampleRate * 0.5)
continue;
float binFloat = freq * (float) spectrumFftSize / (float) spectrumSampleRate;
int bin = (int) binFloat;
float frac = binFloat - (float) bin;
if (bin < 0 || bin >= numBins - 1)
continue;
float dbVal = spectrumDb[bin] * (1.0f - frac) + spectrumDb[bin + 1] * frac;
// Map dB range: -100 dB = bottom, 0 dB = top area
// Shift up so typical audio is visible
float mapped = juce::jmap (dbVal, -80.0f, 0.0f, minDb, maxDb);
mapped = juce::jlimit (minDb - 6.0f, maxDb, mapped);
float yPos = dbToY (mapped);
specPath.lineTo (px, yPos);
hasPoints = true;
}
if (! hasPoints)
return;
specPath.lineTo (area.getRight(), area.getBottom());
specPath.closeSubPath();
// Fill with subtle gradient
juce::ColourGradient specGrad (juce::Colour (0xff4488ff).withAlpha (0.12f), 0, area.getY(),
juce::Colour (0xff4488ff).withAlpha (0.03f), 0, area.getBottom(), false);
g.setGradientFill (specGrad);
g.fillPath (specPath);
}
void EQCurveDisplay::drawResponseCurve (juce::Graphics& g)
{
if (magnitudeResponseDb.empty())