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: 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 1) .

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)`
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 n^(th) sample of a sound 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: ``` > (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 ``` 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 1)` 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)`
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)```
Converts a lisp array of FLONUMs 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`` t0sr object)`
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 FLONUMs. The values in these arrays are concatenated to form the samples of the resulting sound. 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)```
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)`
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)`
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)```
Reads sequential arrays of samples from sound, returning either an array of FLONUMs 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. 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)`
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)`
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)`
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)`
Evaluates expression to obtain a sound or array of sounds, computes all of the samples (without retaining them in memory), and returns. If this happens faster than real time for interesting sounds, you might want to modify Nyquist to actually write the samples directly to an audio output device. Meanwhile, since this function does not save samples in memory or write them to a disk, 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.

`(snd-print-tree sound)`
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)`
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)`
Returns the sample rate of the sound. Safe for ordinary use.

`(snd-time`` sound)`
Returns the start time of the sound. This will probably go away in a future version, so use `snd-t0` instead.

`(snd-t0`` sound)`
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)`
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)```
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)`
Evaluates sound at the global time given by time. Safe for ordinary use, but normally, you should call `sref` instead.

`(snd-stop-time sound)`
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)`
Returns true iff sound is a SOUND. Safe for ordinary use.

`(stats``)`
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.

Miscellaneous Functions

These are all safe and recommended for ordinary use.

`(db-to-linear x)`
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.

`(follow`` sound floor risetime falltime lookahead)`
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 floor risetime falltime lookahead threshold)`
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 ouptut 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.

`(hz-to-step`` freq)`
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)`
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.

`(log`` x)`
Calculates the natural log of x (a FLONUM). (See `s-log` for a version that operates on signals.)

`(set-control-srate`` rate)`
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)`
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)`
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)`
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-duration`` dur)`
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.

`(get-loud``)`
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``)`
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``)`
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``)`
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)`
Converts a score (local) time to a real (global) time according to the current environment.

`(osc-enable`` flag)`
Enable or disable Open Sound Control. (See Appendix "Open Sound Control and Nyquist".) Enabling creates a socket and a service that listens for UDP packets on port 7770. Currently, only messages of the form `\slider` with an integer index and a floating point value are accepted. These set internal slider values accessed by the `snd-slider` function. Disabling terminates the service (polling for messages) and closes the socket. The previous state of enablement is returned, e.g. if OSC is enabled and flag is nil, OSC is disabled and `T` (true) is returned because OSC was enabled at the time of the call. This function only exists if Nyquist is compiled with the compiler flag `OSC`. Otherwise, the function exists but always returns the symbol `DISABLED`. Consider lowering the audio latency using `snd-set-latency`. Warning: there is the potential for network-based attacks using OSC. It is tempting to add the ability to evaluate XLISP expressions sent via OSC, but this would create unlimited and unprotected access to OSC clients. For now, it is unlikely that an attacker could do more than manipulate slider values.

`(snd-set-latency latency)`
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.

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)`
Applies `*loud*`, the starting time from `*warp*`, `*start*`, and `*stop*` to sound.

`(cue-file`` filename)`
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)`
Applies `*loud*`, `*warp*`, `*start*`, and `*stop*` to sound.

`(control`` sound)`
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])`
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])```
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)`
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)`
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])```
Just like `osc` (below) except this computes at the `*control-srate*` and frequency is specified in Hz. Phase is specified in degrees. 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])`
A low-frequency oscillator that computes at the `*control-srate*` using a sound to specify a time-varying frequency in Hz. Phase is a `FLONUM` in degrees. The duration of the result is determined by freq.

`(maketable`` sound)`
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 1,000,000 samples. This limit is the compile-time constant `max_table_len` set in `sound.h`.

`(build-harmonic`` n table-size)`
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 "Waveforms" for an example.

`(clarinet step breath-env)`
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)```
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)```
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.

`(control-warp`` warp-fn signal [wrate])`
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 ...)`
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 ...)`
Same as `mult`.

`(pan`` sound where)`
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 ...)`
Same as `mult`.

