Skip to content

Commit

Permalink
Expanded UI
Browse files Browse the repository at this point in the history
  • Loading branch information
reillypascal committed May 30, 2023
1 parent 815c948 commit 954ea20
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 45 deletions.
3 changes: 2 additions & 1 deletion RSAlgorithmicVerb.jucer
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
jucerFormatVersion="1" companyWebsite="reillyspitzfaden.netlify.app"
companyEmail="[email protected]" pluginManufacturer="Reilly Spitzfaden"
pluginManufacturerCode="Rspi" pluginCode="Rsav" aaxIdentifier="com.reillyspitzfaden.RSAlgorithmicVerb"
bundleIdentifier="com.reillyspitzfaden.RSAlgorithmicVerb" version="0.1.1"
bundleIdentifier="com.reillyspitzfaden.RSAlgorithmicVerb" version="0.2.0"
pluginFormats="buildAU,buildVST3" pluginAUMainType="'aufx'" pluginVST3Category="Fx"
pluginAAXCategory="8" pluginVSTCategory="kPlugCategEffect">
<MAINGROUP id="h5VveC" name="RSAlgorithmicVerb">
Expand All @@ -21,6 +21,7 @@
<FILE id="jwqlsc" name="EarlyReflections.h" compile="0" resource="0"
file="Source/EarlyReflections.h"/>
<FILE id="GtffiZ" name="Freeverb.h" compile="0" resource="0" file="Source/Freeverb.h"/>
<FILE id="E3u2WC" name="IOBlocks.h" compile="0" resource="0" file="Source/IOBlocks.h"/>
<FILE id="mCFD5y" name="DelayLineWithSampleAccess.h" compile="0" resource="0"
file="Source/DelayLineWithSampleAccess.h"/>
<FILE id="mYaXC8" name="ProcessorBase.h" compile="0" resource="0" file="Source/ProcessorBase.h"/>
Expand Down
43 changes: 24 additions & 19 deletions Source/DattorroVerb.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class DattorroPlate : public ProcessorBase

// initialize input chain parameters
preDelay.setDelay(mPreDelayTime);
inputFilter.setCutoffFrequency(mDampingCutoff);
inputFilter.setCutoffFrequency(13500);
allpass1.setDelay(210 * mSize);
allpass2.setDelay(158 * mSize);
allpass3.setDelay(561 * mSize);
Expand All @@ -77,7 +77,7 @@ class DattorroPlate : public ProcessorBase

// break out parameters so mod can add/subtract 12 samples
modulatedAPF1.setDelay(1343 * mSize);
modulatedAPF2.setDelay(995* mSize);
modulatedAPF2.setDelay(995 * mSize);

delay1.setDelay(6241 * mSize);
delay2.setDelay(6590 * mSize);
Expand Down Expand Up @@ -108,7 +108,10 @@ class DattorroPlate : public ProcessorBase
// reverb sample loop params
int channel = 0;
// need separate ones for different delays
float allpassFeedbackCoefficient = 0.5;
float decayDiffusion1 = 0.93;
float decayDiffusion2 = 0.67;
float inputDiffusion1 = 1;
float inputDiffusion2 = 0.83;
auto* channelDataA = monoBufferA.getWritePointer (channel);
auto* channelDataB = monoBufferB.getWritePointer (channel);
for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
Expand All @@ -120,26 +123,26 @@ class DattorroPlate : public ProcessorBase

// apply allpasses
allpassOutput = allpass1.popSample(channel);
feedback = allpassOutput * allpassFeedbackCoefficient;
feedforward = -channelDataA[sample] - allpassOutput * allpassFeedbackCoefficient;
feedback = allpassOutput * inputDiffusion1 * mDiffusion;
feedforward = -channelDataA[sample] - allpassOutput * inputDiffusion1 * mDiffusion;
allpass1.pushSample(channel, channelDataA[sample] + feedback);
channelDataA[sample] = allpassOutput + feedforward;

allpassOutput = allpass2.popSample(channel);
feedback = allpassOutput * allpassFeedbackCoefficient;
feedforward = -channelDataA[sample] - allpassOutput * allpassFeedbackCoefficient;
feedback = allpassOutput * inputDiffusion1 * mDiffusion;
feedforward = -channelDataA[sample] - allpassOutput * inputDiffusion1 * mDiffusion;
allpass2.pushSample(channel, channelDataA[sample] + feedback);
channelDataA[sample] = allpassOutput + feedforward;

allpassOutput = allpass3.popSample(channel);
feedback = allpassOutput * allpassFeedbackCoefficient;
feedforward = -channelDataA[sample] - allpassOutput * allpassFeedbackCoefficient;
feedback = allpassOutput * inputDiffusion2 * mDiffusion;
feedforward = -channelDataA[sample] - allpassOutput * inputDiffusion2 * mDiffusion;
allpass3.pushSample(channel, channelDataA[sample] + feedback);
channelDataA[sample] = allpassOutput + feedforward;

allpassOutput = allpass4.popSample(channel);
feedback = allpassOutput * allpassFeedbackCoefficient;
feedforward = -channelDataA[sample] - allpassOutput * allpassFeedbackCoefficient;
feedback = allpassOutput * inputDiffusion2 * mDiffusion;
feedforward = -channelDataA[sample] - allpassOutput * inputDiffusion2 * mDiffusion;
allpass4.pushSample(channel, channelDataA[sample] + feedback);
channelDataA[sample] = allpassOutput + feedforward;

Expand All @@ -148,8 +151,8 @@ class DattorroPlate : public ProcessorBase

// modulated APF1
allpassOutput = modulatedAPF1.popSample(channel);
feedback = allpassOutput * allpassFeedbackCoefficient;
feedforward = -channelDataA[sample] - allpassOutput * allpassFeedbackCoefficient;
feedback = allpassOutput * decayDiffusion1 * mDiffusion;
feedforward = -channelDataA[sample] - allpassOutput * decayDiffusion1 * mDiffusion;
modulatedAPF1.pushSample(channel, channelDataA[sample] + feedback);
channelDataA[sample] = allpassOutput + feedforward;

Expand All @@ -166,8 +169,8 @@ class DattorroPlate : public ProcessorBase

// allpass 5
allpassOutput = allpass5.popSample(channel);
feedback = allpassOutput * allpassFeedbackCoefficient;
feedforward = -channelDataA[sample] - allpassOutput * allpassFeedbackCoefficient;
feedback = allpassOutput * decayDiffusion1 * mDiffusion;
feedforward = -channelDataA[sample] - allpassOutput * decayDiffusion1 * mDiffusion;
allpass5.pushSample(channel, channelDataA[sample] + feedback);
channelDataA[sample] = allpassOutput + feedforward;

Expand All @@ -194,8 +197,8 @@ class DattorroPlate : public ProcessorBase

// modulated APF2
allpassOutput = modulatedAPF2.popSample(channel);
feedback = allpassOutput * allpassFeedbackCoefficient;
feedforward = -channelDataB[sample] - allpassOutput * allpassFeedbackCoefficient;
feedback = allpassOutput * decayDiffusion2 * mDiffusion;
feedforward = -channelDataB[sample] - allpassOutput * decayDiffusion2 * mDiffusion;
modulatedAPF2.pushSample(channel, channelDataB[sample] + feedback);
channelDataB[sample] = allpassOutput + feedforward;

Expand All @@ -212,8 +215,8 @@ class DattorroPlate : public ProcessorBase

// allpass 6
allpassOutput = allpass6.popSample(channel);
feedback = allpassOutput * allpassFeedbackCoefficient;
feedforward = -channelDataB[sample] - allpassOutput * allpassFeedbackCoefficient;
feedback = allpassOutput * decayDiffusion2 * mDiffusion;
feedforward = -channelDataB[sample] - allpassOutput * decayDiffusion2 * mDiffusion;
allpass6.pushSample(channel, channelDataB[sample] + feedback);
channelDataB[sample] = allpassOutput + feedforward;

