mirror of
https://codeberg.org/armin/gelyk.git
synced 2026-10-11 17:01:53 +02:00
Initial Gelyk EQ plugin
This commit is contained in:
commit
13863f4522
9 changed files with 1080 additions and 0 deletions
203
Source/EqualizerDSP.cpp
Normal file
203
Source/EqualizerDSP.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
#include "EqualizerDSP.h"
|
||||
|
||||
namespace gelyk
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FilterBand
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void FilterBand::prepare(double sampleRate, int blockSize)
|
||||
{
|
||||
juce::dsp::ProcessSpec spec;
|
||||
spec.sampleRate = sampleRate;
|
||||
spec.maximumBlockSize = (juce::uint32) blockSize;
|
||||
spec.numChannels = 2;
|
||||
|
||||
left.prepare(spec);
|
||||
right.prepare(spec);
|
||||
|
||||
Coeffs::Ptr c;
|
||||
const float db = juce::jlimit(-24.0f, 24.0f, gainDb);
|
||||
switch (type)
|
||||
{
|
||||
case Type::lowShelf:
|
||||
c = new Coeffs(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)));
|
||||
break;
|
||||
case Type::peak:
|
||||
default:
|
||||
c = new Coeffs(Coeffs::makePeakFilter(sampleRate, freq, q, juce::Decibels::decibelsToGain(db)));
|
||||
break;
|
||||
}
|
||||
|
||||
left.coefficients = c;
|
||||
right.coefficients = c;
|
||||
}
|
||||
|
||||
void FilterBand::reset()
|
||||
{
|
||||
left.reset();
|
||||
right.reset();
|
||||
}
|
||||
|
||||
void FilterBand::process(juce::dsp::AudioBlock<float>& block)
|
||||
{
|
||||
if (block.getNumChannels() < 2)
|
||||
return;
|
||||
|
||||
// Smooth the coefficients to avoid zipper noise, then process.
|
||||
left.snapToZero();
|
||||
right.snapToZero();
|
||||
left.process(juce::dsp::ProcessContextReplacing<float>(block));
|
||||
right.process(juce::dsp::ProcessContextReplacing<float>(block));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SpectrumAnalyser
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
SpectrumAnalyser::SpectrumAnalyser()
|
||||
{
|
||||
// The timer drives periodic background analysis.
|
||||
startTimerHz(30);
|
||||
}
|
||||
|
||||
void SpectrumAnalyser::prepare(double sr, int maxBlockSize)
|
||||
{
|
||||
const int size = 4096;
|
||||
sampleRate = sr;
|
||||
ring.setSize(2, size);
|
||||
ring.clear();
|
||||
ringFill = 0;
|
||||
ringChannels = 2;
|
||||
}
|
||||
|
||||
void SpectrumAnalyser::push(const float* const* channels, int numChannels, int numSamples)
|
||||
{
|
||||
if (!enabled.load() || ring.getNumSamples() == 0)
|
||||
return;
|
||||
|
||||
const int n = (int) ring.getNumSamples();
|
||||
const int c = juce::jmin(ringChannels, numChannels);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
const int dst = (ringFill + i) % n;
|
||||
for (int ch = 0; ch < c; ++ch)
|
||||
ring.setSample(ch, dst, channels[ch][i]);
|
||||
}
|
||||
ringFill = (ringFill + numSamples) % n;
|
||||
}
|
||||
|
||||
void SpectrumAnalyser::startBackground()
|
||||
{
|
||||
startTimerHz(30);
|
||||
}
|
||||
|
||||
void SpectrumAnalyser::stopBackground()
|
||||
{
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
void SpectrumAnalyser::timerCallback()
|
||||
{
|
||||
if (!enabled.load())
|
||||
return;
|
||||
runAnalysis();
|
||||
}
|
||||
|
||||
void SpectrumAnalyser::runAnalysis()
|
||||
{
|
||||
const int n = (int) ring.getNumSamples();
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
fft.perform((juce::dsp::Complex<float>*) fftData.getData(), false);
|
||||
|
||||
const int numBins = n / 2;
|
||||
juce::Array<float> mags;
|
||||
mags.ensureStorageAllocated(numBins);
|
||||
for (int i = 1; i < numBins; ++i)
|
||||
{
|
||||
float re = fftData[i].real();
|
||||
float im = fftData[i].imag();
|
||||
float mag = std::sqrt(re * re + im * im);
|
||||
float db = 20.0f * std::log10(mag + 1.0e-9f);
|
||||
mags.add(db);
|
||||
}
|
||||
|
||||
{
|
||||
juce::ScopedLock sl(spectrumLock);
|
||||
readySpectrum = mags;
|
||||
}
|
||||
}
|
||||
|
||||
int SpectrumAnalyser::copySpectrum(juce::Array<float>& dest, juce::Array<float>& freqBins,
|
||||
int maxBins) const
|
||||
{
|
||||
juce::Array<float> snapshot;
|
||||
{
|
||||
juce::ScopedLock sl(spectrumLock);
|
||||
snapshot = readySpectrum;
|
||||
}
|
||||
|
||||
if (snapshot.size() == 0)
|
||||
{
|
||||
dest.clear();
|
||||
freqBins.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Log-spaced aggregation from ~20 Hz to 20 kHz.
|
||||
const float fMin = 20.0f;
|
||||
const float fMax = 20000.0f;
|
||||
const double nfft = (double)(snapshot.size() * 2);
|
||||
const float binFreq = (float)(sampleRate / nfft);
|
||||
|
||||
dest.clear();
|
||||
freqBins.clear();
|
||||
|
||||
const int bands = juce::jmin(maxBins, snapshot.size());
|
||||
for (int b = 0; b < bands; ++b)
|
||||
{
|
||||
const float f = fMin * std::pow(fMax / fMin, (float) b / (float) (bands - 1));
|
||||
freqBins.add(f);
|
||||
const int startBin = juce::jmax(1, (int) std::floor(f / binFreq));
|
||||
const int endBin = juce::jmin(snapshot.size() - 1, (int) std::ceil((f * 1.5f) / binFreq));
|
||||
float total = 0.0f;
|
||||
int count = 0;
|
||||
for (int i = startBin; i <= endBin; ++i)
|
||||
{
|
||||
total += snapshot[i];
|
||||
++count;
|
||||
}
|
||||
dest.add(count > 0 ? total / count : -96.0f);
|
||||
}
|
||||
|
||||
return dest.size();
|
||||
}
|
||||
|
||||
void SpectrumAnalyser::setEnabled(bool e)
|
||||
{
|
||||
enabled.store(e);
|
||||
}
|
||||
|
||||
} // namespace gelyk
|
||||
Loading…
Add table
Add a link
Reference in a new issue