-
Notifications
You must be signed in to change notification settings - Fork 1
Jan/fix forcing lfo change #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
reuk
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
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.