How to Generate Arbitrary Waveforms as Envelopes

I am looking for the capability to apply an arbitrary waveform envelope to an audio signal. Something more complex than what can be implemented with ADSR. Is there any way this can be accomplished in Audacity?

CoolEdit/Audition has a drag-and-drop graphical editor for this purpose, but I wouldn’t mind typing in a sequence of X values. Maybe some rounding bewtween points would be useful, as well as fields to set the number of X data points, and the repetition rate of the envelope.

Any suggestions along these lines would be greatly appreciated.

Peter Nielsen

If it is a relatively simple envelope, you can use the Envelope Tool:

If you want an envelope with dozens, or even thousands of points and have a formula to generate the points, it would be possible to create an envelope using a Nyquist Script (Nyquist is a simple programming language that is built into Audacity).
A Nyquist script can either be run in the Nyquist Prompt effect (
or can be made into a plug-in (

An example of a simple Nyquist script that will apply a 1.0 Hz sine wave envelope to the selected track (copy and paste into the Nyquist Prompt effect to apply this to a selected track) :

(mult s 0.5 (sum 1 (hzosc 1)))

Audacity only has the draw tool which only works on individual samples. I think it was intended as a repair tool rather than a production generation tool.


A more complex example. Try applying this to a generated tone:

(setf adsr (pwlv 0 0.05 1 0.3 0.4 0.5 0.4 1 0))
(setq wiggle 0.3)
(setq wigglerate 3)

(setf envelope
  (sim (mult adsr (- 1 (* 2 wiggle)))
    (mult adsr wiggle  (sum 1 (hzosc wigglerate)))))

(mult envelope s)

The envelope tool is very useful, as is the Nyquist “env” function.

But I was thinking of something more like a look-up table, where amplitude points (Y values) are entered at preset X intervals. In other words, a manual process that does not rely upon algebraic functions. The objective is to maximize flexibility. Even a 10x40 grid would provide a workable resolution for many applications.

Useful refinements might include an optional smoothing function and user-defined repetition rate for the generated envelope.

Is something like this beyond the scope of an Audacity plug-in?

Designing a nice interface would be tricky, but the basics of entering a list of numbers and creating an envelope from them is pretty easy.
Nyquist provides a set of functions for creating “piecewise envelopes”, which take lists of points and creates an envelope from those points. The lists are in the form of time/amplitude pairs.

As an example, there is the function PWLV which creates a “piece-wise linear envelope”. “Linear” in the name indicates that the points are joined by straight lines (there is also an exponential version PWEV).
The time of the first point is assumed to be 0, but after that each point is defined as a pair of values (time, amplitude).
The following is a very simple example that rises from 0.1 at time 0, to an amplitude of 1 at time=0.5 and falls to silence at time=1

(pwlv 0.1 0.5 1 1 0)

When used in an effect (or in the Nyquist Prompt effect), the times are, by default, relative to the length of the selection, so a time position of 1.0 refers to the end of the selection.

To apply the envelope, all that is required is to “multiply” the sound by the envelope.
Audacity passes the sound from the selection to Nyquist as a variable called “S”.
So to apply the above envelope to a selected audio track, the following code can be used in the Nyquist Prompt effect:

(mult s
  (pwlv 0.1 0.5 1 1 0))

There is also command that does the same thing, but takes a list of numbers as its input:

(setf point-list (list 0.1 0.5 1 1 0))
(mult s
  (pwlv-list point-list))

The list of points (which have been given the name “point-list” in this example) could have hundreds, or even thousands of points defined.

If we just wanted to add a list of amplitudes that would then be evenly spaced along the sound that we are processing, something like this could be used:

(setf amp-list (list 0.1 1 0))

(setq num (1- (length amp-list)))
(setf point-list (list (first amp-list)))
(dotimes (count num)
  (push (/ (+ 1.0 count) num) point-list)
  (push (nth (1+ count) amp-list) point-list))

(setf point-list (reverse point-list))

(print point-list)

(mult s
  (pwlv-list point-list))

where “amp-list” is out list of amplitudes (in order from left to right along the time line).
The line (print point-list) just prints out the list to the debug window so that we can check which points were used (as time/amplitude pairs). To see the debug output, click the debug button rather than the OK button.

If you were using a very long list (hundreds of points) you would probably want to disable or remove the “print” line. A code line can be disabled by putting a semicolon at the beginning of the line. This is the way that “comments” (to be ignored by the program) are added to a Nyquist script.

; this line will be ignored

… and there’s Steve’s Text Envelope plug-in, where you can enter the values into a text field (I usually Import the values from Excel).
Smoothing and Looping are currently not supported (possible Features?).

Link: Missing features - Audacity Support

I doubt that there is enough user demand to make it a standard feature, but it would probably not be hard to add as a custom feature.

Here’s an idea that you may like:

  1. Create some silence in a mono track,
  2. Zoom in really close
  3. Switch to the Draw Tool and draw an envelope shape.

Select the drawn envelope and apply this code in the Nyquist Prompt to copy the points into memory:

(let ((envlist '()))
  (do ((val (snd-fetch s)(snd-fetch s)))
      ((not val))
    (push val envlist))
  (putprop '*SCRATCH* envlist 'envlist))

(print "done")
  1. Open, import or generate a track to apply the envelope to.
  2. Select the track and run this code in the Nyquist prompt.
;; The next line tells the code to reset (remove) the
;; envelope after processing.
;; Change to 0 if you don't want to reset.
(setq reset 1)

(setf amp-list (get '*SCRATCH* 'envlist))
(setf point-list (list (first amp-list)))

(let ((num (1- (length amp-list))))
  (dotimes (count num)
    (push (- 1.0 (/ count (float num))) point-list)
    (push (nth (1+ count) amp-list) point-list))
  (setf point-list point-list))
; (print point-list)
(when (= reset 1)
  (remprop '*SCRATCH* 'envlist))
(mult s
  (pwlv-list point-list))