Procházet zdrojové kódy

Merged eq/dist and chorus/delay/reverb parts

LuigiBiasi-Athenagroup před 6 měsíci
rodič
revize
179f72a145

+ 1 - 1
JUCE/CMLSProject/Source/CMLSChorus.h

@@ -19,7 +19,7 @@
 #define LFO_MIN_DEPTH 0.0f // Minimum depth of the LFO
 #define LFO_MAX_DEPTH 5.0f // Maximum depth of the LFO
 
-class CMLSChorus : juce::dsp::ProcessorBase {
+class CMLSChorus : public juce::dsp::ProcessorBase {
     public:
 		CMLSChorus();
 		~CMLSChorus() override;

+ 1 - 1
JUCE/CMLSProject/Source/CMLSDelay.cpp

@@ -81,7 +81,7 @@ void CMLSDelay::setDryWet(float value) {
 
 void CMLSDelay::setAmount(float value) {
 	this->delayLength = this->delayLengthRange->convertFrom0to1(value);
-	this->feedback = this->delayLengthRange->convertFrom0to1(value);
+	this->feedback = this->feedbackRange->convertFrom0to1(value);
 
 	std::fill(this->delayValue.begin(), this->delayValue.end(), this->delayLength * this->effectDelaySamples);
 	for (auto& volume : this->delayFeedbackVolume) {

+ 40 - 0
JUCE/CMLSProject/Source/CMLSDistortion.cpp

@@ -0,0 +1,40 @@
+#include "CMLSDistortion.h"
+
+CMLSDistortion::CMLSDistortion() {}
+
+void CMLSDistortion::prepare(const juce::dsp::ProcessSpec& spec) {
+    inputGain.prepare(spec);
+    outputGain.prepare(spec);
+    inputGain.setGainDecibels(0.0f);
+    outputGain.setGainDecibels(0.0f);
+}
+
+void CMLSDistortion::reset() {
+    inputGain.reset();
+    outputGain.reset();
+}
+
+void CMLSDistortion::process(const juce::dsp::ProcessContextReplacing<float>& context) {
+    auto& block = context.getOutputBlock();
+    inputGain.process(context);
+
+    for (size_t ch = 0; ch < block.getNumChannels(); ++ch) {
+        auto* data = block.getChannelPointer(ch);
+        for (size_t i = 0; i < block.getNumSamples(); ++i) {
+            float dry = data[i];
+            float wet = std::tanh(data[i] * drive);  // soft clipping
+            data[i] = dry * (1.0f - mix) + wet * mix; // apply mix
+        }
+    }
+
+    outputGain.process(context);
+}
+
+void CMLSDistortion::setDrive(float newDrive) {
+    drive = newDrive;
+}
+
+void CMLSDistortion::setMix(float newMix)
+{
+    mix = juce::jlimit(0.0f, 1.0f, newMix); // between 0.0 and 1.0
+}

+ 23 - 0
JUCE/CMLSProject/Source/CMLSDistortion.h

@@ -0,0 +1,23 @@
+#pragma once
+
+#include <JuceHeader.h>
+
+class CMLSDistortion : public juce::dsp::ProcessorBase {
+public:
+    CMLSDistortion();
+    ~CMLSDistortion() override = default;
+
+    void prepare(const juce::dsp::ProcessSpec&) override;
+    void reset() override;
+    void process(const juce::dsp::ProcessContextReplacing<float>&) override;
+
+    void setDrive(float drive); // controls intensity
+    void setMix(float mix);     // controls the dry/wet mix ratio,how much of the distorted signal is mixed with the original signal
+                                // 0.0 = dry, 1.0 = full distortion
+
+private:
+    float drive = 1.0f;
+    float mix = 1.0f;
+
+    juce::dsp::Gain<float> inputGain, outputGain;
+};

+ 36 - 0
JUCE/CMLSProject/Source/CMLSEqualizer.cpp

@@ -0,0 +1,36 @@
+#include "CMLSEqualizer.h"
+
+CMLSEqualizer::CMLSEqualizer() {}
+
+void CMLSEqualizer::prepare(const juce::dsp::ProcessSpec& spec) {
+    sampleRate = spec.sampleRate;
+
+    lowBand.prepare(spec);
+    highBand.prepare(spec);
+
+    lowBand.reset();
+    highBand.reset();
+
+    setEqLowGain(0.0f);
+    setEqHighGain(0.0f);
+}
+
+void CMLSEqualizer::reset() {
+    lowBand.reset();
+    highBand.reset();
+}
+
+void CMLSEqualizer::process(const juce::dsp::ProcessContextReplacing<float>& context) {
+    lowBand.process(context);
+    highBand.process(context);
+}
+
+void CMLSEqualizer::setEqLowGain(float gain) {
+    *lowBand.state = *juce::dsp::IIR::Coefficients<float>::makeLowShelf(
+        sampleRate, 200.0f, 0.7f, juce::Decibels::decibelsToGain(gain));
+}
+
+void CMLSEqualizer::setEqHighGain(float gain) {
+    *highBand.state = *juce::dsp::IIR::Coefficients<float>::makeHighShelf(
+        sampleRate, 5000.0f, 0.7f, juce::Decibels::decibelsToGain(gain));
+}

+ 21 - 0
JUCE/CMLSProject/Source/CMLSEqualizer.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include <JuceHeader.h>
+
+class CMLSEqualizer : public juce::dsp::ProcessorBase {
+public:
+    CMLSEqualizer();
+    ~CMLSEqualizer() override = default;
+
+    void prepare(const juce::dsp::ProcessSpec&) override;
+    void reset() override;
+    void process(const juce::dsp::ProcessContextReplacing<float>&) override;
+
+    void setEqLowGain(float);
+    void setEqHighGain(float);
+
+private:
+    double sampleRate = 44100.0; // default, will be updated
+    juce::dsp::ProcessorDuplicator<juce::dsp::IIR::Filter<float>,
+        juce::dsp::IIR::Coefficients<float>> lowBand, highBand;
+};

+ 70 - 0
JUCE/CMLSProject/Source/CMLSProcessorChain.cpp

@@ -0,0 +1,70 @@
+/*
+  ==============================================================================
+
+    CMLSProcessorChain.cpp
+    Created: 12 May 2025 10:05:40am
+    Author:  Luigi
+
+  ==============================================================================
+*/
+
+#include "CMLSProcessorChain.h"
+
+CMLSProcessorChain::CMLSProcessorChain()
+{}
+
+CMLSProcessorChain::~CMLSProcessorChain()
+{}
+
+void CMLSProcessorChain::reset()
+{
+	for (auto& processor : chain)
+	{
+		if (processor)
+			processor->reset();
+	}
+}
+
+void CMLSProcessorChain::prepare(const juce::dsp::ProcessSpec& spec)
+{
+	for (auto& processor : chain)
+	{
+		if (processor)
+			processor->prepare(spec);
+	}
+}
+
+void CMLSProcessorChain::process(const juce::dsp::ProcessContextReplacing<float>& context)
+{
+	for (int i = 0; i < this->chain.size(); ++i)
+	{
+		if (this->chain[i] && this->slots[i] == true)
+			this->chain[i]->process(context);
+	}
+}
+
+int CMLSProcessorChain::pushProcessor(juce::dsp::ProcessorBase& processor)
+{
+	chain.push_back(&processor);
+	slots.push_back(true);
+	return chain.size() - 1;
+}
+
+void CMLSProcessorChain::muteProcessrInSlot(int slot)
+{
+	slots[slot] = false;
+}
+
+void CMLSProcessorChain::unmuteProcessrInSlot(int slot)
+{
+	slots[slot] = true;
+}
+
+void CMLSProcessorChain::swapPlaces(int slot1, int slot2)
+{
+	if (slot1 < 0 || slot2 < 0 || slot1 >= chain.size() || slot2 >= chain.size())
+		return;
+
+	std::swap(chain[slot1], chain[slot2]);
+	std::swap(slots[slot1], slots[slot2]);
+}

+ 32 - 0
JUCE/CMLSProject/Source/CMLSProcessorChain.h

@@ -0,0 +1,32 @@
+/*
+  ==============================================================================
+
+    CMLSProcessorChain.h
+    Created: 12 May 2025 10:05:40am
+    Author:  Luigi
+
+  ==============================================================================
+*/
+
+#pragma once
+#include <JuceHeader.h>
+
+class CMLSProcessorChain
+{
+	public:
+		CMLSProcessorChain();
+		~CMLSProcessorChain();
+
+		void reset();
+		void prepare(const juce::dsp::ProcessSpec&);
+		void process(const juce::dsp::ProcessContextReplacing<float>&);
+		
+		int pushProcessor(juce::dsp::ProcessorBase& processor);
+		void muteProcessrInSlot(int slot);
+		void unmuteProcessrInSlot(int slot);
+		void swapPlaces(int slot1, int slot2);
+	
+	private:
+		std::vector<bool> slots;
+		std::vector<juce::dsp::ProcessorBase*> chain;
+};

+ 74 - 14
JUCE/CMLSProject/Source/PluginEditor.cpp

@@ -17,6 +17,40 @@ CMLSProjectAudioProcessorEditor::CMLSProjectAudioProcessorEditor (CMLSProjectAud
     // editor's size to whatever you need it to be.
     setSize (400, 300);
 
+    // Add aliders to the editor (Equalizer)
+    this->equalizerLowGainSlider.setRange(0.0, 1.0);
+    this->equalizerLowGainSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 100, 20);
+    this->equalizerLowGainSlider.addListener(this);
+    this->equalizerLowGainLabel.setText("Equalizer Low Gain", juce::dontSendNotification);
+
+    addAndMakeVisible(this->equalizerLowGainSlider);
+    addAndMakeVisible(this->equalizerLowGainLabel);
+
+    this->equalizerHighGainSlider.setRange(0.0, 1.0);
+    this->equalizerHighGainSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 100, 20);
+    this->equalizerHighGainSlider.addListener(this);
+    this->equalizerHighGainLabel.setText("Equalizer High Gain", juce::dontSendNotification);
+
+    addAndMakeVisible(this->equalizerHighGainSlider);
+    addAndMakeVisible(this->equalizerHighGainLabel);
+
+    // Add aliders to the editor (Distortion)
+    this->distortionDriveSlider.setRange(0.0, 1.0);
+    this->distortionDriveSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 100, 20);
+    this->distortionDriveSlider.addListener(this);
+    this->distortionDriveLabel.setText("Distortion Drive", juce::dontSendNotification);
+
+    addAndMakeVisible(this->distortionDriveSlider);
+    addAndMakeVisible(this->distortionDriveLabel);
+
+    this->distortionMixSlider.setRange(0.0, 1.0);
+    this->distortionMixSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 100, 20);
+    this->distortionMixSlider.addListener(this);
+    this->distortionMixLabel.setText("Distortion Mix", juce::dontSendNotification);
+
+    addAndMakeVisible(this->distortionMixSlider);
+    addAndMakeVisible(this->distortionMixLabel);
+
 	// Add aliders to the editor (Chorus)
     this->chorusDryWetSlider.setRange(0.0, 1.0);
     this->chorusDryWetSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 100, 20);
@@ -83,20 +117,30 @@ void CMLSProjectAudioProcessorEditor::paint (juce::Graphics& g)
 void CMLSProjectAudioProcessorEditor::resized()
 {
 	//titleLabel.setBounds(10, 10, getWidth() - 20, 20);
-	chorusDryWetSlider.setBounds(130, 10, getWidth() - 130, 20);
-    chorusDryWetLabel.setBounds(10, 10, 100, 20);
-    chorusAmountSlider.setBounds(130, 30, getWidth() - 130, 20);
-	chorusAmountLabel.setBounds(10, 30, 100, 20);
-
-    reverbDryWetSlider.setBounds(130, 70, getWidth() - 130, 20);
-	reverbDryWetLabel.setBounds(10, 70, 100, 20);
-    reverbRoomSizeSlider.setBounds(130, 90, getWidth() - 130, 20);
-	reverbRoomSizeLabel.setBounds(10, 90, 100, 20);
-
-    delayDryWetSlider.setBounds(130, 130, getWidth() - 130, 20);
-	delayDryWetLabel.setBounds(10, 130, 100, 20);
-    delayAmountSlider.setBounds(130, 150, getWidth() - 130, 20);
-	delayAmountLabel.setBounds(10, 150, 100, 20);
+    equalizerLowGainSlider.setBounds(130, 10, getWidth() - 130, 20);
+    equalizerLowGainLabel.setBounds(10, 10, 100, 20);
+    equalizerHighGainSlider.setBounds(130, 30, getWidth() - 130, 20);
+    equalizerHighGainLabel.setBounds(10, 30, 100, 20);
+
+    distortionDriveSlider.setBounds(130, 70, getWidth() - 130, 20);
+    distortionDriveLabel.setBounds(10, 70, 100, 20);
+    distortionMixSlider.setBounds(130, 90, getWidth() - 130, 20);
+    distortionMixLabel.setBounds(10, 90, 100, 20);
+
+    chorusDryWetSlider.setBounds(130, 130, getWidth() - 130, 20);
+    chorusDryWetLabel.setBounds(10, 130, 100, 20);
+    chorusAmountSlider.setBounds(130, 150, getWidth() - 130, 20);
+	chorusAmountLabel.setBounds(10, 150, 100, 20);
+
+    reverbDryWetSlider.setBounds(130, 190, getWidth() - 130, 20);
+	reverbDryWetLabel.setBounds(10, 190, 100, 20);
+    reverbRoomSizeSlider.setBounds(130, 210, getWidth() - 130, 20);
+	reverbRoomSizeLabel.setBounds(10, 210, 100, 20);
+
+    delayDryWetSlider.setBounds(130, 250, getWidth() - 130, 20);
+	delayDryWetLabel.setBounds(10, 250, 100, 20);
+    delayAmountSlider.setBounds(130, 270, getWidth() - 130, 20);
+	delayAmountLabel.setBounds(10, 270, 100, 20);
 }
 
 void CMLSProjectAudioProcessorEditor::sliderValueChanged(juce::Slider* slider){
@@ -124,4 +168,20 @@ void CMLSProjectAudioProcessorEditor::sliderValueChanged(juce::Slider* slider){
 	{
 		this->audioProcessor.setDelayAmount(slider->getValue());
 	}
+    else if (slider == &this->equalizerLowGainSlider)
+    {
+        this->audioProcessor.setEqLowGain(slider->getValue());
+    }
+    else if (slider == &this->equalizerHighGainSlider)
+    {
+        this->audioProcessor.setEqHighGain(slider->getValue());
+    }
+    else if (slider == &this->distortionDriveSlider)
+    {
+        this->audioProcessor.setDistortionDrive(slider->getValue());
+    }
+    else if (slider == &this->distortionMixSlider)
+    {
+        this->audioProcessor.setDistortionMix(slider->getValue());
+    }
 }

+ 12 - 0
JUCE/CMLSProject/Source/PluginEditor.h

@@ -33,6 +33,18 @@ private:
     // Title
 	juce::Label titleLabel;
 
+    // Equalizer
+    juce::Slider equalizerLowGainSlider;
+    juce::Label equalizerLowGainLabel;
+    juce::Slider equalizerHighGainSlider;
+    juce::Label equalizerHighGainLabel;
+
+    // Distortion
+    juce::Slider distortionDriveSlider;
+    juce::Label distortionDriveLabel;
+    juce::Slider distortionMixSlider;
+    juce::Label distortionMixLabel;
+
     // Chorus
     juce::Slider chorusDryWetSlider;
     juce::Label chorusDryWetLabel;

+ 48 - 13
JUCE/CMLSProject/Source/PluginProcessor.cpp

@@ -23,8 +23,19 @@ CMLSProjectAudioProcessor::CMLSProjectAudioProcessor()
 #endif
 {
     // Chaining the effects
+	this->equalizer = new CMLSEqualizer();
+    this->distortion = new CMLSDistortion();
+    this->chorus = new CMLSChorus();
+    this->delay = new CMLSDelay();
+    this->reverb = new CMLSReverb();
+
+    this->processorChain.pushProcessor(*equalizer);
+    this->processorChain.pushProcessor(*distortion);
+    this->processorChain.pushProcessor(*chorus);
+    this->processorChain.pushProcessor(*delay);
+    this->processorChain.pushProcessor(*reverb);
+
     this->processorChain.reset();
-    //this->processorChain.addNode<CMLSDelay>(2);
 }
 
 CMLSProjectAudioProcessor::~CMLSProjectAudioProcessor()
@@ -178,34 +189,58 @@ void CMLSProjectAudioProcessor::setStateInformation (const void* data, int sizeI
     // whose contents will have been created by the getStateInformation() call.
 }
 
+void CMLSProjectAudioProcessor::muteEffectInSlot(int slot) {
+    this->processorChain.muteProcessrInSlot(slot);
+}
+
+void CMLSProjectAudioProcessor::unmuteEffectInSlot(int slot) {
+    this->processorChain.unmuteProcessrInSlot(slot);
+}
+
+void CMLSProjectAudioProcessor::swapEffectInSlot(int slot1, int slot2) {
+	this->processorChain.swapPlaces(slot1, slot2);
+}
+
+void CMLSProjectAudioProcessor::setEqLowGain(float value) {
+	((CMLSEqualizer*)this->equalizer)->setEqLowGain(value);
+}
+
+void CMLSProjectAudioProcessor::setEqHighGain(float value) {
+    ((CMLSEqualizer*)this->equalizer)->setEqHighGain(value);
+}
+
+void CMLSProjectAudioProcessor::setDistortionDrive(float value) {
+    ((CMLSDistortion*)this->distortion)->setDrive(value);
+}
+
+void CMLSProjectAudioProcessor::setDistortionMix(float value) {
+	((CMLSDistortion*)this->distortion)->setMix(value);
+}
+
 void CMLSProjectAudioProcessor::setChorusDryWet(float value) {
-    auto& instance = this->processorChain.template get<0>();
-	instance.setDryWet(value);
+    //auto& instance = this->processorChain.template get<0>();
+	//instance.setDryWet(value);
+	((CMLSChorus*)this->chorus)->setDryWet(value);
 }
 
 void CMLSProjectAudioProcessor::setChorusAmount(float value) {
-	auto& instance = this->processorChain.template get<0>();
-	instance.setAmount(value);
+	((CMLSChorus*)this->chorus)->setAmount(value);
 }
 
 void CMLSProjectAudioProcessor::setReverbDryWet(float value) {
-	auto& instance = this->processorChain.template get<1>();
-	instance.setDryWet(value);
+    ((CMLSReverb*)this->reverb)->setDryWet(value);
 }
 
 void CMLSProjectAudioProcessor::setReverbRoomSize(float value) {
-	auto& instance = this->processorChain.template get<1>();
-	instance.setRoomSize(value);
+	((CMLSReverb*)this->reverb)->setRoomSize(value);
 }
 
 void CMLSProjectAudioProcessor::setDelayDryWet(float value) {
-	auto& instance = this->processorChain.template get<2>();
-	instance.setDryWet(value);
+    ((CMLSDelay*)this->delay)->setDryWet(value);
 }
 
 void CMLSProjectAudioProcessor::setDelayAmount(float value) {
-	auto& instance = this->processorChain.template get<2>();
-	instance.setAmount(value);
+    ((CMLSDelay*)this->delay)->setAmount(value);
 }
 
 //==============================================================================

+ 21 - 1
JUCE/CMLSProject/Source/PluginProcessor.h

@@ -12,6 +12,9 @@
 #include "CMLSReverb.h"
 #include "CMLSDelay.h"
 #include "CMLSChorus.h"
+#include "CMLSProcessorChain.h"
+#include "CMLSEqualizer.h"
+#include "CMLSDistortion.h"
 
 //==============================================================================
 /**
@@ -56,7 +59,18 @@ public:
     void getStateInformation (juce::MemoryBlock& destData) override;
     void setStateInformation (const void* data, int sizeInBytes) override;
 
+    // Mute/unmute slot by number
+    void muteEffectInSlot(int slot);
+    void unmuteEffectInSlot(int slot);
+	void swapEffectInSlot(int slot1, int slot2);
+
     // Parameter controls
+    void setEqLowGain(float value);
+    void setEqHighGain(float value);
+
+    void setDistortionDrive(float value);
+    void setDistortionMix(float value);
+
 	void setChorusDryWet(float value);
 	void setChorusAmount(float value);
 
@@ -75,7 +89,13 @@ private:
     // Buffer for the incoming audio from the generators
 
     // Effects processing chain
-	juce::dsp::ProcessorChain<CMLSChorus, CMLSReverb, CMLSDelay> processorChain;
+    juce::dsp::ProcessorBase* equalizer;
+	juce::dsp::ProcessorBase* distortion;
+    juce::dsp::ProcessorBase* chorus;
+    juce::dsp::ProcessorBase* delay;
+    juce::dsp::ProcessorBase* reverb;
+
+	CMLSProcessorChain processorChain;
 
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CMLSProjectAudioProcessor)
 };