mirror of
https://codeberg.org/armin/beamgrid.git
synced 2026-09-01 04:10:47 +02:00
Initial BEAMGRID VST3/AU spectrum analyzer
This commit is contained in:
commit
0a3fe6d853
15 changed files with 908 additions and 0 deletions
74
Source/Analyser.h
Normal file
74
Source/Analyser.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include "JuceHeader.h"
|
||||
|
||||
// Beamgrid analyser: log-spaced spectrum bands with peak-hold markers.
|
||||
// Each band tracks a current level and a peak that holds for a definable
|
||||
// "grace" time before falling off at a definable rate.
|
||||
class Analyser
|
||||
{
|
||||
public:
|
||||
static constexpr int maxBands = 256;
|
||||
enum { fftOrder = 11, fftSize = 1 << fftOrder, fftBins = fftSize / 2 };
|
||||
|
||||
Analyser();
|
||||
|
||||
void prepare (double sampleRate, int blockSize);
|
||||
void push (const float* channelData, int numSamples);
|
||||
void update (double dt);
|
||||
|
||||
int getNumBands() const noexcept { return numBands; }
|
||||
float getLevel (int band) const noexcept { return band < numBands ? juce::jmin (1.0f, levels[band]) : 0.0f; }
|
||||
float getPeak (int band) const noexcept { return band < numBands ? juce::jmin (1.0f, peaks[band]) : 0.0f; }
|
||||
|
||||
// Helpers for drawing axis legends.
|
||||
double getMinFreq() const noexcept { return minFreq; }
|
||||
double getMaxFreq() const noexcept { return maxFreq; }
|
||||
float freqToFraction (double freq) const noexcept;
|
||||
float dbToFraction (double db) const noexcept;
|
||||
|
||||
void setGraceSeconds (double seconds) noexcept { grace = seconds; }
|
||||
void setFalloffRate (double rate) noexcept { falloffRate = rate; }
|
||||
void setBarReleaseTau (double seconds) noexcept { barReleaseTau = seconds; }
|
||||
void setNumBands (int n) noexcept;
|
||||
double getGraceSeconds() const noexcept { return grace; }
|
||||
double getFalloffRate() const noexcept { return falloffRate; }
|
||||
|
||||
private:
|
||||
void pushSample (float sample);
|
||||
void computeFFT();
|
||||
void computeBandEdges();
|
||||
|
||||
juce::dsp::FFT fft { fftOrder };
|
||||
juce::dsp::WindowingFunction<float> window { fftSize, juce::dsp::WindowingFunction<float>::hann, true };
|
||||
|
||||
// Sliding time-domain window so the FFT is recomputed every `hopSize`
|
||||
// samples (overlapped) instead of only once per full window. This keeps
|
||||
// the visualization temporally smooth.
|
||||
static constexpr int hopSize = 256;
|
||||
|
||||
std::array<float, fftSize> ring {};
|
||||
std::array<float, 2 * fftSize> fftData {};
|
||||
int writePos = 0;
|
||||
int samplesSinceFFT = 0;
|
||||
int totalSamples = 0;
|
||||
|
||||
int numBands = 64;
|
||||
std::array<float, maxBands> levels {};
|
||||
std::array<float, maxBands> targets {};
|
||||
std::array<float, maxBands> peaks {};
|
||||
std::array<float, maxBands> peakTimers {};
|
||||
|
||||
// First/last FFT bin index covered by each band (log spaced).
|
||||
std::array<int, maxBands + 1> bandBinEdges {};
|
||||
|
||||
double minFreq = 20.0;
|
||||
double maxFreq = 22050.0;
|
||||
|
||||
double sampleRate = 44100.0;
|
||||
double grace = 0.8; // seconds the peak is held before falling
|
||||
double falloffRate = 0.8; // normalized units per second while falling
|
||||
double barReleaseTau = 0.2; // seconds for the live bar to fall (release)
|
||||
double minDb = -48.0; // dBFS-equivalent floor (bands below this -> 0)
|
||||
double maxDb = -6.0; // dBFS-equivalent ceiling (bands at/above -> 1)
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue