/* ============================================================================== PluginProcessor.h Audio processor for CrystalizerEQ plugin Manages DSP processing chain, filter coefficients, multiband processing, and parameter state (APVTS) ============================================================================== */ #pragma once #include #include #include class AudioFIFO { public: AudioFIFO(); ~AudioFIFO(); juce::Array sampleStack; void loadSamplesToFIFO(const juce::AudioBuffer &samples); juce::Array sendSamplesToEditor(); juce::SpinLock lock; }; class CrystalizerEQAudioProcessor : public juce::AudioProcessor, public juce::AudioProcessorValueTreeState::Listener { public: //============================================================================== CrystalizerEQAudioProcessor(); ~CrystalizerEQAudioProcessor() override; void parameterChanged(const juce::String &id, float newValue) override; //============================================================================== void prepareToPlay(double sampleRate, int samplesPerBlock) override; void releaseResources() override; #ifndef JucePlugin_PreferredChannelConfigurations bool isBusesLayoutSupported(const BusesLayout &layouts) const override; #endif void processBlock(juce::AudioBuffer &, juce::MidiBuffer &) override; //============================================================================== juce::AudioProcessorEditor *createEditor() override; bool hasEditor() const override; //============================================================================== const juce::String getName() const override; bool acceptsMidi() const override; bool producesMidi() const override; bool isMidiEffect() const override; double getTailLengthSeconds() const override; //============================================================================== int getNumPrograms() override; int getCurrentProgram() override; void setCurrentProgram(int index) override; const juce::String getProgramName(int index) override; void changeProgramName(int index, const juce::String &newName) override; //============================================================================== void getStateInformation(juce::MemoryBlock &destData) override; void setStateInformation(const void *data, int sizeInBytes) override; // --------- Parameter (APVTS) ---------- static juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout(); juce::AudioProcessorValueTreeState apvts{*this, nullptr, "PARAMS", createParameterLayout()}; void setPresetName(const juce::String &s); juce::String getPresetName() const noexcept { return presetName; } juce::StringArray getPresetNamesArray() const; juce::String savePresetToFile() const; void loadPreset(const juce::String &preset); void deletePreset(const juce::String &preset) const; void resetAllParameters(); bool lowCutActive = false; bool highCutActive = false; AudioFIFO audioFIFO; private: using Gain = juce::dsp::Gain; using Filter = juce::dsp::IIR::Filter; using Chain = juce::dsp::ProcessorChain; // 0: LowCut (HP), 1: Peak, 2: HighCut (LP) juce::Random noiseRandL, noiseRandR; Chain leftChain, rightChain; void updateFilters(); juce::AudioBuffer processMultiBand(juce::AudioBuffer &lowBuf, juce::AudioBuffer &highBuf); using Coeff = juce::dsp::IIR::Coefficients; juce::dsp::IIR::Filter mbHighPeakL; juce::dsp::IIR::Filter mbHighPeakR; juce::dsp::LinkwitzRileyFilter mbLowpassL, mbLowpassR; juce::dsp::LinkwitzRileyFilter mbHighpassL, mbHighpassR; juce::dsp::WaveShaper saturatorL, saturatorR; juce::String presetName{"Init"}; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CrystalizerEQAudioProcessor) };