I. Envelopes for Score-Controlled Instruments
When creating sounds in Csound, one of your first tasks is to get rid of the click that
accompanies any raw unenveloped sound. The simplest tool available for de-clicking work is the linen
opcode.
The linen
opcode requires four arguments:
First, to see how this opcode does not work, let us use it in a less than ideal manner. So we create an envelope:
kenv linen 1, .1, 2, .3
then plug it in to an oscillator's amp argument:
a1 oscil iamp*kenv, inote, 1
and play it from the score:
;inst no start duration amp pitch i1 0 2 70 7.00
The note sounds fine. It comes in smoothly and finishes smoothly. But what happens if we change the score duration to 1? Not so smooth now, a very noticeable click at the end. Now try lengthening the note; give it a duration of 4. The note actually gets louder at the end—it fades back in after it fades out. The problem is that the envelope in this example will reach zero at a fixed time; that is, it will fade in, sustain, and fade out for a time equal to that specified in the idur argument. If the score plays the envelope for less than idur, it will suddenly cut off and create the click. This is the main problem that you will face with volume envelopes. If a note finishes before its release segment is finished, then it does not matter how smoothly you have programmed the fade out, it will instantly drop from wherever it is at to zero.
On the other hand, if the note is played for longer than idur then it will have faded to zero before the note is finished playing. This might seem to solve the problem by giving the release more than enough time to finish, but the fade does not stop at 0, it keeps going past zero. This produces increasingly negative values, which has the effect of amplifying the sound. The reasons why increasing negative values create increasing amplitude are outside the scope of this article but will become clearer to anyone who continues study of how Csound produces waveforms.
Obviously using a fixed value for idur is not a good idea, as the envelope can then only be used with instruments whose note duration can be known ahead of time. A more workable value for idur is 'p3':
kenv linen 1, .1, p3, .3
Now try this envelope with a range of different note lengths in the score. It will not click or get unexpectedly louder, unless you use extremely small values for p3.
The adsr
opcode is much more useful if you want to create more traditional synthesizer effects, as it has a decay segment as well as attack and release.
With this opcode there is no need to specify a sustain/duration time, as this information is taken from the duration time specified in the orchestra.
The arguments to the adsr
opcode are:
adsr
times, there is a good chance it will click, and an even better chance to
that it will not sound the way you intended it to sound. The easiest solution to this problem is to always use notes longer than the total duration of the adsr
envelope.
Unlike the linen opcode, adsr does not 'go negative'; when the release portion hits zero. It stays at zero.
A more effective solution is to specify the times as fractions of the duration given in the score:
kenv adsr p3*.1, p3*.3, .4, p3*.4
Make sure that all the fractions add up to a value of 1.0 or less.
While this is an effective way of preventing unwanted noises, and you won't be restricted in the length of note with which it can be used, it is not an ideal solution. Using relative values means that the character of the envelope will change with the length of the note. One obvious problem is that it may create extremely long attack and fade times on very long notes. You will need to experiment with a mixture of relative and absolute values depending on how you want to use your note.
One other thing to be aware of with the adsr
opcode is that if iatt is set to zero, the whole envelope will be zero, and will produce nothing but silence. Of course if any part of the envelope is set to zero this also increases the chances that it will click.
In the manual, linseg
is classified as a line segment generator, but it is very well suited for use as an envelope. linseg
basically creates a pattern
of rising and falling lines between points, which can be used as a control signal. The arguments to linseg
run as follows:
The fact that you can have as many segments as you like means you can use linseg
to create some very unique and finely crafted sounds. But it does
take some work to get it right. The main problem with linseg
is that it is not sensitive to the length of the note, and it is up to you to make sure
that the times you specify don't total any more or less than the total duration of the note. If the envelope is too short it will click, and if longer than the note
may 'go negative'.
Again, the most reliable approach is to make each segment's duration a fraction of p3:
kenv linseg 0, p3*.2, 1, p3*.55, .5, p3*.25, 0
Both the linen
and adsr
envelopes are dependent on information from the score to work properly, and cannot be used very effectively on MIDI-controlled instruments. When triggering a note from a MIDI sequencer or keyboard, the sustain portion is the result of a spontaneous decision by the composer or player. Therefore an envelope which is to work with a real-time instrument must be ready to react to the note's end at any time. All the envelope and envelope-like opcodes are available in a real-time version, mostly with an 'r' appended to the name of the opcode. The main feature of real-time envelope opcodes is that the release portion is only triggered when it receives a MIDI note-off message.
linenr
takes four arguments as does the linen
opcode:
linenr
there is no duration argument, and there is a new argument, iatdec
which interacts with the decay to produce a release segment. With linenr
, idec is not triggered until a note-off message is received. idec behaves
exactly as you would expect a release segment to behave. The iatdec value modifies idec so that the fade out is exponential rather than linear. To explain in simple terms,
the idea is to drop the level as quickly and as low as is possible without a click, then when it is close to zero, create a slower fade to zero. The manual says iatdec
is "normally in the order of .01. A large or excessively small value is apt to produce a cutoff that is audible."
A few more things I have noticed:
The madsr
opcode is almost identical to adsr
except:
madsr
envelope behaves as you would expect an ADSR envelope found in a typical subtractive synthesizer setup to behave.
The linsegr
opcode is actually quite convenient for use as a real-time envelope. As with linseg
, you can define as many levels and durations
as you require, but in this case the final three arguments operate differently:
linseg
, linsegr
must have an a odd number of arguments and a minimum of three employed. However if you define the envelope with three
arguments, you will have a slightly bizarre instrument that makes no sound while the key is held, and produces a single fade when released.
Csound also makes the linseg
and linsegr
opcodes available as expseg
and expsegr
. Using these opcodes produces
exponentially curved, rather than linear, fades between levels, producing a less even and more dynamic shift in volume over the course of a note. These opcodes work
in exactly the same way as their equivalent linear versions, except that you may not use a zero value for any of the levels. If you need an exponential envelope to fade into, or down from silence, you need
to use a very small value which produces virtual silence (ex. .001). You also need all the level arguments to agree in sign, that is, if one level is negative they all must
be negative, and if one level is positive, they all must be positive.
The adsr
and madsr
opcodes are also available in exponential versions — xadsr
and mxadsr
.
When you test out the exponential envelopes, you may notice that when the volume quickly drops to, or rises from, a very small level, it can sometimes create a quiet, but noticeable aliasing sound. I call this sound a 'tickle'. Tickle will be most noticeable when:
The easiest solution is to simply calculate the envelope at audio rate. To do this, just change
the variable pre-fix from 'k' to 'a'. So if you named the envelope 'kenv', rename it to 'aenv', and the tickle should disappear. If you are going to use this
solution with expseg
, use the expsega
opcode, which is expseg
optimized for use at audio rate. Another solution is to double the control rate to 8820 instead
of the usual 4410, bringing the control resolution down to 5 samples per control period. To do this you will need to include the following statement at the beginning
of your orchestra, just before the 'instr 1' statement:
sr = 44100 kr = 8820 ksmps = 5
I have found this will usually reduce the tickle to an acceptable level. You can also simply change kr
to the same as sr
and ksmps
to one for the finest possible resolution on all instruments' control rates.
You can test out the above suggestions using the file ticklekick.csd
(linked at the end of this article).
This opcode gives you the ability to not only define as many segments as you like, but to define the type of curve, and its steepness, for each individual segment.
The transeg
opcode requires you define a minimum of four arguments:
The greater the itype argument, the steeper the curve. The effect of different values depends on the length of the segment, but I have found that the useful range is from around 0-70.
This opcode allows you to define an envelope of unlimited linear segments which loop at a specified rate. The creative potential of this opcode lies in the
fact that each one of it's arguments is controllable at the k-rate. This means that loopseg
can morph from a repetitive LFO-like effect to an ever-changing
envelopein real-time.
The arguments for loopseg are:
The minimum number of segments you must define is one, and so long as that requirement is satisfied the opcode will work regardless of how many arguments you put into it after that. By 'work' I mean simply that the compiler will not flag it as an error, but the envelope may do nothing, or it may do something unexpected.
The envelope used on a sound's volume, pitch or timbral parameters, is in many ways the equivalent to the playing style used to create sound with an acoustic instrument. Designing an envelope can be compared to an individual player's way of plucking a guitar string or sliding a bow across a violin. As you can see now, Csound offers vast resources to allow the sound designer to develop highly unique signature sounds if they willing to move beyond the comfort of ADSR sliders. Experiment and have fun.
Vercoe, B et al, The Canonical Csound Reference Manual.
The opcodes discussed in this article are found under: Part II: Opcodes Overview > Signal Generators > Linear and Exponential Generators/Envelope Generators.
Bianchini, R & Cipriani, A, Virtual Sound: sound synthesis and signal processing, theory and practice with Csound, ConTempo, Rome, 2000.
This is an easy but thorough introduction to the mechanics of Csound, and digital sound in general.