-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Update math functions to C++ standard library #7685
base: master
Are you sure you want to change the base?
Conversation
This updates usages of sin, cos, tan, pow, exp, log, log10, sqrt, fmod, fabs, and fabsf, excluding any usages that look like they might be part of a submodule or 3rd-party code. There's probably some std math functions not listed here that haven't been updated yet.
lmao one always sneaks by
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 took a bit to review this, and here it is.
Also i could only grab a few cases where pow -> exp2 /fastPow10f is applicable. There's lots more you can change. Would appreciate if you did.
- std::pow(2, x) -> std::exp2(x) - std::pow(10, x) -> lmms::fastPow10f(x) - std::pow(x, 2) -> x * x, std::pow(x, 3) -> x * x * x, etc. - Resolve TODOs, fix typos, and so forth Co-authored-by: Rossmaxx <74815851+Rossmaxx@users.noreply.github.com>
I mistakenly introduced a bug in my recent PR regarding template constants, in which a -1 that was supposed to appear outside of an abs() instead was moved inside it, screwing up the generated waveform. I fixed that and also simplified the function by factoring out the phase domain wrapping using the new `ediv()` function from this PR. It should behave how it's supposed to now... assuming all my parentheses are in the right place lol
What else is lmms::numbers for?
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.
This is left
Co-authored-by: Rossmaxx <74815851+Rossmaxx@users.noreply.github.com>
Co-authored-by: Rossmaxx <74815851+Rossmaxx@users.noreply.github.com>
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.
LGTM
Based off the myriad of link errors in the CI, it appears that functions defined in headers are not inline by default after all. I'll fix it tomorrow, for now I sleep |
I thought they were inlined. Sorry @rubiefawn for confusing you. |
Only class member functions are marked as (Crucially, "marked |
For functions, constexpr implies inline so this just re-adds inline to the one that isn't constexpr yet
src/core/DrumSynth.cpp
Outdated
w = std::sin(p); | ||
break; | ||
case 1: // sine^2 | ||
w = std::abs(2.f * std::sin(.5f * p)) - 1.f; |
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.
Starting with the original:
static_cast<float>(fabs(2.0f * static_cast<float>(sin(fmod(0.5f * ph, TwoPi))) - 1.f));
I've tested that the sin(fmod(0.5f * ph, TwoPi))
part is equivalent to:
std::sin(ph / 2)
Plugging that back in, we get:
w = std::abs(2.f * std::sin(.5f * p)) - 1.f; | |
w = std::abs(2 * std::sin(ph / 2) - 1); |
I've confirmed that this result is identical to the original.
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 "original" referenced as well as your suggested change have the - 1
inside the abs()
, which is actually an error I accidentally introduced in my last PR introduced in b2f2fc4. The changes I made here fix that, and reference the original implementation (from
before b2f2fc4 screwed it up). Here are the graphs of both; note that the incorrect version has a range of [0, 3] while the correct one has a range of [-1, 1]:
src/core/DrumSynth.cpp
Outdated
w = p * 2.f * numbers::inv_pi_v<float>; | ||
if (w > 1.f) { w = 2.f - w; } |
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.
w = p * 2.f * numbers::inv_pi_v<float>; | |
if (w > 1.f) { w = 2.f - w; } | |
w = std::abs((2 / numbers::inv_pi_v<float>) * std::remainder(ph, 2 * numbers::inv_pi_v<float>)) - 1; |
I found this function which works.
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.
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.
std::remainder
is not the same as Desmos's mod
. In Desmos it would be x - round(x / y) * y
.
When you do that, you'll get a triangle wave. However, after testing it some more, both your triangle wave and mine appear to be off from the original. I'll look into it some more and see what I can find out.
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.
src/core/DrumSynth.cpp
Outdated
if (w > 1.f) { w = 2.f - w; } | ||
break; | ||
case 3: // sawtooth | ||
w = p * numbers::inv_pi_v<float> - 1.f; |
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.
w = p * numbers::inv_pi_v<float> - 1.f; | |
w = (ph - (2 * numbers::inv_pi_v<float>) * static_cast<int>(ph / (2 * numbers::inv_pi_v<float>))) / numbers::inv_pi_v<float> - 1; |
I think the previous equation was pretty good.
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.
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.
Regarding several of the DrumSynth suggested changes, what is the benefit to using |
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
No ediv(), no std::fmod(), no std::remainder(), just std::floor(). It should all work for negative phase inputs as well. If I end up needing ediv() in the future, I can add it then.
This reuses more work and is also a lot more easy to visualize. It's probably a meaningless micro-optimization, but it might be worth changing it back to a switch-case and just calculating ph_tau and saw01 at the beginning of the function in all code paths, even if it goes unused for the first two cases. Guess I'll see if anybody has strong opinions about it.
src/core/DrumSynth.cpp
Outdated
// sine | ||
if (form == 0) { return std::sin(ph); } | ||
// sine^2 | ||
if (form == 1) { return 2.f * std::abs(std::sin(0.5f * ph)) - 1.f; } |
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.
if (form == 1) { return 2.f * std::abs(std::sin(0.5f * ph)) - 1.f; } | |
if (form == 1) { return std::abs(2.f * std::sin(0.5f * ph) - 1.f); } |
If ph==0, your version would output -1 while the old function would output +1.
Here's what I've been using to test my functions:
https://gist.github.com/messmerd/5ee2e0078b574b9878bdd7224192531e
I've added your functions there too for comparison
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.
If ph==0, your version would output -1 while the old function would output +1.
Yes, and the old function wasn't supposed to. It's an error introduced in b2f2fc4; see the graphs of the functions: #7685 (comment)
Consider the original code prior to b2f2fc4:
// original code
case 1: w = (float)fabs(2.0f*(float)sin(fmod(0.5f*ph,TwoPi)))-1.f;
// delete casts, it's all floats anyways
case 1: w = fabs(2.f * sin(fmod(0.5f * ph, TwoPi))) - 1.f;
// remove unnecessary fmod(), sin() is well-defined for inputs outside [0, τ]
case 1: w = fabs(2.f * sin(0.5f * ph)) - 1.f;
// convert c-style math functions to std::* c++ counterparts
case 1: w = std::abs(2.f * std::sin(0.5f * ph)) - 1.f;
// new code
if (form == 1) { return 2.f * std::abs(std::sin(0.5f * ph)) - 1.f; }
// new code, fixed for consistency
if (form == 1) { return std::abs(2.f * std::sin(0.5f * ph)) - 1.f; }
So my "new" version is in fact identical to the original, intended version, with the exception of the 2.f *
being outside the abs()
rather than inside it. This was an unintentional change, but has no effect on the result in this case. I'll move it back inside to make it match the original better for a cleaner diff history though. (Edit: that has now been done)
This updates usages of
sin()
,cos()
,tan()
,pow()
,exp()
,log()
,log10()
,sqrt()
,fmod()
,fabs()
, andfabsf()
, excluding any usages that look like they might be part of a submodule or 3rd-party code. There's probably some math functions not listed above that haven't been updated yet.I haven't touched any of the following items. If these should be updated, I can do that:
plugins/CarlaBase/*
plugins/LadspaEffect/*
plugins/ZynAddSubFx/*
src/3rdparty/*
*test*
Note
Updating these function usages was brought up in #7558, somewhat related, probably not important.