From 242a4ad9bb66f67539915917dcc7a5786986d7d0 Mon Sep 17 00:00:00 2001 From: Otto Andelin Date: Thu, 21 May 2026 12:56:21 +0300 Subject: [PATCH 1/7] create InsertEffect base class with virtual functions, derive ChorusEngine and LofiEngine from that class, clean up code and fix signature mismatches --- Source/BitCrusher.h | 1 - Source/ChorusEngine.cpp | 5 ++++- Source/ChorusEngine.h | 15 +++++++++------ Source/InsertEffect.h | 15 +++++++++++++++ Source/LofiEngine.cpp | 2 +- Source/LofiEngine.h | 12 +++++++----- 6 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 Source/InsertEffect.h diff --git a/Source/BitCrusher.h b/Source/BitCrusher.h index 3c05a4a..ff097f9 100644 --- a/Source/BitCrusher.h +++ b/Source/BitCrusher.h @@ -1,6 +1,5 @@ #pragma once #include -#include "Parameters.h" class BitCrusher { diff --git a/Source/ChorusEngine.cpp b/Source/ChorusEngine.cpp index cb22c8a..18acc02 100644 --- a/Source/ChorusEngine.cpp +++ b/Source/ChorusEngine.cpp @@ -59,12 +59,15 @@ void ChorusEngine::setModDepth(float modDepth) } } -void ChorusEngine::processSample(const float& inL, const float& inR, float& outL, float& outR, const Parameters& params) +void ChorusEngine::update(const Parameters& params) { setIntensity(params.chorusIntensity()); setModRate(params.chorusModRate()); setModDepth(params.chorusModDepth()); +} +void ChorusEngine::processSample(const float& inL, const float& inR, float& outL, float& outR) +{ // Dual chorus intensity mapping: c1 peaks early (at ~0.6 intensity), // c2 ramps exponentially, staying subtle until higher intensities. // This creates a smooth character progression: barely audible -> chorus1 dominant diff --git a/Source/ChorusEngine.h b/Source/ChorusEngine.h index 28e3452..2e37169 100644 --- a/Source/ChorusEngine.h +++ b/Source/ChorusEngine.h @@ -1,13 +1,13 @@ #pragma once #include +#include "InsertEffect.h" #include "Chorus.h" #include "Parameters.h" using Filter = juce::dsp::StateVariableTPTFilter; - - -class ChorusEngine { +class ChorusEngine : public InsertEffect +{ public: ChorusEngine(); ~ChorusEngine() = default; @@ -16,10 +16,11 @@ class ChorusEngine { static constexpr float chorus2DefaultTime = 11.0f; - void prepareToPlay(double sampleRate, int samplesPerBlock) noexcept; - void reset() noexcept; + void prepareToPlay(double sampleRate, int samplesPerBlock) noexcept override; + void reset() noexcept override; - void processSample(const float& inL, const float& inR, float& outL, float& outR, const Parameters& params); + void processSample(const float& inL, const float& inR, float& outL, float& outR) override; + void update(const Parameters& params) override; private: Chorus m_chorus1L{ chorus1DefaultTime, Parameters::defaultChorusModRate, Parameters::defaultChorusModDepth, 0.0f }; @@ -43,4 +44,6 @@ class ChorusEngine { void setIntensity(float value) { m_intensity = value; } void setModDepth(float newModDepth); void setModRate(float newRate); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChorusEngine) }; diff --git a/Source/InsertEffect.h b/Source/InsertEffect.h new file mode 100644 index 0000000..f6c2330 --- /dev/null +++ b/Source/InsertEffect.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Parameters.h" + +class InsertEffect +{ +public: + InsertEffect() = default; + virtual ~InsertEffect() = default; + + virtual void prepareToPlay(double sampleRate, int samplesPerBlock) noexcept = 0; + virtual void reset() noexcept = 0; + virtual void processSample(const float& inL, const float& inR, float& outL, float& outR) = 0; + virtual void update(const Parameters& params) = 0; +}; \ No newline at end of file diff --git a/Source/LofiEngine.cpp b/Source/LofiEngine.cpp index d6eb4d0..561eba3 100644 --- a/Source/LofiEngine.cpp +++ b/Source/LofiEngine.cpp @@ -4,7 +4,7 @@ LofiEngine::LofiEngine() { } -void LofiEngine::prepareToPlay(double sampleRate) noexcept +void LofiEngine::prepareToPlay(double sampleRate, int samplesPerBlock) noexcept { m_sampleRate = static_cast(sampleRate); m_bitCrusherL.prepareToPlay(m_sampleRate); diff --git a/Source/LofiEngine.h b/Source/LofiEngine.h index 3469ec8..70960f6 100644 --- a/Source/LofiEngine.h +++ b/Source/LofiEngine.h @@ -2,17 +2,19 @@ #include #include "BitCrusher.h" +#include "Parameters.h" +#include "InsertEffect.h" -class LofiEngine +class LofiEngine : public InsertEffect { public: LofiEngine(); ~LofiEngine() = default; - void prepareToPlay(double sampleRate) noexcept; - void reset() noexcept; - void processSample(const float& inL, const float& inR, float& outL, float& outR); - void update(const Parameters& params); + void prepareToPlay(double sampleRate, int samplesPerBlock) noexcept override; + void reset() noexcept override; + void processSample(const float& inL, const float& inR, float& outL, float& outR) override; + void update(const Parameters& params) override; private: BitCrusher m_bitCrusherL{ 12.0f, 22050.0f }; From c677a4b8a19f27a8ca7354324aa4cd5719438b94 Mon Sep 17 00:00:00 2001 From: Otto Andelin Date: Thu, 21 May 2026 14:40:21 +0300 Subject: [PATCH 2/7] implement inserteffectselector, define effect type enums, wire selector to delayengine --- Source/DelayEngine.cpp | 24 +++++++++++++++----- Source/DelayEngine.h | 13 ++++++----- Source/InsertEffectSelector.cpp | 39 +++++++++++++++++++++++++++++++++ Source/InsertEffectSelector.h | 26 ++++++++++++++++++++++ Source/Types.h | 5 +++++ 5 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 Source/InsertEffectSelector.cpp create mode 100644 Source/InsertEffectSelector.h diff --git a/Source/DelayEngine.cpp b/Source/DelayEngine.cpp index d8b4a32..7393f4b 100644 --- a/Source/DelayEngine.cpp +++ b/Source/DelayEngine.cpp @@ -1,6 +1,5 @@ #include "DelayEngine.h" #include "DSP.h" -#include "Types.h" DelayEngine::DelayEngine() { @@ -19,23 +18,26 @@ void DelayEngine::prepareToPlay(double sampleRate, int samplesPerBlock) noexcept spec.numChannels = 2; m_sampleRate = static_cast(sampleRate); m_feedbackCompressor.prepare(spec); + m_insertEffectSelector.prepareToPlay(sampleRate, samplesPerBlock); m_filterEngine.prepareToPlay(sampleRate, samplesPerBlock); m_feedbackHighpass.prepare(spec); - m_chorusEngine.prepareToPlay(sampleRate, samplesPerBlock); + // m_chorusEngine.prepareToPlay(sampleRate, samplesPerBlock); m_stereoDelay.prepareToPlay(sampleRate, samplesPerBlock); m_coeff = onePoleLowpassCoeff(100.0f, static_cast(sampleRate)); - + // m_lofiEngine.prepareToPlay(sampleRate, samplesPerBlock); } void DelayEngine::reset() noexcept { m_stereoDelay.reset(); - m_chorusEngine.reset(); + // m_chorusEngine.reset(); m_filterEngine.reset(); m_feedbackHighpass.reset(); m_feedbackHighpass.setCutoffFrequency(60.0f); // just to remove rumble from fb loop m_feedbackHighpass.setResonance(Parameters::defaultFilterQ); m_feedbackCompressor.reset(); + // m_lofiEngine.reset(); + m_insertEffectSelector.reset(); m_feedbackL = 0.0f; m_feedbackR = 0.0f; m_baseDelayTimeMs = -1.0f; @@ -52,6 +54,15 @@ void DelayEngine::setDelayMode(const int modeIndex) } } +void DelayEngine::setInsertEffect(const int effectIndex) +{ + InsertEffectType newEffect = static_cast(effectIndex); + if (newEffect != m_currentInsertEffect) { + m_currentInsertEffect = newEffect; + m_insertEffectSelector.select(m_currentInsertEffect); + } +} + void DelayEngine::setDelayTimes(const float targetL, const float targetR) { float targetLeftMs = targetL - m_offsetMs; float targetRightMs = targetR + m_offsetMs; @@ -74,6 +85,9 @@ void DelayEngine::update(const Parameters& params) setOffsetMs(params.offset()); setDelayTimes(params.delayTimeL(), params.delayTimeR()); m_filterEngine.update(params); + m_insertEffectSelector.update(params); + // m_chorusEngine.update(params); + // m_lofiEngine.update(params); } void DelayEngine::updateSyncedModulators(const double ppqPosition) @@ -113,7 +127,7 @@ void DelayEngine::processSample(const float& inL, const float& inR, float& outL, m_stereoDelay.processSample(delayInL, wetL, Channel::Left); m_stereoDelay.processSample(delayInR, wetR, Channel::Right); - m_chorusEngine.processSample(wetL, wetR, wetL, wetR, params); + m_insertEffectSelector.processSample(wetL, wetR, wetL, wetR); m_filterEngine.processSample(wetL, wetR, wetL, wetR); diff --git a/Source/DelayEngine.h b/Source/DelayEngine.h index f360c71..b377663 100644 --- a/Source/DelayEngine.h +++ b/Source/DelayEngine.h @@ -1,17 +1,16 @@ #pragma once #include #include "Parameters.h" -#include "ChorusEngine.h" #include "StereoDelay.h" #include "FilterEngine.h" +#include "InsertEffectSelector.h" +#include "Types.h" #if JUCE_DEBUG #include "LFOScopeBuffer.h" #endif using Filter = juce::dsp::StateVariableTPTFilter; -enum class DelayMode { Stereo, Cross, PingPongLR, PingPongRL}; - class DelayEngine { public: @@ -30,6 +29,7 @@ class DelayEngine void setWidthLevel(const float value) { m_widthLevel = value; } void setOffsetMs(const float value) { m_offsetMs = value * .5f; } void setDelayMode(const int modeIndex); + void setInsertEffect(const int effectIndex); void updateSyncedModulators(const double ppqPosition); std::atomic& getLowCutLfoValue() { return m_filterEngine.getLowCutLfoValue(); } @@ -45,8 +45,11 @@ class DelayEngine FilterEngine m_filterEngine; Filter m_feedbackHighpass; juce::dsp::Compressor m_feedbackCompressor; - ChorusEngine m_chorusEngine; - +/* ChorusEngine m_chorusEngine; + LofiEngine m_lofiEngine; */ + InsertEffectSelector m_insertEffectSelector; + InsertEffectType m_currentInsertEffect = InsertEffectType::Chorus; + float m_sampleRate = 0.0f; float m_coeff = 0.0f; diff --git a/Source/InsertEffectSelector.cpp b/Source/InsertEffectSelector.cpp new file mode 100644 index 0000000..888051c --- /dev/null +++ b/Source/InsertEffectSelector.cpp @@ -0,0 +1,39 @@ +#include "InsertEffectSelector.h" + +InsertEffectSelector::InsertEffectSelector() +{ + m_currentType = InsertEffectType::Chorus; + m_active = &m_chorus; +} + +void InsertEffectSelector::prepareToPlay(double sampleRate, int samplesPerBlock) noexcept +{ + m_chorus.prepareToPlay(sampleRate, samplesPerBlock); + m_lofi.prepareToPlay(sampleRate, samplesPerBlock); +} + +void InsertEffectSelector::reset() noexcept +{ + m_chorus.reset(); + m_lofi.reset(); +} + +void InsertEffectSelector::processSample(const float& inL, const float& inR, float& outL, float& outR) +{ + if (m_active) + m_active->processSample(inL, inR, outL, outR); +} + +void InsertEffectSelector::update(const Parameters& params) +{ + if (m_active) + m_active->update(params); +} + +void InsertEffectSelector::select(InsertEffectType type) +{ + InsertEffect* options[] = { &m_chorus, &m_lofi }; + m_active = options[static_cast(type)]; + m_currentType = type; + m_active->reset(); +} \ No newline at end of file diff --git a/Source/InsertEffectSelector.h b/Source/InsertEffectSelector.h new file mode 100644 index 0000000..1c84c4b --- /dev/null +++ b/Source/InsertEffectSelector.h @@ -0,0 +1,26 @@ +#pragma once +#include "InsertEffect.h" +#include "ChorusEngine.h" +#include "LofiEngine.h" +#include "Types.h" + +class InsertEffectSelector +{ +public: + InsertEffectSelector(); + ~InsertEffectSelector() = default; + + void prepareToPlay(double sampleRate, int samplesPerBlock) noexcept; + void reset() noexcept; + void processSample(const float& inL, const float& inR, float& outL, float& outR); + void update(const Parameters& params); + void select(InsertEffectType type); + +private: + ChorusEngine m_chorus; + LofiEngine m_lofi; + InsertEffect* m_active = nullptr; + InsertEffectType m_currentType; + + +}; \ No newline at end of file diff --git a/Source/Types.h b/Source/Types.h index e0374c0..9e7b858 100644 --- a/Source/Types.h +++ b/Source/Types.h @@ -2,4 +2,9 @@ enum Channel { Left = 0, Right = 1 }; +enum class DelayMode { Stereo, Cross, PingPongLR, PingPongRL}; + enum class LFOShape { Sine, Triangle, Square, SawUp, SawDown, SampleAndHold }; + +enum class InsertEffectType { Chorus, Lofi }; + From 8e777f0034f14afabb13373fbaf95d8d45003c59 Mon Sep 17 00:00:00 2001 From: Otto Andelin Date: Thu, 21 May 2026 14:52:07 +0300 Subject: [PATCH 3/7] add effecttype param, add effect type change to processblock --- CMakeLists.txt | 1 + Source/DelayEngine.cpp | 6 ------ Source/DelayEngine.h | 2 -- Source/Parameters.cpp | 42 +++++++++++++++++++++++++++----------- Source/Parameters.h | 8 +++++++- Source/PluginProcessor.cpp | 1 + 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61bb47e..a8e0b43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ set_target_properties(${project_targets} PROPERTIES CXX_EXTENSIONS OFF) target_sources(viive PRIVATE Source/BitCrusher.cpp Source/LofiEngine.cpp + Source/InsertEffectSelector.cpp Source/FilterEngine.cpp Source/Tempo.cpp Source/Selector.cpp diff --git a/Source/DelayEngine.cpp b/Source/DelayEngine.cpp index 7393f4b..5a66f8f 100644 --- a/Source/DelayEngine.cpp +++ b/Source/DelayEngine.cpp @@ -21,22 +21,18 @@ void DelayEngine::prepareToPlay(double sampleRate, int samplesPerBlock) noexcept m_insertEffectSelector.prepareToPlay(sampleRate, samplesPerBlock); m_filterEngine.prepareToPlay(sampleRate, samplesPerBlock); m_feedbackHighpass.prepare(spec); - // m_chorusEngine.prepareToPlay(sampleRate, samplesPerBlock); m_stereoDelay.prepareToPlay(sampleRate, samplesPerBlock); m_coeff = onePoleLowpassCoeff(100.0f, static_cast(sampleRate)); - // m_lofiEngine.prepareToPlay(sampleRate, samplesPerBlock); } void DelayEngine::reset() noexcept { m_stereoDelay.reset(); - // m_chorusEngine.reset(); m_filterEngine.reset(); m_feedbackHighpass.reset(); m_feedbackHighpass.setCutoffFrequency(60.0f); // just to remove rumble from fb loop m_feedbackHighpass.setResonance(Parameters::defaultFilterQ); m_feedbackCompressor.reset(); - // m_lofiEngine.reset(); m_insertEffectSelector.reset(); m_feedbackL = 0.0f; m_feedbackR = 0.0f; @@ -86,8 +82,6 @@ void DelayEngine::update(const Parameters& params) setDelayTimes(params.delayTimeL(), params.delayTimeR()); m_filterEngine.update(params); m_insertEffectSelector.update(params); - // m_chorusEngine.update(params); - // m_lofiEngine.update(params); } void DelayEngine::updateSyncedModulators(const double ppqPosition) diff --git a/Source/DelayEngine.h b/Source/DelayEngine.h index b377663..80a20a9 100644 --- a/Source/DelayEngine.h +++ b/Source/DelayEngine.h @@ -45,8 +45,6 @@ class DelayEngine FilterEngine m_filterEngine; Filter m_feedbackHighpass; juce::dsp::Compressor m_feedbackCompressor; -/* ChorusEngine m_chorusEngine; - LofiEngine m_lofiEngine; */ InsertEffectSelector m_insertEffectSelector; InsertEffectType m_currentInsertEffect = InsertEffectType::Chorus; diff --git a/Source/Parameters.cpp b/Source/Parameters.cpp index 668869d..51399fa 100644 --- a/Source/Parameters.cpp +++ b/Source/Parameters.cpp @@ -78,13 +78,7 @@ static float degreesFromString(const juce::String& text) return text.getFloatValue(); } -const juce::StringArray Parameters::delayModes = { - "Stereo", - "Cross Fb", - "Ping Pong LR", - "Ping Pong RL", -}; - +// keep this syncronized with delayNoteLengthMultipliers in Sync.h const juce::StringArray Parameters::delayNoteLengths = { "1/32", "1/16 trip", @@ -104,6 +98,7 @@ const juce::StringArray Parameters::delayNoteLengths = { "1/1", }; +// keep this syncronized with modNoteLengthMultipliers in Sync.h const juce::StringArray Parameters::modNoteLengths = { "1/8", "1/8 dot", @@ -122,6 +117,15 @@ const juce::StringArray Parameters::modNoteLengths = { "8/1", }; +// keep this syncronized with the DelayMode enum in Types.h +const juce::StringArray Parameters::delayModes = { + "Stereo", + "Cross Fb", + "Ping Pong LR", + "Ping Pong RL", +}; + +// keep this syncronized with the LFOShape enum in Types.h const juce::StringArray Parameters::lfoShapes = { "SIN", "TRI", @@ -131,6 +135,11 @@ const juce::StringArray Parameters::lfoShapes = { "S&H", }; +// keep this syncronized with the InsertEffectType enum in Types.h +const juce::StringArray Parameters::insertEffects = { + "Chorus", + "Lofi", +}; Parameters::Parameters(juce::AudioProcessorValueTreeState& apvts) { @@ -146,7 +155,13 @@ Parameters::Parameters(juce::AudioProcessorValueTreeState& apvts) castParameter(apvts, feedbackParamID, m_feedbackParam); castParameter(apvts, stereoParamID, m_stereoParam); castParameter(apvts, offsetParamID, m_offsetParam); + castParameter(apvts, effectTypeParamID, m_effectTypeParam); castParameter(apvts, chorusIntensityParamID, m_chorusIntensityParam); + castParameter(apvts, chorusModRateParamID, m_chorusModRateParam); + castParameter(apvts, chorusModDepthParamID, m_chorusModDepthParam); + castParameter(apvts, lofiSampleRateParamID, m_lofiSampleRateParam); + castParameter(apvts, lofiBitDepthParamID, m_lofiBitDepthParam); + castParameter(apvts, lofiMixLevelParamID, m_lofiMixLevelParam); castParameter(apvts, lowCutFreqParamID, m_lowCutFreqParam); castParameter(apvts, lowCutQParamID, m_lowCutQParam); castParameter(apvts, lowCutModRateParamID, m_lowCutModRateParam); @@ -164,11 +179,7 @@ Parameters::Parameters(juce::AudioProcessorValueTreeState& apvts) castParameter(apvts, highCutModNoteParamID, m_highCutModNoteParam); castParameter(apvts, highCutModShapeParamID, m_highCutModShapeParam); castParameter(apvts, highCutModInvertParamID, m_highCutModInvertParam); - castParameter(apvts, chorusModRateParamID, m_chorusModRateParam); - castParameter(apvts, chorusModDepthParamID, m_chorusModDepthParam); - castParameter(apvts, lofiSampleRateParamID, m_lofiSampleRateParam); - castParameter(apvts, lofiBitDepthParamID, m_lofiBitDepthParam); - castParameter(apvts, lofiMixLevelParamID, m_lofiMixLevelParam); + } juce::AudioProcessorValueTreeState::ParameterLayout Parameters::createParameterLayout() @@ -261,6 +272,12 @@ juce::AudioProcessorValueTreeState::ParameterLayout Parameters::createParameterL juce::AudioParameterFloatAttributes() .withStringFromValueFunction(stringFromDecibels) )); + layout.add(std::make_unique( + effectTypeParamID, + "Effect Type", + insertEffects, + 0 + )); layout.add(std::make_unique( lowCutFreqParamID.getParamID(), "Low Cut Frequency", @@ -523,6 +540,7 @@ void Parameters::update(const Tempo& tempo) noexcept m_delayNoteL = m_delayNoteLParam->getIndex(); m_delayNoteR = m_delayNoteRParam->getIndex(); m_delayMode = m_delayModeParam->getIndex(); + m_effectType = m_effectTypeParam->getIndex(); m_lowCutModTempoSync = m_lowCutModTempoSyncParam->get(); m_lowCutModNote = m_lowCutModNoteParam->getIndex(); m_highCutModTempoSync = m_highCutModTempoSyncParam->get(); diff --git a/Source/Parameters.h b/Source/Parameters.h index 995465f..1582835 100644 --- a/Source/Parameters.h +++ b/Source/Parameters.h @@ -31,6 +31,7 @@ const juce::ParameterID highCutModTempoSyncParamID{ "highCutModTempoSync", 1 }; const juce::ParameterID highCutModNoteParamID{ "highCutModNote", 1 }; const juce::ParameterID highCutModShapeParamID{ "highCutModShape", 1 }; const juce::ParameterID highCutModInvertParamID{ "highCutModInvert", 1 }; +const juce::ParameterID effectTypeParamID{ "effectType", 1 }; const juce::ParameterID chorusIntensityParamID{ "chorusIntensity", 1 }; const juce::ParameterID chorusModRateParamID{ "chorusModRate", 1 }; const juce::ParameterID chorusModDepthParamID{ "chorusModDepth", 1 }; @@ -62,6 +63,7 @@ class Parameters { static const juce::StringArray delayNoteLengths; static const juce::StringArray modNoteLengths; static const juce::StringArray lfoShapes; + static const juce::StringArray insertEffects; void prepareToPlay(double sampleRate) noexcept; void update(const Tempo& tempo) noexcept; @@ -97,13 +99,15 @@ class Parameters { int highCutModNote() const { return m_highCutModNote; } int highCutModShape() const { return m_highCutModShape; } bool highCutModInvert() const { return m_highCutModInvert; } + int effectType() const { return m_effectType; } float chorusIntensity() const { return m_chorusIntensity; } float chorusModRate() const { return m_chorusModRate; } float chorusModDepth() const { return m_chorusModDepth; } float lofiSampleRate() const { return m_lofiSampleRate; } float lofiBitDepth() const { return m_lofiBitDepth; } float lofiMixLevel() const { return m_lofiMixLevel; } - private: + +private: juce::AudioParameterFloat* m_gainParam; juce::AudioParameterFloat* m_delayTimeLParam; juce::AudioParameterFloat* m_delayTimeRParam; @@ -116,6 +120,7 @@ class Parameters { juce::AudioParameterFloat* m_feedbackParam; juce::AudioParameterFloat* m_stereoParam; juce::AudioParameterFloat* m_offsetParam; + juce::AudioParameterChoice* m_effectTypeParam; juce::AudioParameterFloat* m_lowCutFreqParam; juce::AudioParameterFloat* m_lowCutQParam; juce::AudioParameterFloat* m_lowCutModRateParam; @@ -191,6 +196,7 @@ class Parameters { int m_highCutModNote = 0; int m_highCutModShape = 0; bool m_highCutModInvert = false; + int m_effectType = 0; float m_chorusIntensity = 0.0f; float m_chorusModRate = defaultChorusModRate; float m_chorusModDepth = defaultChorusModDepth; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 3789f73..a043873 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -119,6 +119,7 @@ void ViiveAudioProcessor::processBlock(juce::AudioBuffer& buffer, juce::M if (m_tempo.getIsPlaying()) m_delayEngine.updateSyncedModulators(m_tempo.getPpqPosition()); m_delayEngine.setDelayMode(m_params.delayMode()); + m_delayEngine.setInsertEffect(m_params.effectType()); auto mainInput = getBusBuffer(buffer, true, 0); const float* inputDataL = mainInput.getReadPointer(0); From 5f449bcaf88627c54e850c3195b4d406177e6a83 Mon Sep 17 00:00:00 2001 From: Otto Andelin Date: Thu, 21 May 2026 19:09:19 +0300 Subject: [PATCH 4/7] add effect selector to gui --- Source/PluginEditor.cpp | 34 +++++++++++++++++++++++++++++++--- Source/PluginEditor.h | 8 +++++++- Source/PluginProcessor.cpp | 2 +- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index e03d99d..10127fd 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -55,13 +55,22 @@ ViiveAudioProcessorEditor::ViiveAudioProcessorEditor(ViiveAudioProcessor& p) m_outputGroup.addAndMakeVisible(m_gainKnob); addAndMakeVisible(m_outputGroup); - m_chorusGroup.setText("Chorus"); + m_chorusGroup.setText(""); m_chorusGroup.setTextLabelPosition(juce::Justification::horizontallyCentred); m_chorusGroup.addAndMakeVisible(m_chorusIntensityKnob); m_chorusGroup.addAndMakeVisible(m_chorusModRateKnob); m_chorusGroup.addAndMakeVisible(m_chorusModDepthKnob); addAndMakeVisible(m_chorusGroup); + m_lofiGroup.setText(""); + m_lofiGroup.setTextLabelPosition(juce::Justification::horizontallyCentred); + m_lofiGroup.addAndMakeVisible(m_lofiSampleRateKnob); + m_lofiGroup.addAndMakeVisible(m_lofiBitDepthKnob); + m_lofiGroup.addAndMakeVisible(m_lofiMixLevelKnob); + addChildComponent(m_lofiGroup); +// addAndMakeVisible(m_lofiGroup); + addAndMakeVisible(m_effectTypeSelector); + addAndMakeVisible(m_meter); #if JUCE_DEBUG @@ -80,6 +89,7 @@ ViiveAudioProcessorEditor::ViiveAudioProcessorEditor(ViiveAudioProcessor& p) m_audioProcessor.apvts.addParameterListener(tempoSyncRParamID.getParamID(), this); m_audioProcessor.apvts.addParameterListener(lowCutModTempoSyncParamID.getParamID(), this); m_audioProcessor.apvts.addParameterListener(highCutModTempoSyncParamID.getParamID(), this); + m_audioProcessor.apvts.addParameterListener(effectTypeParamID.getParamID(), this); #if JUCE_DEBUG setSize(770, 670); #else @@ -93,6 +103,7 @@ ViiveAudioProcessorEditor::~ViiveAudioProcessorEditor() m_audioProcessor.apvts.removeParameterListener(tempoSyncRParamID.getParamID(), this); m_audioProcessor.apvts.removeParameterListener(lowCutModTempoSyncParamID.getParamID(), this); m_audioProcessor.apvts.removeParameterListener(highCutModTempoSyncParamID.getParamID(), this); + m_audioProcessor.apvts.removeParameterListener(effectTypeParamID.getParamID(), this); } //============================================================================== @@ -115,6 +126,8 @@ void ViiveAudioProcessorEditor::resized() int height = bounds.getHeight() - 20; #endif m_chorusGroup.setBounds(bounds.getWidth() - 360, y + 35, 300, 165); + m_lofiGroup.setBounds(bounds.getWidth() - 360, y + 35, 300, 165); + m_delayGroup.setBounds(10, y + 35, m_chorusGroup.getX() - 20, 165); m_outputGroup.setBounds(bounds.getWidth() - 360, m_delayGroup.getBottom() + 10, 300, 155); m_filterGroup.setBounds(10, m_delayGroup.getBottom() + 10, m_outputGroup.getX() - 20, 265); @@ -130,6 +143,8 @@ void ViiveAudioProcessorEditor::resized() m_modeSelector.setTopLeftPosition(10, y); + m_effectTypeSelector.setCentrePosition(m_chorusGroup.getX()+m_chorusGroup.getWidth()/2, m_chorusGroup.getY() + 15); + m_offsetKnob.setTopLeftPosition(m_feedbackKnob.getRight() + 20, 20); m_lowCutFreqKnob.setTopLeftPosition(20, 20); m_lowCutQKnob.setTopLeftPosition(m_lowCutFreqKnob.getRight() + 20, 20); @@ -161,10 +176,15 @@ void ViiveAudioProcessorEditor::resized() m_stereoKnob.setTopLeftPosition(20, 20); m_mixKnob.setTopLeftPosition(m_stereoKnob.getRight() + 20, 20); m_gainKnob.setTopLeftPosition(m_mixKnob.getRight() + 20, 20); + m_chorusIntensityKnob.setTopLeftPosition(20, 20); m_chorusModRateKnob.setTopLeftPosition(m_chorusIntensityKnob.getRight() + 20, 20); m_chorusModDepthKnob.setTopLeftPosition(m_chorusModRateKnob.getRight() + 20, 20); + m_lofiMixLevelKnob.setTopLeftPosition(20, 20); + m_lofiSampleRateKnob.setTopLeftPosition(m_lofiMixLevelKnob.getRight() + 20, 20); + m_lofiBitDepthKnob.setTopLeftPosition(m_lofiSampleRateKnob.getRight() + 20, 20); + m_meter.setBounds(m_outputGroup.getRight() + 15, y + 45, 35, height - 45); #if JUCE_DEBUG @@ -182,18 +202,26 @@ void ViiveAudioProcessorEditor::updateSyncedKnobs(bool syncLActive, bool syncRAc m_lowCutModNoteKnob.setVisible(lowCutSyncActive); m_highCutModRateKnob.setVisible(!highCutSyncActive); m_highCutModNoteKnob.setVisible(highCutSyncActive); - DBG("Updated synced knobs: " << (syncLActive ? "Sync L active, " : "Sync L inactive, ") << (syncRActive ? "Sync R active, " : "Sync R inactive, ") << (lowCutSyncActive ? "Low Cut Sync active, " : "Low Cut Sync inactive, ") << (highCutSyncActive ? "High Cut Sync active" : "High Cut Sync inactive")); +} + +void ViiveAudioProcessorEditor::updateEffectControls(int effectType) +{ + bool isChorus = (effectType == 0); + bool isLofi = (effectType == 1); + m_chorusGroup.setVisible(isChorus); + m_lofiGroup.setVisible(isLofi); } void ViiveAudioProcessorEditor::parameterChanged(const juce::String& paramID, float newValue) { - if (paramID == tempoSyncLParamID.getParamID() || paramID == tempoSyncRParamID.getParamID() || paramID == lowCutModTempoSyncParamID.getParamID() || paramID == highCutModTempoSyncParamID.getParamID()){ + if (paramID == tempoSyncLParamID.getParamID() || paramID == tempoSyncRParamID.getParamID() || paramID == lowCutModTempoSyncParamID.getParamID() || paramID == highCutModTempoSyncParamID.getParamID() || paramID == effectTypeParamID.getParamID()){ juce::MessageManager::callAsync([this] { bool syncL = m_audioProcessor.apvts.getParameter(tempoSyncLParamID.getParamID())->getValue() > 0.5f; bool syncR = m_audioProcessor.apvts.getParameter(tempoSyncRParamID.getParamID())->getValue() > 0.5f; bool lowCutSync = m_audioProcessor.apvts.getParameter(lowCutModTempoSyncParamID.getParamID())->getValue() > 0.5f; bool highCutSync = m_audioProcessor.apvts.getParameter(highCutModTempoSyncParamID.getParamID())->getValue() > 0.5f; updateSyncedKnobs(syncL, syncR, lowCutSync, highCutSync); + updateEffectControls(m_audioProcessor.apvts.getParameter(effectTypeParamID.getParamID())->getValue()); }); } } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 8f83751..007853c 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -59,12 +59,17 @@ class ViiveAudioProcessorEditor : public juce::AudioProcessorEditor, RotaryKnob m_chorusModRateKnob{ "Mod Rate", m_audioProcessor.apvts, chorusModRateParamID.getParamID() }; RotaryKnob m_chorusModDepthKnob{ "Mod Depth", m_audioProcessor.apvts, chorusModDepthParamID.getParamID() }; + RotaryKnob m_lofiMixLevelKnob{ "Mix", m_audioProcessor.apvts, lofiMixLevelParamID.getParamID() }; + RotaryKnob m_lofiSampleRateKnob{ "Sample Rate", m_audioProcessor.apvts, lofiSampleRateParamID.getParamID() }; + RotaryKnob m_lofiBitDepthKnob{ "Bit Depth", m_audioProcessor.apvts, lofiBitDepthParamID.getParamID() }; + SyncButton m_tempoSyncLButton{ "Sync", m_audioProcessor.apvts, tempoSyncLParamID.getParamID() }; SyncButton m_tempoSyncRButton{ "Sync", m_audioProcessor.apvts, tempoSyncRParamID.getParamID() }; SyncButton m_lowCutModTempoSyncButton{ "Sync", m_audioProcessor.apvts, lowCutModTempoSyncParamID.getParamID() }; SyncButton m_highCutModTempoSyncButton{ "Sync", m_audioProcessor.apvts, highCutModTempoSyncParamID.getParamID() }; Selector m_modeSelector{ "Delay Mode:", m_audioProcessor.apvts, delayModeParamID.getParamID(), Parameters::delayModes, 215, 0.0f, 85, 25 }; + Selector m_effectTypeSelector{ "", m_audioProcessor.apvts, effectTypeParamID.getParamID(), Parameters::insertEffects, 100, 14.0f, 0, 30 }; Selector m_lowCutModShapeSelector{ "", m_audioProcessor.apvts, lowCutModShapeParamID.getParamID(), Parameters::lfoShapes, 60, 12.0f }; Selector m_highCutModShapeSelector{ "", m_audioProcessor.apvts, highCutModShapeParamID.getParamID(), Parameters::lfoShapes, 60, 12.0f }; @@ -76,7 +81,7 @@ class ViiveAudioProcessorEditor : public juce::AudioProcessorEditor, juce::HashMap m_linkedParams; - juce::GroupComponent m_delayGroup, m_filterGroup, m_outputGroup, m_chorusGroup, m_filterModGroup; + juce::GroupComponent m_delayGroup, m_filterGroup, m_outputGroup, m_chorusGroup, m_lofiGroup, m_filterModGroup; #if JUCE_DEBUG std::unique_ptr m_lfoScope; @@ -84,6 +89,7 @@ class ViiveAudioProcessorEditor : public juce::AudioProcessorEditor, virtual void parameterChanged(const juce::String& paramID, float newValue) override; void updateSyncedKnobs(bool syncLActive, bool syncRActive, bool lowCutSyncActive, bool highCutSyncActive); + void updateEffectControls(int effectType); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ViiveAudioProcessorEditor) }; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index a043873..09a34fd 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -127,7 +127,7 @@ void ViiveAudioProcessor::processBlock(juce::AudioBuffer& buffer, juce::M auto mainOutput = getBusBuffer(buffer, false, 0); float* outputDataL = mainOutput.getWritePointer(0); float* outputDataR = mainOutput.getWritePointer(1); - + float maxL = 0.0f, maxR = 0.0f; for (int sample = 0; sample < buffer.getNumSamples(); ++sample) From 522ef5156d6fb4b03c9c978cf82ad5ed8bdb0e05 Mon Sep 17 00:00:00 2001 From: Otto Andelin Date: Thu, 21 May 2026 22:36:58 +0300 Subject: [PATCH 5/7] select insert effect with switch for safety, remove unused param --- Source/InsertEffectSelector.cpp | 15 +++++++++++---- Source/InsertEffectSelector.h | 3 --- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Source/InsertEffectSelector.cpp b/Source/InsertEffectSelector.cpp index 888051c..aaaf710 100644 --- a/Source/InsertEffectSelector.cpp +++ b/Source/InsertEffectSelector.cpp @@ -2,7 +2,6 @@ InsertEffectSelector::InsertEffectSelector() { - m_currentType = InsertEffectType::Chorus; m_active = &m_chorus; } @@ -32,8 +31,16 @@ void InsertEffectSelector::update(const Parameters& params) void InsertEffectSelector::select(InsertEffectType type) { - InsertEffect* options[] = { &m_chorus, &m_lofi }; - m_active = options[static_cast(type)]; - m_currentType = type; + switch(type) { + case InsertEffectType::Chorus: + m_active = &m_chorus; + break; + case InsertEffectType::Lofi: + m_active = &m_lofi; + break; + default: + jassertfalse; // this shouldn't happen unless the enum and string array get out of sync + return; + } m_active->reset(); } \ No newline at end of file diff --git a/Source/InsertEffectSelector.h b/Source/InsertEffectSelector.h index 1c84c4b..fa4e987 100644 --- a/Source/InsertEffectSelector.h +++ b/Source/InsertEffectSelector.h @@ -20,7 +20,4 @@ class InsertEffectSelector ChorusEngine m_chorus; LofiEngine m_lofi; InsertEffect* m_active = nullptr; - InsertEffectType m_currentType; - - }; \ No newline at end of file From c0f9f93262939027c9c753c81c458a7ce04946d0 Mon Sep 17 00:00:00 2001 From: Otto Andelin Date: Thu, 21 May 2026 22:38:37 +0300 Subject: [PATCH 6/7] fix bug in updateEffectControls, name all insert effect related variabbles as insertEffectEtc --- Source/Parameters.cpp | 6 +++--- Source/Parameters.h | 8 ++++---- Source/PluginEditor.cpp | 20 +++++++++++--------- Source/PluginEditor.h | 4 ++-- Source/PluginProcessor.cpp | 2 +- Source/Types.h | 5 ++++- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Source/Parameters.cpp b/Source/Parameters.cpp index 51399fa..09eff2a 100644 --- a/Source/Parameters.cpp +++ b/Source/Parameters.cpp @@ -155,7 +155,7 @@ Parameters::Parameters(juce::AudioProcessorValueTreeState& apvts) castParameter(apvts, feedbackParamID, m_feedbackParam); castParameter(apvts, stereoParamID, m_stereoParam); castParameter(apvts, offsetParamID, m_offsetParam); - castParameter(apvts, effectTypeParamID, m_effectTypeParam); + castParameter(apvts, insertEffectTypeParamID, m_insertEffectTypeParam); castParameter(apvts, chorusIntensityParamID, m_chorusIntensityParam); castParameter(apvts, chorusModRateParamID, m_chorusModRateParam); castParameter(apvts, chorusModDepthParamID, m_chorusModDepthParam); @@ -273,7 +273,7 @@ juce::AudioProcessorValueTreeState::ParameterLayout Parameters::createParameterL .withStringFromValueFunction(stringFromDecibels) )); layout.add(std::make_unique( - effectTypeParamID, + insertEffectTypeParamID, "Effect Type", insertEffects, 0 @@ -540,7 +540,7 @@ void Parameters::update(const Tempo& tempo) noexcept m_delayNoteL = m_delayNoteLParam->getIndex(); m_delayNoteR = m_delayNoteRParam->getIndex(); m_delayMode = m_delayModeParam->getIndex(); - m_effectType = m_effectTypeParam->getIndex(); + m_insertEffectType = m_insertEffectTypeParam->getIndex(); m_lowCutModTempoSync = m_lowCutModTempoSyncParam->get(); m_lowCutModNote = m_lowCutModNoteParam->getIndex(); m_highCutModTempoSync = m_highCutModTempoSyncParam->get(); diff --git a/Source/Parameters.h b/Source/Parameters.h index 1582835..6db8e33 100644 --- a/Source/Parameters.h +++ b/Source/Parameters.h @@ -31,7 +31,7 @@ const juce::ParameterID highCutModTempoSyncParamID{ "highCutModTempoSync", 1 }; const juce::ParameterID highCutModNoteParamID{ "highCutModNote", 1 }; const juce::ParameterID highCutModShapeParamID{ "highCutModShape", 1 }; const juce::ParameterID highCutModInvertParamID{ "highCutModInvert", 1 }; -const juce::ParameterID effectTypeParamID{ "effectType", 1 }; +const juce::ParameterID insertEffectTypeParamID{ "insertEffectType", 1 }; const juce::ParameterID chorusIntensityParamID{ "chorusIntensity", 1 }; const juce::ParameterID chorusModRateParamID{ "chorusModRate", 1 }; const juce::ParameterID chorusModDepthParamID{ "chorusModDepth", 1 }; @@ -99,7 +99,7 @@ class Parameters { int highCutModNote() const { return m_highCutModNote; } int highCutModShape() const { return m_highCutModShape; } bool highCutModInvert() const { return m_highCutModInvert; } - int effectType() const { return m_effectType; } + int insertEffectType() const { return m_insertEffectType; } float chorusIntensity() const { return m_chorusIntensity; } float chorusModRate() const { return m_chorusModRate; } float chorusModDepth() const { return m_chorusModDepth; } @@ -120,7 +120,7 @@ class Parameters { juce::AudioParameterFloat* m_feedbackParam; juce::AudioParameterFloat* m_stereoParam; juce::AudioParameterFloat* m_offsetParam; - juce::AudioParameterChoice* m_effectTypeParam; + juce::AudioParameterChoice* m_insertEffectTypeParam; juce::AudioParameterFloat* m_lowCutFreqParam; juce::AudioParameterFloat* m_lowCutQParam; juce::AudioParameterFloat* m_lowCutModRateParam; @@ -196,7 +196,7 @@ class Parameters { int m_highCutModNote = 0; int m_highCutModShape = 0; bool m_highCutModInvert = false; - int m_effectType = 0; + int m_insertEffectType = 0; float m_chorusIntensity = 0.0f; float m_chorusModRate = defaultChorusModRate; float m_chorusModDepth = defaultChorusModDepth; diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 10127fd..735f88b 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -69,7 +69,7 @@ ViiveAudioProcessorEditor::ViiveAudioProcessorEditor(ViiveAudioProcessor& p) m_lofiGroup.addAndMakeVisible(m_lofiMixLevelKnob); addChildComponent(m_lofiGroup); // addAndMakeVisible(m_lofiGroup); - addAndMakeVisible(m_effectTypeSelector); + addAndMakeVisible(m_insertEffectTypeSelector); addAndMakeVisible(m_meter); @@ -89,7 +89,7 @@ ViiveAudioProcessorEditor::ViiveAudioProcessorEditor(ViiveAudioProcessor& p) m_audioProcessor.apvts.addParameterListener(tempoSyncRParamID.getParamID(), this); m_audioProcessor.apvts.addParameterListener(lowCutModTempoSyncParamID.getParamID(), this); m_audioProcessor.apvts.addParameterListener(highCutModTempoSyncParamID.getParamID(), this); - m_audioProcessor.apvts.addParameterListener(effectTypeParamID.getParamID(), this); + m_audioProcessor.apvts.addParameterListener(insertEffectTypeParamID.getParamID(), this); #if JUCE_DEBUG setSize(770, 670); #else @@ -103,7 +103,7 @@ ViiveAudioProcessorEditor::~ViiveAudioProcessorEditor() m_audioProcessor.apvts.removeParameterListener(tempoSyncRParamID.getParamID(), this); m_audioProcessor.apvts.removeParameterListener(lowCutModTempoSyncParamID.getParamID(), this); m_audioProcessor.apvts.removeParameterListener(highCutModTempoSyncParamID.getParamID(), this); - m_audioProcessor.apvts.removeParameterListener(effectTypeParamID.getParamID(), this); + m_audioProcessor.apvts.removeParameterListener(insertEffectTypeParamID.getParamID(), this); } //============================================================================== @@ -143,7 +143,7 @@ void ViiveAudioProcessorEditor::resized() m_modeSelector.setTopLeftPosition(10, y); - m_effectTypeSelector.setCentrePosition(m_chorusGroup.getX()+m_chorusGroup.getWidth()/2, m_chorusGroup.getY() + 15); + m_insertEffectTypeSelector.setCentrePosition(m_chorusGroup.getX()+m_chorusGroup.getWidth()/2, m_chorusGroup.getY() + 15); m_offsetKnob.setTopLeftPosition(m_feedbackKnob.getRight() + 20, 20); m_lowCutFreqKnob.setTopLeftPosition(20, 20); @@ -204,24 +204,26 @@ void ViiveAudioProcessorEditor::updateSyncedKnobs(bool syncLActive, bool syncRAc m_highCutModNoteKnob.setVisible(highCutSyncActive); } -void ViiveAudioProcessorEditor::updateEffectControls(int effectType) +void ViiveAudioProcessorEditor::updateInsertEffectControls(int insertEffectType) { - bool isChorus = (effectType == 0); - bool isLofi = (effectType == 1); + DBG("Insert effect type changed: " << insertEffectType); + bool isChorus = (insertEffectType == 0); + bool isLofi = (insertEffectType == 1); m_chorusGroup.setVisible(isChorus); m_lofiGroup.setVisible(isLofi); } void ViiveAudioProcessorEditor::parameterChanged(const juce::String& paramID, float newValue) { - if (paramID == tempoSyncLParamID.getParamID() || paramID == tempoSyncRParamID.getParamID() || paramID == lowCutModTempoSyncParamID.getParamID() || paramID == highCutModTempoSyncParamID.getParamID() || paramID == effectTypeParamID.getParamID()){ + if (paramID == tempoSyncLParamID.getParamID() || paramID == tempoSyncRParamID.getParamID() || paramID == lowCutModTempoSyncParamID.getParamID() || paramID == highCutModTempoSyncParamID.getParamID() || paramID == insertEffectTypeParamID.getParamID()){ juce::MessageManager::callAsync([this] { bool syncL = m_audioProcessor.apvts.getParameter(tempoSyncLParamID.getParamID())->getValue() > 0.5f; bool syncR = m_audioProcessor.apvts.getParameter(tempoSyncRParamID.getParamID())->getValue() > 0.5f; bool lowCutSync = m_audioProcessor.apvts.getParameter(lowCutModTempoSyncParamID.getParamID())->getValue() > 0.5f; bool highCutSync = m_audioProcessor.apvts.getParameter(highCutModTempoSyncParamID.getParamID())->getValue() > 0.5f; updateSyncedKnobs(syncL, syncR, lowCutSync, highCutSync); - updateEffectControls(m_audioProcessor.apvts.getParameter(effectTypeParamID.getParamID())->getValue()); + auto* param = dynamic_cast(m_audioProcessor.apvts.getParameter(insertEffectTypeParamID.getParamID())); + updateInsertEffectControls(param->getIndex()); }); } } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 007853c..7e37cb9 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -69,7 +69,7 @@ class ViiveAudioProcessorEditor : public juce::AudioProcessorEditor, SyncButton m_highCutModTempoSyncButton{ "Sync", m_audioProcessor.apvts, highCutModTempoSyncParamID.getParamID() }; Selector m_modeSelector{ "Delay Mode:", m_audioProcessor.apvts, delayModeParamID.getParamID(), Parameters::delayModes, 215, 0.0f, 85, 25 }; - Selector m_effectTypeSelector{ "", m_audioProcessor.apvts, effectTypeParamID.getParamID(), Parameters::insertEffects, 100, 14.0f, 0, 30 }; + Selector m_insertEffectTypeSelector{ "", m_audioProcessor.apvts, insertEffectTypeParamID.getParamID(), Parameters::insertEffects, 100, 14.0f, 0, 30 }; Selector m_lowCutModShapeSelector{ "", m_audioProcessor.apvts, lowCutModShapeParamID.getParamID(), Parameters::lfoShapes, 60, 12.0f }; Selector m_highCutModShapeSelector{ "", m_audioProcessor.apvts, highCutModShapeParamID.getParamID(), Parameters::lfoShapes, 60, 12.0f }; @@ -89,7 +89,7 @@ class ViiveAudioProcessorEditor : public juce::AudioProcessorEditor, virtual void parameterChanged(const juce::String& paramID, float newValue) override; void updateSyncedKnobs(bool syncLActive, bool syncRActive, bool lowCutSyncActive, bool highCutSyncActive); - void updateEffectControls(int effectType); + void updateInsertEffectControls(int insertEffectType); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ViiveAudioProcessorEditor) }; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 09a34fd..bd880a7 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -119,7 +119,7 @@ void ViiveAudioProcessor::processBlock(juce::AudioBuffer& buffer, juce::M if (m_tempo.getIsPlaying()) m_delayEngine.updateSyncedModulators(m_tempo.getPpqPosition()); m_delayEngine.setDelayMode(m_params.delayMode()); - m_delayEngine.setInsertEffect(m_params.effectType()); + m_delayEngine.setInsertEffect(m_params.insertEffectType()); auto mainInput = getBusBuffer(buffer, true, 0); const float* inputDataL = mainInput.getReadPointer(0); diff --git a/Source/Types.h b/Source/Types.h index 9e7b858..38eeb57 100644 --- a/Source/Types.h +++ b/Source/Types.h @@ -2,9 +2,12 @@ enum Channel { Left = 0, Right = 1 }; +// keep these syncronized with the string arrays in Parameters.cpp +// Parameters::delayModes enum class DelayMode { Stereo, Cross, PingPongLR, PingPongRL}; +// Parameters::lfoShapes enum class LFOShape { Sine, Triangle, Square, SawUp, SawDown, SampleAndHold }; +// Parameters::insertEffects enum class InsertEffectType { Chorus, Lofi }; - From 3f4ae6320f19510fee8074e34f61a94a768b1989 Mon Sep 17 00:00:00 2001 From: Otto Andelin Date: Thu, 21 May 2026 22:51:52 +0300 Subject: [PATCH 7/7] update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ea3cd6..caa5190 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ All notable changes to this project will be documented in this file. * Performs first downsampling and then bit reduction * LofiEngine class which handles Left and Right channel BitCrushers and parameters * Lofi Mix, SampleRate and BitDepth parameters - +* Insert effect selector + * Allows user to switch between chorus and lofi effect in the feedback loop + ## \[0.2.0] - 2026-05-18 ### Added