Jan/fix forcing lfo change - #23
Conversation
reuk
left a comment
There was a problem hiding this comment.
The inline comments are all fairly minor, the code looks generally good.
One thing I noticed while testing is that the LFO seems to "remember" its phase during bypass, so when the bypass is disabled the LFO resumes from its last position. I'm not sure if that's desirable behaviour - normally I'd expect bypass to behave as though the plugin is still active in the background, i.e. the LFO phase would continue to update.
| } | ||
|
|
||
| void setModulationRate(float rateHz) noexcept { | ||
| void setModulationRate(float rateHz, bool force = false) noexcept { |
There was a problem hiding this comment.
Although this matches the JUCE API, I don't think we've done a very good job here. Bool parameters like this (auxiliary flags that modify the "main" behaviour of the function) aren't very readable at the call site. Consider:
lfo.setModulationRate (5.0f, true);
Unless we go and look at the docs, it's not immediately clear what this function will do. Using an enum class ApplySmoothing { no, yes }; might improve readability.
There was a problem hiding this comment.
I was not convinced of this change, but after implementing it, I agree 🙂
What I would do in a plugin is to create a separate struct Tremolo::Parameters with all plugin parameters, and possibly a force field. Then there could be just a single setParameters() function and using designated initializers would get the message across, i.e.,
tremolo.setParameters({
//...
.force = bypassedAndNotTransitioning
});This would allow us avoiding the SerializableParameters struct as well.
|
|
||
| void setModulationRate(float rateHz) noexcept { | ||
| void setModulationRate(float rateHz, bool force = false) noexcept { | ||
| for (auto& lfo : lfos) { |
There was a problem hiding this comment.
Looking at this again, maybe this should be named setModulationRateHz so that the units are slightly more obvious
There was a problem hiding this comment.
Done.
For more clarity, I'd use the ClosedRangeValue<float> or Frequency classes from my wolfsound_dsp_utils library. Then, you could write
tremolo.setModulationRate(Frequency{p.rate});
or even
tremolo.setModulationRate(10_Hz);
I don't like using floats as parameters in general!
| tremolo.setModulationRate(parameters.rate); | ||
| // force updates (=skip transitions) if fully bypassed to avoid peculiar | ||
| // behavior when parameters change under bypass ON | ||
| tremolo.setModulationRate(parameters.rate, bypassedAndNotTransitioning); |
There was a problem hiding this comment.
It would be good to describe exactly the kind of behaviours that we're trying to avoid here. If this comment is here to act as a warning ("something subtle is happening here") then, as a reader/maintainer, I'd want to know what behaviours to test when making changes in this area. The same goes for the comment later on in the file.
There was a problem hiding this comment.
I've tried to clarify, but it's difficult to explain waveform shapes in words! 😄
| // offset the phase by pi/2 to return 0 if phase equals 0 | ||
| // (otherwise, the waveform starts at 1) | ||
| phase -= juce::MathConstants<float>::halfPi; | ||
|
|
There was a problem hiding this comment.
Consider instead introducing a new variable with a different name (maybe just offsetPhase), so that phase always refers to the initial parameter value. I expect this will be marginally clearer
I believe this is a minor thing that requires major changes. I have put that on my TODO list. Let's deal with that once all lessons are published. |

No description provided.