commit eac11a0eec119069bb2cfc0c197e5a0089e85466
parent aec6b58133165862305a1d588da4e79bc5e962f1
Author: jatinchowdhury18 <jatinchowdhury18@gmail.com>
Date: Mon, 25 Apr 2022 21:49:06 +0100
Add stereo balance control (#258)
* Set up stereo balance processing and UI
* Testing stereo balance controls
Diffstat:
7 files changed, 103 insertions(+), 26 deletions(-)
diff --git a/Plugin/Source/GUI/Assets/gui.xml b/Plugin/Source/GUI/Assets/gui.xml
@@ -31,7 +31,7 @@
</Style>
</Styles>
<View id="root" resizable="1" resize-corner="1" flex-direction="column"
- padding="0" width="640" height="620" background-color="FF8B3232"
+ padding="0" width="720" height="620" background-color="FF8B3232"
background-image="Background_svg" image-placement="stretch">
<View max-height="100" padding="0" margin="0" background-color="">
<View margin="2" padding="" background-color="00000000" flex-direction="column"
@@ -47,15 +47,10 @@
plot-decay="0.0" plot-fill-color="FFFFFFFF"/>
</View>
<View padding="0" margin="" background-color="" lookAndFeel="">
- <View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF">
+ <View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF"
+ flex-grow="1.5">
<View flex-direction="column" tab-color="" background-color="FF31323A"
padding="0" tab-caption="Gain">
- <TextButton id="mid_side" tooltip="Toggles between left/right and mid/side processing modes (Stereo only)"
- margin="5" padding="0" parameter="mid_side" text="Stereo" text_on="Mid/Side"
- width="100" height="35" min-height="30" min-width="100" flex-align-self="center"
- max-height="40" name="Mid/Side" lookAndFeel="LookAndFeel_V3"
- button-color="FF33343D" button-on-color="FFB41717" button-off-text="FFFFFFFF"
- button-on-text="FFFFFFFF" enabled="plugin:is_stereo"/>
<Slider caption="Input Gain [dB]" parameter="ingain" class="Slider" name="Input Gain"
padding="0" margin="0" tooltip="Sets the input gain to the tape model in Decibels."/>
<Slider caption="Dry/Wet" parameter="drywet" class="Slider" tooltip="Sets dry/wet mix of the entire plugin."
@@ -78,6 +73,24 @@
padding="0" button-color="ff595c6b" button-on-color="FFEAA92C"
parameter="ifilt_onoff" name="Filters On/Off" tooltip="Turns the pre-processing filters on or off."/>
</View>
+ <View flex-direction="column" tab-color="" background-color="FF31323A"
+ padding="0" tab-caption="Stereo" enabled="plugin:is_stereo">
+ <TextButton tooltip="Toggles between left/right and mid/side processing modes (Stereo only)"
+ margin="0" padding="5" parameter="mid_side" text="Stereo" text_on="Mid/Side"
+ flex-grow="0.35" name="Mid/Side" lookAndFeel="LookAndFeel_V3"
+ button-color="FF33343D" button-on-color="FFB41717" button-off-text="FFFFFFFF"
+ button-on-text="FFFFFFFF" enabled="plugin:is_stereo"/>
+ <View margin="0" padding="0" flex-grow="0.2" background-color="00000000"/>
+ <Slider caption="Balance" parameter="stereo_balance" class="Slider" name="Stereo Balance"
+ padding="5" margin="0" enabled="plugin:is_stereo"
+ tooltip="Controls the balance between the two channels (stereo or mid/side)."/>
+ <View margin="0" padding="0" flex-grow="0.2" background-color="00000000"/>
+ <TextButton parameter="stereo_makeup" text="Makeup" text_on="Makeup" background-color="00000000"
+ margin="0" padding="5" button-color="FF33343D" flex-grow="0.35"
+ button-on-color="FFB41717" lookAndFeel="LookAndFeel_V3" name="Stereo Makeup"
+ tooltip="Compensates for the stereo balance at the plugin output."
+ button-off-text="FFFFFFFF" button-on-text="FFFFFFFF" enabled="plugin:is_stereo"/>
+ </View>
</View>
<View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF"
flex-grow="1.5">
@@ -211,8 +224,7 @@
parameter="chew_onoff" name="Chew On/Off" tooltip="Turns the chew processing on or off."/>
</View>
</View>
- <View display="tabbed" padding="0" margin="2" background-color="FF31323A"
- lookAndFeel="MyLNF">
+ <View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF">
<View tab-caption="Flutter" flex-direction="column" background-color="FF31323A">
<FlutterMenu margin="0" padding="0" background-color="00000000" max-height="30"
name="Flutter Sync" tooltip="Snaps the flutter rate to a synchronized value."/>
diff --git a/Plugin/Source/GUI/Assets/gui_ios.xml b/Plugin/Source/GUI/Assets/gui_ios.xml
@@ -78,15 +78,9 @@
plot-decay="0.0" plot-fill-color="FFFFFFFF"/>
</View>
<ScrollView padding="0" margin="1" background-color="00000000" lookAndFeel="MyLNF">
- <View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF">
+ <View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF" flex-grow="1.5">
<View flex-direction="column" tab-color="" background-color="FF31323A"
padding="0" tab-caption="Gain">
- <TextButton id="mid_side" tooltip="Toggles between left/right and mid/side processing modes (Stereo only)" margin="5" padding="0"
- parameter="mid_side" text="Stereo" text_on="Mid/Side" width="100" height="35"
- min-height="30" min-width="100" flex-align-self="center" max-height="40"
- name="Mid/Side" lookAndFeel="LookAndFeel_V3" button-color="FF33343D"
- button-on-color="FFB41717" button-off-text="FFFFFFFF" button-on-text="FFFFFFFF"
- enabled="plugin:is_stereo"/>
<Slider caption="Input Gain [dB]" parameter="ingain" class="Slider" name="Input Gain"
padding="0" margin="0" tooltip="Sets the input gain to the tape model in Decibels."/>
<View margin="0" padding="0" flex-grow="0.1" background-color="00000000"/>
@@ -112,6 +106,24 @@
tooltip="Adds the signal cut out by the cut filters back to the processed signal."
button-off-text="FFFFFFFF" button-on-text="FFFFFFFF"/>
</View>
+ <View flex-direction="column" tab-color="" background-color="FF31323A"
+ padding="0" tab-caption="Stereo" enabled="plugin:is_stereo">
+ <TextButton id="mid_side" tooltip="Toggles between left/right and mid/side processing modes (Stereo only)"
+ parameter="mid_side" text="Stereo" text_on="Mid/Side" margin="5" padding="0"
+ name="Mid/Side" lookAndFeel="LookAndFeel_V3" button-color="FF33343D" flex-grow="0.35"
+ button-on-color="FFB41717" button-off-text="FFFFFFFF" button-on-text="FFFFFFFF"
+ enabled="plugin:is_stereo"/>
+ <View margin="0" padding="0" flex-grow="0.2" background-color="00000000"/>
+ <Slider caption="Balance" parameter="stereo_balance" class="Slider" name="Stereo Balance"
+ padding="5" margin="0" enabled="plugin:is_stereo"
+ tooltip="Controls the balance between the two channels (stereo or mid/side)."/>
+ <View margin="0" padding="0" flex-grow="0.2" background-color="00000000"/>
+ <TextButton parameter="stereo_makeup" text="Makeup" text_on="Makeup" background-color="00000000"
+ margin="0" padding="5" button-color="FF33343D" flex-grow="0.35"
+ button-on-color="FFB41717" lookAndFeel="LookAndFeel_V3" name="Stereo Makeup"
+ tooltip="Compensates for the stereo balance at the plugin output."
+ button-off-text="FFFFFFFF" button-on-text="FFFFFFFF" enabled="plugin:is_stereo"/>
+ </View>
</View>
<View margin="0" padding="0" flex-grow="0.07" background-color="00000000"/>
<View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF" flex-grow="1.5">
@@ -264,7 +276,7 @@
</View>
</View>
<View margin="0" padding="0" flex-grow="0.07" background-color="00000000"/>
- <View display="tabbed" padding="0" margin="2" background-color="FF31323A" lookAndFeel="MyLNF">
+ <View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF">
<View tab-caption="Flutter" flex-direction="column" background-color="FF31323A">
<PowerButton margin="0" padding="0" background-color="00000000" max-height="32"
min-height="20" button-color="ff595c6b" button-on-color="FFEAA92C"
diff --git a/Plugin/Source/PluginProcessor.cpp b/Plugin/Source/PluginProcessor.cpp
@@ -165,7 +165,7 @@ void ChowtapeModelAudioProcessor::prepareToPlay (double sampleRate, int samplesP
inGain.prepareToPlay (sampleRate, samplesPerBlock);
inputFilters.prepareToPlay (sampleRate, samplesPerBlock, numChannels);
- midSideController.prepare (sampleRate);
+ midSideController.prepare (sampleRate, samplesPerBlock);
toneControl.prepare (sampleRate, numChannels);
compressionProcessor.prepare (sampleRate, samplesPerBlock, numChannels);
hysteresis.prepareToPlay (sampleRate, samplesPerBlock, numChannels);
diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp b/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp
@@ -78,16 +78,16 @@ void HysteresisProcessor::setSolver (int newSolver)
{
case RK2:
case RK4:
- clipLevel = 10.0;
+ clipLevel = 10.0f;
return;
case NR4:
case NR8:
- clipLevel = 12.5;
+ clipLevel = 12.5f;
return;
default:
- clipLevel = 20.0;
+ clipLevel = 20.0f;
};
}
diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.h b/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.h
@@ -67,7 +67,7 @@ private:
double biasFreq = 48000.0;
std::vector<double> biasAngle;
bool wasV1 = false, useV1 = false;
- double clipLevel = 20.0;
+ float clipLevel = 20.0f;
AudioBuffer<double> doubleBuffer;
BypassProcessor bypass;
diff --git a/Plugin/Source/Processors/MidSide/MidSideProcessor.cpp b/Plugin/Source/Processors/MidSide/MidSideProcessor.cpp
@@ -1,21 +1,42 @@
#include "MidSideProcessor.h"
+namespace
+{
+constexpr auto balanceGainDB = 6.0f;
+}
+
MidSideProcessor::MidSideProcessor (AudioProcessorValueTreeState& vts)
{
// set up parameter handle here
midSideParam = vts.getRawParameterValue ("mid_side");
+ balanceParam = vts.getRawParameterValue ("stereo_balance");
+ makeupParam = vts.getRawParameterValue ("stereo_makeup");
}
void MidSideProcessor::createParameterLayout (std::vector<std::unique_ptr<RangedAudioParameter>>& params)
{
- // add parameters here
+ using namespace chowdsp::ParamUtils;
params.push_back (std::make_unique<AudioParameterBool> ("mid_side", "Mid/Side Mode", false));
+ params.push_back (std::make_unique<VTSParam> ("stereo_balance", "Stereo Balance", String(), NormalisableRange { -1.0f, 1.0f }, 0.0f, &percentValToString, &stringToPercentVal));
+ params.push_back (std::make_unique<AudioParameterBool> ("stereo_makeup", "Stereo Makeup", true));
}
-void MidSideProcessor::prepare (double sampleRate)
+void MidSideProcessor::prepare (double sampleRate, int samplesPerBlock)
{
fadeSmooth.reset (sampleRate, 0.04);
+ for (auto& inGain : inBalanceGain)
+ {
+ inGain.prepare ({ sampleRate, (uint32) samplesPerBlock, 2 });
+ inGain.setRampDurationSeconds (0.05);
+ }
+
+ for (auto& outGain : outBalanceGain)
+ {
+ outGain.prepare ({ sampleRate, (uint32) samplesPerBlock, 2 });
+ outGain.setRampDurationSeconds (0.05);
+ }
+
curMS = *midSideParam == 1.0f;
prevMS = curMS;
}
@@ -36,6 +57,18 @@ void MidSideProcessor::processInput (AudioBuffer<float>& buffer)
buffer.applyGain (Decibels::decibelsToGain (-3.0f)); // -3 dB Normalization
}
+
+ // balance processing
+ const auto curBalance = balanceParam->load();
+ auto&& stereoBlock = dsp::AudioBlock<float> { buffer };
+ auto&& leftBlock = stereoBlock.getSingleChannelBlock (0);
+ auto&& rightBlock = stereoBlock.getSingleChannelBlock (1);
+
+ inBalanceGain[0].setGainDecibels (curBalance * balanceGainDB);
+ inBalanceGain[0].process (dsp::ProcessContextReplacing<float> { leftBlock });
+
+ inBalanceGain[1].setGainDecibels (curBalance * -balanceGainDB);
+ inBalanceGain[1].process (dsp::ProcessContextReplacing<float> { rightBlock });
}
void MidSideProcessor::processOutput (AudioBuffer<float>& buffer)
@@ -49,6 +82,21 @@ void MidSideProcessor::processOutput (AudioBuffer<float>& buffer)
fadeSmooth.setTargetValue (0.0f);
}
+ // inverse balance processing
+ if (*makeupParam == 1.0f)
+ {
+ const auto curBalance = balanceParam->load();
+ auto&& stereoBlock = dsp::AudioBlock<float> { buffer };
+ auto&& leftBlock = stereoBlock.getSingleChannelBlock (0);
+ auto&& rightBlock = stereoBlock.getSingleChannelBlock (1);
+
+ outBalanceGain[0].setGainDecibels (curBalance * -balanceGainDB);
+ outBalanceGain[0].process (dsp::ProcessContextReplacing<float> { leftBlock });
+
+ outBalanceGain[1].setGainDecibels (curBalance * balanceGainDB);
+ outBalanceGain[1].process (dsp::ProcessContextReplacing<float> { rightBlock });
+ }
+
//mid - side decoding logic here
const auto numSamples = buffer.getNumSamples();
if (curMS)
diff --git a/Plugin/Source/Processors/MidSide/MidSideProcessor.h b/Plugin/Source/Processors/MidSide/MidSideProcessor.h
@@ -9,18 +9,23 @@ public:
static void createParameterLayout (std::vector<std::unique_ptr<RangedAudioParameter>>& params);
- void prepare (double sampleRate);
+ void prepare (double sampleRate, int samplesPerBlock);
void processInput (AudioBuffer<float>& buffer);
void processOutput (AudioBuffer<float>& buffer);
private:
std::atomic<float>* midSideParam = nullptr; // parameter handle
+ std::atomic<float>* balanceParam = nullptr;
+ std::atomic<float>* makeupParam = nullptr;
bool curMS = false;
bool prevMS = false;
SmoothedValue<float, ValueSmoothingTypes::Linear> fadeSmooth;
+ dsp::Gain<float> inBalanceGain[2];
+ dsp::Gain<float> outBalanceGain[2];
+
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidSideProcessor)
};