I am having an issue with adding a variable to a lambda wave shaping function. I am not sure what im doing wrong. I want to use a knob to change the slope. Am I not approaching this properly?
Thanks!
I am having an issue with adding a variable to a lambda wave shaping function. I am not sure what im doing wrong. I want to use a knob to change the slope. Am I not approaching this properly?
Thanks!
Here is the code text:
struct MultibandDistortion
{
MultibandDistortion()
{
}
void prepare (const juce::dsp::ProcessSpec& spec)
{
waveShaper1.functionToUse = [this] (float x)
{
float originalX = x;
x = (std::tanh(x * 2.f));
x = (x-(slope*x)) / (slope - (2.f * slope * std::abs(x)) + 1.f);
return x;
};
}
void reset() noexcept
{
}
template <typename ProcessContext>
void process (const ProcessContext& context) noexcept
{
waveShaper1.process (context);
}
dsp::WaveShaper<float> waveShaper1;
float slope = 1.f;
};
I never used the DSP module, but after a quick look ; i guess that it can’t compile as a lambda can only be converted to a function pointer if it does not capture.
You could try also with a custom Function
parameter (instead of default) for WaveShapper.
template<typename FloatType, typename Function = FloatType (*) (FloatType)>
The documentation here is not helpful either:
https://docs.juce.com/master/structdsp_1_1WaveShaper.html#ab24e80dd88150137f5814f689c900bb6
However, the source code for the class shows the usage of Function
as this:
typename Function = FloatType (*) (FloatType)
Function functionToUse;
SampleType JUCE_VECTOR_CALLTYPE processSample (SampleType inputSample) const noexcept
{
return functionToUse (inputSample);
}
You can customize this template parameter with a different type that follows the same pattern:
juce::dsp::WaveShaper<float, std::function<float(float)>> waveShaper1;
Once you do this, You’ll be able to capture this
:
However, you should capture this
in a juce::WeakReference
, just in case the lifetime of that callable ends up being different from the lifetime of your waveshaper.
capturing this
in a juce::WeakReference<>
or juce::Component::SafePointer<>
is just a good habit to get into.
Once you make this change to the template parameters, it’ll compile. See this godBolt as proof:
Notice that in that case i suppose that thread safety must be properly handled.
in that case
meaning?
Thanks so much Matkat!
Works like a charm!
Wouldn’t have gotten here without you (everyone should take his course, worth every penny)
Thanks Nicolas too!
Capturing this
.
AFAIK the member values are reachable frrom the DSP perform and from any GUI handling at the same time. I suppose it is what the OP needs to manage saying “I want to use a knob to change the slope”.
You need to use an AudioParameterFloat
to represent the slope.
retrieve the value via the atomic get()
or getValue()
. i can’t remember which one at the moment.
Give your class an AudioParameterFloat*
member variable.
Initialize it when the class is constructed from your APVTS.
MultibandDistortion(APVTS& apvts)
{
slope = dynamic_cast<juce::AudioParameterFloat*>(apvts.getParameter("Slope"));
jassert(slope != nullptr);
}
you can capture the slope in the lambda like this:
waveShaper1.function = [slope = this->slope](float x)
{
// 'slope' is a pointer, captured by copy.
return x;
};
this has come up several times in the forums, might be worth updating the docs to reflect this?