/* ============================================================================== This file contains the basic framework code for a JUCE plugin editor. ============================================================================== */ #pragma once #include #include #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(FFTSIZE); freqPerBin.resize(BINS); peakHoldMagnitudesDb.resize(BINS); DELTAT = static_cast(HOPSIZE) / static_cast(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 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.3f; void processSamples(); void getFftFrame(juce::Array &samples); void applyWindowOnFftFrame(std::vector &fullFrame); juce::dsp::WindowingFunction window { FFTSIZE, juce::dsp::WindowingFunction::hann }; void processWindowedFrame(std::vector &windowedFrame); static constexpr int FFTORDER = 12; juce::dsp::FFT fft { FFTORDER }; std::vector fftData; const float MINDB = -120.f; const float MAXDB = 96.f; std::vector magnitudes; std::vector magnitudesDb; std::vector emaSmoothedMagnitudesDb; std::vector freqSmoothedMagnitudesDb; std::vector peakHoldMagnitudesDb; std::vector 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 freqPerBin; //CHANGE FOR FASTER FALLOFF -- VALUE IS IN DB/S const float FALLOFFRATE = 120.f; float DELTAT = 0.f; float tempPeakHoldDB = 0.f; const float MINFREQ = 20.0f; const float MAXFREQ = static_cast(sampleRate) / 2; void fillFftDataFromFrame(std::vector &windowedFrame); void buildMagnitudeSpectrum(); void convertToDb(); void applySmoothing(); void applyEMA(); void applyFreqSmoothing(); void applyPeakHoldAndFalloff(); std::vector getRenderValues(); }; class CrystalizerEQAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer { 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 testNoiseSlider, lowBandFreqSlider, lowBandSlopeSlider, lowBandGainSlider, lowBandQSlider, peak1FreqSlider, peak1GainSlider, peak1QSlider, peak2FreqSlider, peak2GainSlider, peak2QSlider, peak3FreqSlider, peak3GainSlider, peak3QSlider, highBandFreqSlider, highBandSlopeSlider, highBandGainSlider, highBandQSlider, inputSlider, outputSlider; const juce::Array sliders = { &lowBandGainSlider, &lowBandFreqSlider, &lowBandQSlider, &lowBandSlopeSlider, &peak1GainSlider, &peak1FreqSlider, &peak1QSlider, &peak2GainSlider, &peak2FreqSlider, &peak2QSlider, &peak3GainSlider, &peak3FreqSlider, &peak3QSlider, &highBandGainSlider, &highBandFreqSlider, &highBandQSlider, &highBandSlopeSlider, &inputSlider, &outputSlider }; std::unique_ptr testNoiseAttach, lowBandFreqAttach, lowBandSlopeAttach, lowBandGainAttach, lowBandQAttach, peak1FreqAttach, peak1GainAttach, peak1QAttach, peak2FreqAttach, peak2GainAttach, peak2QAttach, peak3FreqAttach, peak3GainAttach, peak3QAttach, highBandFreqAttach, highBandSlopeAttach, highBandGainAttach, highBandQAttach, inputAttach, outputAttach; juce::Label titleLabel, testNoiseLabel, lowBandFreqLabel, lowBandSlopeLabel, lowBandGainLabel, lowBandQLabel, lowBandModeLabel, low12, low24, low36, low48, peak1FreqLabel, peak1GainLabel, peak1QLabel, peak2FreqLabel, peak2GainLabel, peak2QLabel, peak3FreqLabel, peak3GainLabel, peak3QLabel, highBandFreqLabel, highBandSlopeLabel, highBandGainLabel, highBandQLabel, highBandModeLabel, high12, high24, high36, high48, inputLabel, outputLabel, presetBoxLabel; const juce::Array sliderLabels = { &lowBandFreqLabel, &lowBandSlopeLabel, &lowBandGainLabel, &lowBandQLabel, &lowBandModeLabel, &peak1FreqLabel, &peak1GainLabel, &peak1QLabel, &peak2FreqLabel, &peak2GainLabel, &peak2QLabel, &peak3FreqLabel, &peak3GainLabel, &peak3QLabel, &highBandFreqLabel, &highBandSlopeLabel, &highBandGainLabel, &highBandQLabel, &highBandModeLabel, &inputLabel, &outputLabel }; const juce::Array slopeLabels = { &low12, &low24, &low36, &low48, &high12, &high24, &high36, &high48 }; juce::TextButton testNoiseButton, resetButton, savePresetButton, deletePresetButton; juce::ToggleButton masterBypassButton, crystalizeButton, peak1BypassButton, peak2BypassButton, peak3BypassButton, presetMenuButton; juce::ComboBox presetBox; juce::Component lowBandModeBox, highBandModeBox; juce::Array lowBandModeButtons, highBandModeButtons; std::array lowBandBools, highBandBools; juce::ToggleButton lowBypass, lowCut, lowBell, lowShelf, highBypass, highCut, highBell, highShelf; juce::TextEditor 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(); std::unique_ptr baseLookAndFeel; std::unique_ptr gainLookAndFeel; std::unique_ptr freqQLookAndFeel; std::unique_ptr slopeLookAndFeel; std::unique_ptr globalLookAndFeel; std::unique_ptr bypassButtonLookAndFeel; std::unique_ptr presetMenuButtonLookAndFeel; std::unique_ptr lowBandButtonLookAndFeel; std::unique_ptr highBandButtonLookAndFeel; std::unique_ptr svgToggleButtonLookAndFeel; //SPECRTRUM ANALYZER SpectrumAnalyzer spectrumAnalyzer; juce::Rectangle 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 filterAreas { &lowFilterArea, &lowMidFilterArea, &midFilterArea, &highMidFilterArea, &highFilterArea }; Component globalControlArea; void scalePluginWindow(juce::Rectangle area); void setupMainGrid(juce::Rectangle area); void setupLowBandLayout(); void setupLowMidBandLayout(); void setupMidBandLayout(); void setupHighMidBandLayout(); void setupHighBandLayout(); void setupHeader(); void setupBody(); void setupFooter(); juce::Array 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; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrystalizerEQAudioProcessorEditor) };