391 lines
12 KiB
C++
391 lines
12 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file contains the basic framework code for a JUCE plugin editor.
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <juce_audio_processors/juce_audio_processors.h>
|
|
#include <juce_audio_utils/juce_audio_utils.h>
|
|
#include "PluginProcessor.h"
|
|
#include "AXIOMDesignSystem.h"
|
|
|
|
//==============================================================================
|
|
/**
|
|
*/
|
|
using AXIOM::DesignSystem;
|
|
using Components = DesignSystem::Components;
|
|
using SliderStyles = Components::SliderStyles;
|
|
|
|
class SpectrumAnalyzer {
|
|
public:
|
|
SpectrumAnalyzer(AudioFIFO &fifoRef, CrystalizerEQAudioProcessor &processor) : audioFIFO(fifoRef),
|
|
audioProcessor(processor) {
|
|
fftData.resize(2 * FFTSIZE);
|
|
magnitudes.resize(BINS);
|
|
magnitudesDb.resize(BINS);
|
|
emaSmoothedMagnitudesDb.resize(BINS);
|
|
freqSmoothedMagnitudesDb.resize(BINS);
|
|
sampleRate = audioProcessor.getSampleRate();
|
|
deltaF = sampleRate / static_cast<double>(FFTSIZE);
|
|
freqPerBin.resize(BINS);
|
|
peakHoldMagnitudesDb.resize(BINS);
|
|
DELTAT = static_cast<float>(HOPSIZE) / static_cast<float>(sampleRate);
|
|
renderValuesDb.resize(BINS);
|
|
}
|
|
|
|
~SpectrumAnalyzer() = default;
|
|
|
|
|
|
AudioFIFO &audioFIFO;
|
|
|
|
CrystalizerEQAudioProcessor &audioProcessor;
|
|
|
|
static constexpr int FFTSIZE = 4096;
|
|
|
|
static constexpr int BINS = FFTSIZE / 2 + 1;
|
|
|
|
static constexpr int HOPSIZE = FFTSIZE / 2;
|
|
|
|
juce::Array<float> fftFrame;
|
|
|
|
//CHANGE FOR LOWER/HIGHER EMA-SMOOTHING //LOWER VALUE -> MORE SMOOTHING/SLOW RESPONSE -- HIGHER VALUE -> LESS SMOOTHING/FAST RESPONSE //MAX VALUE = 1.f
|
|
float smoothingFactor = 0.5f;
|
|
|
|
|
|
void processSamples();
|
|
|
|
void getFftFrame(juce::Array<float> &samples);
|
|
|
|
void applyWindowOnFftFrame(std::vector<float> &fullFrame);
|
|
|
|
juce::dsp::WindowingFunction<float> window
|
|
{
|
|
FFTSIZE,
|
|
juce::dsp::WindowingFunction<float>::hann
|
|
};
|
|
|
|
void processWindowedFrame(std::vector<float> &windowedFrame);
|
|
|
|
|
|
static constexpr int FFTORDER = 12;
|
|
juce::dsp::FFT fft{FFTORDER};
|
|
|
|
std::vector<float> fftData;
|
|
|
|
|
|
const float MINDB = -90.f;
|
|
const float MAXDB = 0.f;
|
|
|
|
std::vector<float> magnitudes;
|
|
|
|
std::vector<float> magnitudesDb;
|
|
|
|
std::vector<float> emaSmoothedMagnitudesDb;
|
|
|
|
std::vector<float> freqSmoothedMagnitudesDb;
|
|
|
|
std::vector<float> peakHoldMagnitudesDb;
|
|
|
|
std::vector<float> renderValuesDb;
|
|
|
|
double deltaF = 0;
|
|
double sampleRate = 44100;
|
|
|
|
//CHANGE DENOMINATOR FOR LOWER/HIGHER FREQ-SMOOTHING //HIGHER VALUE -> HIGHER SMOOTHING -- LESS VALUE -> LESS SMOOTHING
|
|
const float BANDWIDTHOCT = 1.f / 6.f;
|
|
|
|
const float OCTAVERADIUS = BANDWIDTHOCT / 2.f;
|
|
|
|
std::vector<double> freqPerBin;
|
|
|
|
//CHANGE FOR FASTER FALLOFF -- VALUE IS IN DB/S
|
|
const float FALLOFFRATE = 240.f;
|
|
|
|
float DELTAT = 0.f;
|
|
|
|
float tempPeakHoldDB = 0.f;
|
|
|
|
|
|
const float MINFREQ = 20.0f;
|
|
const float MAXFREQ = static_cast<float>(sampleRate) / 2;
|
|
|
|
void fillFftDataFromFrame(std::vector<float> &windowedFrame);
|
|
|
|
void buildMagnitudeSpectrum();
|
|
|
|
void convertToDb();
|
|
|
|
void applySmoothing();
|
|
|
|
void applyEMA();
|
|
|
|
void applyFreqSmoothing();
|
|
|
|
void applyPeakHoldAndFalloff();
|
|
|
|
std::vector<float> getRenderValues();
|
|
};
|
|
|
|
|
|
class CrystalizerEQAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer, private juce::AudioProcessorValueTreeState::Listener {
|
|
public:
|
|
CrystalizerEQAudioProcessorEditor(CrystalizerEQAudioProcessor &);
|
|
|
|
~CrystalizerEQAudioProcessorEditor() override;
|
|
|
|
void paintAnalyzer(juce::Graphics &g);
|
|
|
|
void paintModeBoxBorders(juce::Graphics &g);
|
|
|
|
void paintBorderLines(juce::Graphics &g);
|
|
|
|
//===================================================================
|
|
void timerCallback();
|
|
|
|
void paint(juce::Graphics &) override;
|
|
|
|
|
|
void resized() override;
|
|
|
|
void resetAllCheckboxes();
|
|
|
|
using SliderAttach = juce::AudioProcessorValueTreeState::SliderAttachment;
|
|
|
|
using ButtonAttach = juce::AudioProcessorValueTreeState::ButtonAttachment;
|
|
|
|
using ComboBoxAttach = juce::AudioProcessorValueTreeState::ComboBoxAttachment;
|
|
|
|
juce::Slider
|
|
lowBandFreqSlider, lowBandSlopeSlider, lowBandGainSlider, lowBandQSlider,
|
|
peak1FreqSlider, peak1GainSlider, peak1QSlider,
|
|
peak2FreqSlider, peak2GainSlider, peak2QSlider,
|
|
peak3FreqSlider, peak3GainSlider, peak3QSlider,
|
|
highBandFreqSlider, highBandSlopeSlider, highBandGainSlider, highBandQSlider,
|
|
inputSlider, outputSlider;
|
|
|
|
const juce::Array<juce::Slider *> sliders = {
|
|
&lowBandGainSlider, &lowBandFreqSlider, &lowBandQSlider, &lowBandSlopeSlider,
|
|
&peak1GainSlider, &peak1FreqSlider, &peak1QSlider,
|
|
&peak2GainSlider, &peak2FreqSlider, &peak2QSlider,
|
|
&peak3GainSlider, &peak3FreqSlider, &peak3QSlider,
|
|
&highBandGainSlider, &highBandFreqSlider, &highBandQSlider, &highBandSlopeSlider,
|
|
&inputSlider, &outputSlider
|
|
};
|
|
|
|
std::unique_ptr<SliderAttach>
|
|
lowBandFreqAttach, lowBandSlopeAttach, lowBandGainAttach, lowBandQAttach,
|
|
peak1FreqAttach, peak1GainAttach, peak1QAttach,
|
|
peak2FreqAttach, peak2GainAttach, peak2QAttach,
|
|
peak3FreqAttach, peak3GainAttach, peak3QAttach,
|
|
highBandFreqAttach, highBandSlopeAttach, highBandGainAttach, highBandQAttach,
|
|
inputAttach, outputAttach;
|
|
|
|
std::unique_ptr<ButtonAttach>
|
|
peak1BypassAttach, peak2BypassAttach, peak3BypassAttach,
|
|
crystalizeAttach, masterBypassAttach;
|
|
|
|
juce::Label titleLabel,
|
|
lowBandFreqLabel, lowBandSlopeLabel, lowBandGainLabel, lowBandQLabel, lowBandModeLabel,
|
|
low12, low24, low36, low48, lowdBOctLabel,
|
|
peak1FreqLabel, peak1GainLabel, peak1QLabel,
|
|
peak2FreqLabel, peak2GainLabel, peak2QLabel,
|
|
peak3FreqLabel, peak3GainLabel, peak3QLabel,
|
|
highBandFreqLabel, highBandSlopeLabel, highBandGainLabel, highBandQLabel, highBandModeLabel,
|
|
high12, high24, high36, high48, highdBOctLabel,
|
|
inputLabel, outputLabel,
|
|
presetBoxLabel;
|
|
|
|
const juce::Array<juce::Label *> sliderLabels = {
|
|
&lowBandFreqLabel, &lowBandSlopeLabel, &lowBandGainLabel, &lowBandQLabel, &lowBandModeLabel, &lowdBOctLabel,
|
|
&peak1FreqLabel, &peak1GainLabel, &peak1QLabel,
|
|
&peak2FreqLabel, &peak2GainLabel, &peak2QLabel,
|
|
&peak3FreqLabel, &peak3GainLabel, &peak3QLabel,
|
|
&highBandFreqLabel, &highBandSlopeLabel, &highBandGainLabel, &highBandQLabel, &highBandModeLabel,
|
|
&highdBOctLabel,
|
|
&inputLabel, &outputLabel
|
|
};
|
|
const juce::Array<juce::Label *> slopeLabels = {
|
|
&low12, &low24, &low36, &low48,
|
|
&high12, &high24, &high36, &high48
|
|
};
|
|
|
|
|
|
juce::TextButton resetButton, savePresetButton, deletePresetButton;
|
|
|
|
juce::ToggleButton masterBypassButton, crystalizeButton, peak1BypassButton, peak2BypassButton, peak3BypassButton,
|
|
presetMenuButton;
|
|
|
|
const juce::Array<juce::ToggleButton *> peakBypassButtons = {
|
|
&peak1BypassButton, &peak2BypassButton, &peak3BypassButton
|
|
};
|
|
|
|
juce::ComboBox presetBox;
|
|
|
|
juce::Component lowBandModeBox, highBandModeBox;
|
|
|
|
juce::Array<juce::ToggleButton *> lowBandModeButtons, highBandModeButtons;
|
|
|
|
std::array<bool, 4> lowBandBools, highBandBools;
|
|
|
|
|
|
juce::ToggleButton lowBypass, lowCut, lowBell, lowShelf,
|
|
highBypass, highCut, highBell, highShelf;
|
|
|
|
DesignSystem::ClickableTextEditor presetNameInput;
|
|
|
|
private:
|
|
// This reference is provided as a quick way for your editor to
|
|
// access the processor object that created it.
|
|
CrystalizerEQAudioProcessor &audioProcessor;
|
|
|
|
|
|
void setKnobVisibility();
|
|
|
|
void animateCrystalizeButton();
|
|
|
|
void setupSliders();
|
|
|
|
void setupSliderTextBoxes();
|
|
|
|
void handleLowBandModes();
|
|
|
|
void handleHighBandModes();
|
|
|
|
void setupAttachments();
|
|
|
|
void setupDisplayNames();
|
|
|
|
void setupToggleButtons();
|
|
|
|
void disableLowBand(float target);
|
|
|
|
void disableLowMidBand(float target);
|
|
|
|
void disableMidBand(float target);
|
|
|
|
void disableHighMidBand(float target);
|
|
|
|
void disableHighBand(float target);
|
|
|
|
void disableEverything(float target);
|
|
|
|
void addComponentsToLayout();
|
|
|
|
void setupLabels();
|
|
|
|
void setupFontsWithColours();
|
|
|
|
void setupEventListeners();
|
|
|
|
void initPresetSystem();
|
|
|
|
void updateFrequencyRanges();
|
|
|
|
void updateModeButtons();
|
|
|
|
|
|
std::unique_ptr<AXIOM::DesignSystem::Components::BaseSliderLookAndFeel> baseLookAndFeel;
|
|
std::unique_ptr<DesignSystem::Components::GainSliderLookAndFeel> gainLookAndFeel;
|
|
std::unique_ptr<DesignSystem::Components::FreqQSliderLookAndFeel> freqQLookAndFeel;
|
|
std::unique_ptr<DesignSystem::Components::SlopeSliderLookAndFeel> slopeLookAndFeel;
|
|
std::unique_ptr<DesignSystem::Components::GlobalSliderLookAndFeel> globalLookAndFeel;
|
|
std::unique_ptr<Components::BypassButtonLookAndFeel> bypassButtonLookAndFeel;
|
|
std::unique_ptr<Components::PresetMenuButtonLookAndFeel> presetMenuButtonLookAndFeel;
|
|
std::unique_ptr<Components::lowBandButtonLookAndFeel> lowBandButtonLookAndFeel;
|
|
std::unique_ptr<Components::highBandButtonLookAndFeel> highBandButtonLookAndFeel;
|
|
std::unique_ptr<Components::SvgToggleButtonLookAndFeel> svgToggleButtonLookAndFeel;
|
|
std::unique_ptr<DesignSystem::PresetMenuLookAndFeel> presetMenuLookAndFeel;
|
|
std::unique_ptr<DesignSystem::PresetButtonsLookAndFeel> presetButtonLookAndFeel;
|
|
std::unique_ptr<DesignSystem::PresetComboBoxLookAndFeel> presetComboBoxLookAndFeel;
|
|
std::unique_ptr<DesignSystem::PresetInputLookAndFeel> presetInputLookAndFeel;
|
|
|
|
|
|
//SPECRTRUM ANALYZER
|
|
|
|
|
|
SpectrumAnalyzer spectrumAnalyzer;
|
|
|
|
juce::Rectangle<int> analyzerRect;
|
|
|
|
Component headerBar;
|
|
Component mainPanel;
|
|
Component footerBar;
|
|
|
|
Component presetArea;
|
|
Component presetMenu;
|
|
Component analyzerArea;
|
|
|
|
Component filterArea;
|
|
Component lowFilterArea;
|
|
Component lowMidFilterArea;
|
|
Component midFilterArea;
|
|
Component highMidFilterArea;
|
|
Component highFilterArea;
|
|
|
|
const juce::Array<juce::Component *> filterAreas{
|
|
&lowFilterArea, &lowMidFilterArea, &midFilterArea, &highMidFilterArea, &highFilterArea
|
|
};
|
|
|
|
Component globalControlArea;
|
|
|
|
|
|
void scalePluginWindow(juce::Rectangle<int> area);
|
|
|
|
void setupMainGrid(juce::Rectangle<int> area);
|
|
|
|
void setupLowBandLayout();
|
|
|
|
void setupLowMidBandLayout();
|
|
|
|
void setupMidBandLayout();
|
|
|
|
void setupHighMidBandLayout();
|
|
|
|
void setupHighBandLayout();
|
|
|
|
void setupHeader();
|
|
|
|
void setupBody();
|
|
|
|
void setupFooter();
|
|
|
|
juce::Array<float> getReferenceCell();
|
|
|
|
const float gainMod = SliderStyles::Size::getSliderSizeMod(SliderStyles::Size::SizeMode::Gain);
|
|
const float freqMod = SliderStyles::Size::getSliderSizeMod(SliderStyles::Size::SizeMode::Freq);
|
|
const float qMod = SliderStyles::Size::getSliderSizeMod(SliderStyles::Size::SizeMode::Q);
|
|
const float slopeMod = SliderStyles::Size::getSliderSizeMod(SliderStyles::Size::SizeMode::Slope);
|
|
const float globalMod = SliderStyles::Size::getSliderSizeMod(SliderStyles::Size::SizeMode::Global);
|
|
|
|
const float filterAreaMargin = 15.0f;
|
|
|
|
bool isAnimatingCrystalize = false;
|
|
bool isFadingToActive = false;
|
|
|
|
std::unique_ptr<juce::Drawable> logoDrawable;
|
|
|
|
juce::Component::SafePointer<DesignSystem::PresetMenu> presetMenuSafePtr;
|
|
|
|
bool inputFocused = false;
|
|
|
|
float mapFrequencyToX(float freq, float minFreq, float maxFreq, float width);
|
|
|
|
int getClosestBinForFrequency(float freq);
|
|
|
|
void drawFrequencyGrid(juce::Graphics &g, const float dbRange);
|
|
|
|
float getInterpolatedDb(float exactBin);
|
|
|
|
void parameterChanged(const juce::String& parameterID, float newValue) override;
|
|
|
|
void syncAllButtonStates();
|
|
|
|
void syncPresetBox();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CrystalizerEQAudioProcessorEditor)
|
|
};
|