Previous Section | Next Section | Table of Contents | Index | Title Page

## Nyquist Functions

This chapter provides a language reference for Nyquist. Operations are categorized by functionality and abstraction level. Nyquist is implemented in two important levels: the “high level” supports behavioral abstraction, which means that operations like `stretch` and `at` can be applied. These functions are the ones that typical users are expected to use, and most of these functions are written in XLISP.

The “low-level” primitives directly operate on sounds, but know nothing of environmental variables (such as `*warp*`, etc.). The names of most of these low-level functions start with “`snd-`”. In general, programmers should avoid any function with the “`snd-`” prefix. Instead, use the “high-level” functions, which know about the environment and react appropriately. The names of high-level functions do not have prefixes like the low-level functions.

There are certain low-level operations that apply directly to sounds (as opposed to behaviors) and are relatively “safe” for ordinary use. These are marked as such.

Nyquist uses both linear frequency and equal-temperament pitch numbers to specify repetition rates. Frequency is always specified in either cycles per second (hz), or pitch numbers, also referred to as “steps,” as in steps of the chromatic scale. Steps are floating point numbers such that 60 = Middle C, 61 = C#, 61.23 is C# plus 23 cents, etc. The mapping from pitch number to frequency is the standard exponential conversion, and fractional pitch numbers are allowed:

> frequency = 440 * 2((pitch - 69)/12)

There are many predefined pitch names. By default these are tuned in equal temperament, with A4 = 440Hz, but these may be changed. (See Section Predefined Constants).

### Sounds

A sound is a primitive data type in Nyquist. Sounds can be created, passed as parameters, garbage collected, printed, and set to variables just like strings, atoms, numbers, and other data types.

#### What is a Sound?

Sounds have 5 components:

- `srate` – the sample rate of the sound.
- `samples` – the samples.
- `signal-start` – the time of the first sample.
- `signal-stop` – the time of one past the last sample.
- `logical-stop` – the time at which the sound logically ends, e.g. a sound may end at the beginning of a decay. This value defaults to `signal-stop`, but may be set to any value.

It may seem that there should be `logical-start` to indicate the logical or perceptual beginning of a sound as well as a `logical-stop` to indicate the logical ending of a sound. In practice, only `logical-stop` is needed; this attribute tells when the next sound should begin to form a sequence of sounds. In this respect, Nyquist sounds are asymmetric: it is possible to compute sequences forward in time by aligning the logical start of each sound with the `logical-stop` of the previous one, but one cannot compute “backwards”, aligning the logical end of each sound with the logical start of its successor. The root of this asymmetry is the fact that when we invoke a behavior, we say when to start, and the result of the behavior tells us its logical duration. There is no way to invoke a behavior with a direct specification of when to stop (Footnote 3) . Note: there is no way to enforce the intended “perceptual” interpretation of `logical-stop`. As far as Nyquist is concerned, these are just numbers to guide the alignment of sounds within various control constructs.

#### Multichannel Sounds

Multichannel sounds are represented by Lisp arrays of sounds. To create an array of sounds the XLISP `vector` function is useful. Most low-level Nyquist functions (the ones starting with `snd-`) do not operate on multichannel sounds. Most high-level functions do operate on multichannel sounds.

#### Accessing and Creating Sound

Several functions display information concerning a sound and can be used to query the components of a sound. There are functions that access samples in a sound and functions that construct sounds from samples.

`sref(sound, time)` [SAL]
`(sref sound time)` [LISP]
  Accesses sound at the point time, which is a local time. If time does not correspond to a sample time, then the nearest samples are linearly interpolated to form the result. To access a particular sample, either convert the sound to an array (see `snd-samples` below), or use `snd-srate` and `snd-t0` (see below) to find the sample rate and starting time, and compute a time (t) from the sample number (n):

  > t = (n / srate) + t0

  Thus, the Lisp code to access the nth sample of a sound would look like:

      (sref sound (global-to-local (+ (/ n (snd-srate sound)) (snd-t0 sound))))

  Or in SAL, it would look like:

      sref(sound, global-to-local(n / snd-srate(sound) + snd-t0(sound)))

  Here is why `sref` interprets its time argument as a local time (shown first in LISP and then in SAL syntax):

      > (sref (ramp 1) 0.5) ; evaluate a ramp at time 0.5
      0.5
      SAL> print sref(ramp(1), 0.5) ; evaluate a ramp at time 0.5
      0.5
      > (at 2.0 (sref (ramp 1) 0.5)) ; ramp is shifted to start at 2.0
      		; the time, 0.5, is shifted to 2.5
      0.5
      SAL> sref(ramp(1), 0.5) @ 2.0 ; ramp is shifted to start at 2.0
      		; the time, 0.5, is shifted to 2.5
      0.5

  If you were to use `snd-sref`, which treats time as global, instead of `sref`, which treats time as local, then the first example above would return the same answer (0.5), but the second example would return 0. Why? Because the `ramp` behavior would be shifted to start at time 2.0, but the resulting sound would be evaluated at global time 0.5. By definition, sounds have a value of zero before their start time.

`sref-inverse(sound, value)` [SAL]
`(sref-inverse sound value)` [LISP]
  Search sound for the first point at which it achieves value and return the corresponding (linearly interpolated) time. If no inverse exists, an error is raised. This function is used by Nyquist in the implementation of time warping.
`snd-from-array(t0, sr, array)` [SAL]
`(snd-from-array t0 sr array)` [LISP]
  Converts a lisp array of `FLONUM`s into a sound with starting time t0 and sample rate sr. Safe for ordinary use. Be aware that arrays of floating-point samples use 14 bytes per sample, and an additional 4 bytes per sample are allocated by this function to create a sound type.
`snd-fromarraystream(t0, sr, object)` [SAL]
`(snd-fromarraystream t0 sr object)` [LISP]
  Creates a sound for which samples come from object. The starting time is t0 (a `FLONUM`), and the sample rate is sr. The object is an XLISP object (see Section Objects for information on objects.) A sound is returned. When the sound needs samples, they are generated by sending the message `:next` to object. If object returns `NIL`, the sound terminates. Otherwise, object must return an array of `FLONUM`s. The values in these arrays are concatenated to form the samples of the resulting sound. In the current implementation, all arrays must have the same length. There is no provision for object to specify the logical stop time of the sound, so the logical stop time is the termination time.
`snd-fromobject(t0, sr, object)` [SAL]
`(snd-fromobject t0 sr object)` [LISP]
  Creates a sound for which samples come from object. The starting time is t0 (a `FLONUM`), and the sample rate is sr. The object is an XLISP object (see Section Objects for information on objects. A sound is returned. When the sound needs samples, they are generated by sending the message `:next` to object. If object returns `NIL`, the sound terminates. Otherwise, object must return a `FLONUM`. There is no provision for object to specify the logical stop time of the sound, so the logical stop time is the termination time.
`snd-extent(sound, maxsamples)` [SAL]
`(snd-extent sound maxsamples)` [LISP]
  Returns a list of two numbers: the starting time of sound and the terminate time of sound. Finding the terminate time requires that samples be computed. Like most Nyquist functions, this is non-destructive, so memory will be allocated to preserve the sound samples. If the sound is very long or infinite, this may exhaust all memory, so the maxsamples parameter specifies a limit on how many samples to compute. If this limit is reached, the terminate time will be (incorrectly) based on the sound having maxsamples samples. This function is safe for ordinary use.
`snd-fetch(sound)` [SAL]
`(snd-fetch sound)` [LISP]
  Reads samples sequentially from sound. This returns a `FLONUM` after each call, or `NIL` when sound terminates. Note: `snd-fetch` modifies sound; it is strongly recommended to copy sound using `snd-copy` and access only the copy with `snd-fetch`.
`snd-fetch-array(sound, len, step)` [SAL]
`(snd-fetch-array sound len step)` [LISP]
  Reads sequential arrays of samples from sound, returning either an array of `FLONUM`s or `NIL` when the sound terminates. The len parameter, a `FIXNUM`, indicates how many samples should be returned in the result array. After the array is returned, sound is modified by skipping over step (a `FIXNUM`) samples. If step equals len, then every sample is returned once. If step is less than len, each returned array will overlap the previous one, so some samples will be returned more than once. If step is greater than len, then some samples will be skipped and not returned in any array. The step and len may change at each call, but in the current implementation, an internal buffer is allocated for sound on the first call, so subsequent calls may not specify a greater len than the first. When an array is returned, it will have len samples. If necessary, `snd-fetch-array` will read zeros beyond the end of the sound to fill the array. When this happens, `*rslt*` is set to a FIXNUM number of samples in the array that were read from the sound before the physical stop time of the sound. If all samples in the array are “valid” samples from the sound (coming from the sound before the sound terminates), `*rslt*` is set to `NIL`. The `*rslt*` variable is global and used to return extra results from other functions, so programs should not assume `*rslt*` is valid after subsequent function calls. Note: `snd-fetch-array` modifies sound; it is strongly recommended to copy sound using `snd-copy` and access only the copy with `snd-fetch-array`.
`snd-flatten(sound, maxlen)` [SAL]
`(snd-flatten sound maxlen)` [LISP]
  This function is identical to `snd-length`. You would use this function to force samples to be computed in memory. Normally, this is not a good thing to do, but here is one appropriate use: In the case of sounds intended for wavetables, the unevaluated sound may be larger than the evaluated (and typically short) one. Calling `snd-flatten` will compute the samples and allow the unit generators to be freed in the next garbage collection. Note: If a sound is computed from many instances of table-lookup oscillators, calling `snd-flatten` will free the oscillators and their tables. Calling `(stats)` will print how many total bytes have been allocated to tables.
`snd-length(sound, maxlen)` [SAL]
`(snd-length sound maxlen)` [LISP]
  Counts the number of samples in sound up to the physical stop time. If the sound has more than maxlen samples, maxlen is returned. Calling this function will cause all samples of the sound to be computed and saved in memory (about 4 bytes per sample). Otherwise, this function is safe for ordinary use.
`snd-maxsamp(sound)` [SAL]
`(snd-maxsamp sound)` [LISP]
  Computes the maximum of the absolute value of the samples in sound. Calling this function will cause samples to be computed and saved in memory. (This function should have a maxlen parameter to allow self-defense against sounds that would exhaust available memory.) Otherwise, this function is safe for ordinary use. This function will probably be removed in a future version. See `peak`, a replacement (Signal Operations).
`snd-play(expression)` [SAL]
`(snd-play expression)` [LISP]
  Evaluates expression to obtain a sound, computes all of the samples (without retaining them in memory), and returns the number of samples computed. Originally, this was a placeholder for a facility to play samples directly to an audio output device, but playback is now accomplished by `s-save`. Meanwhile, since this function does not write samples to a file, it is useful in determining how much time is spent calculating samples. See `s-save` (Section Sound File Input and Output) for saving samples to a file, and `play` (Section Sound File Input and Output) to play a sound. This function is safe for ordinary use. Note that it does not accept multichannel sounds. To time mult-channel sound computation, you might try applying `to-mono` (see Section Miscellaneous Functions) to get a SOUND.
`snd-print-tree(sound)` [SAL]
`(snd-print-tree sound)` [LISP]
  Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging Nyquist. This function is safe for ordinary use.
`snd-samples(sound, limit)` [SAL]
`(snd-samples sound limit)` [LISP]
  Converts the samples into a lisp array. The data is taken directly from the samples, ignoring shifts. For example, if the sound starts at 3.0 seconds, the first sample will refer to time 3.0, not time 0.0. A maximum of limit samples is returned. This function is safe for ordinary use, but like `snd-from-array`, it requires a total of slightly over 18 bytes per sample.
`snd-srate(sound)` [SAL]
`(snd-srate sound)` [LISP]
  Returns the sample rate of the sound. Safe for ordinary use.
`snd-time(sound)` [SAL]
`(snd-time sound)` [LISP]
  Returns the start time of the sound. This will probably go away in a future version, so use `snd-t0` instead.
`snd-t0(sound)` [SAL]
`(snd-t0 sound)` [LISP]
  Returns the time of the first sample of the sound. Note that Nyquist operators such as add always copy the sound and are allowed to shift the copy up to one half sample period in either direction to align the samples of two operands. Safe for ordinary use.
`snd-print(expression, maxlen)` [SAL]
`(snd-print expression maxlen)` [LISP]
  Evaluates expression to yield a sound or an array of sounds, then prints up to maxlen samples to the screen (stdout). This is similar to `snd-save`, but samples appear in text on the screen instead of in binary in a file. This function is intended for debugging. Safe for ordinary use.
`snd-set-logical-stop(sound, time)` [SAL]
`(snd-set-logical-stop sound time)` [LISP]
  Returns a sound which is sound, except that the logical stop of the sound occurs at time. Note: do not call this function. When defining a behavior, use `set-logical-stop` or `set-logical-stop-abs` instead.
`snd-sref(sound, time)` [SAL]
`(snd-sref sound time)` [LISP]
  Evaluates sound at the global time given by time. Safe for ordinary use, but normally, you should call `sref` instead.
`snd-stop-time(sound)` [SAL]
`(snd-stop-time sound)` [LISP]
  Returns the stop time of sound. Sounds can be “clipped” or truncated at a particular time. This function returns that time or MAX-STOP-TIME if he programmer has not specified a stop time for the sound. Safe for ordinary use.
`soundp(sound)` [SAL]
`(soundp sound)` [LISP]
  Returns true iff sound is a SOUND. Safe for ordinary use.
`stats()` [SAL]
`(stats)` [LISP]
  Prints the memory usage status. See also the XLISP `mem` function. Safe for ordinary use. This is the only way to find out how much memory is being used by table-lookup oscillator instances.
`snd-set-max-audio-mem(bytes)` [SAL]
`(snd-set-max-audio-mem bytes)` [LISP]
  Sets a limit (a FIXNUM in bytes) on the amount of main memory that Nyquist will allocate for SOUNDs (this does not count table memory). The default is about 1GB. The return value is the previous limit, in bytes. This is not a limit on how big sounds can be. Since Nyquist computes sound incrementally, it can generally play sounds or write sounds to files without storing them in memory. However, if you store large sounds in variables, memory usage can exceed your available RAM, causing extremely slow computation as main memory is swapped to and from disk or Nyquist might run out of memory and crash. The goal of placing a limit on audio memory is to terminate computations before memory is totally exhausted, allowing Nyquist to print an error message and allowing the user to view or save work. Generally, if you see the message “The maximum number of sample blocks has been reached, ...,” you should fix your code to avoid accumulating samples in memory, e.g. do not assign sounds to global variables. Alternatively, you can use this function to increase the limit, but of course you are still limited by the actual size of memory on your computer, and exceeding that could cause severe performance problems in Nyquist and and any other applications that are running. See also Section Command Line for command line options to limit yquist memory, run time, and file access (these options are not available through the NyquistIDE.)

#### Miscellaneous Functions

These are all safe and recommended for ordinary use.

`to-mono(sound)` [SAL]
`(to-mono sound)` [LISP]
  Returns the sum of all channels of sound if it is a multichannel sound. If sound is a SOUND, it is simply returned unchanged. See `sim` (Section Combination and Time Structure) for more details on how channels are summed.
`db-to-linear(x)` [SAL]
`(db-to-linear x)` [LISP]
  Returns the conversion of x from decibels to linear. 0dB is converted to 1. 20dB represents a linear factor of 10. If x is a sound, each sample is converted and a sound is returned. If x is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. Note: With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Sample rates, start times, etc. are taken from x.
`db-to-vel(x [, float])` [SAL]
`(db-to-vel x [float])` [LISP]
  Returns the conversion of x from decibels to MIDI velocity using a rule that maps -60 dB to 1 and 0 dB to 127. The MIDI velocity varies linearly with the square root of amplitude. The default value of float is `nil` and the result is a `FIXNUM` clipped to fall in the legal range of 1-127, but if a non-`nil` value is provided, the result is a `FLONUM` that is not rounded or clipped. The input parameter must be a `FIXNUM` or `FLONUM`. Sounds are not allowed.
`follow(sound, floor, risetime, falltime, lookahead)` [SAL]
`(follow sound floor risetime falltime lookahead)` [LISP]
  An envelope follower intended as a commponent for compressor and limiter functions. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The floor is the minimum output value. The risetime is the time (in seconds) it takes for the output to rise (exponentially) from floor to unity (1.0) and the falltime is the time it takes for the output to fall (exponentially) from unity to floor. The algorithm looks ahead for peaks and will begin to increase the output signal according to risetime in anticipation of a peak. The amount of anticipation (in seconds) is given by lookahead. The algorithm is as follows: the output value is allowed to increase according to risetime or decrease according to falltime. If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to risetime to meet the new value. The algorithm will only work backward as far as lookahead. If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by falltime, the output fall rate will be limited by falltime, and the fall in output will stop when the output reaches floor. This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See `snd-avg` for a function that can help to generate a low-sample-rate input for `follow`. See `snd-chase` in Section Filters for a related filter.
`gate(sound, lookahead, risetime, falltime, floor, threshold)` [SAL]
`(gate sound lookahead risetime falltime floor threshold)` [LISP]
  Generate an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below threshold and stays there for longer than lookahead (a `FLONUM` in seconds). (The signal begins to drop when the signal crosses threshold, not after lookahead.) Decay continues until the value reaches floor (a `FLONUM`), at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the output value will rise to unity (1.0) at the point the signal crosses the threshold. Because of internal lookahead, the signal actually begins to rise before the signal crosses threshold. The rise is a constant-rate exponential and set so that a rise from floor to unity occurs in risetime. Similary, the fall is a constant-rate exponential such that a fall from unity to floor takes falltime.
`noise-gate(sound [, lookahead, risetime, falltime, floor, threshold] [, rms: use-rms, link: link-option])` [SAL]
`(noise-gate sound [lookahead risetime falltime floor threshold] [:rms use-rms :link link-option])` [LISP]
  A simple noise gate implementation based on `gate`. All parameters except snd are optional and default values are lookahead: 0.5, risetime: 0.02, falltime: 0.5, floor: 0.01, threshold: 0.01. The keyword parameters `:rms` and `:link` are also optional with default values of use-rms: `NIL` (false) and link-option: T (true). The result is the input snd, where below-threshold segments of sound are attenuated to a maximum of floor (see the `gate` function above). If use-rms is non-NIL, the threshold applies to the RMS of the sound computed with 10 ms non-overlapping rectangular windows. Otherwise, threshold applies to the absolute value of each sample in sound. If link-option is non-NIL, and if the input sound is multichannel, then a single gate is computed and applied to all channels. The gate threshold is considered to be exceeded when any channel would exceed the threshold and open the gate. (In other words, whether use-rms or not, a maximum value is computed from all the channels and used to control the gate.)
`hz-to-step(freq)` [SAL]
`(hz-to-step freq)` [LISP]
  Returns a step number for freq (in hz), which can be either a number of a `SOUND`. The result has the same type as the argument. See also `step-to-hz` (below).
`linear-to-db(x)` [SAL]
`(linear-to-db x)` [LISP]
  Returns the conversion of x from linear to decibels. 1 is converted to 0. 0 is converted to -INF (a special IEEE floating point value.) A factor of 10 represents a 20dB change. If x is a sound, each sample is converted and a sound is returned. If x is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. Note: With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Start times, sample rates, etc. are taken from x.
`linear-to-vel(x [, float])` [SAL]
`(linear-to-vel x [float])` [LISP]
  Returns the conversion of x from linear amplitude to MIDI velocity using a rule that maps -60 dB to 1 and 0 dB to 127. The MIDI velocity varies linearly with the square root of amplitude. The default value of float is `nil` and the result is a `FIXNUM` clipped to fall in the legal range of 1-127, but if a non-`nil` value is provided, the result is a `FLONUM` that is not rounded or clipped. The input parameter must be a `FIXNUM` or `FLONUM`. Sounds are not allowed.
`log(x)` [SAL]
`(log x)` [LISP]
  Calculates the natural log of x (a `FLONUM`). (See `s-log` for a version that operates on signals.)
`set-control-srate(rate)` [SAL]
`(set-control-srate rate)` [LISP]
  Sets the default sampling rate for control signals to rate by setting `*default-control-srate*` and reinitializing the environment. Do not call this within any synthesis function (see the `control-srate-abs` transformation, Section Transformations).
`set-sound-srate(rate)` [SAL]
`(set-sound-srate rate)` [LISP]
  Sets the default sampling rate for audio signals to rate by setting `*default-sound-srate*` and reinitializing the environment. Do not call this within any synthesis function (see the `sound-srate-abs` transformation, Section Transformations).
`set-pitch-names()` [SAL]
`(set-pitch-names)` [LIS]
  Initializes pitch variables (`c0`, `cs0`, `df0`, `d0`, ... `b0`, `c1`, ... `b7`). A440 (the default tuning) is represented by the step 69.0, so the variable `a4` (fourth octave A) is set to 69.0. You can change the tuning by setting `*A4-Hertz*` to a value (in Hertz) and calling `set-pitch-names` to reinitialize the pitch variables. Note that this will result in non-integer step values. It does not alter the mapping from step values to frequency. There is no built-in provision for stretched scales or non-equal temperament, although users can write or compute any desired fractional step values.
`step-to-hz(pitch)` [SAL]
`(step-to-hz pitch)` [LISP]
  Returns a frequency in hz for pitch, a step number or a `SOUND` type representing a time-varying step number. The result is a `FLONUM` if pitch is a number, and a `SOUND` if pitch is a `SOUND`. See also `hz-to-step` (above).
`get-ioi(dur)` [SAL]
`(get-ioi dur)` [LISP]
  Gets the duration of of something starting at a local time of 0 and ending at a local time of dur. For convenience, `*rslt*` is set to the global time corresponding to local time zero. Note that sustain is ignored in this calculation. The intent is to calculate the nominal start time of the next event in a sequence (or the logical stop time of the current event) rather than the actual sound duration of the current event.
`get-duration(dur)` [SAL]
`(get-duration dur)` [LISP]
  Gets the actual duration of of something starting at a local time of 0 and ending at a local time of dur times the current sustain. For convenience, `*rslt*` is set to the global time corresponding to local time zero. See also `get-ioi` (above).
`get-loud()` [SAL]
`(get-loud)` [LISP]
  Gets the current value of the `*loud*` environment variable. If `*loud*` is a signal, it is evaluated at local time 0 and a number (`FLONUM`) is returned.
`get-sustain()` [SAL]
`(get-sustain)` [LISP]
  Gets the current value of the `*sustain*` environment variable. If `*sustain*` is a signal, it is evaluated at local time 0 and a number (`FLONUM`) is returned.
`get-transpose()` [SAL]
`(get-transpose)` [LISP]
  Gets the current value of the `*transpose*` environment variable. If `*transpose*` is a signal, it is evaluated at local time 0 and a number (`FLONUM`) is returned.
`get-warp()` [SAL]
`(get-warp)` [LISP]
  Gets a function corresponding to the current value of the `*warp*` environment variable. For efficiency, `*warp*` is stored in three parts representing a shift, a scale factor, and a continuous warp function. `Get-warp` is used to retrieve a signal that maps logical time to real time. This signal combines the information of all three components of `*warp*` into a single signal. If the continuous warp function component is not present (indicating that the time warp is a simple combination of `at` and `stretch` transformations), an error is raised. This function is mainly for internal system use. In the future, `get-warp` will probably be reimplemented to always return a signal and never raise an error.
`local-to-global(local-time)` [SAL]
`(local-to-global local-time)` [LISP]
  Converts a score (local) time to a real (global) time according to the current environment.
`round(x)` [SAL]
`(round x)` [LISP]
  Round x to the nearest integer. If x is n + 0.5, where n is an integer, then return n + 1, even if n is negative.
`snd-set-latency(latency)` [SAL]
`(snd-set-latency latency)` [LISP]
  Set the latency requested when Nyquist plays sound to latency, a `FLONUM`. The previous value is returned. The default is 0.3 seconds. To avoid glitches, the latency should be greater than the time required for garbage collection and message printing and any other system activity external to Nyquist.
`vel-to-db(x)` [SAL]
`(vel-to-db x)` [LISP]
  Returns the conversion of x from MIDI velocity to decibels using a rule that maps MIDI velocity 1 to -60 dB and 127 to 0 dB. The amplitude is proportional to the square of MIDI velocity. The input x can be a `FIXNUM` or `FLONUM` but not a sound. The result is a `FLONUM`.
`vel-to-linear(x)` [SAL]
`(vel-to-linear x)` [LISP]
  Returns the conversion of x from MIDI velocity to linear amplitude ratio using a rule that maps MIDI velocity 1 to -60 dB (0.001) and 127 to unity gain. The amplitude is proportional to the square of MIDI velocity. The input x can be a `FIXNUM` or `FLONUM` but not a sound. The result is a `FLONUM`.

### Behaviors

#### Using Previously Created Sounds

These behaviors take a sound and transform that sound according to the environment. These are useful when writing code to make a high-level function from a low-level function, or when cuing sounds which were previously created:

`cue(sound)` [SAL]
`(cue sound)` [LISP]
  Applies `*loud*`, the starting time from `*warp*`, `*start*`, and `*stop*` to sound.
`cue-file(filename)` [SAL]
`(cue-file filename)` [LISP]
  Same as `cue`, except the sound comes from the named file, samples from which are coerced to the current default `*sound-srate*` sample rate.
`sound(sound)` [SAL]
`(sound sound)` [LISP]
  Applies `*loud*`, the starting time and (possibly continuously varying) stretching from `*warp*`, `*start*`, and `*stop*` to sound.
`control(sound)` [SAL]
`(control sound)` [LISP]
  This function is identical to `sound`, but by convention is used when sound is a control signal rather than an audio signal.

#### Sound Synthesis

These functions provide musically interesting creation behaviors that react to their environment; these are the “unit generators” of Nyquist:

`const(value [, duration])` [SAL]
`(const value [duration])` [LISP]
  Creates a constant function at the `*control-srate*`. Every sample has the given value, and the default duration is 1.0. See also `s-rest`, which is equivalent to calling `const` with zero, and note that you can pass scalar constants (numbers) to `sim`, `sum`, and `mult` where they are handled more efficiently than constant functions.
`env(t1, t2, t4, l1, l2, l3, [dur])` [SAL]
`(env t1 t2 t4 l1 l2 l3 dur)` [LISP]
  Creates a 4-phase envelope. ti is the duration of phase i, and li is the final level of phase i. t3 is implied by the duration dur, and l4 is `0.0`. If dur is not supplied, then `1.0` is assumed. The envelope duration is the product of dur, `*stretch*`, and `*sustain*`. If t1 + t2 + 2ms + t4 is greater than the envelope duration, then a two-phase envelope is substituted that has an attack/release time ratio of t1/t4. The sample rate of the returned sound is `*control-srate*`. (See `pwl` for a more general piece-wise linear function generator.) The effect of time warping is to warp the starting time and ending time. The intermediate breakpoints are then computed as described above.
`exp-dec(hold, halfdec, length)` [SAL]
`(exp-dec hold halfdec length)` [LISP]
  This convenient envelope shape is a special case of `pwev` (see Section Piece-wise Approximations). The envelope starts at 1 and is constant for hold seconds. It then decays with a half life of halfdec seconds until length. (The total duration is length.) In other words, the amplitude falls by half each halfdec seconds. When stretched, this envelope scales linearly, which means the hold time increases and the half decay time increases.
`force-srate(srate, sound)` [SAL]
`(force-srate srate sound)` [LISP]
  Returns a sound which is up- or down-sampled to srate. Interpolation is linear, and no prefiltering is applied in the down-sample case, so aliasing may occur. See also `resample`.
`lfo(freq [, duration, table, phase])` [SAL]
`(lfo freq duration table phase)` [LISP]
  Just like `osc` (below) except this computes at the `*control-srate*` and frequency is specified in Hz. Initial phase is specified in degrees, defaulting to zero. The `*transpose*` and `*sustain*` is not applied. The effect of time warping is to warp the starting and ending times. The signal itself will have a constant unwarped frequency.
`fmlfo(freq [, table, phase])` [SAL]
`(fmlfo freq [table phase])` [LISP]
  A low-frequency oscillator that computes at the `*control-srate*` using a sound to specify a time-varying frequency in Hz. Initial phase is a `FLONUM` in degrees. The duration of the result is determined by freq.
`maketable(sound)` [SAL]
`(maketable sound)` [LISP]
  Assumes that the samples in sound constitute one period of a wavetable, and returns a wavetable suitable for use as the table argument to the `osc` function (see below). Currently, tables are limited to 100,000,000 samples. This limit is the compile-time constant `max_table_len` set in `sound.h`. A wavetable is a list of the form

  > (sound pitch-number periodic)

  where the first element is a sound, the second is the pitch of the sound (this is not redundant, because the sound may represent any number of periods), and the third element is `T` if the sound is one period of a periodic signal, or `nil` if the sound is a sample that should not be looped. Wavetables are used by `osc`, `osc`, `hzosc`, `amosc`, `fmosc`, `lfo`, and `fmlfo`.
`build-harmonic(n, table-size)` [SAL]
`(build-harmonic n table-size)` [LISP]
  Intended for constructing wavetables, this function returns a sound of length table-size samples containing n periods of a sinusoid. These can be scaled and summed to form a waveform with the desired harmonic content. See Non-Sinusoidal Waveforms for an example. A scaled sum of these harmonics can be passed to `maketable` to construct a wavetable suitable for `osc` and other oscillators.
`control-warp(warp-fn, signal, [wrate])` [SAL]
`(control-warp warp-fn signal wrate)` [LISP]
  Applies a warp function warp-fn to signal using function composition. If wrate is omitted, linear interpolation is used. warp-fn is a mapping from score (logical) time to real time, and signal is a function from score time to real values. The result is a function from real time to real values at a sample rate of `*control-srate*`. See `sound-warp` for an explanation of wrate and high-quality warping.
`mult(beh1, beh2, ...)` [SAL]
`(mult beh1 beh2 ...)` [LISP]
  Returns the product of behaviors. The arguments may also be numbers, in which case simple multiplication is performed. If a number and sound are mixed, the `scale` function is used to scale the sound by the number. When sounds are multiplied, the resulting sample rate is the maximum sample rate of the factors.
`prod(beh1, beh2, ...)` [SAL]
`(prod beh1 beh2 ...)` [LISP]
  Same as `mult`.
`pan(sound, where)` [SAL]
`(pan sound where)` [LISP]
  Pans sound (a behavior) according to where (another behavior or a number). Sound must be monophonic. Where may be a monophonic sound (e.g. `(ramp)` or simply a number (e.g. `0.5`). In either case, where should range from 0 to 1, where 0 means pan completely left, and 1 means pan completely right. For intermediate values, the sound to each channel is scaled linearly. Presently, `pan` does not check its arguments carefully.
`prod(beh1, beh2, ...)` [SAL]
`(prod beh1 beh2 ...)` [LISP]
  Same as `mult`.
`resample(sound, srate)` [SAL]
`(resample sound srate)` [LISP]
  Similar to `force-srate`, except high-quality interpolation is used to prefilter and reconstruct the signal at the new sample rate. Also, the result is scaled by 0.95 to reduce problems with clipping. (See also `sound-warp`.)
`scale(scale, sound)` [SAL]
`(scale scale sound)` [LISP]
  Scales the amplitude of sound by the factor scale. Identical function to `snd-scale`, except that it handles multichannel sounds. Sample rates, start times, etc. are taken from sound.
`scale-db(db, sound)` [SAL]
`(scale-db db sound)` [LISP]
  Scales the amplitude of sound by the factor db, expressed in decibels. Sample rates, start times, etc. are taken from sound.
`scale-srate(sound, scale)` [SAL]
`(scale-srate sound scale)` [LISP]
  Scales the sample rate of sound by scale factor. This has the effect of linearly shrinking or stretching time (the sound is not upsampled or downsampled). This is a special case of `snd-xform` (see Section Signal Operations).
`shift-time(sound, shift)` [SAL]
`(shift-time sound shift)` [LISP]
  Shift sound by shift seconds. If the sound is f(t), then the result is f(t - shift). See Figure 5. This is a special case of `snd-xform` (see Section Signal Operations).

Figure 5: The `shift-time` function shifts a sound in time according to its shift argument.

`sound-warp(warp-fn, signal [, wrate])` [SAL]
`(sound-warp warp-fn signal [wrate])` [LISP]
  Applies a warp function warp-fn to signal using function composition. If the optional parameter wrate is omitted or NIL, linear interpolation is used. Otherwise, high-quality sample interpolation is used, and the result is scaled by 0.95 to reduce problems with clipping (interpolated samples can exceed the peak values of the input samples.) warp-fn is a mapping from score (logical) time to real time, and signal is a function from score time to real values. The result is a function from real time to real values at a sample rate of `*sound-srate*`. See also `control-warp`. If wrate is not NIL, it must be a number. The parameter indicates that high-quality resampling should be used and specifies the sample rate for the inverse of warp-fn. Use the lowest number you can. (See below for details.) Note that high-quality resampling is much slower than linear interpolation. To perform high-quality resampling by a fixed ratio, as opposed to a variable ratio allowed in `sound-warp`, use `scale-srate` to stretch or shrink the sound, and then `resample` to restore the original sample rate. `Sound-warp` and `control-warp` both take the inverse of warp-fn to get a function from real time to score time. Each sample of this inverse is thus a score time; signal is evaluated at each of these score times to yield a value, which is the desired result. The sample rate of the inverse warp function is somewhat arbitrary. With linear interpolation, the inverse warp function sample rate is taken to be the output sample rate. Note, however, that the samples of the inverse warp function are stored as 32-bit floats, so they have limited precision. Since these floats represent sample times, rounding can be a problem. Rounding in this case is equivalent to adding jitter to the sample times. Nyquist ignores this problem for ordinary warping, but for high-quality warping, the jitter cannot be ignored. The solution is to use a rather low sample rate for the inverse warp function. `Sound-warp` can then linearly interpolate this signal using double-precision floats to minimize jitter between samples. The sample rate is a compromise: a low sample rate minimizes jitter, while a high sample rate does a better job of capturing detail (e.g. rapid fluctuations) in the warp function. A good rule of thumb is to use at most 1,000 to 10,000 samples for the inverse warp function. For example, if the result will be 1 minute of sound, use a sample rate of 3000 samples / 60 seconds = 50 samples/second. Because Nyquist has no advance information about the warp function, the inverse warp function sample rate must be provided as a parameter. When in doubt, just try something and let your ears be the judge.
`integrate(signal)` [SAL]
`(integrate signal)` [LISP]
  Computes the integral of signal. The start time, sample rate, etc. are taken from signal.
`slope(signal)` [SAL]
`(slope signal)` [LISP]
  Computes the first derivative (slope) of signal. The start time, sample rate, etc. are taken from signal.

##### Oscillators

`osc(pitch [, duration, table, phase])` [SAL]
`(osc pitch [duration table phase])` [LISP]
  Returns a sound which is the table oscillated at pitch for the given duration, starting with the phase (in degrees). Defaults are: duration `1.0` (second), table `*table*`, phase `0.0`. The default value of `*table*` is a sinusoid. Duration is stretched by `*warp*` and `*sustain*`, amplitude is nominally 1, but scaled by `*loud*` (in dB), the start time is logical time 0, transformed by `*warp*`, and the sample rate is `*sound-srate*`. The effect of time-warping is to warp the starting and ending times only; the signal has a constant unwarped frequency.
  Note 1: A `table` is 3-element list. See `maketable` for a detailed description.
  Note 2: in the current implementation, it is assumed that the output should be periodic. See `snd-down` and `snd-up` for resampling one-shot sounds to a desired sample rate. A future version of `osc` will handle both cases.
  Note 3: When `osc` is called, memory is allocated for the table, and samples are copied from the sound (the first element of the list which is the table parameter) to the memory. Every instance of `osc` has a private copy of the table, so the total storage can become large in some cases, for example in granular synthesis with many instances of `osc`. In some cases, it may make sense to use `snd-flatten` (see Section Accessing and Creating Sound) to cause the sound to be fully realized, after which the `osc` and its table memory can be reclaimed by garbage collection. The `partial` function (see below) does not need a private table and does not use much space.
`partial(pitch, env)` [SAL]
`(partial pitch env)` [LISP]
  Returns a sinusoid at the indicated pitch; the sound is multiplied by env. The start time and duration are taken from env, which is of course subject to transformations. The sample rate is `*sound-srate*`. The `partial` function is faster than `osc`.
`sine(pitch [, duration])` [SAL]
`(sine pitch [duration])` [LISP]
  Returns a sinusoid at the indicated pitch. The sample rate is `*sound-srate*`. This function is like `osc` with respect to transformations. The `sine` function is faster than `osc`.
`hzosc(hz [, table, phase])` [SAL]
`(hzosc hz [table phase])` [LISP]
  Returns a sound which is the table oscillated at hz starting at phase degrees. The default table is `*table*` and the default phase is 0.0 degrees. The default duration is `1.0`, but this is stretched as in `osc` (see above). The hz parameter may be a `SOUND`, in which case the duration of the result is the duration of hz. The sample rate is `*sound-srate*`.
`osc-saw(hz)` [SAL]
`(osc-saw hz)` [LISP]
  Returns a sawtooth waveshape at the indicated frequency (in Hertz). The sample rate is `*sound-srate*`. The hz parameter may be a sound as in hzosc (see above).
`osc-tri(hz)` [SAL]
`(osc-tri hz)` [LISP]
  Returns a triangle waveshape at the indicated frequency (in Hertz). The sample rate is `*sound-srate*`. The hz parameter may be a sound as in hzosc (see above).
`osc-pulse(hz, bias [, compare-shape])` [SAL]
`(osc-pulse hz bias [compare-shape])` [LISP]
  Returns a square pulse with variable width at the indicated frequency (in Hertz). The bias parameter controls the pulse width and should be between `-1` and `+1`, giving a pulse width from 0% (always at `-1`) to 100% (always at `+1`). When bias is zero, a square wave is generated. Bias may be a `SOUND` to create varying pulse width. If bias changes rapidly, strange effects may occur. The optional compare-shape defaults to a hard step at zero, but other shapes may be used to achieve non-square pulses. The `osc-pulse` behavior is written in terms of other behaviors and defined in the file `nyquist.lsp` using just a few lines of code. Read the code for the complete story.
`amosc(pitch, modulation [, table, phase])` [SAL]
`(amosc pitch modulation [table phase])` [LISP]
  Returns a sound which is table oscillated at pitch. The output is multiplied by modulation for the duration of the sound modulation. osc-table defaults to `*table*`, and phase is the starting phase (default 0.0 degrees) within osc-table. The sample rate is `*sound-srate*`.
`fmosc(pitch, modulation [, table, phase])` [SAL]
`(fmosc pitch modulation [table phase])` [LISP]
  Returns a sound which is table oscillated at pitch plus modulation for the duration of the sound modulation. osc-table defaults to `*table*`, and phase is the starting phase (default 0.0 degrees) within osc-table. The modulation is expressed in hz, e.g. a sinusoid modulation signal with an amplitude of 1.0 (2.0 peak to peak), will cause a +/- 1.0 hz frequency deviation in sound. Negative frequencies are correctly handled. The sample rate is `*sound-srate*`.
`fmfb(pitch, index [, dur])` [SAL]
`(fmfb pitch index [dur])` [LISP]
  Returns a sound generated by feedback FM synthesis. The pitch parameter (given in the usual half-step units) controls the fundamental frequency. The index is the amount of feedback, which may be a `SOUND` or a `FLONUM`. If index is a `FLONUM`, dur must be provided (a `FLONUM`) to specify the duration. Otherwise, dur is ignored if present and the duration is determined by that of index. The sample rate is `*sound-srate*`. A sinusoid table is used. If index is below 1.1, this generates a sawtooth-like waveform.
`buzz(n, pitch, modulation)` [SAL]
`(buzz n pitch modulation)` [LISP]
  Returns a sound with n harmonics of equal amplitude and a total amplitude of 1.0, using a well-known function of two cosines. If n (an integer) is less than 1, it is set to 1. Aliasing will occur if n is too large. The pitchspecifies the fundamental frequency (a number, in steps) assuming no modulation. The duration is determined by the duration of the sound modulation, which is a frequency modulation term expressed in Hz (see Section Oscillators). Negative frequencies are correctly handled. The sample rate is `*sound-srate*`.
`pluck(pitch [, duration, final-amplitude])` [SAL]
`(pluck pitch [duration final-amplitude])` [LISP]
  Returns a sound at the given pitch created using a modified Karplus-Strong plucked string algorithm. The tone decays from an amplitude of about 1.0 to about final-amplitude in duration seconds. The default values are to decay to 0.001 (-60dB) in 1 second. The sample rate is `*sound-srate*`.
`siosc(pitch, modulation, tables)` [SAL]
`(siosc pitch modulation tables)` [LISP]
  Returns a sound constructed by interpolating through a succession of periodic waveforms. The frequency is given (in half steps) by pitch to which a modulation signal (in hz) is added, exactly as in `fmosc`. The tables specify a list of waveforms as follows: (table0 time1 table2 ... timeN tableN), where each table is a sound representing one period. Each time is a time interval measured from the starting time. The time is scaled by the nominal duration (computed using `(local-to-global (get-sustain))`) to get the actual time. Note that this implies linear stretching rather than continuous timewarping of the interpolation or the breakpoints. The waveform is table0 at the starting time, table1 after time1 (scaled as described), and so on. The duration and logical stop time is given by modulation. If modulation is shorter than timeN, then the full sequence of waveforms is not used. If modulation is longer than timeN, tableN is used after timeN without further interpolation.
`sampler(pitch, modulation [, sample, npoints])` [SAL]
`(sampler pitch modulation [sample npoints])` [LISP]
  Returns a sound constructed by reading a sample from beginning to end and then splicing on copies of the same sound from a loop point to the end. The pitch and modulation parameters are used as in `fmosc` described above. The optional sample (which defaults to 2048-point sinusoid) is a list of the form

  > (sound pitch-number loop-start)

  where the first element is a sound containing the sample, the second is the pitch of the sample, and the third element is the time of the loop point. If the loop point is not in the bounds of the sound, it is set to zero. The optional npoints specifies how many points should be used for sample interpolation. Currently this parameter defaults to 2 and only 2-point (linear) interpolation is implemented. It is an error to modulate such that the frequency is negative. Note also that the loop point may be fractional. The sample rate is `*sound-srate*`.

##### Piece-wise Approximations

There are a number of related behaviors for piece-wise approximations to functions. The simplest of these, `pwl` was mentioned earlier in the manual. It takes a list of breakpoints, assuming an initial point at (0, 0), and a final value of 0. An analogous piece-wise exponential function, `pwe`, is provided. Its implicit starting and stopping values are 1 rather than 0 because exponential decays never reach zero. This inability to reach zero can be addressed by a pseudo-exponential function, `pwz`, whose design was borrowed from the ZynAddSubFx software synthesizer, where we add a small bias (0.01) to breakpoints, compute the exponential envelope between these new breakpoints, then subtract 0.01 so that the envelope can actually decay all the way to zero. These curves are very close to exponential (within 0.01) until they approach zero, where they become essentially linear. Like `pwl` (linear), the `pwz` envelopes assume an initial point at (0, 0) and a final value of 0. For amplitude envelopes, the `linear-attack` option for the `pwz` variants is suggested for a more natural-sounding envelope.

Each of these three forms has variants. You can specify the initial and final values (instead of taking the default). You can specify time in intervals rather than cummulative time. Finally, you can pass a list rather than an argument list. This leads to 24 versions:

    Piece-wise Linear Functions:
    	Cummulative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwl
    			pwl-list
    		Explicit initial value:
    			pwlv
    			pwlv-list
    	Relative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwlr
    			pwlr-list
    		Explicit initial value:
    			pwlvr
    			pwlvr-list

    Piece-wise Exponential Functions:
    	Cummulative Time:
    		Default initial point at (0, 1), final value at 1:
    			pwe
    			pwe-list
    		Explicit initial value:
    			pwev
    			pwev-list
    	Relative Time:
    		Default initial point at (0, 1), final value at 1:
    			pwer
    			pwer-list
    		Explicit initial value:
    			pwevr
    			pwevr-list
    Piece-wise Pseudo-Exponential Functions with Bias:
    	Cummulative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwz
    			pwz-list
    		Explicit initial value:
    			pwzv
    			pwzv-list
    	Relative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwzr
    			pwzr-list
    		Explicit initial value:
    			pwzvr
    			pwzvr-list

All of these functions are implemented in terms of `pwl` (see `nyquist.lsp` for the implementations. There are infinite opportunities for errors in these functions: if you leave off a data point, try to specify points in reverse order, try to create an exponential that goes to zero or negative values, or many other bad things, the behavior is not well-defined. Nyquist should not crash, but Nyquist does not necessarily attempt to report errors at this time.

`pwl(t1, l1, t2, l2, ... tn)` [SAL]
`(pwl t1 l1 t2 l2 ... tn)` [LISP]
  Creates a piece-wise linear envelope with breakpoints at (0, 0), (t1, l1), (t2, l2), ... (tn, 0). The breakpoint times are scaled linearly by the value of `*sustain*` (if `*sustain*` is a `SOUND`, it is evaluated once at the starting time of the envelope). Each breakpoint time is then mapped according to `*warp*`. The result is a linear interpolation (unwarped) between the breakpoints. The sample rate is `*control-srate*`. Breakpoint times are quantized to the nearest sample time. If you specify one or more breakpoints withing one sample period, `pwl` attempts to give a good approximation to the specified function. In particular, if two breakpoints are simultaneous, `pwl` will move one of them to an adjacent sample, producing a steepest possible step in the signal. The exact details of this “breakpoint munging” is subject to change in future versions. Please report any cases where breakpoint lists give unexpected behaviors. The author will try to apply the “principle of least surprise” to the design. Note that the times are relative to 0; they are not durations of each envelope segment.
`pwl-list(breakpoints)` [SAL]
`(pwl-list breakpoints)` [LISP]
  If you have a list of breakpoints, you can use `apply` to apply the `pwl` function to the breakpoints, but if the list is very long (hundreds or thousands of points), you might get a stack overflow because XLISP has a fixed-size argument stack. Instead, call `pwl-list`, passing one argument, the list of breakpoints.
`pwlv(l1, t2, l2, t3, l3, ... tn, ln)` [SAL]
`(pwlv l1 t2 l2 t3 l3 ... tn ln)` [LISP]
  Creates a piece-wise linear envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln). Otherwise, the behavior is like that of `pwl`.
`pwlv-list(breakpoints)` [SAL]
`(pwlv-list breakpoints)` [LISP]
  A version of `pwlv` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rationale.
`pwlr(i1, l1, i2, l2, ... in)` [SAL]
`(pwlr i1 l1 i2 l2 ... in)` [LISP]
  Creates a piece-wise linear envelope with breakpoints at (0, 0), (t1, l1), (t2, l2), ... (tn, 0), where tj is the sum of i1 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of `pwl`.
`pwlr-list(breakpoints)` [SAL]
`(pwlr-list breakpoints)` [LISP]
  A version of `pwlr` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rationale.
`pwlvr(l1, i2, l2, i3, i3, ... in, ln)` [SAL]
`(pwlvr l1 i2 l2 i3 i3 ... in ln)` [LISP]
  Creates a piece-wise linear envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln, where tj is the sum of i2 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of `pwlv`.
`pwlvr-list(breakpoints)` [SAL]
`(pwlvr-list breakpoints)` [LISP]
  A version of `pwlvr` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rationale.
`pwe(t1, l1, t2, l2, ... tn)` [SAL]
`(pwe t1 l1 t2 l2 ... tn)` [LISP]
  Creates a piece-wise exponential envelope with breakpoints at (0, 1), (t1, l1), (t2, l2), ... (tn, 1). Exponential segments means that the ratio of values from sample to sample is constant within the segment. (The current implementation actually takes the log of each value, computes a piece-wise exponential from the points using `pwl`, then exponentiates each resulting sample. A faster implementation is certainly possible!) Breakpoint values (lj) must be greater than zero. Otherwise, this function is similar to `pwl`, including stretch by `*sustain*`, mapping according to `*warp*`, sample rate based on `*control-srate*`, and "breakpoint munging" (see `pwl` described above). Default initial and final values are of dubious value with exponentials. See the `pwz` functions which allow decay to zero, and `pwev` which has explicit initial and final values.
`pwe-list(breakpoints)` [SAL]
`(pwe-list breakpoints)` [LISP]
  A version of `pwe` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rationale.
`pwev(l1, t2, l2, t3, t3, ... tn, ln)` [SAL]
`(pwev l1 t2 l2 t3 t3 ... tn ln)` [LISP]
  Creates a piece-wise exponential envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln). Otherwise, the behavior is like that of `pwe`.
`pwev-list(breakpoints)` [SAL]
`(pwev-list breakpoints)` [LISP]
  A version of `pwev` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rationale.
`pwer(i1, l1, i2, l2, ... in)` [SAL]
`(pwer i1 l1 i2 l2 ... in)` [LISP]
  Creates a piece-wise exponential envelope with breakpoints at (0, 1), (t1, l1), (t2, l2), ... (tn, 1), where tj is the sum of i1 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of `pwe`. Consider using `pwerv` instead of this one.
`pwer-list(breakpoints)` [SAL]
`(pwer-list breakpoints)` [LISP]
  A version of `pwer` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rationale.
`pwevr(l1, i2, l2, i3, i3, ... in, ln)` [SAL]
`(pwevr l1 i2 l2 i3 i3 ... in ln)` [LISP]
  Creates a piece-wise exponential envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln, where tj is the sum of i2 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of `pwev`. Note that this is similar to the csound GEN05 generator. Which is uglier, GEN05 or pwevr?
`pwevr-list(breakpoints)` [SAL]
`(pwevr-list breakpoints)` [LISP]
  A version of `pwevr` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rationale.
`pwz(t1, l1, t2, l2, ... tn, [bias: bias], [linear-attack: linatk])` [SAL]
`(pwz t1 l1 t2 l2 ... tn [:bias bias] [:linear-attack linatk])` [LISP]
  Creates a piece-wise pseudo-exponential envelope with breakpoints at (0, 0), (t1, l1), (t2, l2), ... (tn, 0). Each breakpoint value is first incremented by bias, then interpolated with exponentials as in `pwe` (see above), then bias is subtracted from all samples so that the envelope passes through the original breakpoints as specified, including decay to zero. Breakpoint values (lj) must be non-negative. Otherwise, this function is similar to `pwl`, including stretch by `*sustain*`, mapping according to `*warp*`, sample rate based on `*control-srate*`, and "breakpoint munging" (see `pwl` described above). The `linear-attack` keyword parameter, if true (default is false), causes a linear interpolation from (0, 0) to (t1, l1) rather than exponential. The `bias` keyword parameter is optional, and defaults to 0.01 (about -40dB). As bias grows large, the “half-life” of the decay becomes large, so the decay is more linear. Even large values such as 1 are possible. As bias grows small, the “half-life” of the decay becomes small, so the decay is more rapid. Example: If bias is 0.01 (default), a decay from 1 to 0 in 1 second will decay to about -20dB in 0.5 seconds. If bias is 0.0001 (-80dB), the envelope will decay to about -20dB in only 0.25 seconds. You can think of bias as approximately how much attenuation you want to occur exponentially before the final decay to zero where the envelope becomes more linear. With bias values at or below 0.01, the “linear part” occurs when the signal is barely audible anyway.
`pwz-list(breakpoints, [bias: bias], [linear-attack: linatk])` [SAL]
`(pwz-list breakpoints [:bias bias] [:linear-attack linatk])` [LISP]
  A version of `pwz` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rational for this “-list” form of `pwz` and for an explanation of the `linear-attack` keyword parameter.
`pwzv(l1, t2, l2, t3, t3, ... tn, ln, [bias: bias], [linear-attack: linatk])` [SAL]
`(pwzv l1 t2 l2 t3 t3 ... tn ln [:bias bias] [:linear-attack linatk])` [LISP]
  Creates a piece-wise pseudo-exponential envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln). If the `linear-attack` parameter is true (default is false), linear interpolation is used from (0, l1) to (t2, l2). Otherwise, the behavior is like that of `pwz`.
`pwzv-list(breakpoints, [bias: bias], [linear-attack: linatk])` [SAL]
`(pwzv-list breakpoints [:bias bias] [:linear-attack linatk])` [LISP]
  A version of `pwzv` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rational for this “-list” form of `pwzv`.
`pwzr(i1, l1, i2, l2, ... in, [bias: bias], [linear-attack: linatk])` [SAL]
`(pwzr i1 l1 i2 l2 ... in [:bias bias] [:linear-attack linatk])` [LISP]
  Creates a piece-wise pseudo-exponential envelope with breakpoints at (0, 0), (t1, l1), (t2, l2), ... (tn, 0), where tj is the sum of i1 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of `pwz`.
`pwzr-list(breakpoints, [bias: bias], [linear-attack: linatk])` [SAL]
`(pwzr-list breakpoints [:bias bias] [:linear-attack linatk])` [LISP]
  A version of `pwzr` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rational for this “-list” form of `pwzr`.
`pwzvr(l1, i2, l2, i3, i3, ... in, ln, [bias: bias], [linear-attack: linatk])` [SAL]
`(pwzvr l1 i2 l2 i3 i3 ... in ln [:bias bias] [:linear-attack linatk])` [LISP]
  Creates a piece-wise exponential envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln, where tj is the sum of i2 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of `pwzv`. See `pwz` (above) for an explanation of bias and linatk.
`pwzvr-list(breakpoints, [bias: bias], [linear-attack: linatk])` [SAL]
`(pwzvr-list breakpoints [:bias bias] [:linear-attack linatk])` [LISP]
  A version of `pwzvr` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rational for this “-list” form of `pwzvr`.

##### Filter Behaviors

`alpass(sound, decay, hz [, minhz])` [SAL]
`(alpass sound decay hz [minhz])` [LISP]
  Applies an all-pass filter to sound. This all-pass filter creates a delay effect without the resonances of a comb filter. The decay time of the filter is given by decay. The hz parameter must be a number or sound greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The decay may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert decay into the feedback parameter, and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide decay at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of sound. If hz is of type `SOUND`, the delay may be time-varying. Linear interpolation is then used for fractional sample delay, but it should be noted that linear interpolation implies a low-pass transfer function. Thus, this filter may behave differently with a constant `SOUND` than it does with a `FLONUM` value for hz. In addition, if hz is of type `SOUND`, then minhz is required. The hz parameter will be clipped to be greater than minhz, placing an upper bound on the delay buffer length.
`comb(sound, decay, hz)` [SAL]
`(comb sound decay hz)` [LISP]
  Applies a comb filter to sound. A comb filter emphasizes (resonates at) frequencies that are multiples of a hz. The decay time of the resonance is given by decay. This is a variation on `feedback-delay` (see below). The hz parameter must be a number greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The decay may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert decay into the feedback parameter for `feedback-delay`, and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide decay at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of sound.
`congen(gate, risetime, falltime)` [SAL]
`(congen gate risetime falltime)` [LISP]
  Implements an analog synthesizer-style contour generator. The input gate normally goes from 0.0 to 1.0 to create an attack and from 1.0 to 0.0 to start a release. During the attack (output is increasing), the output converges half-way to gate in risetime (a `FLONUM`) seconds. During the decay, the half-time is falltime seconds. The sample rate, start time, logical stop, and terminate time all come from gate. If you want a nice decay, be sure that the gate goes to zero and stays there for awhile before gate terminates, because `congen` (and all Nyquist sounds) go immediately to zero at termination time. For example, you can use `pwl` to build a pulse followed by some zero time:

      (pwl 0 1 duty 1 duty 0 1)

  Assuming duty is less than 1.0, this will be a pulse of duration duty followed by zero for a total duration of 1.0.

      (congen (pwl 0 1 duty 1 duty 0 1) 0.01 0.05)

  will have a duration of 1.0 because that is the termination time of the `pwl` input. The decaying release of the resulting envelope will be truncated to zero at time 1.0. (Since the decay is theoretically infinite, there is no way to avoid truncation, although you could multiply by another envelope that smoothly truncates to zero in the last millisecond or two to get both an exponential decay and a smooth final transition to zero.)

`convolve(sound, response)` [SAL]
`(convolve sound response)` [LISP]
  Convolves two signals. The first can be any length, but the total space required is proportional to the length of response. The start time, logical stop time, and sample rate of the output match those of the input sound. The physical stop time of the result is the physical stop time of sound plus the duration of the response so that the result sound includes the “tail” of the filter response. The response is linearly interpolated if necessary to have same sample rate as sound. The current implementation uses a “fast convolution” algorithm with a maximum FFT size of 64K, which after zero padding allows up to 32K point convolutions. If the impulse response is longer, it is broken into multiple blocks of 32K samples. There is no limit on the length of the impulse response. This is an Order(N x M) algorithm where N and M are the number of 32K sample blocks in the sound and response, respectively. Further discussion and examples can be found in `nyquist/lib/convolve/convolution.html`.
`feedback-delay(sound, delay, feedback)` [SAL]
`(feedback-delay sound delay feedback)` [LISP]
  Applies feedback delay to sound. The delay must be a number (in seconds). It is rounded to the nearest sample to determine the length of the delay. The sample rate is the maximum from sound and feedback (if feedback is also a sound). The amound of feedback should be less than one to avoid an exponential increase in amplitude. The start time and stop time, and logical stop time are taken from sound. Since output is truncated at the stop time of sound, you may want to append some silence to sound to give the filter time to decay.
`lp(sound, cutoff)` [SAL]
`(lp sound cutoff)` [LISP]
  Filters sound using a first-order Butterworth low-pass filter. Cutoff may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of cutoff. The resulting sample rate, start time, etc. are taken from sound.
`tone(sound, cutoff)` [SAL]
`(tone sound cutoff)` [LISP]
  No longer defined; use `lp` instead, or define it by adding `(setfn tone lp)` to your program.
`hp(sound, cutoff)` [SAL]
`(hp sound cutoff)` [LISP]
  Filters sound using a first-order Butterworth high-pass filter. Cutoff may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of cutoff. This filter is an exact complement of `lp`.
`atone(sound, cutoff)` [SAL]
`(atone sound cutoff)` [LISP]
  No longer defined; use `hp` instead, or define it by adding `(setfn atone hp)` to your program.
`reson(sound, center, bandwidth [, n])` [SAL]
`(reson sound center bandwidth [n])` [LISP]
  Apply a resonating filter to sound with center frequency center (in hertz), which may be a float or a signal. Bandwidth is the filter bandwidth (in hertz), which may also be a signal. Filter coefficients (requiring trig functions) are recomputed at each new sample of either center or bandwidth, and coefficients are not interpolated. The last parameter n specifies the type of normalization as in Csound: A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than hz are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The resulting sample rate, start time, etc. are taken from sound.
One application of `reson` is to simulate resonances in the human vocal tract. See `nyquist/lib/voice/voice_synthesis.html` for sample code and documentation.
`areson(sound, center, bandwidth [, n])` [SAL]
`(areson sound center bandwidth [n])` [LISP]
  The `areson` filter is an exact complement of `reson` such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal.
`shape(signal, table, origin)` [SAL]
`(shape signal table origin)` [LISP]
  A waveshaping function. Use table as a function; apply the function to each sample of signal to yield a new sound. Signal should range from -1 to +1. Anything beyond these bounds is clipped. Table is also a sound, but it is converted into a lookup table (similar to table-lookup oscillators). The origin is a `FLONUM` and gives the time which should be considered the origin of table. (This is important because table cannot have values at negative times, but signal will often have negative values. The origin gives an offset so that you can produce suitable tables.) The output at time t is:

  > table(origin + clip(signal(t))

  where clip(x) = max(1, min(-1, x)). (E.g. if table is a signal defined over the interval [0, 2], then origin should be 1.0. The value of table at time 1.0 will be output when the input signal is zero.) The output has the same start time, sample rate, etc. as signal. The `shape` function will also accept multichannel signals and tables. Further discussion and examples can be found by installing the “distortion” extension with the NyquistIDE Extension Manager. The code will appear in `nyquist/lib/distortion/distortion.html`. The `shape` function is also used to map frequency to amplitude to achieve a spectral envelope for Shepard tones (install the “shepard” extension) in `nyquist/lib/shepard/shepard.lsp`.
`biquad(signal, b0, b1, b2, a0, a1, a2)` [SAL]
`(biquad signal b0 b1 b2 a0 a1 a2)` [LISP]
  A fixed-parameter biquad filter. All filter coefficients are `FLONUM`s. See also `lowpass2`, `highpass2`, `bandpass2`, `notch2`, `allpass2`, `eq-lowshelf`, `eq-highshelf`, `eq-band`, `lowpass4`, `lowpass6`, `highpass4`, and `highpass8` in this section for convenient variations based on the same filter. The equations for the filter are: zn = sn + a1 * zn-1 + a2 * zn-2, and yn = zn * b0 + zn-1 * b1 + zn-2 * b2.
`biquad-m(signal, b0, b1, b2, a0, a1, a2)` [SAL]
`(biquad-m signal b0 b1 b2 a0 a1 a2)` [LISP]
  A fixed-parameter biquad filter with Matlab sign conventions for a0, a1, and a2. All filter coefficients are `FLONUM`s.
`lowpass2(signal, hz [, q])` [SAL]
`(lowpass2 signal hz [q])` [LISP]
  A fixed-parameter, second-order lowpass filter based on `snd-biquad`. The cutoff frequency is given by hz (a `FLONUM`) and an optional Q factor is given by q (a `FLONUM`).
`highpass2(signal, hz [, q])` [SAL]
`(highpass2 signal hz [q])` [LISP]
  A fixed-parameter, second-order highpass filter based on `snd-biquad`. The cutoff frequency is given by hz (a `FLONUM`) and an optional Q factor is given by q (a `FLONUM`).
`bandpass2(signal, hz [, q])` [SAL]
`(bandpass2 signal hz [q])` [LISP]
  A fixed-parameter, second-order bandpass filter based on `snd-biquad`. The center frequency is given by hz (a `FLONUM`) and an optional Q factor is given by q (a `FLONUM`).
`notch2(signal, hz [, q])` [SAL]
`(notch2 signal hz [q])` [LISP]
  A fixed-parameter, second-order notch filter based on `snd-biquad`. The center frequency is given by hz (a `FLONUM`) and an optional Q factor is given by q (a `FLONUM`).
`allpass2(signal, hz [, q])` [SAL]
`(allpass2 signal hz [q])` [LISP]
  A fixed-parameter, second-order allpass filter based on `snd-biquad`. The frequency is given by hz (a `FLONUM`) and an optional Q factor is given by q (a `FLONUM`).
`eq-lowshelf(signal, hz, gain [, slope])` [SAL]
`(eq-lowshelf signal hz gain [slope])` [LISP]
  A fixed-parameter, second-order bass shelving equalization (EQ) filter based on `snd-biquad`. The hz parameter (a `FLONUM`)is the halfway point in the transition, and gain (a `FLONUM`) is the bass boost (or cut) in dB. The optional slope (a `FLONUM`) is 1.0 by default, and response becomes peaky at values greater than 1.0.
`eq-highshelf(signal, hz, gain [, slope])` [SAL]
`(eq-highshelf signal hz gain [slope])` [LISP]
  A fixed-parameter, second-order treble shelving equalization (EQ) filter based on `snd-biquad`. The hz parameter (a `FLONUM`)is the halfway point in the transition, and gain (a `FLONUM`) is the treble boost (or cut) in dB. The optional slope (a `FLONUM`) is 1.0 by default, and response becomes peaky at values greater than 1.0.
`eq-band(signal, hz, gain, width)` [SAL]
`(eq-band signal hz gain width)` [LISP]
  A fixed- or variable-parameter, second-order midrange equalization (EQ) filter based on `snd-biquad`, `eq-band-ccc` and `eq-band-vvv`. The hz parameter (a `FLONUM`) is the center frequency, gain (a `FLONUM`) is the boost (or cut) in dB, and width (a `FLONUM`) is the half-gain width in octaves. Alternatively, hz, gain, and width may be `SOUND`s, but they must all have the same sample rate, e.g. they should all run at the control rate or at the sample rate.
`lowpass4(signal, hz)` [SAL]
`(lowpass4 signal hz)` [LISP]
  A four-pole Butterworth lowpass filter. The cutoff frequency is hz (a `FLONUM`).
`lowpass6(signal, hz)` [SAL]
`(lowpass6 signal hz)` [LISP]
  A six-pole Butterworth lowpass filter. The cutoff frequency is hz (a `FLONUM`).
`lowpass8(signal, hz)` [SAL]
`(lowpass8 signal hz)` [LISP]
  An eight-pole Butterworth lowpass filter. The cutoff frequency is hz (a `FLONUM`).
`highpass4(signal, hz)` [SAL]
`(highpass4 signal hz)` [LISP]
  A four-pole Butterworth highpass filter. The cutoff frequency is hz (a `FLONUM`).
`highpass6(signal, hz)` [SAL]
`(highpass6 signal hz)` [LISP]
  A six-pole Butterworth highpass filter. The cutoff frequency is hz (a `FLONUM`).
`highpass8(signal, hz)` [SAL]
`(highpass8 signal hz)` [LISP]
  An eight-pole Butterworth highpass filter. The cutoff frequency is hz (a `FLONUM`).
`tapv(sound, offset, vardelay, maxdelay)` [SAL]
`(tapv sound offset vardelay maxdelay)` [LISP]
  A delay line with a variable position tap. Identical to `snd-tapv`. See it for details (page Signal Operations).

##### Effects

`nrev(sound, decay, mix)` [SAL]
`(nrev sound decay mix)` [LISP]
`jcrev(sound, decay, mix)` [SAL]
`(jcrev sound decay mix)` [LISP]
`prcrev(sound, decay, mix)` [SAL]
`(prcrev sound decay mix)` [LISP]
  These reverbs (`nrev`, `jcrev`, and `prcrev`) are implemented in STK (running within Nyquist). `nrev` derives from Common Music's NRev, which consists of 6 comb filters followed by 3 allpass filters, a lowpass filter, and another allpass in series followed by two allpass filters in parallel. `jcrev` is the John Chowning reverberator which is based on the use of networks of simple allpass and comb delay filters. This reverb implements three series allpass units, followed by four parallel comb filters, and two decorrelation delay lines in parallel at the output. `prcrev` is a Perry Cook's reverberator which is based on the Chowning/Moorer/Schroeder reverberators using networks of simple allpass and comb delay filters. This one implements two series allpass units and two parallel comb filters. The sound input may be single or multichannel. The decay time is in seconds, and mix sets the mixture of input sound reverb sound, where 0.0 means input only (dry) and 1.0 means reverb only (wet).
`stkchorus(sound, depth, freq, mix [, delay])` [SAL]
`(stkchorus sound depth freq mix [delay])` [LISP]
  Chorus implemented in STK. The input sound can be single or multichannel. The `FLONUM` parameters depth and freq set the modulation depth from 0 to 1 and modulation frequency (in Hz), and mix sets the mixture of input sound and chorused sound, where 0.0 means input sound only (dry) and 1.0 means chorused sound only (wet). The parameter delay is a `FIXNUM` representing the median desired delay length in samples.
`pitshift(sound, shift, mix)` [SAL]
`(pitshift sound shift mix)` [LISP]
  A pitch shifter implemented in STK. The input sound, a single-channel or multichannel `SOUND` is pitch-shifted by shift, a `FLONUM` ratio. A value of 1.0 means no shift. The parameter mix sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet).

##### Physical Models

`clarinet(step, breath-env)` [SAL]
`(clarinet step breath-env)` [LISP]
  A physical model of a clarinet from STK. The step parameter is a `FLONUM` that controls the tube length, and the breath-env (a `SOUND`) controls the air pressure and also determines the length of the resulting sound. The breath-env signal should range from zero to one.
`clarinet-freq(step, breath-env, freq-env)` [SAL]
`(clarinet-freq step breath-env freq-env)` [LISP]
  A variation of `clarinet` that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type `FLONUM` or `SOUND`. `FLONUM`s are coerced into `SOUND`s with a nominal duration arbitrarily set to 30.
`clarinet-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, reed-stiffness, noise)` [SAL]
`(clarinet-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise)` [LISP]
  A variation of `clarinet-freq` that includes controls vibrato-freq (a `FLONUM` for vibrato frequency in Hertz), vibrato-gain (a `FLONUM` for the amount of amplitude vibrato), reed-stiffness (a `FLONUM` or `SOUND` controlling reed stiffness in the clarinet model), and noise (a `FLONUM` or `SOUND` controlling noise amplitude in the input air pressure). The vibrato-gain is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The reed-stiffness parameter varies from zero to one. The duration of the resulting sound is the minimum duration of breath-env, freq-env, reed-stiffness, and noise. As with `clarinet-freq`, these parameters may be either `FLONUM`s or `SOUND`s, and `FLONUM`s are coerced to sounds with a nominal duration of 30.
`sax(step, breath-env)` [SAL]
`(sax step breath-env)` [LISP]
  A physical model of a sax from STK. The step parameter is a `FLONUM` that controls the tube length, and the breath-env controls the air pressure and also determines the length of the resulting sound. The breath-env signal should range from zero to one.
`sax-freq(step, breath-env, freq-env)` [SAL]
`(sax-freq step breath-env freq-env)` [LISP]
  A variation of `sax` that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type `FLONUM` or `SOUND`. `FLONUM`s are coerced into `SOUND`s with a nominal duration arbitrarily set to 30.
`sax-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, reed-stiffness, noise, blow-pos, reed-table-offset)` [SAL]
`(sax-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise blow-pos reed-table-offset)` [LISP]
  A variation of `sax-freq` that includes controls vibrato-freq (a `FLONUM` for vibrato frequency in Hertz), vibrato-gain (a `FLONUM` for the amount of amplitude vibrato), reed-stiffness (a `SOUND` controlling reed stiffness in the sax model), noise (a `SOUND` controlling noise amplitude in the input air pressure), blow-pos (a `SOUND` controlling the point of excitation of the air column), and reed-table-offset (a `SOUND` controlling a parameter of the reed model). The vibrato-gain is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The reed-stiffness, blow-pos, and reed-table-offset parameters all vary from zero to one. The duration of the resulting sound is the minimum duration of breath-env, freq-env, reed-stiffness, noise, breath-env, blow-pos, and reed-table-offset. As with `sax-freq`, these parameters may be either `FLONUM`s or `SOUND`s, and `FLONUM`s are coerced to sounds with a nominal duration of 30.
`flute(step, breath-env)` [SAL]
`(flute step breath-env)` [LISP]
  A physical model of a flute from STK. The step parameter is a `FLONUM` that controls the tube length, and the breath-env controls the air pressure and also determines the starting time and length of the resulting sound. The breath-env signal should range from zero to one.
`flute-freq(step, breath-env, freq-env)` [SAL]
`(flute-freq step breath-env freq-env)` [LISP]
  A variation of `flute` that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type `FLONUM` or `SOUND`. `FLONUM`s are coerced into SOUNDs with a nominal duration arbitrarily set to 30.
`flute-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, jet-delay, noise)` [SAL]
`(flute-all step breath-env freq-env vibrato-freq vibrato-gain jet-delay noise)` [LISP]
  A variation of `clarinet-freq` that includes controls vibrato-freq (a `FLONUM` for vibrato frequency in Hz), vibrato-gain (a `FLONUM` for the amount of amplitude vibrato), jet-delay (a `FLONUM` or `SOUND` controlling jet delay in the flute model), and noise (a `FLONUM` or `SOUND` controlling noise amplitude in the input air pressure). The vibrato-gain is a number from zero to one where zero means no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one, where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The jet-delay is a ratio that controls a delay length from the flute model, and therefore it changes the pitch of the resulting sound. A value of 0.5 will maintain the pitch indicated by the step parameter. The duration of the resulting sound is the minimum duration of breath-env, freq-env, jet-delay, and noise. These parameters may be either `FLONUM`s or `SOUND`s, and `FLONUM`s are coerced to sounds with a nominal duration of 30.
`bowed(step, bowpress-env)` [SAL]
`(bowed step bowpress-env)` [LISP]
  A physical model of a bowed string instrument from STK. The step parameter is a `FLONUM` that controls the string length, and the bowpress-env controls the bow pressure and also determines the duration of the resulting sound. The bowpress-env signal should range from zero to one.
`bowed-freq(step, bowpress-env, freq-env)` [SAL]
`(bowed-freq step bowpress-env freq-env)` [LISP]
  A variation of `bowed` that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of bowpress-env and freq-env. These parameters may be of type `FLONUM` or `SOUND`. `FLONUM`s are coerced into `SOUND`s with a nominal duration arbitrarily set to 30s.
`mandolin(step, dur, &optional detune)` [SAL]
`(mandolin step dur detune)` [LISP]
  A physical model of a plucked double-string instrument from STK. The step parameter is a `FLONUM` wich specifies the desired pitch, dur means the duration of the resulting sound and detune is a `FLONUM` that controls the relative detune of the two strings. A value of 1.0 means unison. The default value is 4.0. Note: body-size (see `snd-mandolin` does not seem to work correctly, so a default value is always used by `mandolin`.
`wg-uniform-bar(step, bowpress-env)` [SAL]
`(wg-uniform-bar step bowpress-env)` [LISP]
`wg-tuned-bar(step, bowpress-env)` [SAL]
`(wg-tuned-bar step bowpress-env)` [LISP]
`wg-glass-harm(step, bowpress-env)` [SAL]
`(wg-glass-harm step bowpress-env)` [LISP]
`wg-tibetan-bowl(step, bowpress-env)` [SAL]
`(wg-tibetan-bowl step bowpress-env)` [LISP]
  These sounds are presets for a Banded Wave Guide Percussion instrument implemented in STK. The parameter step is a `FLONUM` that controls the resultant pitch, and bowpress-env is a `SOUND` ranging from zero to one that controls a parameter of the model. In addition, bowpress-env determines the duration of the resulting sound. (Note: The bowpress-env does not seems influence the timbral quality of the resulting sound).
`modalbar(preset, step, dur)` [SAL]
`(modalbar preset step dur)` [LISP]
  A physical model of a struck bar instrument implemented in STK. The parameter preset is one of the symbols `MARIMBA`, `VIBRAPHONE`, `AGOGO`, `WOOD1`, `RESO`, `WOOD2`, `BEATS`, `TWO-FIXED`, or `CLUMP`. The symbol must be quoted, e.g. for SAL syntax use `quote(marimba)`, and for Lisp syntax use `'marimba`. The parameter step is a `FLONUM` that sets the pitch (in steps), and dur is the duration in seconds.
`sitar(step, dur)` [SAL]
`(sitar step dur)` [LISP]
  A sitar physical model implemented in STK. The parameter step is a `FLONUM` that sets the pitch, and dur is the duration.
`stk-breath-env(dur, note-on note-off)` [SAL]
`(stk-breath-env dur note-on note-off)` [LISP]
  A simple envelope function intended for STK instruments such as `CLARINET`, where dur is the duration, note-on is the attack time, and note-off is the decay time, all `FLONUM`s in seconds.

##### Phase Vocoder

`phasevocoder(s, map, [fftsize, hopsize, mode])` [SAL]
`(phasevocoder s map [fftsize hopsize mode])` [LISP]
  Phase vocoder: the input SOUND s is stretched in time according to the control signal (a SOUND) map. The map parameter must be strictly non-decreasing. It specifies the input time for each time in the output. E.g. if map at time 3 is 4, then the output at time 3 will sound like the input at time 4, assuming s and map start at time 0. In the general case, s and map must start at the same time. The phase vocoder operation is applied as if s and map started at time 0, and the result is shifted to start at the same starting time as s and map. The fftsize is a FIXNUM and power of 2, indicating the size of the analysis and synthesis windows in samples. The default is 2048. The hopsize is the hop size (in samples, a FIXNUM) of the synthesis stage where overlapping windows are added. The hopsize should be a power of 2 that is smaller than the fftsize. The default is the fftsize/8. Note that the analysis hopsize is determined by the map. If the playback speed (slope of map) is too great, the analysis hopsize will be large and the sound quality will suffer. You can always make the analysis hopsize smaller by making the synthesis hopsize smaller (at the cost of greater computation). The mode is a FIXNUM that defaults to 0, meaning a standard phase vocoder. A value of 1 invokes a phase computation that attempts to reduce phase artifacts by preserving the phase relationships between peaks and nearby bins. A value of 2 invokes a “robot voice” mode that assigns fixed phases and creates a constant pitch (controlled by the hopsize) vocoder-like effect. (Thanks to M.C.Sharma for this idea.) A phase vocoder constructs output from overlapped and added windowed IFFT frames. This presents a special problem at the beginning and ending of the output sound. To output a sound starting at time t, the first frame is centered at t + fftsize/2, so the output at t will smoothly rise from zero because all frames are smoothed by a windowing function. Considerations are: (1) The output at time t will rise from zero rather than being the sum of multiple overlapping windows; (2) if t maps to an input window that begins before the start time of the input sound, the input window will be padded with zeros and may include an abrupt onset if one exists at the start of the input sound.
`pv-time-pitch(s, stretchfn, pitchfn, dur, [fftsize, hopsize, mode])` [SAL]
`(pv-time-pitch s stretchfn pitchfn dur [fftsize hopsize mode])` [LISP]
  Combines phase vocoder and resampling to perform simultaneous time stretching and pitch shifting. The input SOUND s is stretched according to SOUND stretchfn and pitch-shifted according to SOUND pitchfn. The approximate output duration should be specified by dur (which is used to optimize the sample rate of computed control functions), and the remaining parameters fftsize, hopsize and mode are passed to the phase vocoder (see `phasevocoder` above). The stretchfn gives the factor by which the input should be stretched at each point in time; thus, the total duration is the integral of this function. The pitchfn specifies the amount by which pitch should be shifted at each point in time. For example, where pitchfn is 2, the sample rate will be doubled, increasing pitch and frequencies by an octave. The phase vocoder is used to compensate for time stretching caused by resampling, so stretchfn and pitchfn operate independently.

##### More Behaviors

`clip(sound, peak)` [SAL]
`(clip sound peak)` [LISP]
  Hard limit sound to the given peak, a positive number. The samples of sound are constrained between an upper value of peak and a lower value of -peak. If sound is a number, `clip` will return sound limited by peak. If sound is a multichannel sound, `clip` returns a multichannel sound where each channel is clipped. The result has the type, sample rate, starting time, etc. of sound. Note: Many systems clip output when converting to fixed-point audio, e.g. 16-bit samples. Instead Nyquist simply takes the low-order 16 bits, allowing samples to “wrap around.” This sounds terrible, but that is the point: It is hard to miss when your samples go out of range. One use of this function is to clip rather than wrap output. Warning: A floating point sample value of 1.0 maps to 215 in 16-bit audio, but the maximum 16-bit sample value is 215-1! If your goal is to clip to the 16-bit range, you should set peak to the ratio 32767.0/32768.0. For 24-bit audio, use (223-1)/223, etc.
`s-abs(sound)` [SAL]
`(s-abs sound)` [LISP]
  A generalized absolute value function. If sound is a `SOUND`, compute the absolute value of each sample. If sound is a number, just compute the absolute value. If sound is a multichannel sound, return a multichannel sound with `s-abs` applied to each element. The result has the type, sample rate, starting time, etc. of sound.
`s-avg(sound, blocksize, stepsize, operation)` [SAL]
`(s-avg sound blocksize stepsize operation)` [LISP]
  Computes the averages or peak values of blocks of samples. Each output sample is an average or peak of blocksize (a fixnum) adjacent samples from the input sound. After each average or peak is taken, the input is advanced by stepsize, a fixnum which may be greater or less than blocksize. The output sample rate is the sound (input) sample rate divided by stepsize. The duration of the output is the same (approximately, due to rounding) as that of sound. Notice however, that the features of the input will appear earlier in the output by half the window size. For example, a sharp peak in the input will result in a smoothed peak (using `OP-AVERAGE`) one half blocksize earlier. You can correct for this shift by inserting one half blocksize of silence before sound, e.g. if `s` has a sample rate of 44100 Hz, then `snd-avg(seq(s-rest(0.01), cue(s)), 882, 441, OP-AVERAGE)` will shift `s` by 0.01 s to compensate for the shift introduced by a smoothing window of size 0.02 s (882/44100). If sound is a multichannel sound, return a multichannel sound with `s-avg` applied to each element. This function is useful for computing low-sample-rate rms or peak amplitude signals for input to `snd-gate` or `snd-follow`. To select the operation, operation should be one of `OP-AVERAGE` or `OP-PEAK`. (These are global lisp variables; the actual operation parameter is an integer.) For RMS computation, see `rms` in Section More Behaviors.
`s-sqrt(sound)` [SAL]
`(s-sqrt sound)` [LISP]
  A generalized square root function. If sound is a `SOUND`, compute the square root of each sample. If sound is a number, just compute the square root. If sound is a multichannel sound, return a multichannel sound with `s-sqrt` applied to each element. The result has the type, sample rate, starting time, etc. of sound. In taking square roots, if an input sample is less than zero, the corresponding output sample is zero. This is done because the square root of a negative number is undefined.
`s-exp(sound)` [SAL]
`(s-exp sound)` [LISP]
  A generalized exponential function. If sound is a `SOUND`, compute ex for each sample x. If sound is a number x, just compute ex. If sound is a multichannel sound, return a multichannel sound with `s-exp` applied to each element. The result has the type, sample rate, starting time, etc. of sound.
`s-log(sound)` [SAL]
`(s-log sound)` [LISP]
  A generalized natural log function. If sound is a `SOUND`, compute ln(x) for each sample x. If sound is a number x, just compute ln(x). If sound is a multichannel sound, return a multichannel sound with `s-log` applied to each element. The result has the type, sample rate, starting time, etc. of sound. Note that the ln of 0 is undefined (some implementations return negative infinity), so use this function with care.
`s-max(sound1, sound2)` [SAL]
`(s-max sound1 sound2)` [LISP]
  Compute the maximum of two functions, sound1 and sound2. This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of sound1 and sound2. The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of sound1 and sound2. Note, therefore, that the result value is zero except within the bounds of both input sounds.
`s-min(sound1, sound2)` [SAL]
`(s-min sound1 sound2)` [LISP]
  Compute the minimum of two functions, sound1 and sound2. This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of sound1 and sound2. The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of sound1 and sound2. Note, therefore, that the result value is zero except within the bounds of both input sounds.
`osc-note(pitch [, duration, env, loud, table])` [SAL]
`(osc-note pitch [duration env loud table])` [LISP]
  Same as `osc`, but `osc-note` multiplies the result by env. The env may be a sound, or a list supplying (t1 t2 t4 l1 l2 l3). The result has a sample rate of `*sound-srate*`.
`quantize(sound, steps)` [SAL]
`(quantize sound steps)` [LISP]
  Quantizes sound as follows: sound is multiplied by steps and rounded to the nearest integer. The result is then divided by steps. For example, if steps is 127, then a signal that ranges from -1 to +1 will be quantized to 255 levels (127 less than zero, 127 greater than zero, and zero itself). This would match the quantization Nyquist performs when writing a signal to an 8-bit audio file. The sound may be multichannel.
`ramp([duration])` [SAL]
`(ramp [duration])` [LISP]
  Returns a linear ramp from 0 to 1 over duration (default is 1). The function actually reaches 1 at duration, and therefore has one extra sample, making the total duration be duration + 1/`*Control-srate*`. See Figure 6 for more detail. Ramp is unaffected by the `sustain` transformation. The effect of time warping is to warp the starting and ending times only. The ramp itself is unwarped (linear). The sample rate is `*control-srate*`.
`rms(sound [, rate, window-size])` [SAL]
`(rms sound [rate window-size])` [LISP]
  Computes the RMS of sound using a square window of size window-size. The result has a sample rate of rate. The default value of rate is 100 Hz, and the default window size is 1/rate seconds (converted to samples). The sound is a SOUND or a multichannel sound (in which case the result is a multichannel sound). The rate is a `FLONUM` and window-size is a `FIXNUM`.
`recip(sound)` [SAL]
`(recip sound)` [LISP]
  A generalized reciprocal function. If sound is a `SOUND`, compute 1/x for each sample x. If sound is a number x, just compute 1/x. If sound is a multichannel sound, return a multichannel sound with `recip` applied to each element. The result has the type, sample rate, starting time, etc. of sound. Note that the reciprocal of 0 is undefined (some implementations return infinity), so use this function with care on sounds. Division of sounds is accomplished by multiplying by the reciprocal. Again, be careful not to divide by zero.

Figure 6: Ramps generated by `pwl` and `ramp` functions. The `pwl` version ramps toward the breakpoint (1, 1), but in order to ramp back to zero at breakpoint (1, 0), the function never reaches an amplitude of 1. If used at the beginning of a `seq` construct, the next sound will begin at time 1. The `ramp` version actually reaches breakpoint (1, 1); notice that it is one sample longer than the `pwl` version. If used in a sequence, the next sound after `ramp` would start at time 1 + P, where P is the sample period.

`s-rest([duration])` [SAL]
`(s-rest [duration])` [LISP]
  Create silence (zero samples) for the given duration at the sample rate `*sound-srate*`. Default duration is 1.0 sec, and the sound is transformed in time according to `*warp*`. Note: `rest` is a Lisp function that is equivalent to `cdr`. Be careful to use `s-rest` when you need a sound!
`noise([duration])` [SAL]
`(noise duration)` [LISP]
  Generate noise with the given duration. Duration (default is 1.0) is transformed according to `*warp*`. The sample rate is `*sound-srate*` and the amplitude is +/- `*loud*`.
`yin(sound, minstep, maxstep, stepsize)` [SAL]
`(yin sound minstep maxstep stepsize)` [LISP]
  Fundamental frequency estimation (pitch detection. Use the YIN algorithm to estimate the fundamental frequency of sound, which must be a `SOUND`. The minstep, a `FLONUM`, is the minimum frequency considered (in steps), maxstep, a `FLONUM`, is the maximum frequency considered (in steps), and stepsize, a `FIXNUM`, is the desired hop size. The result is a “stereo” signal, i.e. an array of two `SOUND`s, both at the same sample rate, which is approximately the sample rate of sound divided by stepsize. The first `SOUND` consists of frequency estimates (in units of steps, i.e. middle C = 60). The second sound consists of values that measure the confidence or reliability of the frequency estimate. A small value (less than 0.1) indicates fairly high confidence. A larger value indicates lower confidence. This number can also be thought of as a ratio of non-periodic power to periodic power. When the number is low, it means the signal is highly periodic at that point in time, so the period estimate will be reliable. Hint #1: See Alain de Cheveigne and Hideki Kawahara's article "YIN, a Fundamental Frequency Estimator for Speech and Music" in the Journal of the Acoustic Society of America, April 2002 for details on the yin algorithm. Hint #2: Typically, the stepsize should be at least the expected number of samples in one period so that the fundamental frequency estimates are calculated at a rate far below the sample rate of the signal. Frequency does not change rapidly and the yin algorithm is fairly slow. To optimize speed, you may want to use less than 44.1 kHz sample rates for input sounds.Yin uses interpolation to achieve potentially fractional-sample-accurate estimates, so higher sample rates do not necessarily help the algorithm and definitely slow it down. The computation time is O(n2) per estimate, where n is the number of samples in the longest period considered. Therefore, each increase of minstep by 12 (an octave) gives you a factor of 4 speedup, and each decrease of the sample rate of sound by a factor of two gives you another factor of 4 speedup. Finally, the number of estimates is inversely proportional to stepsize. Hint #3: Use `snd-srate` (see Section Accessing and Creating Sound) to get the exact sample rate of the result, which will be the sample rate of sound divided by stepsize. E.g. `(snd-srate (aref yin-output 0))`, where `yin-output` is a result returned by `yin`, will be the sample rate of the estimates.

### Transformations

These functions change the environment that is seen by other high-level functions. Note that these changes are usually relative to the current environment. There are also “absolute” versions of each transformation function, with the exception of `seq`, `seqrep`, `sim`, and `simrep`. The “absolute” versions (starting or ending with “abs”) do not look at the current environment, but rather set an environment variable to a specific value. In this way, sections of code can be insulated from external transformations.

`abs-env(beh)` [SAL]
`(abs-env beh)` [LISP]
  Compute beh in the default environment. This is useful for computing waveform tables and signals that are “outside” of time. For example, `(at 10.0 (abs-env (my-beh)))` is equivalent to `(abs-env (my-beh))` because `abs-env` forces the default environment. Or in SAL, we would say `abs-env(my-beh()) @ 10` is equivalent to `abs-env(my-beh())`.
`at(time, beh)` [SAL]
`(at time beh)` [LISP]
  Evaluate beh with `*warp*` shifted by time. In SAL, you can use the infix operator `@` as in `beh @ time`. To discover how the environment is shifting time, use `local-to-global(time)`. Most commonly, you call `local-to-global(0)` to find when a sound created in the current environment will start, expressed in absolute (global) terms. This can be regarded as the “current time.”
`at-abs(time, beh)` [SAL]
`(at-abs time beh)` [LISP]
  Evaluate beh with `*warp*` shifted so that local time 0 maps to time. In SAL, you can use the infix operator `@@` as in `beh @@ time`.
`continuous-control-warp(beh)` [SAL]
`(continuous-control-warp beh)` [LISP]
  Applies the current warp environment to the signal returned by beh. The result has the default control sample rate `*control-srate*`. Linear interpolation is currently used. Implementation: beh is first evaluated without any shifting, stretching, or warping. The result is functionally composed with the inverse of the environment's warp function.
`continuous-sound-warp(beh)` [SAL]
`(continuous-sound-warp beh)` [LISP]
  Applies the current warp environment to the signal returned by beh. The result has the default sound sample rate `*sound-srate*`. Linear interpolation is currently used. See `continuous-control-warp` for implementation notes.
`control-srate-abs(srate, beh)` [SAL]
`(control-srate-abs srate beh)` [LISP]
  Evaluate beh with `*control-srate*` set to sample rate srate. Note: there is no “relative” version of this function.
`extract(start, stop, beh)` [SAL]
`(extract start stop beh)` [LISP]
  Returns a sound which is the portion of beh between start and stop. Note that this is done relative to the current `*warp*`. The result is shifted to start according to `*warp*`, so normally the result will start without a delay of start.
`extract-abs(start, stop, beh)` [SAL]
`(extract-abs start stop beh)` [LISP]
  Returns a sound which is the portion of beh between start and stop, independent of the current `*warp*`. The result is shifted to start at time zero. Wrapping a call to `extract-abs` in `cue` will shift the result to start at the current time, which is `local-to-global(0`).
`loud(volume, beh)` [SAL]
`(loud volume beh)` [LISP]
  Evaluates beh with `*loud*` incremented by volume. (Recall that `*loud*` is in decibels, so increment is the proper operation.)
`loud-abs(volume, beh)` [SAL]
`(loud-abs volume beh)` [LISP]
  Evaluates beh with `*loud*` set to volume.
`sound-srate-abs(srate, beh)` [SAL]
`(sound-srate-abs srate beh)` [LISP]
  Evaluate beh with `*sound-srate*` set to sample rate srate. Note: there is no “relative” version of this function.
`stretch(factor, beh)` [SAL]
`(stretch factor beh)` [LISP]
  Evaluates beh with `*warp*` scaled by factor. The effect is to “stretch” the result of beh (under the current environment) by factor. See Chapter Continuous Transformations and Time Warps for more information. Use `get-duration(dur)` to get the nominal actual duration of a behavior that locally has a duration of dur. Here, “nominal” means what would be expected if the behavior obeys the shift, stretch, and warp components of the environment. (Any behavior is free to deviate from the nominal timing. For example, a percussion sound might have a fixed duration independent of the stretch factor.) Also, “actual” means global or absolute time, and “locally” means within the environment where `get-duration` is called. `get-duration` works by mapping the current time (local time 0) using `local-to-global` to obtain an actual start time, and mapping dur to obtain an actual end time. The difference is returned.
`stretch-abs(factor, beh)` [SAL]
`(stretch-abs factor beh)` [LISP]
  Evaluates beh with `*warp*` set to a linear time transformation where each unit of logical time maps to factor units of real time. The effect is to stretch the nominal behavior of beh (under the default global environment) by factor. See Chapter Continuous Transformations and Time Warps for more information.
`sustain(factor, beh)` [SAL]
`(sustain factor beh)` [LISP]
  Evaluates beh with `*sustain*` scaled by factor. The effect is to “stretch” the result of beh (under the current environment) by factor; however, the logical stop times are not stretched. Therefore, the overall duration of a sequence is not changed, and sounds will tend to overlap if `*sustain*` is greater than one (legato) and be separated by silence if `*sustain*` is less than one.
`sustain-abs(factor, beh)` [SAL]
`(sustain-abs factor beh)` [LISP]
  Evaluates beh with `*sustain*` set to factor. (See `sustain`, above.)
`transpose(amount, beh)` [SAL]
`(transpose amount beh)` [LISP]
  Evaluates beh with `*transpose*` shifted by amount. The effect is relative transposition by amount semitones.
`transpose-abs(amount, beh)` [SAL]
`(transpose-abs amount beh)` [LISP]
  Evaluates beh with `*transpose*` set to amount. The effect is the transposition of the nominal pitches in beh (under the default global environment) by amount.
`warp(fn, beh)` [SAL]
`(warp fn beh)` [LISP]
  Evaluates beh with `*warp*` modified by fn. The idea is that beh and fn are written in the same time system, and fn warps that time system to local time. The current environment already contains a mapping from local time to global (real) time. The value of `*warp*` in effect when beh is evaluated is the functional composition of the initial `*warp*` with fn.
`warp-abs(fn, beh)` [SAL]
`(warp-abs fn beh)` [LISP]
  Evaluates beh with `*warp*` set to fn. In other words, the current `*warp*` is ignored and not composed with fn to form the new `*warp*`.

### Combination and Time Structure

These behaviors combine component behaviors into structures, including sequences (melodies), simultaneous sounds (chords), and structures based on iteration. See also the `trigger` function, described in Section Starting and Stopping Sounds, which uses a SOUND to trigger instances of a behavior.

`seq(beh1 [, beh2, ...])` [SAL]
`(seq beh1 [beh2 ...])` [LISP]
  Evaluates the first behavior beh1 according to the current time in the environment and each successive behavior at the `logical-stop` time of the previous one. The results are summed to form a sound whose `logical-stop` is the `logical-stop` of the last behavior in the sequence. Each behavior can result in a multichannel sound, in which case, the logical stop time is considered to be the maximum logical stop time of any channel. The number of channels in the result is the number of channels of the first behavior. If other behaviors return fewer channels, new channels are created containing constant zero signals until the required number of channels is obtained. If other behaviors return a simple sound rather than multichannel sounds, the sound is automatically assigned to the first channel of a multichannel sound that is then filled out with zero signals. If another behavior returns more channels than the first behavior, the error is reported and the computation is stopped. Sample rates are converted up or down to match the sample rate of the first sound in a sequence. Nyquist programs should generally avoid storing sounds in global variables because that tends to cause sound samples to be retained in memory. A related problem can occur with `seq` and `seqrep`. With these functions, behaviors are not evaluated until needed, but what if the behaviors depend on local variables as parameters? Ordinarily, the variables would be long gone and garbage collected by the time the behavior is evaluated. So, `seq` and `seqrep` capture all local variables and their bindings (values) in closures. This solves the problem of retaining local variables and values until they are needed by the behaviors, but it has a problem similar to global variables in that any sounds captured in the closure cannot be released until the last behavior in the sequence is evaluated. Here is an example:

      load "reverb"

      function long-tone() return buzz(15, c4, lfo(5, 10))

      function rev-with-tail(s, rt)
        return reverb(seq(s, s-rest(rt * 2)), rt)

      play rev-with-tail(pluck(c4), 10)

  This SAL function uses `seq` to append `rt * 2` seconds of silence to sound `s` before passing it to `reverb` ensuring that the reverb tail will not be cut off immediately at the end of `s`. Behavior 2, `s-rest(rt * 2)`, is wrapped in a closure which also captures the binding of `s` to the input sound (returned from `long-tone()`) and that of `rt` to 10. If there were no closure, then when `rev-with-tail` returns a sound to `play`, the variable `s` would be freed by garbage collection, and the only remaining reference to `long-tone()` would be internal to the `reverb` sound computation. `reverb` disposes of samples as soon as they are computed and used, so the total memory requirements would be minimal. In this case, however, since `s` is captured in a closure, as `reverb` demands computation of samples from `long-tone()`, `reverb` releases its claim on the samples, but `s` does not, so all the samples are retained in memory until `s-rest(rt * 2)` is evaluated and the closure (and `s`) are freed. For 10 seconds of sound (such as `long-tone(`)), this is not a big problem. In fact, if you use the default settings for autonorm, Nyquist will store about 20 seconds of sound in memory anyway just to do some look-ahead for normalization, but if `s` represents an hour-long stereo recording, or if there are many other sounds bound in local variables and captured in closures, the memory overhead can be too great. The solution is to override the default scopes and bindings to achieve the variable lifetimes we want. At any time, we can set a variable to `nil`, freeing the previous value to allow garbage collection. In LISP, we can write `(prog1 s (setf s nil))` to evaluate `s`, then free `s` by setting it to `nil`. The original value of `s` is returned from the `prog1` expression. In SAL, we can use the same trick, using `setf` rather than the typical SAL assignment operator (`=`). To change the example to be memory efficient, we change the definition of `rev-with-tail` to:

      function rev-with-tail(s, rt)
        return reverb(seq(prog1(s, setf(s, nil)), s-rest(rt * 2)), rt)

  Note in this example that the variable `s` loses its reference to the `long-tone()` sound right after it is evaluated by `prog1`, so now `reverb` has the only reference to this sound, and it can free samples from `long-tone()` as they are consumed. (In case you are wondering, the actual mechanism is that when `reverb` frees samples, their reference count goes to zero since no other reference exists to the possibly shared list of samples. There is no other reference because the reference previously bound to `s` is released by the garbage collector.) It should be noted that the variable `rt` is retained in the closure and remains accessible there, so when `s` terminates, `s-rest(rt`) will evaluate as expected, using the value that `rt` acquired way back when `rev-with-tail` was called. This illustrates why the local variables must be saved in closures at the time `seq` is called.

`seqrep(var, limit, beh)` [SAL]
`(seqrep (var limit) beh)` [LISP]
  Iteratively evaluates beh with the atom var set with values from 0 to limit-1, inclusive. These sounds are placed sequentially in time as if by `seq`. The symbol var is a read-only local variable to beh. Assignments are not restricted or detected, but may cause a run-time error or crash. In LISP, the syntax is `(seqrep (var limit) beh)`.
`sim([beh1, beh2, ...])` [SAL]
`(sim [beh1 beh2 ...])` [LISP]
  Returns a sound which is the sum of the given behaviors evaluated with the current value of `*warp*`. If behaviors return multiple channel sounds, the corresponding channels are added. If the number of channels does not match, the result has as many channels as the argument with the most channels. For example, if a two-channel sound [L, R] is added to a four-channel sound [C1, C2, C3, C4], the result is [L + C1, R + C2, C3, C4]. Arguments to `sim` may also be numbers. If all arguments are numbers, `sim` is equivalent (although slower than) the LISP `+` function. If a number is added to a sound, `snd-offset` is used to add the number to each sample of the sound. The result of adding a number to two or more sounds with different durations is not defined. Use `const` to coerce a number to a sound of a specified duration. An important limitation of `sim` is that it cannot handle hundreds of behaviors due to a stack size limitation in XLISP. To compute hundreds of sounds (e.g. notes) at specified times, see `timed-seq`, below. See also `sum` below. Notce that `sim` is not transitive due to coercion rules: Using SAL syntax, `sim(a, sim(b, c))` may not produce the same result as `sim(sim(a, b), c)`.
