On Thu, 2006-06-29 at 13:38 +0100, james(a)dis-dot-dat.net wrote:
Hi peeps.
I've been writing an app that requires volume envelopes. I've
implemented the envelope part myself, but I was wondering if there
was a library about to do it.
I ask because I realised that probably everyone on this list has
written something that uses envelopes, and probably written it
better and with more features than I have.
Well, I don't know what features you have implemented or wish for, but
for what it is worth, I implemented 8 stage envelopes with looping
sustainlevels, key- and velocity-follow, the works ... and it is all
crap! :-D Honestly, I never use all those features (spare the
key-follow) and am instead returning to a much more basic view of
envelopes where even the standard ADSR appears to be a bit over-worked.
The focus on complex envelopes is perhaps a left-over from another era
when stable oscillators were expensive and envelopes fairly cheap to
implement, adding a welcomed illusion of complexity. Other
implementations made from many smaller basic building blocks, like the
ones from Bucla and EMS, was an exclusive for radio-stations and
research-centers.
Bucla only had attack/decay (but you could chain several elements),
EMS had attack/decay/release which I believe comes pretty close to an
ideal minimalist approach:
* Attack is needed because it may take some time before the system
stabilizes after we start adding energy.
* Decay is needed because we may have added a single burst of energy,
fading away with no further energy being added.
* Release is needed for damping, or else all our instruments will be
variations of tubular bells and marimbas. A straight forward Farfisa
organ has its place too.
Is this then really enough to cater for all our envelöpe needs?
Given we have a few of them, say a small number like four, and a
patchbay, I believe it is.
Say we wanted to use a wobbling complex envelope for a punchy trombone
bratt? That can still be done with simple envelopes, perhaps even better
than with a complex, by routing an LFO through a second (shortish)
envelope, modulating the sounding oscillator on top of the main
envelope. Combine and conquer! Oscillators are cheap these days and we
do not need to rely on a single LFO implemented as a shared resource.
Or perhaps we would like a bit of envelope delay to make a sudden change
of the sound after a while? One way of doing this could be to put the
envelope through a delay line (which we would then need to have made
part of the synthesizing algorithm.) There is no need to put the delay
feature into the envelope itself. Delay lines are inexpensive these days
and, given a patch bay, very flexible and useful little tools also for
peak and notch filters. Hey, given enough feedback, we can even use them
as spare oscillators ...
Another argument in favour of ADR rather than, say ADSR, is if we
compare by counting the number of knobs to be assigned. Given a finite
amount of knobs, I am convinced it would be more flexible to have four
ADR's rather than three ADSR's. And knobs are a finite resource, if for
no other reason than the lenght of your arms.
Finally, we could throw in a bit of Bucla wisdom and allow the
envelopes to retrigger themselves, so as to get us a bank of LFO's
instead.
With all this being said, what would then be a desireable implementation
of a very basic ADR?
The decay and release is probably the easiest to come to terms with,
because we will simply borrow from physics, which tells us that the
system should decay exponentially towards zero. And then some ...
Because of the inner damping, we actually do reach zero in finite time.
Following the same strategy backwards for the attack unfortunately does
not work. Our instruments will sound uninspired and booring ... But if
we instead allow us to do it upside down, an exponential decay from zero
towards one so to say, then we appear to come much closer to the desired
result. Now why is that?
I can see two reasons, the first one again having to do with physics.
Say we were playing the trombone, then the energy applied from the
buildup of pressure is almost explosive in the initial phase,
accellerating the system response very quickly, but over time the intial
pressure diminishes, giving us a smoother rounding into the sustained
part. So it is in part because that that's the way attacks tend to
appear naturally. The second reason is that given a choice we wouldn't
really like to do it any other way, not even in situations where we
gently fade the notes in ... because it makes no sense to play below the
hearing-treshold. A fast fade-in to just above hearing-treshold,
grabbing the attention, followed by a smooth parking at the sustain
level, allows us to be both soft and distinct at the same time.
Although technically not part of the envelope itself, a keyfollow,
modifying the time of the envelope is a must have. Small high pitced
systems tends to decay much faster than the huge and low pithed ones.
One thing to remember here, is to keep the unmodifyed reference note
within the part of the keyboard that we actually own. Having key zero as
a reference is an annoying mistake.
The real kicker would of course be if we have aimed high enough in the
quality of implementation, as well as applied the re-trigger feature.
Then the keyfollow could potentially turn the envelope into a pitched
oscillator with variable shape. Aim even higher and make it a stateless
function, and we can start implementing FM-synthesis. We could also let
one envelope re-trigger another, re-triggering the first. With
appropiate settings we would then be on our way into the realms of the
Casio CZ-101 ...
Oy, this became somewhat lengthier than I intended. I better stop now
before it turns into a complete design document for a synthesizer based
on simple envelopes and short delay lines. Also ... It is friday evening
and I have a beer to attend to :-D
More generally, is there a library/toolkit of audio
bits and bobs
about?
Well if you like, you can copy/paste the old ones I have. In the
innermost loop there are a few mmx instructions adding up progress and
squaring the current value, but they can easily be rewritten to plain C.
And like I said, it is perfectly possible to ignore the excess
parameters and make a simplified UI
James
--
cheers! // Jens M Andreasen