Complete Gelyk EQ plugin (dark/cyber/neon, scaling UI, git status bar)

This commit is contained in:
Gelyk 2026-08-29 13:26:26 +02:00
commit 580fcf7fec
7 changed files with 145 additions and 113 deletions

View file

@ -22,14 +22,14 @@ void FilterBand::prepare(double sampleRate, int blockSize)
switch (type)
{
case Type::lowShelf:
c = new Coeffs(Coeffs::makeLowShelf(sampleRate, freq, q, juce::Decibels::decibelsToGain(db)));
c = Coeffs::makeLowShelf(sampleRate, freq, q, juce::Decibels::decibelsToGain(db));
break;
case Type::highShelf:
c = new Coeffs(Coeffs::makeHighShelf(sampleRate, freq, q, juce::Decibels::decibelsToGain(db)));
c = Coeffs::makeHighShelf(sampleRate, freq, q, juce::Decibels::decibelsToGain(db));
break;
case Type::peak:
default:
c = new Coeffs(Coeffs::makePeakFilter(sampleRate, freq, q, juce::Decibels::decibelsToGain(db)));
c = Coeffs::makePeakFilter(sampleRate, freq, q, juce::Decibels::decibelsToGain(db));
break;
}
@ -60,7 +60,10 @@ void FilterBand::process(juce::dsp::AudioBlock<float>& block)
// ---------------------------------------------------------------------------
SpectrumAnalyser::SpectrumAnalyser()
: fft(12) // 4096 point FFT
{
const int size = fft.getSize();
fftBuffer.resize((size_t) (size * 2), 0.0f);
// The timer drives periodic background analysis.
startTimerHz(30);
}
@ -68,6 +71,7 @@ SpectrumAnalyser::SpectrumAnalyser()
void SpectrumAnalyser::prepare(double sr, int maxBlockSize)
{
const int size = 4096;
(void) maxBlockSize;
sampleRate = sr;
ring.setSize(2, size);
ring.clear();
@ -115,31 +119,29 @@ void SpectrumAnalyser::runAnalysis()
if (n == 0)
return;
juce::AudioBuffer<float> block(1, n);
// Mesa of the two channels and window with a Hann.
block.copyFrom(0, 0, ring, 0, 0, n);
if (ringChannels > 1)
block.addFrom(0, 0, ring, 1, 0, n);
juce::dsp::FFT fft(12); // 4096 point
juce::HeapBlock<std::complex<float>> fftData;
fftData.calloc((size_t) n);
for (int i = 0; i < n; ++i)
// Mesa of the two channels, Hann-windowed into the FFT buffer.
const auto fftSize = fft.getSize();
for (int i = 0; i < fftSize; ++i)
{
float v = block.getSample(0, i) * 0.5f;
const float win = 0.5f * (1.0f - std::cos(2.0f * juce::MathConstants<float>::pi * i / (n - 1)));
fftData[i] = std::complex<float>(v * win, 0.0f);
const int src = (ringFill - fftSize + i + n) % n; // contiguously oldest of last fftSize
float v = ring.getSample(0, src);
if (ringChannels > 1)
v = 0.5f * (v + ring.getSample(1, src));
const float win = 0.5f * (1.0f - std::cos(2.0f * juce::MathConstants<float>::pi * i / (fftSize - 1)));
fftBuffer[(size_t) i] = v * win;
}
fft.perform((juce::dsp::Complex<float>*) fftData.getData(), false);
for (size_t i = (size_t) fftSize; i < fftBuffer.size(); ++i)
fftBuffer[i] = 0.0f;
const int numBins = n / 2;
fft.performFrequencyOnlyForwardTransform(fftBuffer.data());
// Magnitude values (non-negative frequencies) are in the first size/2+1 entries.
const int numBins = juce::jmin((int) fftBuffer.size(), fftSize / 2 + 1);
juce::Array<float> mags;
mags.ensureStorageAllocated(numBins);
for (int i = 1; i < numBins; ++i)
for (int i = 0; i < numBins; ++i)
{
float re = fftData[i].real();
float im = fftData[i].imag();
float mag = std::sqrt(re * re + im * im);
float mag = fftBuffer[(size_t) i];
float db = 20.0f * std::log10(mag + 1.0e-9f);
mags.add(db);
}