`simrep(var, limit, beh)` [SAL]
`(simrep var limit beh)` [LISP]
  Iteratively evaluates beh with the atom var set with values from 0 to limit-1, inclusive. These sounds are then placed simultaneously in time as if by `sim`. In LISP, the syntax is `(seqrep (var limit) beh)`.
`set-logical-stop(beh, time)` [SAL]
`(set-logical-stop beh time)` [LISP]
  Returns a sound with time as the logical stop time.
`sum(a [, b, ...])`[SAL]
`(sum a [b ...])` [LISP]
  Returns the sum of a, b, ..., allowing mixed addition of sounds, multichannel sounds and numbers. Identical to sim. In SAL, use the infix “+” operator. See `sim` just above for more detail.
`mult(a [, b, ...])` [SAL]
`(mult a [b ...])` [LISP]
  Returns the product of a, b, ..., allowing mixed multiplication of sounds, multichannel sounds and numbers.
`diff(a, b)` [SAL]
`(diff a b)` [LISP]
  Returns the difference between a and b. This function is defined as `(sum a (prod -1 b))`.
`timed-seq(score)` [SAL]
`(timed-seq score)` [LISP]
  Computes sounds from a note list or “score.” The score is of the form: ``((time1 stretch1 beh1) (time2 stretch2 beh2) ...)`, where timeN is the starting time, stretchN is the stretch factor, and behN is the behavior. Note that score is normally a quoted list! The times must be in increasing order, and each behN is evaluated using lisp's `eval`, so the behN behaviors cannot refer to local parameters or local variables. The advantage of this form over `seq` is that the behaviors are evaluated one-at-a-time which can take much less stack space and overall memory. One special “behavior” expression is interpreted directly by `timed-seq`: `(SCORE-BEGIN-END)` is ignored, not evaluated as a function. Normally, this special behavior is placed at time 0 and has two parameters: the score start time and the score end time. These are used in Xmusic functions. If the behavior has a `:pitch` keyword parameter which is a list, the list represents a chord, and the expression is replaced by a set of behaviors, one for each note in the chord. It follows that if `:pitch` is `nil`, the behavior represents a rest and is ignored.

### Sound File Input and Output

`play sound` [SAL]
`(play sound)` [LISP]
  Play the sound through the DAC. In XLISP, it is a function. In SAL, you can invoke `play` as either a command or a function:

      play pluck(c4)
      ;; or call the function #play like this:
      exec #play(pluck(c4))

  The `play` command or function writes a file and plays it. The sound is any expression that evaluates to a SOUND. Typically, this should be function call, in which case the samples are computed incrementally and not retained in main memory (an advantage for large sounds). If the expression is a variable containing a SOUND (which may or may not be fully evaluated yet), the SOUND is fully evaluated and all samples are retained in the variable. The `play` function is defined in the file `system.lsp`. The variable `*default-sf-dir*` names a directory into which to save a sound file, and `*default-sound-file*` names the file. If `*default-sound-file*` contains a slash (`/`), it is treated as an absolute path or path relative to the current directory, ignoring `*default-sf-dir*`. Be careful not to call `play` or `sound-play` within a function and then invoke that function from another `play` command. By default, Nyquist will try to normalize sounds using the method named by `*autonorm-type*`, which is `'lookahead` by default. The lookahead method precomputes and buffers `*autonorm-max-samples*` samples, finds the peak value, and normalizes accordingly. The `'previous` method bases the normalization of the current sound on the peak value of the (entire) previous sound. This might be good if you are working with long sounds that start rather softly. See Section Memory Space and Normalization for more details. If you want precise control over output levels, you should turn this feature off by typing (using SAL syntax):

      autonorm-off()

  Reenable the automatic normalization feature by typing:

      autonorm-on()

  Play normally produces real-time output. The default is to send audio data to the DAC as it is computed in addition to saving samples in a file. If computation is slower than real-time, output will be choppy, but since the samples end up in a file, you can type `(r)` to replay the stored sound. Real-time playback can be disabled by (using SAL syntax):

      sound-off()

  and reenabled by:

      sound-on()

  Disabling real-time playback has no effect on `(play-file)` or `(r)`. While sounds are playing, typing control-A to Nyquist (or clicking the Mark button in the NyquistIDE) will push the estimated elapsed audio time onto the head of the list stored in `*audio-markers*`. Because samples are computed in blocks and because there is latency between sample computation and sample playback, the elapsed time may not be too accurate, and the computed elapsed time may not advance after all samples have been computed but the sound is still playing.

`play-file(filename)` [SAL]
`(play-file filename)` [LISP]
  Play the contents of a sound file named by filename. The `s-read` function is used to read the file, and unless filename specifies an absolute path or starts with “.”, it will be read from `*default-sf-dir*`.
`autonorm-on()` [SAL]
`(autonorm-on)` [LISP]
  Enable automatic adjustment of a scale factor applied to sounds computed using the `play` command.
`autonorm-off()` [SAL]
`(autonorm-off)` [LISP]
  Disable automatic adjustment of a scale factor applied to sounds computed using the `play` command.
`sound-on()` [SAL]
`(sound-on)` [LISP]
  Enable real-time audio output when sound is computed by the the `play` command.
`sound-off()` [SAL]
`(sound-off)` [LISP]
  Disable real-time audio output when sound is computed by the the `play` command.
`s-save(expression, [maxlen, filename, progress], format: format, mode: mode, bits: bits, swap: flag, play: play)` [SAL]
`(s-save expression [maxlen filename progress] :format format :mode mode :bits bits :swap flag :play play)` [LISP]
  Evaluates the expression, which should result in a sound or an array of sounds, and writes the result to the given filename. (If omitted, `*default-sound-file*` is used instead.) A `FLONUM` is returned giving the maximum absolute value of all samples written. (This is useful for normalizing sounds and detecting sample overflow.) If play is not `NIL`, the sound will be output through the computer's audio output system. (play: [SAL] or :play [LISP] is not implemented on all systems; if it is implemented, and filename is `NIL`, then this will play the file without also writing a file.) The latency (length of audio buffering) used to play the sound is 0.3s by default, but see `snd-set-latency`. If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is optionally given by maxlen, which allows writing the initial part of a very long or infinite sound. Progress is indicated by printing the sample count after writing each 10 seconds of frames. If progress is specified and greater than 10,000, progress is printed at this specified frame count increment. A header is written according to format, samples are encoded according to mode, using bits bits/sample, and bytes are swapped if flag is not NIL. Defaults for these are `*default-sf-format*`, `*default-sf-mode*`, and `*default-sf-bits*`. The default for flag is NIL. The bits parameter may be 8, 16, or 32. The values for the format and mode options are described below:

Format

`snd-head-none`
  The format is unknown and should be determined by reading the file.
`snd-head-raw`
  A raw format file has no header.
`snd-head-AIFF`
  AIFF format header.
`snd-head-IRCAM`
  IRCAM format header.
`snd-head-NeXT`
  1024-byte NeXT/SUN format header followed by IRCAM header ala CMIX. Note that the NeXT/SUN format has a header-length field, so it really is legal to have a large header, even though the normal minimal header is only 24 bytes. The additional space leaves room for maximum amplitudes, which can be used for normalizing floating-point soundfiles, and for other data. Nyquist follows the CMIX convention of placing an IRCAM format header immediately after the NeXT-style header.
`snd-head-Wave`
  Microsoft Wave format header.
`snd-head-WaveX`
  Microsoft Wave with WAVEFORMATEX format header.
`snd-head-flac`
  FLAC lossless compressed audio.
`snd-head-ogg`
  OGG-VORBIS compressed audio.
`snd-head-*`
  See sndfnint.lsp in the `nyquist/runtime` directory for more formats. The current list includes `paf`, `svx`, `nist`, `voc`, `w64`, `mat4`, `mat5`, `pvf`, `xi`, `htk`, `sds`, `avr`, `sd2`, and `caf`.

Mode

`snd-mode-adpcm`
  ADPCM mode (not supported).
`snd-mode-pcm`
  signed binary PCM mode.
`snd-mode-ulaw`
  8-bit U-Law mode.
`snd-mode-alaw`
  8-bit A-Law mode (not supported).
`snd-mode-float`
  32-bit floating point mode.
`snd-mode-upcm`
  unsigned binary PCM mode.
`snd-mode-*`
  See sndfnint.lsp in the `nyquist/runtime` for more modes. The current list includes `double`, `gsm610`, `dwvw`, `dpcm`, and `msadpcm`.

The defaults for format, mode, and bits are as follows:

NeXT and Sun machines:
  `snd-head-NeXT`, `snd-mode-pcm`, `16`
SGI and Macintosh machines:
  `snd-head-AIFF`, `snd-mode-pcm`, `16`

`s-read(filename, time-offset: offset, srate: sr, dur: dur, nchans: chans, format: format, mode: mode, bits: n, swap: flag)` [SAL]
`(s-read filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag)` [LISP]
  Reads a sound from filename. The global `*default-sf-dir*` applies. If a header is detected, the header is used to determine the format of the file, and header information overrides format information provided by keywords (except for `time-offset:` and `dur:`).

      s-read("mysound.snd", srate: 44100)

  specifies a sample rate of 44100 hz, but if the file has a header specifying 22050 hz, the resulting sample rate will be 22050. The parameters are:

  - offset – the amount of time (in seconds) to skip from the beginning of the file. The default is 0.0.
  - sr – the sample rate of the samples in the file. Default is `*default-sf-srate*` , which is normally 44100.
  - dur – the maximum duration in seconds to read. Default is 10000.
  - chans – the number of channels to read. It is assumed that samples from each channel are interleaved. Default is 1.
  - format – the header format. See `s-save` for details. Default is `*default-sf-format*`, although this parameter is currently ignored.
  - mode – the sample representation, e.g. PCM or float. See `s-save` for details. Default is `*default-sf-format*`.
  - n – the number of bits per sample. See `s-save` for details. Default is `*default-sf-bits*`.
  - flag – (T or NIL) swap byte order of each sample. Default is NIL.
  If there is an error, for example if offset is greater than the length of the file, then `NIL` is returned rather than a sound. Information about the sound is also returned by `s-read` through `*rslt*` (Footnote 4) . The list assigned to `*rslt*` is of the form: (format channels mode bits swap samplerate duration flags), which are defined as follows:
  - format – the header format. See `s-save` for details. Access this element of `*rslt*` by calling `snd-read-format(*rslt*)`.
  - channels – the number of channels. Access this element of `*rslt*` by calling `snd-read-channels(*rslt*)`.
  - mode – the sample representation, e.g. PCM or float. Access this element of `*rslt*` by calling `snd-read-mode(*rslt*)`. See `s-save` for details.
  - bits – the number of bits per sample. Access this element of `*rslt*` by calling `snd-read-bits(*rslt*)`.
  - swap – 1 if byte-swapping is needed, 0 otherwise. Access this element of `*rslt*` by calling `snd-read-swap(*rslt*)`.
  - samplerate – the sample rate, expressed as a `FLONUM`. Access this element of `*rslt*` by calling `snd-read-srate(*rslt*)`.
  - duration – the duration of the sound, in seconds. Access this element of `*rslt*` by calling `snd-read-dur(*rslt*)`.
  - flags – The values for format, channels, mode, bits, samplerate, and duration are initially just the values passed in as parameters or default values to `s-read`. If a value is actually read from the sound file header, a flag is set. The flags are: `snd-head-type` (format), `snd-head-channels`, `snd-head-mode`, `snd-head-bits`, `snd-head-srate`, and `snd-head-dur`. For example,

        (let ((flags (s-read-flags *rslt*)))
          (not (zerop (logand flags snd-head-srate))))

    tells whether the sample rate was specified in the file. See also `sf-info` below. Access this element of `*rslt*` by calling `snd-read-flags(*rslt*)`.

`s-add-to(expression, maxlen, filename [, offset, progress])` [SAL]
`(s-add-to expression maxlen filename [offset progress])` [LISP]
  Evaluates the expression, which should result in a sound or an array of sounds, and adds the result to the given filename. The global `*default-sf-dir*` applies. A `FLONUM` is returned, giving the maximum absolute value of all samples written. The sample rate(s) of expression must match those of the file. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. If offset is specified, the new sound is added to the file beginning at an offset from the beginning (in seconds). Progress is indicated by printing the sample count after writing each 10 seconds of frames. If progress is specified and greater than 10,000, progress is printed at this specified frame count increment. The file is extended if necessary to accommodate the new addition, but if offset falls outside of the original file, the file is not modified. (If necessary, use `s-add-to` to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file).
`s-overwrite(expression, maxlen, filename [, offset, progress])` [SAL]
`(s-overwrite expression maxlen filename [offset progress])` [LISP]
  Evaluates the expression, which should result in a sound or an array of sounds, and replaces samples in the given filename. The global `*default-sf-dir*` applies. A `FLONUM` is returned, giving the maximum absolute value of all samples written. The sample rate(s) of expression must match those of the file. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. If offset is specified, the new sound is written to the file beginning at an offset from the beginning (in seconds). The file is extended if necessary to accommodate the new insert, but if offset falls outside of the original file, the file is not modified. (If necessary, use `s-add-to` to extend the file with zeros.) Progress is indicated by printing the sample count after writing each 10 seconds of frames. If progress is specified and greater than 10,000, progress is printed at this specified frame count increment. The file must be a recognized sound file with a header (not a raw sound file).
`sf-info(filename)` [SAL]
`(sf-info filename)` [LISP]
  Prints information about a sound file. The parameter filename is a string. The file is assumed to be in *default-sf-dir* (see `soundfilename` below) unless the filename begins with “.” or “/”. The source for this function is in the `runtime` and provides an example of how to determine sound file parameters.
`soundfilename(name)` [SAL]
`(soundfilename name)` [LISP]
  Converts a string name to a soundfile name. If name begins with “.” or “/”, the name is returned without alteration. Otherwise, a path taken from `*default-sf-dir*` is prepended to name. The `s-plot`, `s-read`, and `s-save` functions all use `soundfilename` to translate filenames.
`s-plot(sound [, dur, n])` [SAL]
`(s-plot sound [dur n])` [LISP]
  Plots sound in a window. This function was designed to run a `plot` program on a Unix workstation, but now is primarily used with `NyquistIDE`, which has self-contained plotting. Normally, time/value pairs in ascii are written to `points.dat` and system-dependent code (or the `NyquistIDE` program) takes it from there. If the sound is longer than the optional dur (default is 2 seconds), only the first dur seconds are plotted. If there are more than n samples to be plotted, the signal is interpolated to have n samples before plotting. The data file used is `*default-plot-file*`:
`*default-plot-file*`
  The file containing the data points, defaults to "points.dat".
`spec-plot(sound [, offset: offset, dur: dur, res: res, bw: bw, db: db])` [SAL]
`(spec-plot sound [:offset offset :dur dur :res res :bw bw :db db])` [LISP]
  Computes and plots the short-time magnitude spectrum of sound (a SOUND or STRING). If sound is a filename (a STRING), a sound is read from the file. The bandwidth of each bin is given by the res (resolution) keyword parameter, which defaults to `*spec-plot-res*. Since one is often interested in lower frequencies, the bw (bandwidth` keyword parameter limits the range of bins which are plotted, and defaults to `*spec-plot-bw*`. The output can be presented on a dB scale by setting the db keyword parameter to `t` (true). The default is to use a linear scale. The offset (in seconds) skips initial samples before taking a frame of samples from sound. The dur keyword parameter (in seconds) limits the number of samples taken from sound. If dur is shorter than the FFT window size, the sound is zero-padded. If dur is longer than the FFT window size, the extra samples are ignored. The magnitude spectrum is sent to `s-plot` as a signal. The sample rate of the signal is set so that the plot labels on the horizontal axis represent Hz (not bin numbers.) To align bins with grid lines, one normally specifies res values in round numbers, e.g. 10 or 20. To achieve an arbitrary bin size, `spec-plot` resamples sound to a carefully computed sample rate that, after a power-of-2-sized FFT, yields the desired bin size.
`spec-print(file sound [, offset: offset, dur: dur, res: res, bw: bw, threshold: threshold])` [SAL]
`(spec-print file sound [:offset offset :dur dur :res res :bw bw :threshold threshold])` [LISP]
  Computes and prints an ASCII plot of the short-time magnitude spectrum of sound using `sa-print` (see Spectral Processing). The file can be `T` to print to the console or a file open for writing. Other parameters are as in `spec-plot` (see above) except for threshold, which is passed to `sa-print`. Note that bw is passed to `sa-print` as cutoff. The global variables `*spec-plot-res*` and `*spec-plot-bw*` apply to `spec-print` as well as `spec-plot`. Important: The printed and plotted magnitudes are normalized to a peak value of 1 (see `sa-normalize`).
`*spec-plot-res*`
  The default bin resolution (separation in Hz between adjacent bins) for `spec-plot`. Defaults to 20 Hz. You can override this by using a keyword parameter when you call `spec-plot` or `spec-print`, or for convenience, you can change this variable which will affect all future calls to `spec-plot` where the keyword parameter is omitted.
`*spec-plot-bw*`
  The default highest frequency to include in `spec-plot`. Defaults to 8000 Hz. You can override this by using a keyword parameter when you call `spec-plot` or `spec-print`, or for convenience, you can change this variable which will affect all future calls to `spec-plot` where the keyword parameter is omitted.
`*spec-plot-db*`
  The default output from `spec-plot` displays magnitude on a linear scale, but there is an option to display on a dB scale. You can change the default behavior by setting this variable to `t` (true), or you can override the default in any call to `spec-plot` using a keyword parameter.
`s-print-tree(sound)` [SAL]
`(s-print-tree sound)` [LISP]
  Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging Nyquist. Identical to `snd-print-tree`.

### Low-level Functions

Nyquist includes many low-level functions that are used to implement the functions and behaviors described in previous sections. For completeness, these functions are described here. Remember that these are low-level functions that are not intended for normal use. Unless you are trying to understand the inner workings of Nyquist, you can skip this section.

#### Creating Sounds

The basic operations that create sounds are described here.

`snd-const(value, t0, srate, duration)` [SAL]
`(snd-const value t0 srate duration)` [LISP]
  Returns a sound with constant value, starting at t0 with the given duration, at the sample rate srate. You might want to use `pwl` (see Section Piece-wise Approximations) instead.
`snd-read(filename, offset, t0, format, channels, mode, bits, swap, sr, dur)` [SAL]
`(snd-read filename offset t0 format channels mode bits swap sr dur)` [LISP]
  Loads a sound from a file with name filename. Files are assumed to consist of a header followed by frames consisting of one sample from each channel. The format specifies the type of header, but this information is currently ignored. Nyquist looks for a number of header formats and automatically figures out which format to read. If a header can be identified, the header is first read from the file. Then, the file pointer is advanced by the indicated offset (in seconds). If there is an unrecognized header, Nyquist will assume the file has no header. If the header size is a multiple of the frame size (bytes/sample * number-of-channels), you can use offset to skip over the header. To skip N bytes, use an offset of:

      (/ (float N) sr (/ bits 8) channels)

  If the header is not a multiple of the frame size, either write a header or contact the author (dannenberg@cs.cmu.edu) for assistance. Nyquist will round offset to the nearest sample. The resulting sound will start at time t0. If a header is found, the file will be interpreted according to the header information. If no header was found, channels tells how many channels there are, the samples are encoded according to mode, the sample length is bits, and sr is the sample rate. The swap flag is 0 or 1, where 1 means to swap sample bytes. The duration to be read (in seconds) is given by dur. If dur is longer than the data in the file, then a shorter duration will be returned. If the file contains one channel, a sound is returned. If the file contains 2 or more channels, an array of sounds is returned. Note: you probably want to call `s-read` (see Section Sound File Input and Output) instead of `snd-read`. Also, see Section Sound File Input and Output for information on the mode and format parameters.

`snd-save(expression, maxlen, filename, format, mode, bits, swap, play, progress)` [SAL]
`(snd-save expression maxlen filename format mode bits swap play progress)` [LISP]
  Evaluates the expression, which should result in a sound or an array of sounds, and writes the result to the given filename. If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. A header is written according to format, samples are encoded according to mode, using bits bits/sample, and swapping bytes if swap is 1 (otherwise it should be 0). If play is not null, the audio is played in real time (to the extent possible) as it is computed. Progress is indicated by printing the sample count after writing each 10 seconds of frames. If progress is specified and greater than 10,000, progress is printed at this specified frame count increment. The peak value of the sound is returned. In addition, the symbol `*RSLT*` is bound to a list containing the sample rate, number of channels, and duration (in that order) of the saved sound. Note: you probably want to call `s-save` (see Section Sound File Input and Output) instead. The format and mode parameters are described in Section Sound File Input and Output.
`snd-overwrite(expression, maxlen, filename, offset, progress)` [SAL]
`(snd-overwrite expression maxlen filename offset progress)` [LISP]
  Evaluates the expression, which should result in a sound or an array of sounds, and replaces samples in the given filename, writing the first frame at a time of offset seconds. The offset must be less than or equal to the duration of the existing file. Progress is indicated by printing the sample count after writing each 10 seconds of frames. If progress is specified and greater than 10,000, progress is printed at this specified frame count increment. The duration of the written samples may be greater than that of the file, in which case the file is extended as necessary. The sample rate(s) of expression and the number of channels must match those of the file. Up to a maximum of maxlen samples will be written per channel. The peak value of the sound is returned. In addition, the symbol `*RSLT*` is bound to a list containing the duration of the written sound (which may not be the duration of the sound file). Use `s-add-to` (in Section Sound File Input and Output or `s-overwrite` (in Section Sound File Input and Output instead of this function.
`snd-coterm(s1, s2)` [SAL]
`(snd-coterm s1 s2)` [LISP]
  Returns a copy of s1, except the start time is the maximum of the start times of s1 and s2, and the termination time is the minimum of s1 and s2. (After the termination time, the sound is zero as if s1 is gated by s2.) Some rationale follows: In order to implement `s-add-to`, we need to read from the target sound file, add the sounds to a new sound, and overwrite the result back into the file. We only want to write as many samples into the file as there are samples in the new sound. However, if we are adding in samples read from the file, the result of a `snd-add` in Nyquist will have the maximum duration of either sound. Therefore, we may read to the end of the file. What we need is a way to truncate the read, but we cannot easily do that, because we do not know in advance how long the new sound will be. The solution is to use `snd-coterm`, which will allow us to truncate the sound that is read from the file (s1) according to the duration of the new sound (s2). When this truncated sound is added to the new sound, the result will have only the duration of the new sound, and this can be used to overwrite the file. This function is used in the implementation of `s-add-to`, which is defined in `runtime/fileio.lsp`.
`(snd-from-array ...)` [SAL]
`(snd-from-array ...)` [LISP]
  See Accessing and Creating Sound.
`snd-white(t0, sr, d)` [SAL]
`(snd-white t0 sr d)` [LISP]
  Generate white noise, starting at t0, with sample rate sr, and duration d. You probably want to use `noise` (see Section More Behaviors).
`snd-zero(t0, srate)` [SAL]
`(snd-zero t0 srate)` [LISP]
  Creates a sound that is zero everywhere, starts at t0, and has sample rate srate. The logical stop time is immediate, i.e. also at t0. You probably want to use `pwl` (see Section Piece-wise Approximations) instead.

#### Signal Operations

This next set of functions take sounds as arguments, operate on them, and return a sound.

`snd-abs(sound)` [SAL]
`(snd-abs sound)` [LISP]
  Computes a new sound where each sample is the absolute value of the corresponding sample in sound. You should probably use `s-abs` instead. (See Section More Behaviors.)
`snd-sqrt(sound)` [SAL]
`(snd-sqrt sound)` [LISP]
  Computes a new sound where each sample is the square root of the corresponding sample in sound. If a sample is negative, it is taken to be zero to avoid raising a floating point error. You should probably use `s-sqrt` instead. (See Section More Behaviors.)
`snd-add(sound1, sound)` [SAL]
`(snd-add sound1 sound)` [LISP]
  Adds two sounds. The resulting start time is the minimum of the two parameter start times, the logical stop time is the maximum of the two parameter stop times, and the sample rate is the maximum of the two parameter sample rates. Use `sim` or `sum` instead of `snd-add` (see Section Combination and Time Structure).
`snd-offset(sound, offset)` [SAL]
`(snd-offset sound offset)` [LISP]
  Add an offset to a sound. The resulting start time, logical stop time, stop time, and sample rate are those of sound. Use `sum` instead (see Section Combination and Time Structure).
`snd-avg(sound, blocksize, stepsize, operation)` [SAL]
`(snd-avg sound blocksize stepsize operation)` [LISP]
  Use `s-avg` instead (see Section More Behaviors). The `s-avg` function extends `snd-avg` to multichannel input sounds.
`snd-clip(sound, peak)` [SAL]
`(snd-clip sound peak)` [LISP]
  Hard limit sound to the given peak, a positive number. The samples of sound are constrained between an upper value of peak and a lower value of -peak. Use `clip` instead (see Section More Behaviors).
`snd-compose(f, g)` [SAL]
`(snd-compose f g)` [LISP]
  Compose two signals, i.e. compute f(g(t)), where f and g are sounds. This function is used primarily to implement time warping, but it can be used in other applications such as frequency modulation. For each sample x in g, snd-compose looks up the value of f(x) using linear interpolation. The resulting sample rate, start time, etc. are taken from g. The sound f is used in effect as a lookup table, but it is assumed that g is non-decreasing, so that f is accessed in time order. This allows samples of f to be computed and discarded incrementally. If in fact g decreases, the current sample of g is replaced by the previous one, forcing g into compliance with the non-decreasing restriction. See also `sref`, `shape`, and `snd-resample`. For an extended example that uses `snd-compose` for variable pitch shifting, see `nyquist/demos/pitch_change.htm`.
`snd-tapv(sound, offset, vardelay, maxdelay)` [SAL]
`(snd-tapv sound offset vardelay maxdelay)` [LISP]
  A variable delay: sound is delayed by the sum of offset (a `FIXNUM` or `FLONUM`) and vardelay (a `SOUND`). The specified delay is adjusted to lie in the range of zero to maxdelay seconds to yield the actual delay, and the delay is implemented using linear interpolation. This function was designed specifically for use in a chorus effect: the offset is set to half of maxdelay, and the vardelay input is a slow sinusoid. The maximum delay is limited to maxdelay, which determines the length of a fixed-sized buffer. The function `tapv` is equivalent and preferred (see Section Filter Behaviors).
`snd-tapf(sound, offset, vardelay, maxdelay)` [SAL]
`(snd-tapf sound offset vardelay maxdelay)` [LISP]
  A variable delay like `snd-tapv` except there is no linear interpolation. By eliminating interpolation, the output is an exact copy of the input with no filtering or distortion. On the other hand, delays jump by samples causing samples to double or skip even when the delay is changed smoothly.
`snd-copy(sound)` [SAL]
`(snd-copy sound)` [LISP]
  Makes a copy of sound. Since operators always make (logical) copies of their sound parameters, this function should never be needed. This function is here for debugging.
`snd-down(srate, sound)` [SAL]
`(snd-down srate sound)` [LISP]
  Linear interpolation of samples down to the given sample rate srate, which must be lower than the sample rate of sound. Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call `force-srate` (see Section Sound Synthesis).
`snd-exp(sound)` [SAL]
`(snd-exp sound)` [LISP]
  Compute the exponential of each sample of sound. Use `s-exp` instead (see Section More Behaviors).
`snd-follow(sound, floor, risetime, falltime, lookahead)` [SAL]
`(snd-follow sound floor risetime falltime lookahead)` [LISP]
  An envelope follower. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The floor is the minimum output value. The risetime is the time (in seconds) it takes for the output to rise (exponentially) from floor to unity (1.0) and the falltime is the time it takes for the output to fall (exponentially) from unity to floor. The algorithm looks ahead for peaks and will begin to increase the output signal according to risetime in anticipation of a peak. The amount of anticipation (in samples) is given by lookahead. The algorithm is as follows: the output value is allowed to increase according to risetime or decrease according to falltime. If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to risetime to meet the new value. The algorithm will only work backward as far as lookahead. If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by falltime, the output fall rate will be limited by falltime, and the fall in output will stop when the output reaches floor. This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See `snd-avg` above for a function that can help to generate a low-sample-rate input for `snd-follow`. See `snd-chase` in Section Filters for a related filter.
`snd-gate(sound, lookahead, risetime, falltime, floor, threshold)` [SAL]
`(snd-gate sound lookahead risetime falltime floor threshold)` [LISP]
  This function generates an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below threshold and stays there for longer than lookahead. Decay continues until the value reaches floor, at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the output value will rise to unity (1.0) at the point the signal crosses the threshold. Again, look-ahead is used, so the rise actually starts before the signal crosses the threshold. The rise is a constant-rate exponential and set so that a rise from floor to unity occurs in risetime. Similarly, the fall is a constant-rate exponential such that a fall from unity to floor takes falltime. The result is delayed by lookahead, so the output is not actually synchronized with the input. To compensate, you should drop the initial lookahead of samples. Thus, `snd-gate` is not recommended for direct use. Use `gate` instead (see Section Miscellaneous Functions).
`snd-inverse(signal, start, srate)` [SAL]
`(snd-inverse signal start srate)` [LISP]
  Compute the function inverse of signal, that is, compute g(t) such that signal(g(t)) = t. This function assumes that signal is non-decreasing, it uses linear interpolation, the resulting sample rate is srate, and the result is shifted to have a starting time of start. If signal decreases, the true inverse may be undefined, so we define `snd-inverse` operationally as follows: for each output time point t, scan ahead in signal until the value of signal exceeds t. Interpolate to find an exact time point x from signal and output x at time t. This function is intended for internal system use in implementing time warps.
`snd-log(sound)` [SAL]
`(snd-log sound)` [LISP]
  Compute the natural logorithm of each sample of sound. Use `s-log` instead (see Section More Behaviors).
`peak(expression, maxlen)` [SAL]
`(peak expression maxlen)` [LISP]
  Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating expression (as in `s-save`). Only the first maxlen samples are evaluated. The expression is automatically quoted (`peak` is a macro), so do not quote this parameter. If expression is a variable, then the global binding of that variable will be used. Also, since the variable retains a reference to the sound, the sound will be evaluated and left in memory. See Section Memory Space and Normalization on Memory Space and Normalization for examples.
`snd-max(expression, maxlen)` [SAL]
`(snd-max expression maxlen)` [LISP]
  Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating expression (as in `snd-save`), which is therefore normally quoted by the caller. At most maxlen samples are computed. The result is the maximum of the absolute values of the samples. Notes: It is recommended to use `peak` (see above) instead. If you want to find the maximum of a sound bound to a local variable and it is acceptable to save the samples in memory, then this is probably the function to call. Otherwise, use `peak`.
`snd-maxv(sound1, sound2)` [SAL]
`(snd-maxv sound1 sound2)` [LISP]
  Compute the maximum of sound1 and sound2 on a sample-by-sample basis. The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. The physical stop time is the minimum of the physical stop times of the two sounds. Note that this violates the “normal” interpretation that sounds are zero outside their start and stop times. For example, even if sound1 extends beyond sound2 and is greater than zero, the result value in this extension will be zero because it will be after the physical stop time, whereas if we simply treated sound2 as zero in this region and took the maximum, we would get a non-zero result. Use `s-max` instead (see Section More Behaviors).
`snd-normalize(sound)` [SAL]
`(snd-normalize sound)` [LISP]
  Internally, sounds are stored with a scale factor that applies to all samples of the sound. All operators that take sound arguments take this scale factor into account (although it is not always necessary to perform an actual multiply per sample), so you should never need to call this function. This function multiplies each sample of a sound by its scale factor, returning a sound that represents the same signal, but whose scale factor is 1.0.
`snd-oneshot(sound, threshold, ontime)` [SAL]
`(snd-oneshot sound threshold ontime)` [LISP]
  Computes a new sound that is zero except where sound exceeds threshold. From these points, the result is 1.0 until sound remains below threshold for ontime (in seconds). The result has the same sample rate, start time, logical stop time, and duration as sound.
`snd-prod(sound1, sound2)` [SAL]
`(snd-prod sound1 sound2)` [LISP]
  Computes the product of sound1 and sound2. The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. Do not use this function. Use `mult` or `prod` instead (see Section Sound Synthesis). Sample rate, start time, etc. are taken from sound.
`snd-pwl(t0, sr, lis)` [SAL]
`(snd-pwl t0 sr lis)` [LISP]
  Computes a piece-wise linear function according to the breakpoints in lis. The starting time is t0, and the sample rate is sr. The breakpoints are passed in an XLISP list (of type `LVAL`) where the list alternates sample numbers (`FIXNUM`s, computed in samples from the beginning of the pwl function) and values (the value of the pwl function, given as a `FLONUM`). There is an implicit starting point of (0, 0). The list must contain an odd number of points, the omitted last value being implicitly zero (0). The list is assumed to be well-formed. Do not call this function. Use `pwl` instead (see Section Piece-wise Approximations).
`snd-quantize(sound, steps)` [SAL]
`(snd-quantize sound steps)` [LISP]
  Quantizes a sound. See Section More Behaviors for details.
`snd-recip(sound)` [SAL]
`(snd-recip sound)` [LISP]
  Compute the reciprocal of each sample of sound. Use `recip` instead (see Section More Behaviors).
`snd-resample(f, rate)` [SAL]
`(snd-resample f rate)` [LISP]
  Resample sound f using high-quality interpolation, yielding a new sound with the specified rate. The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. The resulting start time, etc. are taken from f. Use `resample` instead.
`snd-resamplev(f, rate, g)` [SAL]
`(snd-resamplev f rate g)` [LISP]
  Compose two signals, i.e. compute f(g(t)), where f and g are sounds. The result has sample rate given by rate. At each time t (according to the rate), g is linearly interpolated to yield an increasing sequence of high-precision score-time values. f is then interpolated at each value to yield a result sample. If in fact g decreases, the current sample of g is replaced by the previous one, forcing g into compliance with the non-decreasing restriction. The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. Note that if g has a high sample rate, this may introduce unwanted jitter into sample times. See `sound-warp` for a detailed discussion. See `snd-compose` for a fast, low-quality alternative to this function. Normally, you should use `sound-warp` instead of this function.
`snd-scale(scale, sound)` [SAL]
`(snd-scale scale sound)` [LISP]
  Scales the amplitude of sound by the factor scale. Use `scale` instead (see Section Sound Synthesis).
`snd-shape(signal, table, origin)` [SAL]
`(snd-shape signal table origin)` [LISP]
  A waveshaping function. This is the primitive upon which `shape` is based. The `snd-shape` function is like `shape` except that signal and table must be (single-channel) sounds. Use `shape` instead (see Section Filter Behaviors).
`snd-up(srate, sound)` [SAL]
`(snd-up srate sound)` [LISP]
  Increases sample rate by linear interpolation. The sound is the signal to be up-sampled, and srate is the output sample rate. Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call `force-srate` (see Section Sound Synthesis).
`snd-xform(sound, sr, time, start, stop, scale)` [SAL]
`(snd-xform sound sr time start stop scale)` [LISP]
  Makes a copy of sound and then alters it in the following order: (1) the start time (`snd-t0`) of the sound is shifted to time, (2) the sound is stretched as a result of setting the sample rate to sr (the start time is unchanged by this), (3) the sound is clipped from start to stop, (4) if start is greater than time, the sound is shifted shifted by time - start, so that the start time is time, (5) the sound is scaled by scale. An empty (zero) sound at time will be returned if all samples are clipped. Normally, you should accomplish all this using transformations. A transformation applied to a sound has no effect, so use `cue` or `sound` to create a transformable sound (see Section Using Previously Created Sounds).
`snd-yin(sound, minstep, maxstep, rate)` [SAL]
`(snd-yin sound minstep maxstep rate)` [LISP]
  Identical to `yin`. See Section More Behaviors.

#### Filters

These are also “Signal Operators,” the subject of the previous section, but there are so many filter functions, they are documented in this special section.

Some filters allow time-varying filter parameters. In these functions, filter coefficients are calculated at the sample rate of the filter parameter, and coefficients are not interpolated.

`snd-alpass(sound, delay, feedback)` [SAL]
`(snd-alpass sound delay feedback)` [LISP]
  An all-pass filter. This produces a repeating echo effect without the resonances of `snd-delay`. The feedback should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use `alpass` instead (see Section Filter Behaviors).
`snd-alpasscv(sound, delay, feedback)` [SAL]
`(snd-alpasscv sound delay feedback)` [LISP]
  An all-pass filter with variable feedback. This is just like snd-alpass except feedback is a sound. You should use `alpass` instead (see Section Filter Behaviors).
`snd-alpassvv(sound, delay, feedback, maxdelay)` [SAL]
`(snd-alpassvv sound delay feedback maxdelay)` [LISP]
  An all-pass filter with variable feedback and delay. This is just like snd-alpass except feedback and delay are sounds, and there is an additional `FLONUM` parameter, maxdelay, that gives an upper bound on the value of delay. Note: delay must remain between zero and maxdelay. If not, results are undefined, and Nyquist may crash. You should use `alpass` instead (see Section Filter Behaviors).
`snd-areson(sound, hz, bw, normalization)` [SAL]
`(snd-areson sound hz bw normalization)` [LISP]
  A notch filter modeled after the `areson` unit generator in Csound. The `snd-areson` filter is an exact complement of `snd-reson` such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. Note that because of this complementary design, the power is not normalized as in `snd-reson`. See `snd-reson` for details on normalization. You should use `areson` instead (see Section Filter Behaviors).
`snd-aresoncv(sound, hz, bw, normalization)` [SAL]
`(snd-aresoncv sound hz bw normalization)` [LISP]
  This function is identical to `snd-areson` except the bw (bandwidth) parameter is a sound. Filter coefficients are updated at the sample rate of bw. The “`cv`” suffix stands for Constant, Variable, indicating that hz and bw are constant (a number) and variable (a sound), respectively. This naming convention is used throughout. You should use `areson` instead (see Section Filter Behaviors).
`snd-aresonvc(sound, hz, bw, normalization)` [SAL]
`(snd-aresonvc sound hz bw normalization)` [LISP]
  This function is identical to `snd-areson` except the hz (center frequency) parameter is a sound. Filter coefficients are updated at the sample rate of hz. You should use `areson` instead (see Section Filter Behaviors).
`snd-aresonvv(sound, hz, bw, normalization)` [SAL]
`(snd-aresonvv sound hz bw normalization)` [LISP]
  This function is identical to `snd-areson` except both hz (center frequency) and bw (bandwidth) are sounds. Filter coefficients are updated at the next sample of either hz or bw. You should use `areson` instead (see Section Filter Behaviors).
`snd-atone(sound, hz)` [SAL]
`(snd-atone sound hz)` [LISP]
  A high-pass filter modeled after the `atone` unit generator in Csound. The `snd-atone` filter is an exact complement of `snd-tone` such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. You should use `hp` instead (see Section Filter Behaviors).
`snd-atonev(sound, hz)` [SAL]
`(snd-atonev sound hz)` [LISP]
  This is just like `snd-atone` except that the hz cutoff frequency is a sound. Filter coefficients are updated at the sample rate of hz. You should use `hp` instead (see Section Filter Behaviors).
`snd-biquad(sound, b0, b1, b2, a1, a2, z1init, z2init)` [SAL]
`(snd-biquad sound b0 b1 b2 a1 a2 z1init z2init)` [LISP]
  A general second order IIR filter, where a0 is assumed to be unity. For a1 and a2, the sign convention is opposite to that of Matlab. All parameters except the input sound are of type `FLONUM`. You should probably use one of `lowpass2`, `highpass2`, `bandpass2`, `notch2`, `allpass2`, `eq-lowshelf`, `eq-highshelf`, `eq-band`, `lowpass4`, `lowpass6`, `lowpass8`, `highpass4`, `highpass6`, or `highpass8`, which are all based on `snd-biquad` and described in Section Filter Behaviors. For completeness, you will also find `biquad` and `biquad-m` described in that section.
`snd-chase(sound, risetime, falltime)` [SAL]
`(snd-chase sound risetime falltime)` [LISP]
  A slew rate limiter. The output “chases” the input at rates determined by risetime and falltime. If the input changes too fast, the output will lag behind the input. This is a form of lowpass filter, but it was created to turn hard-switching square waves into smoother control signals that could be used for linear crossfades. If the input switches from 0 to 1, the output will linearly rise to 1 in risetime seconds. If the input switches from 1 to 0, the output will linearly fall to 0 in falltime seconds. The generated slope is constant; the transition is linear; this is not an exponential rise or fall. The risetime and falltime must be scalar constants; complain to the author if this is not adequate. The `snd-chase` function is safe for ordinary use. See `snd-follow` in Section Signal Operations for a related function.
`snd-congen(gate, risetime, falltime)` [SAL]
`(snd-congen gate risetime falltime)` [LISP]
  A simple “contour generator” based on analog synthesizers. The gate is a sound that normally steps from 0.0 to 1.0 at the start of an envelop and goes from 1.0 back to 0.0 at the beginning of the release. At each sample, the output converges to the input exponentially. If gate is greater than the output, e.g. the attack, then the output converges half-way to the output in risetime. If the gate is less than the output, the half-time is falltime. The sample rate, starting time, logical-stop-time, and terminate time are taken from gate. You should use `congen` instead (see Section Filter Behaviors.
`snd-convolve(sound, response)` [SAL]
`(snd-convolve sound response)` [LISP]
  Convolves sound by response using a fast convolution algorithm. The sound can be any length, but the response is computed and stored in in memory. The required compuation time per sample and total space are proportional to the length of response. Use `convolve` instead (see Section Filter Behaviors).
`snd-delay(sound, delay, feedback)` [SAL]
`(snd-delay sound delay feedback)` [LISP]
  Feedback delay. The output, initially sound, is recursively delayed by delay, scaled by feedback, and added to itself, producing an repeating echo effect. The feedback should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use `feedback-delay` instead (see Section Filter Behaviors)
`snd-delaycv(sound, delay, feedback)` [SAL]
`(snd-delaycv sound delay feedback)` [LISP]
  Feedback delay with variable feedback. This is just like snd-delay except feedback is a sound. You should use `feedback-delay` instead (see Section Filter Behaviors).
`snd-reson(sound, hz, bw, normalization)` [SAL]
`(snd-reson sound hz bw normalization)` [LISP]
  A second-order resonating (bandpass) filter with center frequency hz and bandwidth bw, modeled after the `reson` unit generator in Csound. The normalization parameter must be an integer and (like in Csound) specifies a scaling factor. A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than hz are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The result sample rate, start time, etc. are takend from sound. You should use `reson` instead (see Section Filter Behaviors).
`snd-resoncv(sound, hz, bw, normalization)` [SAL]
`(snd-resoncv sound hz bw normalization)` [LISP]
  This function is identical to `snd-reson` except bw (bandwidth) is a sound. Filter coefficients are updated at the sample rate of bw. You should use `reson` instead (see Section Filter Behaviors).
`snd-resonvc(sound, hz, bw, normalization)` [SAL]
`(snd-resonvc sound hz bw normalization)` [LISP]
  This function is identical to `snd-reson` except hz (center frequency) is a sound. Filter coefficients are updated at the sample rate of hz. You should use `reson` instead (see Section Filter Behaviors).
`snd-resonvv(sound, hz, bw, normalization)` [SAL]
`(snd-resonvv sound hz bw normalization)` [LISP]
  This function is identical to `snd-reson` except botth hz (center frequency) and bw (bandwidth) are sounds. Filter coefficients are updated at the next sample from either hz or bw. You should use `reson` instead (see Section Filter Behaviors).
`snd-stkchorus(sound, delay, depth, freq, mix)` [SAL]
`(snd-stkchorus sound delay depth freq mix)` [LISP]
  A chorus implemented in STK. The parameter delay is a `FIXNUM` representing the median desired delay length in samples. A typical value is 6000. The `FLONUM` parameters depth and freq set the modulation depth (from 0 to 1) and modulation frequency (in Hz), mix sets the mixture of input sound and chorused sound, where a value of 0.0 means input sound only (dry) and a value of 1.0 means chorused sound only (wet). You should use `stkchorus` instead (see Section Effects).
`snd-stkpitshift(sound, shift, mix)` [SAL]
`(snd-stkpitshift sound shift mix)` [LISP]
  A pitch shifter implemented in STK. The sound is shifted in pitch by shift, a `FLONUM` representing the shift factor. A value of 1.0 means no shift. The parameter mix sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet). You should use `pitshift` instead (see Section Effects).
`snd-stkrev(rev-type, sound, decay, mix)` [SAL]
`(snd-stkrev rev-type sound decay mix)` [LISP]
  A reverb implemented in STK. The parameter rev-type is a `FIXNUM` ranging from zero to two and selects the type of reverb. Zero selects NRev type, one selects JCRev, and two selects PRCRev. The input sound is processed by the reverb with a decay time in seconds (a `FLONUM`). The mix, a `FLONUM`, sets the mixture of dry input and reverb output. A value of 0.0 means input only (dry) and a value of 1.0 means reverb only (wet). The sample rate is that of sound. You should use `nrev`, `jcrev` or `prcrev` instead (see Section Effects).
`snd-tone(sound, hz)` [SAL]
`(snd-tone sound hz)` [LISP]
  A first-order recursive low-pass filter, based on the tone unit generator of Csound. The hz parameter is the cutoff frequency, the response curve's half-power point. The result sample rate, start time, etc. are takend from sound. You should use `lp` instead (see Section Filter Behaviors).
`snd-tonev(sound, hz)` [SAL]
`(snd-tonev sound hz)` [LISP]
  This function is identical to `snd-tone` except hz (cutoff frequency) is a sound. The filter coefficients are updated at the sample rate of hz. You should use `lp` instead (see Section Filter Behaviors).

#### Table-Lookup Oscillator Functions

These functions all use a sound to describe one period of a periodic waveform. In the current implementation, the sound samples are copied to an array (the waveform table) when the function is called. To make a table-lookup oscillator generate a specific pitch, we need to have several pieces of information:

- A waveform to put into the table. This comes from the sound parameter.
- The length (in samples) of the waveform. This is obtained by reading samples (starting at the sound's start time, not necessarily at time zero) until the physical stop time of the sound. (If you read the waveform from a file or generate it with functions like `sim` and `sine`, then the physical and logical stop times will be the same and will correspond to the duration you specified, rounded to the nearest sample.)
- The intrinsic sample rate of the waveform. This sample rate is simply the sample rate property of sound.
- The pitch of the waveform. This is supplied by the step parameter and indicates the pitch (in steps) of sound. You might expect that the pitch would be related to the period (length) of sound, but there is the interesting case that synthesis based on sampling often loops over multiple periods. This means that the fundamental frequency of a generated tone may be some multiple of the looping rate. In Nyquist, you always specify the perceived pitch of the looped sound if the sound is played at the sound's own sample rate.
- The desired pitch. This is specified by the hz parameter in Hertz (cycles per second) in these low-level functions. Note that this is not necessarily the “loop” rate at which the table is scanned. Instead, Nyquist figures what sample rate conversion would be necessary to “transpose” from the step which specifies the original pitch of sound to hz, which gives the desired pitch. The mixed use of steps and Hertz came about because it seemed that sample tables would be tagged with steps (“I sampled a middle-C”), whereas frequency deviation in the `fmosc` function is linear, thus calling for a specification in Hertz.
- The desired sample rate. This is given by the sr parameter in Hertz.

Other parameters common to all of these oscillator functions are:

- t0, the starting time, and
- phase, the starting phase in degrees. Note that if the step parameter indicates that the table holds more than one fundamental period, then a starting phase of 360 will be different than a starting phase of 0.

`snd-amosc(sound, step, sr, hz, t0, am, phase)` [SAL]
`(snd-amosc sound step sr hz t0 am phase)` [LISP]
  An oscillator with amplitude modulation. The sound am specifies the amplitude and the logical stop time. The physical stop time is also that of am. You should use `amosc` instead (see Section Oscillators).
`snd-fmosc(s, step, sr, hz, t0, fm, phase)` [SAL]
`(snd-fmosc s step sr hz t0 fm phase)` [LISP]
  A Frequency Modulation oscillator. The sound fm specifies frequency deviation (in Hertz) from hz. You should use `fmosc` instead (see Section Oscillators).
`snd-fmfb(t0, hz, sr, index, dur)` [SAL]
`(snd-fmfb t0 hz sr index dur)` [LISP]
  A Feedback FM oscillator. The resulting sound starts at t0, has a fundamental frequency of hz, a sample rate of sr, and a duration of dur seconds. The index is a `FLONUM` that specifies the amount of feedback. You should use `fmfb` instead (see Section Oscillators).
`snd-fmfbv(t0, hz, sr, index)`
`(snd-fmfv t0 hz sr index)` [LISP]
  A Feedback FM oscillator. The resulting sound starts at t0, has a fundamental frequency of hz, and a sample rate of sr. The index is a `SOUND` that specifies the amount of feedback and determines the duration. You should use `fmfb` instead (see Section Oscillators).
`snd-buzz(n, sr, hz, t0, fm)` [SAL]
`(snd-buzz n sr hz t0 fm)` [LISP]
  A buzz oscillator, which generates n harmonics of equal amplitude. The fm specifies frequency deviation (in Hertz) from hz. You should use `buzz` instead (see Section Oscillators).
`snd-pluck(sr, hz, t0, d, final-amp)` [SAL]
`(snd-pluck sr hz t0 d final-amp)` [LISP]
  A Karplus-Strong plucked string oscillator with sample rate sr, fundamental frequency hz, starting time t0, duration d, initial amplitude approximately 1.0 (not exact because the string is initialized with random values) and final amplitude approximately final-amp. You should use `pluck` instead (see Section Oscillators).
`snd-osc(s, step, sr, hz, t0, d, phase)` [SAL]
`(snd-osc s step sr hz t0 d phase)` [LISP]
  A simple table lookup oscillator with fixed frequency. The duration is d seconds. You should use `osc` instead (see Section Oscillators).
`snd-partial(sr, hz, t0, env)` [SAL]
`(snd-partial sr hz t0 env)` [LISP]
  This is a special case of `snd-amosc` that generates a sinusoid starting at phase 0 degrees. The env parameter gives the envelope or any other amplitude modulation. You should use `partial` instead (see Section Oscillators).
`snd-sine(t0, hz, sr, d)` [SAL]
`(snd-sine t0 hz sr d)` [LISP]
  This is a special case of `snd-osc` that always generates a sinusoid with initial phase of 0 degrees. You should use `sine` instead (see Section Oscillators).
`snd-sampler(s, step, start, sr, hz, t0, fm, npoints)` [SAL]
`(snd-sampler s step start sr hz t0 fm npoints)` [LISP]
  Returns a sound constructed by reading a sample from beginning to end and then splicing on copies of the same sound from a loop point to the end. The sound s is the source sound to be looped, and step (a FLONUM) is the nominal fundamental frequency (in steps, not Hz) of s. The start (a FLONUM) is the time in seconds at which to start the loop, sr (a FLONUM) is the desired sample rate of the output, hz is the nominal fundamental frequency of the output, t0 (a FLONUM) is the starting time of the output, and fm (a SOUND) is frequency modulation that is added to hz to determine the output fundamental frequency. The parameter npoints (a FIXNUM) specifies how many points should be used for sample interpolation. Currently this parameter defaults to 2 and only 2-point (linear) interpolation is implemented. It is an error to modulate such that the frequency is negative. Note also that the loop point may be fractional. This function implements a typical sampling synthesis algorithm, looping and resampling the input according to the ratio between the desired fundamental frequency (which is the sum of hz and fm) and the nominal fundamental of the looped sound (which is assumed to be given by step). You should use `sampler` instead (see Section Oscillators).
`snd-siosc(tables, sr, hz, t0, fm)` [SAL]
`(snd-siosc tables sr hz t0 fm)` [LISP]
  A Spectral Interpolation Oscillator with frequency modulation. The tables is a list of sounds and sample counts as follows: (table0 count1 table1 ... countN tableN). The initial waveform is given by table0, which is interpolated linearly to table1 over the first count1 samples. From count1 to count2 samples, the waveform is interpolated from table1 to table2, and so on. If more than countN samples are generated, tableN is used for the remainder of the sound. The duration and logical stop time of the sound is taken from fm, which specified frequency modulation (deviation) in Hertz. You should use `siosc` instead (see Section Oscillators).

#### Phase Vocoder Functions

`snd-phasevocoder(s, map, fftsize, hopsize mode)` [SAL]
code{(snd-phasevocoder s map fftsize hopsize mode) [LISP]}
  Phase vocoder: Identical to `phasevocoder` except that fftsize, hopsize and mode are not optional. Specify -1 to get the default values for fftsize and hopsize. Specify 0 for the default value of mode. You should use `phasevocoder` instead (see Section Phase Vocoder).

#### Physical Model Functions

These functions perform some sort of physically-based modeling synthesis.

`snd-bandedwg(freq, bowpress-env, preset, sr)` [SAL]
`(snd-bandedwg freq bowpress-env preset sr)` [LISP]
  A Banded Wave Guide Percussion instrument implemented in STK. The parameter freq is a `FLONUM` in Hz, bowpress-env is a `SOUND` that ranges from zero to one, preset is a `FIXNUM`, and sr is the desired sample rate in Hz. Currently, there are four presets: uniform-bar (0), tuned-bar (1), glass-harmonica (2), and tibetan-bowl (3). You should use `wg-uniform-bar`, `wg-tuned-bar`, `wg-glass-harm`, or `wg-tibetan-bowl` instead (see Section Physical Models).
`snd-bowed(freq, bowpress-env, sr)` [SAL]
`(snd-bowed freq bowpress-env sr)` [LISP]
  A bowed string instrument implemented in STK. The freq is a `FLONUM` in Hertz, bowpress-env is a `SOUND` that ranges from z ero to one, and sr is the desired sample rate (a `FLONUM`). You should use bowed instead (see Section Physical Models).
`snd-bowed-freq(freq, bowpress-env, freq-env, sr)` [SAL]
`(snd-bowed-freq freq bowpress-env freq-env sr)` [LISP]
  A bowed model just like `snd-bowed` but with an additional parameter for continuous frequency control. You should use `bowed-freq` instead (see Section Physical Models).
`snd-clarinet(freq, breath-env, sr)` [SAL]
`(snd-clarinet freq breath-env sr)` [LISP]
  A clarinet model implemented in STK. The freq is a `FLONUM` in Hertz, breath-env is a `SOUND` that ranges from zero to one, and sr is the desired sample rate (a `FLONUM`). You should use `clarinet` instead (see Section Physical Models).
`snd-clarinet-freq(freq, breath-env, freq-env, sr)` [SAL]
`(snd-clarinet-freq freq breath-env freq-env sr)` [LISP]
  A clarinet model just like `snd-clarinet` but with an additional parameter for continuous frequency control. You should use `clarinet-freq` instead (see Section Physical Models).
`snd-clarinet-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, reed-stiffness, noise, sr)` [SAL]
`(snd-clarinet-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise sr)` [LISP]
  A clarinet model just like `snd-clarinet-freq` but with additional parameters for vibrato generation and continuous control of reed stiffness and breath noise. You should use `clarinet-all` instead (see Section Physical Models).
`snd-flute(freq, breath-env, sr)` [SAL]
`(snd-flute freq breath-env sr)` [LISP]
  A flute implemented in STK. The freq is a `FLONUM` in Hertz, breath-env is a `SOUND` that ranges from zero to one, and sr is the desired sample rate (a `FLONUM`). You should use `flute` instead (see Section Physical Models).
`snd-flute-freq(freq, breath-env, freq-env, sr)` [SAL]
`(snd-flute-freq freq breath-env freq-env sr)` [LISP]
  A flute model just like `snd-flute` but with an additional parameter for continuous frequency control. You should use `flute-freq` instead (see Section Physical Models).
`snd-flute-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, jet-delay, noise, sr)` [SAL]
`(snd-flute-all freq vibrato-freq vibrato-gain freq-env breath-env jet-delay noise sr)` [LISP]
  A flute model just like `snd-flute-freq` but with additional parameters for vibrato generation and continuous control of breath noise. You should use `flute-all` instead (see Section Physical Models).
`snd-mandolin(t0, freq, dur, body-size, detune, sr)` [SAL]
`(snd-mandolin t0 freq dur body-size detune sr)` [LISP]
  A plucked double-string instrument model implemented in STK. The t0 parameter is the starting time (in seconds), freq is a `FLONUM` in Hz, body-size and detune are `FLONUM`s, and `sr` is the desired sample rate. You should use `mandolin` instead (see Section Physical Models).
`snd-modalbar(t0, freq, preset, dur, sr)` [SAL]
`(snd-modalbar t0 freq preset dur sr)` [LISP]
  Struck bar instrument model implemented in STK. The parameter t0 is the starting time (in seconds), freq is a `FLONUM` in Hz, `preset` is a `FIXNUM` ranging from 0 to 8, dur is a `FLONUM` that sets the duration (in seconds) and sr is the desired sample rate. You should use `modalbar` instead (see Section Physical Models).
`snd-sax(freq, breath-env, sr)` [SAL]
`(snd-sax freq breath-env sr)` [LISP]
  A sax model implemented in STK. The freq is a `FLONUM` in Hertz, breath-env is a `SOUND` that ranges from zero to one, and sr is the desired sample rate (a `FLONUM`). You should use `sax` instead (see Section Physical Models).
`snd-sax-freq(freq, freq-env, breath-env, sr)` [SAL]
`(snd-sax-freq freq freq-env breath-env sr)` [LISP]
  A sax model just like `snd-sax` but with an additional parameter for continuous frequency control. You should use `sax-freq` instead (see Section Physical Models).
`snd-sax-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, reed-stiffness, noise, blow-pos, reed-table-offset, sr)` [SAL]
`(snd-sax-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise blow-pos reed-table-offset sr)` [LISP]
  A sax model just like `snd-sax-freq` but with additional parameters for vibrato generation and continuous control of reed stiffness, breath noise, excitation position, and reed table offset. You should use `sax-all` instead (see Section Physical Models).
`snd-sitar(t0, freq, dur, sr)` [SAL]
`(snd-sitar t0 freq dur sr)` [LISP]
  A sitar model implemented in STK. The parameter t0 is the starting time, freq is a `FLONUM` (in Hz), E dur sets the duration and sr is the sample rate (in Hz) of the resulting sound. You should use `sitar` instead (see Section Physical Models).

#### Sequence Support Functions

The next two functions are used to implement Nyquist's `seq` construct.

`snd-seq(sound, closure)` [SAL]
`(snd-seq sound closure)` [LISP]
  This function returns sound until the logical stop time of sound. Then, the XLISP closure is evaluated, passing it the logical stop time of sound as a parameter. The closure must return a sound, which is then added to sound. (An add is used so that sound can continue past its logical stop if desired.) Do not call this function directly.
`snd-multiseq(array, closure)` [SAL]
`(snd-multiseq array closure)` [LISP]
  This function is similar to `snd-seq` except the first parameter is a multichannel sound rather than a single sound. A multichannel sound is simply an XLISP array of sounds. An array of sounds is returned which is the sum of array and another array of sounds returned by closure. The closure is passed the logical stop time of the multichannel sound, which is the maximum logical stop time of any element of array. The sample rates and number of channels returned from the closure must match the first multi-channel sound in the sequence. Do not call this function directly.

Previous Section | Next Section | Table of Contents | Index | Title Page