Expand Down Expand Up @@ -284,6 +287,7 @@ class DattorroPlate : public ProcessorBase
void setSize(float newSize) override { mSize = newSize; }
void setDecay(float newDecay) override { mDecay = pow(newDecay, 2); }
void setDampingCutoff(float newCutoff) override { mDampingCutoff = newCutoff; }
void setDiffusion(float newDiffusion) override { mDiffusion = newDiffusion; }
void setPreDelay(float newPreDelay) override { mPreDelayTime = newPreDelay; }
void setEarlyLateMix(float newMix) override { mEarlyLateMix = newMix; }
void setDryWetMix(float newMix) override { mDryWetMix = newMix; }
Expand Down Expand Up @@ -324,6 +328,7 @@ class DattorroPlate : public ProcessorBase
float mSize = 1;
float mDecay = 0.25;
float mDampingCutoff = 6500;
float mDiffusion = 0.75;
float mEarlyLateMix = 1;
float mDryWetMix = 0.25;
};
65 changes: 65 additions & 0 deletions Source/IOBlocks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
==============================================================================
IOBlocks.h
Created: 30 May 2023 1:46:25pm
Author: Reilly Spitzfaden
==============================================================================
*/

#pragma once

#include <JuceHeader.h>

#include "ProcessorBase.h"

class OutputBlock : public ProcessorBase
{
public:
OutputBlock() {}

void prepareToPlay(double sampleRate, int samplesPerBlock) override
{
juce::dsp::ProcessSpec spec;
spec.sampleRate = sampleRate;
spec.maximumBlockSize = samplesPerBlock;
spec.numChannels = getMainBusNumInputChannels();

lowCutFilter.prepare(spec);
lowCutFilter.reset();
lowCutFilter.setType(juce::dsp::FirstOrderTPTFilterType::highpass);
highCutFilter.prepare(spec);
highCutFilter.reset();
highCutFilter.setType(juce::dsp::FirstOrderTPTFilterType::lowpass);
}

void processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer&) override
{
juce::ScopedNoDenormals noDenormals;
auto totalNumInputChannels = getTotalNumInputChannels();
auto totalNumOutputChannels = getTotalNumOutputChannels();

for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear (i, 0, buffer.getNumSamples());

// filtering
lowCutFilter.setCutoffFrequency(mLowCut);
highCutFilter.setCutoffFrequency(mHighCut);

juce::dsp::AudioBlock<float> block { buffer };

lowCutFilter.process(juce::dsp::ProcessContextReplacing<float>(block));
highCutFilter.process(juce::dsp::ProcessContextReplacing<float>(block));
}

void setLowCut(float newCutoff) { mLowCut = newCutoff; }
void setHighCut(float newCutoff) { mHighCut = newCutoff; }

private:
juce::dsp::FirstOrderTPTFilter<float> lowCutFilter;
juce::dsp::FirstOrderTPTFilter<float> highCutFilter;