`(resample`` sound srate)`
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`.)

`(sax`` step breath-env)`
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)```
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)```
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.

`(scale`` scale sound)`
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)`
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)`
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)`
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])`
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)`
Computes the integral of signal. The start time, sample rate, etc. are taken from signal.

`(slope`` signal)`
Computes the first derivative (slope) of signal. The start time, sample rate, etc. are taken from signal.

Oscillators
`(osc pitch [duration table phase])`
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 `*loudness*`, 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: table 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. The maximum table size is set by `max_table_len` in `sound.h`, and is currently set to 1,000,000. 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)`
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])`
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])`
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. 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)`
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)`
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])`
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])```
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])```
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*`.

`(buzz`` n pitch modulation)`
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 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])```
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)```
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])```
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 the global variable `*table*` 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. Each of these 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 16 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
```
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)`
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)`
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 t3 ... tn ln)`
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)`
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)`
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)`
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)`
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)`
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)```
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 `pwev` below for the function you are probably looking for.

`(pwe-list`` breakpoints)`
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)`
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)`
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)`
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)`
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)`
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)`
A version of `pwevr` that takes a single list of breakpoints as its argument. See `pwl-list` above for the rationale.
Filter Behaviors
`(alpass sound decay hz [minhz])`
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)`
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)`
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)```
Convolves two signals. The first can be any length, but the computation time per sample and the total space required are proportional to the length of response.

`(feedback-delay`` sound delay feedback)`
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)`
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)`
No longer defined; use `lp` instead, or define it by adding `(setfn tone lp)` to your program.

`(hp`` sound cutoff)`
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)`
No longer defined; use `hp` instead, or define it by adding `(setfn atone hp)` to your program.

`(reson`` sound center bandwidth n)`
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 `demos/voice_synthesis.htm` for sample code and documentation.

`(areson`` sound center bandwidth n)`
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)`
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 in `demos/distortion.htm`. The `shape` function is also used to map frequency to amplitude to achieve a spectral envelope for Shepard tones in `demos/shepard.lsp`.

`(biquad`` signal b0 b1 b2 a0 a1 a2)`
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)`
A fixed-parameter biquad filter with Matlab sign conventions for a0, a1, and a2. All filter coefficients are `FLONUM`s.

`(lowpass2`` signal hz [q])`
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])`
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])`
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])`
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])`
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])`
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])`
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)`
A fixed- or variable-parameter, second-order midrange equalization (EQ) filter based on `snd-biquad`, `snd-eqbandcv` and `snd-eqbandvvv`. 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)`
A four-pole Butterworth lowpass filter. The cutoff frequency is hz (a `FLONUM`).

`(lowpass6`` signal hz)`
A six-pole Butterworth lowpass filter. The cutoff frequency is hz (a `FLONUM`).

`(lowpass8`` signal hz)`
An eight-pole Butterworth lowpass filter. The cutoff frequency is hz (a `FLONUM`).

`(highpass4`` signal hz)`
A four-pole Butterworth highpass filter. The cutoff frequency is hz (a `FLONUM`).

`(highpass6`` signal hz)`
A six-pole Butterworth highpass filter. The cutoff frequency is hz (a `FLONUM`).

`(highpass8`` signal hz)`
An eight-pole Butterworth highpass filter. The cutoff frequency is hz (a `FLONUM`).

`(tapv```` sound offset vardelay maxdelay)```
A delay line with a variable position tap. Identical to `snd-tapv`. See it for details ("Signal Operations").

More Behaviors
`(clip sound peak)`
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.

`(s-abs`` sound)`
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-sqrt`` sound)`
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)`
A generalized exponential function. If sound is a SOUND, compute e^(x) for each sample x. If sound is a number x, just compute e^(x). 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)`
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)`
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)`
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])```
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)`
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 multi-channel.

`(ramp`` [duration])`
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])`
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 rate is a `FLONUM` and window-size is a `FIXNUM`.

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.

`(recip`` sound)`
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.

