Envelope shapes in sfz

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

Music Engineer wrote: Tue May 24, 2022 11:09 am I suppose, the error accumulation could be problematic though - especially for the concave shapes which would require an unstable filter
Not necessarily. If you use a level-threshold for terminating the envelope stage (rather than trying to predict the time at which it terminates), then any error accumulation will result in slight timing error, but won't cause any other harm.

Post

Interesting idea. One would trade one type of error for another. One could also just re-initialize the state every couple of hundreds or thousands of samples according to a closed form formula for what it should be at that instant.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Music Engineer wrote: Tue May 24, 2022 10:32 am That shouldn't be a problem. I'm scaling and shifting the raw leaky integrator output anyway to exactly hit the desired endpoints and I'm also fitzdazzing my denormals (FTZ/DAZ) on the framework side.
Could you post a code snippet of this?
Thanks

Post

I'm currently just calling

_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); // #defined in xmmintrin.h
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); // #defined in pmmintrin.h

at the entry of my plugin class processing function. But this is crude not really production ready yet. You probably rather want to use something like this:

https://forum.juce.com/t/state-of-the-a ... tion/16802
https://blog.audio-tk.com/2016/09/20/au ... denormals/

...or do you mean the scale-and-shift stuff?
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Sorry for beeing unclear. I did refer to the scale-and-shift stuff.

By the way: Do we still need to take care of the denormals also on the Mac - especially on the M1 machines. Not sure here.

Post

My code for this is probably a bit hard to decipher, so maybe this plot is clearer:

https://www.desmos.com/calculator/wvhvokixrr

The first (red) function is the regular unmodified decaying exponential with a decay time of "T" (usually called tau but desmos doesn't like this for a parameter). Then there is a second parameter that I called "a" which determines the desired end time of the envelope segment (here: a=2.4). I first subtract the value that the envelope actually hits at x=2.4 to make it hit zero at the end (blue) and then I scale the whole function by the reciprocal of 1 minus this offset to scale the start-value back up to one (green).

So the shift is given by s = exp(t_end/tau) and the scale (applied post-shift) is 1/(1-s)

Edit: This is my envelope generator code as used in Straightliner:

https://github.com/RobinSchmidt/RS-MET/ ... odulator.h
https://github.com/RobinSchmidt/RS-MET/ ... ulator.cpp

relevant are the

rsBreakpointModulator<T>::getSample()

function the .h and the

rsBreakpointModulator<T>::setupStateVariables()

function in the .cpp file for the per-sample-processing and per-breakpoint-handling code and there in particular the "ANALOG" branches. ...but it's about 15 years ago that I wrote this, so I don't really know anymore how it works in detail. But this envelope uses recursive implementations of all available shapes and uses appropriate scale-and-shift formulas (aka affine transforms) to hit the desired start- and endpoints exactly.
Last edited by Music Engineer on Wed May 25, 2022 12:51 pm, edited 4 times in total.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

There are other ways of thinking about this in terms of "aiming beyond the actual target" but I usually think about this in terms scale-and-shift (or rather shift-and-scale in this case - which is the same thing, just using a different value for the shift)
Last edited by Music Engineer on Wed May 25, 2022 11:37 am, edited 2 times in total.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Markus Krause wrote: Tue May 24, 2022 10:14 am Modulation and random-access works well with the formulas posted above. I use them in my synths since many years. They are a polynomal approximation of the exp shape.
In what sense do they approximate the exp shape? Least squares? I guess, if I would try to get a polynomial approximation of a parameterized exp (or really any other function), I'd probably first try to match the values and one or more derivatives at the endpoints, i.e. use some formulas based on the idea of Hermite interpolation. Another option could be to use an interpolation polynomial matching the target function at judiciously selected x-values (maybe at the roots of (suitably scaled-and-shifted) Chebychev polynomials?)...in any case, one would need something that gives easily evaluatable formulas for the polynomial coeffs in terms of the shape parameter.
Last edited by Music Engineer on Wed May 25, 2022 12:55 pm, edited 1 time in total.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

They have been tweaked for musicality and low CPU.
What they do is that they shape a linear slope ranging from [0;1] to an exp-style slope ranging from [0;1].
You can see the input X as the Y axis of a linear ADSR ranging from [0;1]. envshape is valid for [-1;1]. An envshape of 0 returns the linear slope. You get good analog ('exp style') results with an envshape of 0.8.

Post

They have been tweaked for musicality and low CPU.
Ah - OK, I see. So, it's some hand-tuned function. Thanks for sharing. I'll take a closer look at them soon.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Hmm... have you checked how liquidsfz (by Stefan Westerfeld) implements those ampeg_* opcodes in mentioned in opening post - https://github.com/swesterfeld/liquidsfz

Post

juha_p wrote: Tue May 24, 2022 8:59 pm Hmm... have you checked how liquidsfz (by Stefan Westerfeld) implements those ampeg_* opcodes in mentioned in opening post - https://github.com/swesterfeld/liquidsfz
I tried looking at the loader (to see where the parameters go) and it looks an awful lot like it doesn't actually parse _shape even if those are mentioned in the opcode list.

Post

juha_p wrote: Tue May 24, 2022 8:59 pm Hmm... have you checked how liquidsfz (by Stefan Westerfeld) implements those ampeg_* opcodes in mentioned in opening post - https://github.com/swesterfeld/liquidsfz
No - I wasn't aware of that project yet. Yet another FOSS sfz engine! Great! Another resource to figure out how to interpret the spec. Thanks for the hint!
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

mystran wrote: Tue May 24, 2022 9:18 pm
I tried looking at the loader (to see where the parameters go) and it looks an awful lot like it doesn't actually parse _shape even if those are mentioned in the opcode list.
Ah - yes - you mean here at line 508?:
https://github.com/swesterfeld/liquidsf ... /loader.cc
yeah...that's where I would expect to see them as well
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post Reply

Return to “DSP and Plugin Development”