float mLowCut = 0;
float mHighCut = 20000;
};
78 changes: 58 additions & 20 deletions Source/PluginEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
RSAlgorithmicVerbAudioProcessorEditor::RSAlgorithmicVerbAudioProcessorEditor (RSAlgorithmicVerbAudioProcessor& p, juce::AudioProcessorValueTreeState& vts)
: AudioProcessorEditor (&p), audioProcessor (p), valueTreeState(vts)
{
// labels
// labels row 1
reverbMenuLabel.setText("Reverb Type", juce::dontSendNotification);
reverbMenuLabel.setJustificationType(juce::Justification::centred);
addAndMakeVisible(reverbMenuLabel);
Expand All @@ -30,6 +30,19 @@ RSAlgorithmicVerbAudioProcessorEditor::RSAlgorithmicVerbAudioProcessorEditor (RS
dampingLabel.setJustificationType(juce::Justification::centred);
addAndMakeVisible(dampingLabel);

diffusionLabel.setText("Diffusion", juce::dontSendNotification);
diffusionLabel.setJustificationType(juce::Justification::centred);
addAndMakeVisible(diffusionLabel);

// labels row 2
lowCutLabel.setText("Low Cut", juce::dontSendNotification);
lowCutLabel.setJustificationType(juce::Justification::centred);
addAndMakeVisible(lowCutLabel);

highCutLabel.setText("High Cut", juce::dontSendNotification);
highCutLabel.setJustificationType(juce::Justification::centred);
addAndMakeVisible(highCutLabel);

preDelayLabel.setText("Pre-Delay", juce::dontSendNotification);
preDelayLabel.setJustificationType(juce::Justification::centred);
addAndMakeVisible(preDelayLabel);
Expand All @@ -54,7 +67,7 @@ RSAlgorithmicVerbAudioProcessorEditor::RSAlgorithmicVerbAudioProcessorEditor (RS
reverbMenuBox.setSelectedId(dattorro);
reverbMenuAttachment.reset(new ComboBoxAttachment(valueTreeState, "reverbType", reverbMenuBox));

// sliders
// sliders row 1
roomSizeSlider.setSliderStyle(juce::Slider::SliderStyle::RotaryHorizontalVerticalDrag);
roomSizeSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, false, textBoxWidth, textBoxHeight);
addAndMakeVisible(roomSizeSlider);
Expand All @@ -70,6 +83,22 @@ RSAlgorithmicVerbAudioProcessorEditor::RSAlgorithmicVerbAudioProcessorEditor (RS
addAndMakeVisible(dampingSlider);
dampingAttachment.reset(new SliderAttachment(valueTreeState, "damping", dampingSlider));

diffusionSlider.setSliderStyle(juce::Slider::SliderStyle::RotaryHorizontalVerticalDrag);
diffusionSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, false, textBoxWidth, textBoxHeight);
addAndMakeVisible(diffusionSlider);
diffusionAttachment.reset(new SliderAttachment(valueTreeState, "diffusion", diffusionSlider));

// sliders row 2
lowCutSlider.setSliderStyle(juce::Slider::SliderStyle::RotaryHorizontalVerticalDrag);
lowCutSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, false, textBoxWidth, textBoxHeight);
addAndMakeVisible(lowCutSlider);
lowCutAttachment.reset(new SliderAttachment(valueTreeState, "lowCut", lowCutSlider));

highCutSlider.setSliderStyle(juce::Slider::SliderStyle::RotaryHorizontalVerticalDrag);
highCutSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, false, textBoxWidth, textBoxHeight);
addAndMakeVisible(highCutSlider);
highCutAttachment.reset(new SliderAttachment(valueTreeState, "highCut", highCutSlider));

preDelaySlider.setSliderStyle(juce::Slider::SliderStyle::RotaryHorizontalVerticalDrag);
preDelaySlider.setTextBoxStyle(juce::Slider::TextBoxBelow, false, textBoxWidth, textBoxHeight);
addAndMakeVisible(preDelaySlider);
Expand All @@ -89,7 +118,7 @@ RSAlgorithmicVerbAudioProcessorEditor::RSAlgorithmicVerbAudioProcessorEditor (RS
getLookAndFeel().setDefaultLookAndFeel(&grayBlueLookAndFeel);

// panel size
setSize (700, 575);
setSize (800, 525);
}