`(s-rest`` [duration])`
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])`
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)`
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 SOUNDs, both at the same sample rate, which is approximately the sample rate of sound divided by stepsize. The first SOUND consists of frequency estimates. 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(n^(2)) 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)`
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.

`(at`` time beh)`
Evaluate beh with `*warp*` shifted by time.

`(at-abs`` time beh)`
Evaluate beh with `*warp*` shifted so that local time 0 maps to time.

`(continuous-control-warp`` beh)`
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)`
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)```
Evaluate beh with `*control-srate*` set to sample rate srate. Note: there is no "relative" version of this function.

`(extract`` start stop beh)`
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)`
Returns a sound which is the portion of beh between start and stop, independent of the current `*warp*`. The result is shifted to start according to `*warp*`.

`(loud`` volume beh)`
Evaluates beh with `*loud*` incremented by volume. (Recall that `*loud*` is in decibels, so increment is the proper operation.)

`(loud-abs`` volume beh)`
Evaluates beh with `*loud*` set to volume.

`(sound-srate-abs`` srate beh)`
Evaluate beh with `*sound-srate*` set to sample rate srate. Note: there is no "relative" version of this function.

`(stretch`` factor beh)`
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.

`(stretch-abs factor beh)`
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)`
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)`
Evaluates beh with `*sustain*` set to factor. (See `sustain`, above.)

`(transpose`` amount beh)`
Evaluates beh with `*transpose*` shifted by amount. The effect is relative transposition by amount semitones.

`(transpose-abs`` amount beh)`
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)`
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)`
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.

`(seq`` beh1 [beh2 ...])`
Evaluates the first behavior beh1 according to `*time*` 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.

`(seqrep`` (var limit) beh)`
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.

`(sim`` [beh1 beh2 ...])`
Returns a sound which is the sum of the given behaviors evaluated with 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 the maximum. 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 `+` 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.

`(simrep`` (var limit) beh)`
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`.

`(trigger`` s beh)`
Returns a sound which is the sum of instances of the behavior beh. One instance is created each time `SOUND` s makes a transition from less than or equal to zero to greater than zero. (If the first sample of s is greater than zero, an instance is created immediately.) The sample rate of s and all behaviors must be the same, and the behaviors must be (monophonic) `SOUND`s. This function is particularly designed to allow behaviors to be invoked in real time by making s a function of a Nyquist slider, which can be controlled by a graphical interface or by OSC messages. See `snd-slider` in Section "Creating Sounds".

`(set-logical-stop beh time)`
Returns a sound with time as the logical stop time.

`(sum`` a [b c ...])`
Returns the sum of a, b, c, ..., allowing mixed addition of sounds, multichannel sounds and numbers. Identical to sim.

`(mult`` a [b c ...])`
Returns the product of a, b, c, ..., allowing mixed multiplication of sounds, multichannel sounds and numbers.

`(diff`` a b)`
Returns the difference between a and b. This function is defined as `(sum a (prod -1 b))`.

`(timed-seq```` score)```
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)`
Play the sound through the DAC. The `play` function writes a file and plays it. The details of this are system-dependent, but `play` is defined in the file `system.lsp`. The variable `*default-sf-dir*` names a directory into which to save a sound file.

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:
```(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:
```(sound-off)
```
and reenabled by:
```(sound-on)
```
Disabling real-time playback has no effect on `(play-file)` or `(r)`.

`(play-file`` filename)`
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``)`
Enable automatic adjustment of a scale factor applied to sounds computed using the `play` command.

`(autonorm-off``)`
Disable automatic adjustment of a scale factor applied to sounds computed using the `play` command.

`(sound-on``)`
Enable real-time audio output when sound is computed by the the `play` command.

`(sound-off``)`
Disable real-time audio output when sound is computed by the the `play` command.

