-
Notifications
You must be signed in to change notification settings - Fork 0
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
Better curve algorithm wanted. #6
Comments
It seems like used in this line. This function is a bit tricky, because both inputs of If it's OK to change function, combination of rate limiter and smoother (some 1-pole lowpass) might be an alternative. // a, b, c, d are tuning constants.
func(x, target) =
x : rate_limiter(up * a * curve, down * b * curve) : smooth(y) with {
y = if(x - target < 0, down * c * curve, up * d * curve);
}; |
Thanks, but I don't want a time-variable behavior, like a rate limiter. I want something that looks more like this: The formula should have the following features:
Your proposal does none of the above. |
Closest I can think of is the top left part of superellipse. However, this doesn't satisfy the third point. Also heavy to compute. |
That does come close. Otoh: I'm only calculating this 4 times, so how bad can it be? I hope I'll find the perfect algo soon! |
I put one more. The algorithm in bezier-easing library might be used. This satisfies 1st and 3rd point, and probably 2nd point with some tuning. The algorithm uses newton-raphson and switches to bisection where slope is close to flat. So it's heavy.
I once profiled SyncSawSynth with valgrind, and iirc, found that 20~30% of CPU time is spent on 2 sin and 1 cos, which are called once per frame. However, the rule of thumb is better not assume anything until take some benchmarks. I'll open a issue around benchmark soon. |
I looked into cubic beziers a while ago, for my new limiter. The problem is that they give you x and y as a function of t, so you need to solve for t, and you end up with this monster formula! |
Or are you suggesting you do it in C++? Another way would be a 3d lookup-table in faust. |
There's an article of numerical algorithm by the author of bezier-easing library. Implementation section has a code. |
If I understand correctly, he's solving the same problem:
He definitely lost me in the part that follows though. I'd love to implement this in faust, also for my limiter, and this code looks a lot simpler than my monster formula, so I hope it will run quicker too. |
The core algorithm is on If I understanc correctly, following javascript code: function KeySpline (mX1, mY1, mX2, mY2) {
this.get = function(aX) {
if (mX1 == mY1 && mX2 == mY2) return aX; // linear
return CalcBezier(GetTForX(aX), mY1, mY2);
}
function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
function C(aA1) { return 3.0 * aA1; }
// ...
} can be translated to Faust as: KeySpline(aX, mX1, mY1, mX2, mY2) = out with {
out = if(mX1 == mY1 && mX2 == mY2,
aX,
CalcBezier(GetTForX(aX), mY1, mY2));
A(aA1, aA2) = 1.0 - 3.0 * aA2 + 3.0 * aA1;
B(aA1, aA2) = 3.0 * aA2 - 6.0 * aA1;
C(aA1) = 3.0 * aA1;
// ...
}; I'm not sure how to translate for loop in // Maybe use case of `seq` in Faust?
for (var i = 0; i < 4; ++i) {
var currentSlope = GetSlope(aGuessT, mX1, mX2);
if (currentSlope == 0.0) return aGuessT;
var currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
} The library implementation is a bit more complicated (link). If you consider using this, I'd recommend to take a look at it. |
I just remembered surge has a similar feature, so I looked up how they did it The curve looks pretty good in desmos and the math is extremely simple. |
Surge's bend3 looks good to me. Just to point out, it looks like positive/negative rotates the curve 180°. |
If we can optimize the synth a lot, I hope to add curve per parameter. |
Do you mean literally all parameters? Or just parameters under modulation tab? |
I was hoping for all, but I'm afraid we can't bring down the DSP-usage enough. Only the mod tab could be a nice compromise. |
Currently
tab macros -> curve
is implemented as:This gives an asymmetric behavior, both between positive and negative values of
curveSlider
and between low and high values ofx
.I'm looking for a better algorithm.
The text was updated successfully, but these errors were encountered: