From The MPEG-4 Structured Audio Book by John Lazzaro and John Wawrzynek.

Part II/1: SAOL Numbers and Variables

Sections

  • Introduction.
  • Numbers. Shows correct syntax for numeric constants.
  • Names. Choosing legal names for your SAOL variables (and other elements).
  • Declarations. Describes the types of variable declarations in SAOL.
  • Instr Parameters. Declaring parameters in the instr preamble.
  • Instr Variables. Syntax for scalar and array variable declarations, including imports and exports.
  • Global Variables. How to declare and initialize global variables.
  • Standard Names. Describes the general-purpose standard names, and provides links for the special-purpose ones.
  • Global Parameters. Shows how to change system defaults with global parameters.

Introduction

In this chapter, we describe the atoms of SAOL expressions:

  • Numbers
  • instr parameters
  • instr signal variables
  • global signal variables
  • Standard names

We introduced these elements in the tutorial examples in Part I of this book.

In this chapter, we provide a complete description of each element type. We explain the declaration syntax for variables, and define the rate and width properties for all elements. These properties are the foundation of the rate and width rules for SAOL expressions and statements covered in Part II/2.

We also describe global parameters, and explain the rules for setting a-rate and k-rate values.

 

Numbers

Numbers in SAOL expressions are represented as 32-bit floating point quantities. The panel on the right shows correct and incorrect ways to write numbers in SAOL, in the context of a SAOL assignment statement.

The SAOL language specification specifies the floating-point representation loosely ("32-bit") instead of requiring the IEEE 754 floating point format, so that digital signal processing chips that use non-standard floating-point formats may host compliant MP4-SA decoders.

The rate and width rules we present in Part II/2 treat numbers as i-rate quantities with scalar width.

There are several SAOL language constructs that use positive integers (for example, the width specifier in an array declaration). Unless otherwise noted, these integers may take any value up to 4,294,967,295.

Legal number syntax:

a =  32.0;  // floating point number
a =   32;   // also floating point! 
a = -6.0;   // a negative number
a = .0923;  // no digit before . ok
a = -.0923; // even with minus sign

a = 23e+12; // exponent may have plus,
a = 23e-12; // minus,
a = 23e12;  // or neither

a = 2.0e-12; // mantissa may have .
a = .2e12;   // no digit before . ok

Illegal number syntax:

a =   +1;   // illegal use of +
a = 2e12.0; // illegal use of . 
a = 2 3e-1; // illegal space
a = 2,302;  // illegal comma

Common error:

a =  1/10;  // is equal to 0.1,
            // not zero!

Names

The names chosen for variables must conform to SAOL naming rules. These rules also apply to other named elements in SAOL, such as buses and instrs.

Names must start with a letter or the underscore symbol. The rest of the characters may be letters, digits, or the underscore symbol. SAOL names are case sensitive (abba and ABBA are different names in SAOL). Two names that share the first 16 characters are considered identical.

SAOL language keywords, standard names, core opcode names, and core wavetable names may not be used as names. The right panel shows a list of these reserved words. In addition, all names starting with _sym_ are reserved.

Jump to next section.

Reserved Words

abs            
acos           
aexpon         
aexprand       
agaussrand     
aline          
alinrand       
allpass        
ampdb          
aopcode        
aphasor        
apoissonrand   
arand          
asig           
asin           
atan           
balance        
bandpass       
bandstop       
biquad         
buzz           
ceil           
channel        
chorus         
comb           
compressor     
concat         
cos            
cpsmidi        
cpsoct         
cpspch         
cpuload        
cubicseg       
data           
dbamp          
decimate       
delay          
delay1
destroy
direction
doscil
downsamp
dur
else
empty
exp
exports
expseg
extend
fft
fir
firt
flange
floor
frac
fracdelay
ftbasecps
ftlen
ftloop
ftloopend
ftsetbase
ftsetend
ftsetloop
ftsetsr
ftsr
fx_speedc
gain
gettempo
gettune
global
grain
harm
harm_phase
hipass
iexprand
if
ifft
igaussrand
iir
iirt
ilinrand
imports
inchan
inchannels
ingroup
input
input_bus
inputmod
instr
int
interp

(continued)

iopcode
irand
itime
ivar
k_rate
kexpon
kexprand
kgaussrand
kline
klinrand
kopcode
koscil
kphasor
kpoissonrand
krand
krate
ksig
lineseg
listenerDirection
listenerPosition
log
log10
lopass
loscil
map
max
maxBack
maxFront
midicps
midioct
midipch
min
minBack
minFront
octcps
octmidi
octpch
oparray
opcode
oscil
outbus
outchan
outchannels
output
output_bus
params
pchcps
pchmidi
pchoct
periodic
pluck
polynomial
port
position
pow
preset
random
released
return
reverb
rms
route
s_rate
samphold
sample
sasbf
sblock
send
sequence
settempo
settune
sgn
sin
soundfile
spatialize
speedt
spline
sqrt
srate
startup
step
table
tablemap
tableread
tablewrite
template
time
turnoff
upsamp
while
window
with
xsig

Declarations

If a signal variable appears in the code block of an instr definition, it also must appear in exactly one of two places in the instr definition: the parameter list of the instr preamble or the variable declaration block. Some instr variable declarations may also require a corresponding global declaration.

The next three sections describe preamble parameter, instr variable, and global variable declarations.

 

Instr Parameters

Parameter declarations are a part of the instr preamble. The panel on the right shows the three types of legal instr preambles, declaring zero, one, or many parameters.

Each parameter and declared variable in an instr must have a unique name. Parameters hold 32-bit floating point values.

Instr parameters are always scalar width and always i-rate. Syntactic elements such as ksig, imports, and [3] are illegal in a parameter declaration.

As shown in the tutorial in Part I of the book, instrs may be instantiated by SASL instr commands or by SAOL send statements. In later chapters of the book, we show other ways to instantiate instrs in MP4-SA.

Each type of instantiation has a method for initializing the value of the instr parameters. If the instantiation method does not supply an initialization value, the parameter is set to zero.

Aside from the issues described above, instr parameters behave exactly like ivar scalar signal variables.

Legal instr Preambles

instr none () { }

instr one (p1) { }

instr many (p1, p2, p3) { }

Illegal instr Preambles

instr bad(imports p1) { } // illegal use of "import"

instr bad1(ksig p1) { }   // illegal: rates not allowed

instr bad2(p1[4]) { }     // illegal: array not allowed

Instr Variables

Signal variable declarations in SAOL instrs occur after the open curly-brace of the instr preamble. The first SAOL statement in the instr marks the end of the variable declaration section: declarations and statements cannot be interspersed.

Each declared variable and parameter in an instr must have a unique name. Signal variables hold 32-bit floating point values and are initialized to zero.

Scalars

The simplest variable declaration consists of a rate identifier (ivar for i-rate, ksig for k-rate, or asig for a-rate), a name, and a semicolon (see right panel for examples). These variables are scalars, and have width 1. Multiple variables can be declared on the same line, separated by commas.

Legal Declarations

instr foo () {

ivar a;
ksig b,c;
asig d;

b = a;

}

Illegal Declarations

instr foo () {

ivar a;  // legal
asig d;  // legal 

a = 1;

ksig b; // illegal: must precede a = 1;

b = a;

}

Arrays

Array declarations build on this syntax, by adding an open bracket, a width specifier and a closed bracket. Arrays and scalars may share the same declaration line. The width specifier, that sets the width of the array, is usually numeric (an integer greater than zero).

Alternatively, the keyword inchannels or outchannels may serve as a width specifier. In an instr, arrays declared with the width specifier inchannels take the width of the audio input presented to the instrument. Arrays declared with the width specifier outchannels take the width of the audio data written by output statements in the instr. In Part II/5 we describe how to determine these widths for an instr.

Legal Array Declarations

ivar a[3];
ksig b,c[2];
asig d[inchannels],f[outchannels];

Illegal Array Declarations

ivar a[0];   // illegal: must be >= 1
ksig c[2.0]; // illegal: must be integer

Imports and Exports

Global variables are not visible inside of instrs by default. Global variables must be imported or exported by an instr to provide read or write access. This process involves declaring a variable in the instr with the same name and rate identifier as the global variable, prepended with the keywords imports and/or exports.

Both scalar and array global variables may be imported or exported into an instr. The rate and width of the global and instr variables must be the same. Since globals may not be asig, neither may imported or exported instr declarations. See the right panel for examples.

If an instr variable is declared with imports, then at the start of the i-pass (for ivars) or at the start of each k-pass (for ksigs), the value of the global variable is copied into the instr variable.

If an instr variable is declared with exports, then at the end of the i-pass following instr instantiation (for ivars) or at the end of each k-pass (for ksigs), the final value of the instr variable is copied into the global variable.

If both imports and exports are used, both behaviors described above happen.

Legal imports and exports

global {
ivar a, c;
ksig b[3];
}

instr example () {

imports ivar a;
exports ivar c;
imports exports ksig b[3];

}

Illegal imports and exports

global {
ivar a;
}

instr example () {

imports ivar a[2]; // illegal: size mismatch
imports ksig a;    // illegal: rate mismatch
}

Imports for SASL

If an instr signal variable is declared using the imports keyword, but no global variable of the same name exists in the global block, the import semantics described in the previous section do not apply.

Instead, the imports keyword signifies that a variable may be targeted by a SASL labelled control command. This SASL command writes a new value into a ksig variable of an instr instance at the start of a k-pass.

Only scalar ksig variables may be used in this construction, and only imports may be used in the declaration, not exports.

An example in the tutorial in Part I shows this usage of the imports keyword in detail. A later section of this book explains SASL control statements in detail.

Imports for SASL:

See tutorial example.

Global Variables

Global signal variables are scalar or array variables declared in a global block of a SAOL program. Global signal variables may be declared ivar or ksig but not asig. The imports and exports keywords may not be used with global variables. Apart from these differences, global declarations share the same syntax as instr declarations.

Global variable names must be unique among all the global variables.

Array declarations may use the keywords inchannels or outchannels as width specifiers. For global arrays, these keywords indicate that the array should take the same width as the the input_bus or output_bus, respectively. These system buses are dedicated to external audio input and output, and are described in detail in Part II/5.

Distributed Global Blocks

The MP4-SA standard states that only one global block may exist in a SAOL program. This restriction makes it difficult to develop modular SAOL libraries.

Sfront relaxes this rule, and permits many global blocks in a SAOL program. To create MP4 files that comply with the standard, sfront collapses all global blocks into a single large global block when encoding .mp4 files.

startup

Global variables hold 32-bit floating-point numbers initialized to zero. To initialize global variable to non-zero values, define an instr named startup and assign initialization values to the global variables in its code block (using imports and exports to access the global variables).

This method works because the SAOL instr execution rules ensure that if the instr startup is defined, it is instanced and run at i-rate as part of the start up sequence of a SAOL program, before the first k-cycle begins.

In addition, by default the startup instrument executes first in each execution cycle, so that k-rate global variables may also be initialized. See Part II/5 for more details on the startup instrument.

Legal Global Declarations


global {

ivar a;
ksig b[2],c;
ivar d[outchannels];
ksig e[inchannels];

}

Illegal Global Declarations


global {  // all lines below are illegal

asig a;         // a-rate globals not allowed 
imports ksig c; // imports globals not allowed 
exports ksig c; // exports globals not allowed 
ivar d[0];      // width 0 not allowed

}

Standard Names

Standard names are read-only variables that hold system information. The panel on the right lists the SAOL standard names and the declaration each would have if it were a normal variable.

This book describes most standard names in chapters related to their function. The list on the right panel includes links to the parts of chapters on buses, MIDI control, SAOL instrument control, and MPEG 4 integration that describe the standard names related to these topics.

Two standard names are general purpose in nature, and we explain them now. The ivar standard name k_rate holds the k-rate of the SAOL program, and the ivar standard name s_rate holds the a-rate of the SAOL program.

SAOL programs often compute constant values based on the value of k_rate and s_rate. The sfront distribution includes a library of SAOL utilities, called Slib, that defines a set of useful constants derived from k_rate and s_rate.

Standard Names

Described in this section

ivar k_rate;
ivar s_rate;

For buses: see Part II/5

ivar inchan;
ivar outchan;
asig input[inchannels];
ivar inGroup[inchannels];

For MIDI: see Part III/2

ivar preset;
ivar channel;
ksig MIDIctrl[128];
ksig MIDItouch;
ksig MIDIbend;

For instr control: see Part III/3

ivar dur;
ksig itime;
ksig released;
ivar time;
ksig cpuload;

For AudioBIFS: see Sfront manual

imports ksig position[3];
ksig direction[3];
ksig listenerPosition[3];
ksig listenerDirection[3];
ksig minFront;
ksig maxFront;
ksig minBack;
ksig maxBack;
imports exports ksig params[128];

Global Parameters

Global parameters may be used to change system constants in SAOL. Global parameters are set in the global block, using the syntax shown in the right panel. Each global parameter may only be set once.

Unlike instr parameters, global parameters may not be used as variables in SAOL expressions. Use the standard name related to the global parameter instead.

There are five global parameters. The parameters inchannels and outchannels concern the special buses input_bus and output_bus and are explained in Part II/5. The parameter interp concerns wavetables and is explained in Part II/4.

The last two global parameters, srate and krate, set the a-rate and k-rate of the system. The srate parameter may be set to an integer in the range 4000 Hz to 96000 Hz.

The krate parameter may be set to an integer in the range 1 Hz to the audio sampling rate.

The k-rate of a SAOL program defaults to 100 Hz. The a-rate of a SAOL program defaults to 32,000 Hz. (but see this exception if processing external audio input).

If krate does not evenly divide into srate, the k-rate of the SAOL program is the first integer larger than krate which does evenly divide srate.

Syntax

globals {

srate 48000; // note: no = 

}

The Global Parameters

Described in this section

srate
krate

For buses: see Part II/5

inchannel
outchannel

For wavetables: see Part II/4

interp

Next section: Part II/2: Expressions and Statements

 

Copyright 1999 John Lazzaro and John Wawrzynek.