RSAlgorithmicVerbAudioProcessorEditor::~RSAlgorithmicVerbAudioProcessorEditor()
Expand All @@ -109,14 +138,16 @@ void RSAlgorithmicVerbAudioProcessorEditor::paint (juce::Graphics& g)
void RSAlgorithmicVerbAudioProcessorEditor::resized()
{
const int xBorder = 30;
const int yBorderTop = 125;
const int yBorderBottom = 70;
const int rowSpacer = 35;
const int yBorderTop = 135;
const int yBorderBottom = 50;
const int rowSpacer = 45;

const int menuWidth = 135;
const int menuHeight = 20;
const int sliderWidth = (getWidth() - (2 * xBorder)) / 3;
const int sliderHeight = (getHeight() - (yBorderTop + yBorderBottom) - rowSpacer) / 2;
const int sliderWidth1 = (getWidth() - (2 * xBorder)) / 4;
const int sliderWidth2 = (getWidth() - (2 * xBorder)) / 5;
const int sliderHeight1 = (getHeight() - (yBorderTop + yBorderBottom) - rowSpacer) / 2;
const int sliderHeight2 = sliderHeight1 * 0.8;
const int textLabelWidth = 150;
const int textLabelHeight = 20;
const int textLabelSpacer = 7;
Expand All @@ -126,22 +157,29 @@ void RSAlgorithmicVerbAudioProcessorEditor::resized()
reverbMenuLabel.setJustificationType(juce::Justification::centred);

// row 1 sliders
roomSizeSlider.setBounds(xBorder, yBorderTop, sliderWidth, sliderHeight);
feedbackSlider.setBounds(xBorder + sliderWidth, yBorderTop, sliderWidth, sliderHeight);
dampingSlider.setBounds(xBorder + (2 * sliderWidth), yBorderTop, sliderWidth, sliderHeight);
roomSizeSlider.setBounds(xBorder, yBorderTop, sliderWidth1, sliderHeight1);
feedbackSlider.setBounds(xBorder + sliderWidth1, yBorderTop, sliderWidth1, sliderHeight1);
dampingSlider.setBounds(xBorder + (2 * sliderWidth1), yBorderTop, sliderWidth1, sliderHeight1);
diffusionSlider.setBounds(xBorder + (3 * sliderWidth1), yBorderTop, sliderWidth1, sliderHeight1);

// row 1 labels
roomSizeLabel.setBounds(xBorder + ((sliderWidth / 2) - (textLabelWidth / 2)), yBorderTop + sliderHeight + textLabelSpacer, textLabelWidth, textLabelHeight);
decayLabel.setBounds(xBorder + sliderWidth + ((sliderWidth / 2) - (textLabelWidth / 2)), yBorderTop + sliderHeight + textLabelSpacer, textLabelWidth, textLabelHeight);
dampingLabel.setBounds(xBorder + (sliderWidth * 2) + ((sliderWidth / 2) - (textLabelWidth / 2)), yBorderTop + sliderHeight + textLabelSpacer, textLabelWidth, textLabelHeight);
roomSizeLabel.setBounds(xBorder + ((sliderWidth1 / 2) - (textLabelWidth / 2)), yBorderTop + sliderHeight1 + textLabelSpacer, textLabelWidth, textLabelHeight);
decayLabel.setBounds(xBorder + sliderWidth1 + ((sliderWidth1 / 2) - (textLabelWidth / 2)), yBorderTop + sliderHeight1 + textLabelSpacer, textLabelWidth, textLabelHeight);
dampingLabel.setBounds(xBorder + (sliderWidth1 * 2) + ((sliderWidth1 / 2) - (textLabelWidth / 2)), yBorderTop + sliderHeight1 + textLabelSpacer, textLabelWidth, textLabelHeight);
diffusionLabel.setBounds(xBorder + (sliderWidth1 * 3) + ((sliderWidth1 / 2) - (textLabelWidth / 2)), yBorderTop + sliderHeight1 + textLabelSpacer, textLabelWidth, textLabelHeight);


// row 2 sliders
preDelaySlider.setBounds(xBorder, yBorderTop + sliderHeight + rowSpacer, sliderWidth, sliderHeight);
earlyLateMixSlider.setBounds(xBorder + sliderWidth, yBorderTop + sliderHeight + rowSpacer, sliderWidth, sliderHeight);
dryWetMixSlider.setBounds(xBorder + (2 * sliderWidth), yBorderTop + sliderHeight + rowSpacer, sliderWidth, sliderHeight);
preDelaySlider.setBounds(xBorder, yBorderTop + sliderHeight1 + rowSpacer, sliderWidth2, sliderHeight2);
lowCutSlider.setBounds(xBorder + (sliderWidth2 * 1), yBorderTop + sliderHeight1 + rowSpacer, sliderWidth2, sliderHeight2);
highCutSlider.setBounds(xBorder + (sliderWidth2 * 2), yBorderTop + sliderHeight1 + rowSpacer, sliderWidth2, sliderHeight2);
earlyLateMixSlider.setBounds(xBorder + (sliderWidth2 * 3), yBorderTop + sliderHeight1 + rowSpacer, sliderWidth2, sliderHeight2);
dryWetMixSlider.setBounds(xBorder + (sliderWidth2 * 4), yBorderTop + sliderHeight1 + rowSpacer, sliderWidth2, sliderHeight2);

// row 2 labels
preDelayLabel.setBounds(xBorder + (sliderWidth / 2) - (textLabelWidth / 2), yBorderTop + (sliderHeight * 2) + rowSpacer + textLabelSpacer, textLabelWidth, textLabelHeight);
earlyLateMixLabel.setBounds(xBorder + sliderWidth + (sliderWidth / 2) - (textLabelWidth / 2), yBorderTop + (sliderHeight * 2) + rowSpacer + textLabelSpacer, textLabelWidth, textLabelHeight);
dryWetMixLabel.setBounds(xBorder + (sliderWidth * 2) + (sliderWidth / 2) - (textLabelWidth / 2), yBorderTop + (sliderHeight * 2) + rowSpacer + textLabelSpacer, textLabelWidth, textLabelHeight);
preDelayLabel.setBounds(xBorder + (sliderWidth2 / 2) - (textLabelWidth / 2), yBorderTop + sliderHeight1 + sliderHeight2 + rowSpacer + textLabelSpacer, textLabelWidth, textLabelHeight);
lowCutLabel.setBounds(xBorder + (sliderWidth2 * 1) + (sliderWidth2 / 2) - (textLabelWidth / 2), yBorderTop + sliderHeight1 + sliderHeight2 + rowSpacer + textLabelSpacer, textLabelWidth, textLabelHeight);
highCutLabel.setBounds(xBorder + (sliderWidth2 * 2) + (sliderWidth2 / 2) - (textLabelWidth / 2), yBorderTop + sliderHeight1 + sliderHeight2 + rowSpacer + textLabelSpacer, textLabelWidth, textLabelHeight);
earlyLateMixLabel.setBounds(xBorder + (sliderWidth2 * 3) + (sliderWidth2 / 2) - (textLabelWidth / 2), yBorderTop + sliderHeight1 + sliderHeight2 + rowSpacer + textLabelSpacer, textLabelWidth, textLabelHeight);
dryWetMixLabel.setBounds(xBorder + (sliderWidth2 * 4) + (sliderWidth2 / 2) - (textLabelWidth / 2), yBorderTop + sliderHeight1 + sliderHeight2 + rowSpacer + textLabelSpacer, textLabelWidth, textLabelHeight);
}
16 changes: 15 additions & 1 deletion Source/PluginEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,15 @@ class RSAlgorithmicVerbAudioProcessorEditor : public juce::AudioProcessorEditor
juce::AudioProcessorValueTreeState& valueTreeState;

