Nyquist, like other effects in Audacity, processes in 32 bit float. It is highly recommended that you work in 32 bit float format in Audacity (unless you have a really good overriding reason not to ) 32 bit float format provides extreme accuracy when generating and processing sound. I don’t know how deeply you want to go into the explanation here, but as you’re working with Nyquist I think that you may be interested in the technical details…
Let’s take an example (these snippets can be run in the Nyquist Prompt effect).
For the first part, ensure that your track is 32 bit float format.
Let’s say that we want to generate a short “plink” sound that rises rapidly to 0.25 (-12 dB) and then decays exponentially over about 2 seconds.
We can generate a tone with osc (which has a default duration of 1).
Because we are using the Nyquist Prompt, which is a “process” effect, warp is such that by default 1 second of “local time” is stretched to the duration of the selection - but we don’t want that behaviour here - we want “1” to be “1 second” of actual track time and “2” to be “2 seconds” of actual track time, so we will wrap out code in abs-env so that it is evaluated with “absolute” (global / real) time values. So this will generate a 2 second tone (and it does not matter how long the track selection is)
(osc 72 2))
Now we want to shape the tone with an “envelope”.
Nyquist provides a number of “piece-wise approximation” functions that are really useful for creating envelopes http://www.cs.cmu.edu/~rbd/doc/nyquist/part8.html#index386
Because we want an exponential decay, we can use one of the exponential variants, for example pwev. Now we need to be a bit careful when using these exponential functions because if we set a break-point to have an amplitude of zero, the function will end up trying to calculate “log 0” which is undefined/infinite. To avoid this, we will define a very small number:
(setq zero (/ (power 2 16)))
So now we can create an envelope that rises in, say 2 milliseconds, from “zero” (our very small number) up to 0.25, then decays exponentially over the rest of the 2 seconds duration to “zero”
(pwev zero 0.002 0.25 2 zero))
In order to apply our envelope to the tone, all we need to do is to “multiply” the tone by the envelope. Thus, each sample value of the sound (the tone) is multiplied by the corresponding sample value of the envelope:
(setq zero (/ (power 2 16)))
(mult (pwev zero 0.002 0.25 2 zero)
(osc 72 2))))
And there is our “plink”
Now, let’s see close up what is happening at the very end of the “plink”.
We will now use a second piece of code to amplify the Plink with an envelope that expands rapidly from an amplitude of 1 to a very large value.
We don’t need to use abs-env this time because we can just select the entire tone (which is 2 second duration in “real” time, but is stretched to “1” in “local” time because we are applying a process type effect).
For the “reverse envelope” we will use:
(pwev 1 1 (power 2 14))
This envelope rises exponentially from 1 (which will give unity gain when we multiply the sound by "1) up to 2^14 (which, if my arithmetic is correct should give us an end amplitude of 0.25)
(mult s (pwev 1 1 (power 2 14)))
Assuming that you are using a 32 bit float format track, you should now have a fairly constant tone, amplitude 0.25 and duration 2 seconds (still has the fast fade-in at the start).
Now try the same steps with a 16 bit track
The problem here is that our original plink went so quiet that the 16 bit format “ran out of bits” - Audacity did it’s best to “round” the sample values, but when we amplified the end of the plink to 16384 times it’s original level we run head on into the “dither noise”