SAU language syntax

A brief overview of how to use the syntax of the SAU language provided by the saugns program. It is meant to make things simple rather than cover everything. (For usage examples for the command-line program, see the usage page.)

A concise language reference (as in listing of details) can be found in the doc/README.SAU file (GitHub view).

Note that this page is updated along with work proceeding on the git master branch (what you get with a `git clone https://github.com/saugns/saugns.git`).

Contents

Generating sound

To generate a single pure tone in the SAU language:

Osin f440 p0 a0.5 t1

In this case, frequency is set to 440 Hz, phase to 0% of the wave cycle, and amplitude to 0.5 (-6dB). The time duration will be 1 second.

The "O" adds an oscillator (also called an "operator" in FM synth terminology). It is followed by a wave type value, in this case "sin" (there's also "tri", "sqr", "saw", and more). The other parameters are named, but not ordered, and any which are left out will be given default values. (All of them could be left out, for the shortest script which generates audio: "Osin" beeps for 1 second.)

A cosine can be generated using the "sin" wave type, by setting phase to 25% of the wave cycle, using "p(1/4)" or "p0.25".

Using modulation

Oscillators can be used in a nested way, as in this example which uses PM (phase modulation):

// Generate 10 seconds of "engine rumble"
Osin f137 t10 p+[
	Osin f32 p+[
		Osin f42
	]
]

The oscillators with frequency 32 Hz and 42 Hz are modulators, linked in a chain which ends at the carrier (with frequency 137 Hz), and play for the same time (10 seconds). Modulators only run when their carriers do; their default time durations, unlike for carriers, is actually infinite, which means playing as long as the carrier does. (The "p+" means "add to the phase", and PM means adding modulator amplitudes to the phase.)

For modulators, frequency can be specified using 'r' (relative frequency) instead of 'f'. The value assigned to 'r' will be multiplied by the carrier frequency in order to give the frequency of the modulator. For example, a modulator with "r(2/3)" will maintain a frequency 2/3 times the frequency of the carrier.

Frequency and amplitude can be given values which are computed using FM or AM, respectively. See the section Modulation with value range.

Timing

A "|" separates that before and that after in time, while "\" (followed by a time in seconds) adds delay independently of that.

To generate two tones, separated in time, and also insert an extra 2.5 seconds of silence in-between them:

Osin f440 t2
|\2.5

Osin f220 t2

To change the frequency for an oscillator after inserting a 1 second delay:

Osin f440 t2 \1 f220

Parameters for an oscillator can also be changed after a time duration without affecting surrounding timing, adding a new time duration for which the new values apply. This uses the ";" separator:

Osin f440 t1
; f220 t1

This can also be done for an oscillator within a list.

Compared to SuperCollider

This example for SuperCollider generates a sine wave (without actually playing it, which requires a few additional details):

SinOsc.ar(440, 0, 0.5);

In SAU, the closest-looking equivalent is:

Osin f440 p0 a0.5

By itself, this is a carrier oscillator which will play for the default time of 1 second. It could also be included in a list of modulators, and will then be linked to a carrier and play when the carrier does.

In SAU, data cannot currently be held or combined without specifying carrier oscillators which play.

Values and expressions

For most parameters, a single number is a value. The number may be written simply, or as an expression which is evaluated to yield the number. A simple number can be written with or without a decimal point. Negative numbers require the use of parentheses, so as to enclose the minus (-) sign, as in "(-0.5)".

Other types of values also exist. Parameters for amplitude, frequency, and panning support using value ramp values for timed "ramping" or "sweeping" instead of the instantaneous setting of a value.

Frequency and amplitude parameters support yet another type of value, for FM or AM with a value range, respectively.

All types of modulation use the list of oscillators as a type of parameter value, supported in a nested way.

Comments are text which is ignored; several comment styles are supported.

Numerical expressions

Within parentheses, numbers can be combined with arithmetic operators. The result is treated as a number. For example, "(1/2)" is another way of writing "0.5". Plus or minus signs (+, -) can only be added to numbers within parentheses. (Negative numbers require the use of parentheses.)

Individual numbers can be specified with or without a decimal point. If a decimal point is used, a leading "0" can be left out – as in ".25".

Supported arithmetic operators are: +, -, *, /, and ^ (to the power of). Conventional rules determine precedence when not made explicitly clear using parentheses. Nested parentheses can be used for multiplication in the customary way, e.g. "(2(3))" means "6".

Comment syntax

Several comment styles exist:

Labels and referencing

The declaration of an oscillator/operator can be prefixed by "'label ", where label is a case-sensitive alphanumeric name. (Underscores can also be used.) That which is labeled can be referred to using the syntax "@label", to place changes to it in any time scope later in the script.

Note that a "@label" reference placed in a nesting scope different from the original does not add the operator to the new nesting scope. (It will not be moved out from nor into a list by being referenced anywhere.) The time scope is however new and of the reference.

For example, the modulator used in this PM example has its frequency relative to the carrier changed at one-second intervals:

Osin f500 t5 p+[
	'name Osin r(1/1)
]

\1
@name r(1/2)
\1
@name r(1/3)
\1
@name r(1/4)
\1
@name r(1/5)

A shorter alternative for the second half is this:

\1
@name r(1/2) \1 r(1/3) \1 r(1/4) \1 r(1/5)

The section Timing describes more means of placing changes in time. The ";" separator is often a simpler alternative, but can also be combined with label referencing:

\1
@name r(1/2) t1
; r(1/3) t1
; r(1/4) t1
; r(1/5)

Value ramps

To ramp, or "sweep", a parameter value towards a goal, a set of value ramp arguments can be given instead of the usual number. (This is currently supported for amplitude, frequency, and panning parameters.) The usual number is used as the starting value for the trajectory, and the parameter can be assigned a value twice in order to provide both.

The ramp sub-parameters are as follows:

For example, the following tone begins at 20 Hz and rises exponentially to 20000 Hz, over 10 seconds:

Osin f20 f{v20000 cexp} t10 a0.25

The exponential and logarithmic curves are polynomial approximations with definite beginnings and ends, rather than real exponential and logarithmic curves. (The 'log' curve also skips the below-zero part of a real logarithmic curve, i.e. it really approximates the mathematical function "log(1 + x)".) These approximations have been tuned by ear to sound "smooth" and natural.

The 'esd' curve exponentially saturates and decays, like a capacitor – this means an upside-down decay for the increase (it increases like the 'log' curve and decreases like the 'exp' curve). This is natural-sounding behavior for envelope-like use. The 'lsd' curve behaves the opposite, logarithmically saturating and decaying (increasing like 'exp' and decreasing like 'log').

Modulation with value range

Amplitude and frequency (absolute or relative) parameters support AM or FM, respectively, with a value range. Two values are used instead of the usual one value, and become the bounds of a range of values. The actual amplitude or frequency in use at any given time is the result of modulation with a list of oscillators, where the output is scaled to the value range.

A simple FM example:

// Vary frequency between 250 Hz and 500 Hz, using a 0.1 Hz sine wave
Osin f250,500~[Osin f0.1] t10

A simple AM example:

// Vary amplitude, using a half-wave with 1/5 the frequency
Osin f200 a(1/4),(4/4)~[Oszh r(1/5)] t5

The second value is only used when this kind of modulation is done, and defaults to 0. It can be specified without changing the first value, by leaving out the first value before the comma.

After value(s) or by itself, "~[]" (tilde and square brackets) can be used to set a list of modulator operators specified within the "[]"; the list replaces any previous modulators set, and may be empty.

Each such modulator will produce a result in a 0.0 to 1.0 range, i.e. a positive signal, multiplied by its amplitude parameter (defaulting to 1.0).

The product of modulator amplitudes is mapped to the value range; 0.0 means the normal value and 1.0 means the second value. Setting (changing) the amplitude for modulators may thus change the range, but is allowed for the sake of flexibility.