juce::Label reverbMenuLabel;
// row 1
juce::Label roomSizeLabel;
juce::Label decayLabel;
juce::Label dampingLabel;
juce::Label diffusionLabel;
// row 2
juce::Label preDelayLabel;
juce::Label lowCutLabel;
juce::Label highCutLabel;
juce::Label earlyLateMixLabel;
juce::Label dryWetMixLabel;

Expand All @@ -72,19 +77,28 @@ class RSAlgorithmicVerbAudioProcessorEditor : public juce::AudioProcessorEditor
dattorro = 1,
freeverb,
};

// row 1
juce::Slider roomSizeSlider;
juce::Slider feedbackSlider;
juce::Slider dampingSlider;
juce::Slider diffusionSlider;
// row 2
juce::Slider preDelaySlider;
juce::Slider lowCutSlider;
juce::Slider highCutSlider;
juce::Slider earlyLateMixSlider;
juce::Slider dryWetMixSlider;

std::unique_ptr<ComboBoxAttachment> reverbMenuAttachment;
// row 1
std::unique_ptr<SliderAttachment> roomSizeAttachment;
std::unique_ptr<SliderAttachment> feedbackAttachment;
std::unique_ptr<SliderAttachment> dampingAttachment;
std::unique_ptr<SliderAttachment> diffusionAttachment;
// row 2
std::unique_ptr<SliderAttachment> preDelayAttachment;
std::unique_ptr<SliderAttachment> lowCutAttachment;
std::unique_ptr<SliderAttachment> highCutAttachment;
std::unique_ptr<SliderAttachment> earlyLateMixAttachment;
std::unique_ptr<SliderAttachment> dryWetMixAttachment;

Expand Down
Loading

0 comments on commit 954ea20

Please sign in to comment.