Im working on a synth and I’d like to add an adjustable level of curve (both concave and convex) to the attack stage of my ADSR envelope generator.

Problem is, it looks like common solutions for similar problems (e.g. Bezier curves) are too computationally expensive.

My initial thought is to generate a series of line segments that approximate the desired curve. For example, i made a rough formula to approximate a variable “curving” of the line [y=x, 0<=x<=1] with 4 linear functions. It finds a point along [y=1-x], finds 2 line that intersect at it, then calculates 2 more lines to “smooth out” the “curve”:

Hi @Evan - I’m not sure if this is ‘guidance or direction’ but a few thoughts:

It sounds like you’re re-‘inventing’ Calculus.

There are two separate times you might have to do this and they can be chosen - when the musician changes the ADSR settings and-or when the musician-sequencer-whatever requests-‘hits’ a note to be played.

Perhaps you could do your ‘calculations’ - the ones that are too ‘expensive-long’ only when the ADSR settings are changed, save the results in a usable form-table, and use them when playing a note.

If the functions are too computationally expensive, why not use something similar to wavetables:

generate the envelope using an external tool (Python script, etc)

allocate an array and store the precalculated envelope curve there

divide the array into segments (A, D, S, R, etc.)

stretch and interpolate each individual segment as needed

All things considered, this trades CPU cycles for memory and may not be the best approach. Somehow I think it would be possible to calculate the curves you need in realtime, provided the algorithm is optimized.

After coding everything up, i was actually surprised to see that the “curve” generated by 4 linear functions produced musically pleasing results. For now, think im going to accept that “good enough is good enough” and run with it even though it’s not an ideal solution. I’ll publish my (hideous) source code in a separate post once the project is done.

I particularly like the wavetable idea and will likely circle back and implement that later down the road. It seems like a clean solution since memory doesn’t seem to be a huge constraint for this project.

IMHO, 4 linear functions should be more than sufficient. It is worth mentioning that logarithmic pots taper approximation uses only two linear segments (and the taper not even close to being logarithmic):