diff --git a/src/processors/other/Delay.cpp b/src/processors/other/Delay.cpp index 4c62a325..618f8fc2 100644 --- a/src/processors/other/Delay.cpp +++ b/src/processors/other/Delay.cpp @@ -1,24 +1,35 @@ #include "Delay.h" #include "../ParameterHelpers.h" +#include "gui/utils/ModulatableSlider.h" namespace { const String delayTypeTag = "delay_type"; const String pingPongTag = "ping_pong"; +const String freqTag = "freq"; +const String feedBackTag = "feedback"; +const String mixTag = "mix"; + +const String delayTimeMsTag = "time_ms"; +const String tempoSyncTag = "tempo_sync"; +const String tempoSyncAmountTag = "delay_time_type"; } // namespace DelayModule::DelayModule (UndoManager* um) : BaseProcessor ("Delay", createParameterLayout(), um) { using namespace ParameterHelpers; - loadParameterPointer (delayTimeMsParam, vts, "time_ms"); - loadParameterPointer (freqParam, vts, "freq"); - loadParameterPointer (feedbackParam, vts, "feedback"); - loadParameterPointer (mixParam, vts, "mix"); + loadParameterPointer (freqParam, vts, freqTag); + loadParameterPointer (feedbackParam, vts, feedBackTag); + loadParameterPointer (mixParam, vts, mixTag); + loadParameterPointer (delayTimeMsParam, vts, delayTimeMsTag); + delayTimeTempoSyncParam = vts.getRawParameterValue (tempoSyncAmountTag); + tempoSyncOnOffParam = vts.getRawParameterValue (tempoSyncTag); delayTypeParam = vts.getRawParameterValue (delayTypeTag); pingPongParam = vts.getRawParameterValue (pingPongTag); addPopupMenuParameter (delayTypeTag); addPopupMenuParameter (pingPongTag); + addPopupMenuParameter (tempoSyncTag); uiOptions.backgroundColour = Colours::cyan.darker (0.1f); uiOptions.powerColour = Colours::gold; @@ -31,12 +42,17 @@ ParamLayout DelayModule::createParameterLayout() using namespace ParameterHelpers; auto params = createBaseParams(); - createTimeMsParameter (params, "time_ms", "Delay Time", createNormalisableRange (20.0f, 2000.0f, 200.0f), 100.0f); - - createFreqParameter (params, "freq", "Cutoff", 500.0f, 10000.0f, 4000.0f, 10000.0f); - createPercentParameter (params, "feedback", "Feedback", 0.0f); - createPercentParameter (params, "mix", "Mix", 0.5f); - + createTimeMsParameter (params, delayTimeMsTag, "Delay Time", createNormalisableRange (20.0f, 2000.0f, 200.0f), 100.0f); + createFreqParameter (params, freqTag, "Cutoff", 500.0f, 10000.0f, 4000.0f, 10000.0f); + createPercentParameter (params, feedBackTag, "Feedback", 0.0f); + createPercentParameter (params, mixTag, "Mix", 0.5f); + + emplace_param (params, + tempoSyncAmountTag, + "Tempo Sync", + StringArray { "1/2", "1/4", "1/8" }, + 0); + emplace_param (params, tempoSyncTag, "Tempo Sync Delay", false); emplace_param (params, delayTypeTag, "Delay Type", StringArray { "Clean", "Lo-Fi" }, 0); emplace_param (params, pingPongTag, "Ping-Pong", false); @@ -218,10 +234,11 @@ void DelayModule::processPingPongDelay (AudioBuffer& buffer, DelayType& d void DelayModule::processAudio (AudioBuffer& buffer) { feedbackSmoothBuffer.process (std::pow (feedbackParam->getCurrentValue() * 0.67f, 0.9f), buffer.getNumSamples()); - delaySmooth.setTargetValue (fs * *delayTimeMsParam * 0.001f); + delaySmooth.setTargetValue (fs * *delayTimeMsParam * 0.001f); //delay time in samples (if tempo-sync change the calculation here?) freqSmooth.setTargetValue (*freqParam); const auto delayTypeIndex = (int) *delayTypeParam; + const auto tempoSyncAmountIndex = (int) *delayTimeTempoSyncParam; if (delayTypeIndex != prevDelayTypeIndex) { cleanDelayLine.reset(); @@ -261,3 +278,103 @@ void DelayModule::processAudioBypassed (AudioBuffer& buffer) outputBuffers.getReference (0) = &buffer; } + +bool DelayModule::getCustomComponents (OwnedArray& customComps, chowdsp::HostContextProvider& hcp) +{ + using namespace chowdsp::ParamUtils; + class DelayTimeModeControl : public Slider + { + public: + DelayTimeModeControl (AudioProcessorValueTreeState& vtState, chowdsp::HostContextProvider& hcp) + : vts (vtState), + tempoSyncSelectorAttach (vts, tempoSyncAmountTag, tempoSyncSelector), + delayTimeSlider (*getParameterPointer (vts, delayTimeMsTag), hcp), + delayTimeAttach(vts, delayTimeMsTag, delayTimeSlider), + tempoSyncOnOffAttach ( + *vts.getParameter (tempoSyncTag), + [this] (float newValue) + { updateControlVisibility (newValue == 1.0f); }, + vts.undoManager) + { + addChildComponent (tempoSyncSelector); + addChildComponent (delayTimeSlider); + + const auto* modeChoiceParam = getParameterPointer (vts, tempoSyncAmountTag); + tempoSyncSelector.addItemList (modeChoiceParam->choices, 1); + tempoSyncSelector.setSelectedItemIndex (0); + tempoSyncSelector.setScrollWheelEnabled (true); + hcp.registerParameterComponent (tempoSyncSelector, *modeChoiceParam); + + hcp.registerParameterComponent (delayTimeSlider, delayTimeSlider.getParameter()); + + this->setName (tempoSyncAmountTag + "__" + delayTimeMsTag + "__"); + } + + void colourChanged() override + { + for (auto colourID : { Slider::textBoxOutlineColourId, + Slider::textBoxTextColourId, + Slider::textBoxBackgroundColourId, + Slider::textBoxHighlightColourId, + Slider::thumbColourId }) + { + delayTimeSlider.setColour (colourID, findColour (colourID, false)); + } + + for (auto colourID : { ComboBox::outlineColourId, + ComboBox::textColourId, + ComboBox::arrowColourId }) + { + tempoSyncSelector.setColour (colourID, findColour (Slider::textBoxTextColourId, false)); + } + } + + void updateControlVisibility (bool tempoSyncOn) + { + tempoSyncSelector.setVisible (tempoSyncOn); + delayTimeSlider.setVisible (!tempoSyncOn); + + setName (vts.getParameter (tempoSyncOn ? tempoSyncAmountTag : delayTimeMsTag)->name); + if (auto* parent = getParentComponent()) + parent->repaint(); + } + + void visibilityChanged() override + { + updateControlVisibility (vts.getRawParameterValue (tempoSyncTag)->load() == 1.0f); + } + + void resized() override + { + delayTimeSlider.setSliderStyle (getSliderStyle()); + delayTimeSlider.setTextBoxStyle (getTextBoxPosition(), false, getTextBoxWidth(), getTextBoxHeight()); + + const auto bounds = getLocalBounds(); + tempoSyncSelector.setBounds (bounds.proportionOfWidth(0.15f), + bounds.proportionOfHeight(0.1f), + bounds.proportionOfWidth(0.7f), + bounds.proportionOfHeight(0.25f)); + delayTimeSlider.setBounds (bounds); + } + + private: + using SliderAttachment = AudioProcessorValueTreeState::SliderAttachment; + using BoxAttachment = AudioProcessorValueTreeState::ComboBoxAttachment; + + AudioProcessorValueTreeState& vts; + + ComboBox tempoSyncSelector; + BoxAttachment tempoSyncSelectorAttach; + + ModulatableSlider delayTimeSlider; + SliderAttachment delayTimeAttach; + + ParameterAttachment tempoSyncOnOffAttach; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DelayTimeModeControl) + }; + + customComps.add (std::make_unique (vts, hcp)); + + return false; +} \ No newline at end of file diff --git a/src/processors/other/Delay.h b/src/processors/other/Delay.h index 0804f788..6c43125d 100644 --- a/src/processors/other/Delay.h +++ b/src/processors/other/Delay.h @@ -9,6 +9,7 @@ class DelayModule : public BaseProcessor ProcessorType getProcessorType() const override { return Other; } static ParamLayout createParameterLayout(); + bool getCustomComponents (OwnedArray& customComps, chowdsp::HostContextProvider& hcp) override; void prepare (double sampleRate, int samplesPerBlock) override; void releaseMemory() override; @@ -21,13 +22,16 @@ class DelayModule : public BaseProcessor template void processPingPongDelay (AudioBuffer& buffer, DelayType& delayLine); - chowdsp::FloatParameter* delayTimeMsParam = nullptr; chowdsp::FloatParameter* freqParam = nullptr; chowdsp::FloatParameter* feedbackParam = nullptr; chowdsp::FloatParameter* mixParam = nullptr; std::atomic* delayTypeParam = nullptr; std::atomic* pingPongParam = nullptr; + chowdsp::FloatParameter* delayTimeMsParam = nullptr; + std::atomic* delayTimeTempoSyncParam = nullptr; + std::atomic* tempoSyncOnOffParam = nullptr; + dsp::DryWetMixer dryWetMixer; dsp::DryWetMixer dryWetMixerMono;