`(s-save```` expression maxlen filename [:format format] [:mode mode] [:bits bits] [:swap flag] [:play play])```
Evaluates the expression, which should result in a sound or an array of sounds, and writes the result to the given filename. 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 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 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 bytes are swapped if swap is not NIL. Defaults for these are `*default-sf-format*`, `*default-sf-mode*`, and `*default-sf-bits*`. The default for swap 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`

`snd-head-AIFF`

`snd-head-IRCAM`

`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`

Mode

`snd-head-mode-adpcm`

`snd-head-mode-pcm`
signed binary PCM mode.

`snd-head-mode-ulaw`
8-bit U-Law mode.

`snd-head-mode-alaw`
8-bit A-Law mode (not supported).

`snd-head-mode-float`
32-bit floating point mode.

`snd-head-mode-upcm`
unsigned binary PCM mode.

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

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

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

`(s-read```` filename [:time-offset offset] [:srate sr] [:dur dur] [:nchans chans] [:format format] [:mode mode] [:bits n] [:swap flag])```
Reads a sound from a file. 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:
If there is an error, for example if `:time-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 2) . The list assigned to `*rslt*` is of the form: (format channels mode bits samplerate duration flags byte-offset), which are defined as follows:
• format - the header format. See `s-save` for details.
• channels - the number of channels.
• mode - the sample representation, e.g. PCM or float. See `s-save` for details.
• bits - the number of bits per sample.
• samplerate - the sample rate, expressed as a FLONUM.
• duration - the duration of the sound, in seconds.
• 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-format`, `snd-head-channels`, `snd-head-mode`, `snd-head-bits`, `snd-head-srate`, and `snd-head-dur`. For example,
```(let ((flags (caddr (cddddr  *rslt*))))
```
tells whether the sample rate was specified in the file. See also `sf-info` below.
• byte-offset - the byte offset into the file of the first sample to be read (this is used by the `s-overwrite` and `s-add-to` functions).

```(s-add-to expression maxlen filename [offset])```
Evaluates the expression, which should result in a sound or an array of sounds, and adds the result to the given filename. 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). 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.)

`(s-overwrite`` expression maxlen filename [offset])`
Evaluates the expression, which should result in a sound or an array of sounds, and replaces samples in the given filename. 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.)

`(sf-info`` filename)`
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)`
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` translate filenames.

`(s-plot`` sound n)`
Plots sound in a window. The current implementations are minimal. For the RS6000/AIX implementation, `s-plot` simply writes time/value pairs in ascii to a file named `points.dat`. Then, an `xterm` is created in Tektronix emulation mode, and the Unix `plot` program is used to plot the points. The files used are:
`*default-plot-file*`
The file containing the data points, defaults to "points.dat".

`*plotscript-file*`
The file containing the script for the `xterm`, defaults to "sys/unix/rs6k/plotscript".
The script for plotting is typically something like:
```graph < points.dat | plot -Ttek
```
This runs the Unix graph program which reads the input, scales it, and adds axes and labels. The output is piped to the plot program which converts the graphics data into Tektronix commands. It's crude but works well even over a serial line.

Under the Macintosh, plotting is performed using some built-in graphics commands. Select "Split Screen" on the Control menu to get a nice area for plotting.

Under Windows, using the NyqIDE program, plotting is built-in.

If you are interested in making a nicer plot program for any platform, please contact the author.

`(s-print-tree`` sound)`
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)```
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)```
```(/ (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)```
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. 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 byte-offset mode bits swap sr channels)`
Evaluates the expression, which should result in a sound or an array of sounds, and replaces samples in the given filename. The sample rate(s) of expression must match those of the file and the parameter sr. The file is not read to determine its format, so it is essential to specify the proper parameters: byte-offset is the offset in bytes of the first sound sample to be written, mode is the representation (see `snd-save`), bits is the number of bits per sample, swap is 0 or 1, where 1 means to swap sample bytes, sr is the sample rate, and channels is the number of channels. If these do not match the parameters for filename, it is likely that filename will be corrupted. Up to a maximum of maxlen samples will be written per channel. 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)`
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 ...)`
See "Accessing and Creating Sound".

`(snd-white t0 sr d)`
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)`
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.

`(get-slider-value index)`
Return the current value of the slider named by index (an integer index into the array of sliders). Note that this "slider" is just a floating point value in an array. Sliders can be changed by OSC messages (see `osc-enable`) and by sending character sequences to Nyquist's standard input. (Normally, these character sequences would not be typed but generated by the jNyqIDE interactive development environment, which runs Nyquist as a sub-process, and which present the user with graphical sliders.)

`(snd-slider`` index t0 srate duration)`
Create a sound controlled by the slider named by index (an integer index into the array of sliders; see `get-slider-value` for more information). The function returns a sound. Since Nyquist sounds are computed in blocks of samples, and each block is computed at once, each block will contain copies of the current slider value. To obtain reasonable responsiveness, slider sounds should have high (audio) sample rates so that the block rate will be reasonably high. Also, consider lowering the audio latency using `snd-set-latency`. To "trigger" a Nyquist behavior using slider input, see the `trigger` function in Section "Combination and Time Structure".

Signal Operations

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

`(snd-abs sound)`
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)`
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)`
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)`
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)```
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. 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".

`(snd-clip sound peak)`
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)`
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 `demos/pitch_change.htm`.

`(snd-tapv`` sound offset vardelay maxdelay)`
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.

`(snd-tapf`` sound offset vardelay maxdelay)`
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)`
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)`
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)`
Compute the exponential of each sample of sound. Use `s-exp` instead (see Section "More Behaviors").

```(snd-follow sound floor risetime falltime lookahead)```
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 sampless) 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)`
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)`
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)`
Compute the natural logorithm of each sample of sound. Use `s-log` instead (see Section "More Behaviors").

`(peak expression maxlen)`
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)`
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)`
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)`
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)```
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)`
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)```
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)`
Quantizes a sound. See Section "More Behaviors" for details.

`(snd-recip sound)`
Compute the reciprocal of each sample of sound. Use `recip` instead (see Section "More Behaviors").

```(snd-resample f rate)```
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)`
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)`
Scales the amplitude of sound by the factor scale. Use `scale` instead (see Section "Sound Synthesis").

`(snd-shape signal table origin)`
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)`
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)```
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, (1) 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` to create a transformable sound (see Section "Using Previously Created Sounds").

`(snd-yin sound minstep maxstep rate)`
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)`
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)```
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)`
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)```
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)```
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)```
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)```
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)`
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)`
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)`
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)`
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)`
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)`
Convolves sound by response using a simple O(N x M) algorithm. The sound can be any length, but the response is computed and stored in a table. 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)`
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)```
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)`
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)```
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)```
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)```
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-tone sound hz)`
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)`
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)```
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)```
A Frequency Modulation oscillator. The sound fm specifies frequency deviation (in Hertz) from hz. You should use `fmosc` instead (see Section "Oscillators").

`(snd-buzz n sr hz t0 fm)`
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)```
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)`
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)`
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)`
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-siosc tables sr hz t0 fm)```
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").

Physical Model Functions

These functions perform some sort of physically-based modeling synthesis.
`(snd-clarinet freq breath-env sr)`
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 "Sound Synthesis").

```(snd-clarinet-freq freq breath-env freq-env sr)```
A clarinet model just like `snd-clarinet` but with an additional parameter for continuous frequency control. You should use `clarinet-freq` instead (see Section "Sound Synthesis").

```(snd-clarinet-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise sr)```
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 "Sound Synthesis").

`(snd-sax freq breath-env sr)`
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 "Sound Synthesis").

```(snd-sax-freq freq freq-env breath-env sr)```
A sax model just like `snd-sax` but with an additional parameter for continuous frequency control. You should use `sax-freq` instead (see Section "Sound Synthesis").

```(snd-sax-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise blow-pos reed-table-offset sr)```
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 "Sound Synthesis").

Sequence Support Functions

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

`(snd-seq sound closure)`
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. See `seq` in Section "Combination and Time Structure".

`(snd-multiseq array closure)`
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. Do not call this function. See `seq` in Section "Combination and Time Structure".

An implementation note: There is no way to have `snd-trigger` return a multichannel sound. An alternative implementation would be a built-in function to scan ahead in a sound to find the time of the next zero crossing. This could be combined with some LISP code similar to `seq` to sum up instances of the closure. However, this would force arbitrary look-ahead and therefore would not work with real-time inputs, which was the motivation for `snd-trigger` in the first place.