Sound envelope generator

by Theo Verelst

Musical instruments, and in fact all sound sources, can be analized by plotting the amplitude of the sound against time.

That plot of evolution of that amplitude is in synthesizer terminology called the 'envelope' of a sound.

To create a synthetic sound, the making of such an envelope is one of the ingredients for a succesfull sound imitation, which since the first analog electronic synthesizers is done in ways which can also be simulated by computers.

 amplitude
 ^
 |        /--
 |       /   \ D
 |      /     \         S
 |     /       -------------//----
 |  A /                           \
 |   /                             \ R
 |  /                               \
 | /                                 \
 +--------------------------//------------> time

The above is a schematic representation of how the loudness of a sound can vary from the start to the end of the sound, using what is called a ADSR curve, which we will simulate in tcl.

ADSR stands for Attack, Decay, Sustain, and release, corresponding with the phases of a sound coming up, decaying, being sustained (for instance like the key on an organ bein held down), and finally dies away.

On traditional synthesizers, there are knobs for these 3 rates (ADR) and level (S), so that each phase of the sound can be made to take as long as seems fitting to the synthesizer programmer.

The envelope is not the waveshape of the actual sound, it's only an approximation of the amplitude of the sound, because a sound is always made of vibrating waves, in the range of 20 Herz to 20kHz, so that the amplitude is always an approximate of some kind, for instance the average root mean square power of the sound signal (in electrical or sound wave form), or the height at the top of the bottom of the wave (at the zero crossing of the derivative).

The amplitude gaph can be seen as multiplied with the waveform of the sound source at each point in time.


Am I the only one who finds pages like these pretty far off-topic for a Tcler's Wiki? -jcw

(Well, I don't determine that eventually, but it doesn't feel nice to be cut short before I bring in both Snack (an important tcl/tk package), programs that are written in tcl and graphs and interesting interactors written in Tk, and even a relevant and interesting hardware link with direc tcl/tk interaction. Am I the only one to feel miserable about such comments? http://82.170.247.158/Wiki/are1.gif

or all we all to get lost in this sort of attitude?)

KJN - I consider this page to be very much on-topic for the Wiki, as it is an excellent example of how Tcl/Tk can provide a simple and nice-looking solution to a complex problem. It shows that you can do very nice work without C++ and KDE or the equivalent. I hope this page will encourage people with an interest in sound or signal processing to use Tcl/Tk and Snack.

The page has an accurate title, so it is likely that anyone reaching it from within the Wiki will have a reasonable idea of what the contents will be. Anyone who is not interested is unlikely to follow the link.


The envelope of a sound is perceptually important, and often overlooked in a fourier analysis, see:

Yet the envelope itself influences the perceived and mathematical harmonics of the signal possibly quite a bit. Another important factor when dealing with sounds (as with tcl/tk's snack below) is frequency variation, see:

In fact both envelope adding to a signal or sound and frequency changes will easily generate a theoretically unbounded spectrum, which makes correct sampling of the result impossible without breaking the Shannon sampling frequency condition. Considering the interest amoung tcl users in various kinds of signals and their processing, an important consideration, using the frequency analysis of snack this soon becomes clear, too.

Using snack (version 2.2), I recorded a piano sound , a single note, which you can listen to from here [L1 ] , and of which the (meanwhile well known) waves in the snack main 'xs' window look like this:

http://82.170.247.158/Wiki/pianowave1.jpg

The reason for the double shape of the 'envelope' above is that we actually see the whole wave being drawn in snack, where everywhere the waves goes up or down, black gets drawn, so the boundaries of the black both up and down indicate the envelope.

Assuming we want to mimic the envelope of this example in tcl, we could use the above graph from snack and for instance some form of Polynomial fitting, which then of course would have to do it's job right. And, it's a good practica exercise to make sure that the resulting solutio is numerically decent, and well-controllable, and tcl is of course a good way to test all these things interactively, it being an interpreted language with math built in.

We could take a quadric function for the first segment, so:

 proc attack {npoints} {
    set o {}
    for {set i 0} {$i < $npoints} {incr i} {
       lappend o [expr 1-pow($npoints-$i,2)/pow($npoints,2) ]
    }
    return $o
 }

The quadric is simple, and mainly is constructed by thinking about it's top being at point ($npoints,1.0), and it having a reasonable weight factor for the quadric. Later on I'll go into more elaborate synthesis of such practically useful waveshapes in overseeable tcl code.

I'm not sure it's a good idea to take pow(..,2) as pow(...,2.0), though at some point it might be good to make sure all math is done in floating point.

As a quick test for our application let's run the loop from the tcl prompt, printing the values:

 % set npoints 10 ; for {set i 0} {$i < $npoints} {incr i} { puts [expr 1-pow($npoints-$i,2)/pow($npoints,2) ] }
 0.0
 0.19
 0.36
 0.51
 0.64
 0.75
 0.84
 0.91
 0.96
 0.99

The values go up and eventualy reach 1 (well, nearly).

To see the result on a bwise canvas, or on any Tk canvas of which the path is in the variable 'mc', this long oneliner can help:

 $mc del gr1; set a [attack 32]; set al [llength $a]; set ag {}; for {set i 0} {$i < $al} {incr i} {lappend ag [expr 3*$i] [expr 300-300*[lindex $a $i] ] } ; eval $mc create line $ag -tag gr1

Which shows the intended curveas a line on the canvas.

With the same thinking, a quadric ADSR procedure can look like:

 proc adsr {{attack 16} {decay 32} {sustain 0.5} {release 8} } {
   set o {}
   for {set i 0} {$i < $attack} {incr i} {
      lappend o [expr 1-pow($attack-$i,2)/pow($attack,2) ]
   }
   for {set i 0} {$i < $decay} {incr i} {
     lappend o [expr $sustain+(1.0-$sustain)*pow($decay-$i,2)/pow($decay,2) ] 
   }
   for {set i 0} {$i < $release} {incr i} {
     lappend o [expr $sustain*pow($release-$i,2)/pow($release,2) ]
   }
   return $o
 }

using this adapted oneliner

 $mc del gr1;
 set a [adsr 32 64 0.7 32] ;
 set al [llength $a];
 set ag {}; 
 for {set i 0} {$i < $al} {incr i} {
    lappend ag [expr 3*$i] [expr 300-300*[lindex $a $i] ]
 } ;
 eval $mc create line $ag -tag gr1

the following envelope can be graphed

http://82.170.247.158/Wiki/adsr3.jpg

How do we get from the envelope to the actual sound ? Basically by multiplying the envelope at each point in time with a sample represented signal, for instance a sine wave. In another short script:

 $mc del gr1;                    # delete previous graph from canvas
 set a [adsr 128 256 0.7 64] ;   # make list of envelope values
 set al [llength $a];            # get number of envelope samples
 set ag {};                      # empty result
 for {set i 0} {$i < $al} {incr i} {
    lappend ag [expr 1*$i] \
               [expr 150 - sin($i/3.1415)*150*[lindex $a $i] ]
 } ;
 eval $mc create line $ag -tag gr1

The result looks like this:

http://82.170.247.158/Wiki/adsr4.jpg

Of course the clearness of the envelope in the result depends on the frequency of the signal compared to the lengths of the segments of the envelope: in this exampe it is all well visible, but that isn't necessarily so.

Also, form musical, programming or numerical point of view, this envelope has got 'hard' discontinuities in it, when one segment crosses to the other, which in principle gives an infinite spectrum when the signal isn't preventing that under a fourier transform, which given that signals in a programming language are always sampled in any case gives aliasing errors, so the samples don't unambiguously represent one particualar equivalent continuous signal anymore.

Also, A quadric envelope is just one of the many possible numerical constructions, in electronics, one would easily take a exponential one, which is probably closer to most physical systems, or even a linear approximation, or alternatively, a spline to get rid of the discontinuities.

Given time, I'll to some binary stuff to generate waveforms in tcl, so that no C program is needed to generate example files like wav files. IIRC snack too has binary access possibilities built in, though I'm not experienced with version 2.2 .

Isn't tcl great? Well, it depends on how it is used, but it can be a hell of a laboratory language, as we'll see in other page, too.

TV Nov 23, '04 For those with interest in music and tcl, this page I recently made may be of interest:

   http://82.170.247.158/Soundtest

Related pages: http://members.tripod.com/%7Etheover/bwiseapp.html , http://members.tripod.com/%7Etheover/softsyn.html , http://theover.tripod.com/so1.html

Sampled Signal Reconstruction in Tcl driven Maxima


Category Sound | Category Plotting | Category Signal Processing