From your code I guess the envelope is linear.
Yup, it's linear.
It also has a limitation of 8 sample timing resolution, which allows for a highly optimized implementation with the Cortex-M4 DSP instructions. The linear ramp is updated for each sample, but each timed phase (delay, attack, hold, decay, and release) has to be a multiple of 8 samples.
I wanted to make a "default" envelope that's extremely efficient. I'm happy to accept more sophisticated envelopes into the library, with more CPU usage as the trade-off for their advanced shapes. They should be named with an extra word added on the end, to indicate what their extra features are.
However, I want to use exponential envelopes.
What would you recommend?
- modding your code to support exponential envelopes or
- using the envelope, waveshape it and then apply it with a multiply block?
Without any programming in the library, yeah, you could create any arbitrary envelope as sequence of positive integers and use a AudioPlayMemory object to stream it into an AudioEffectMultiply object to apply it. Of course, this approach will give a fixed length envelope, rather than allowing the sustain phase to continue for arbitrary times.
If you care about efficiency using the CPU, perhaps 2, 3 or 4 linear segments could be a close enough fit to the desired exponential curve? Creating a new object with more linear segments should be pretty simple.
The other alternative would be storing a lookup table of the exponential curve, and read pairs from the table and use linear interpolation (like the sine wave gen) to stretch the curve. Or if you need exponential only in the attack phase, or only in attack and decay, and fixed lengths are ok, just read a fixed table rather than computing a linear ramp.
Actually computing the exponential curve on every sample in update() is probably too expensive. But maybe a 2nd or 3rd order polynomial (with integer-only math handled well) could give a close enough approximation?