### 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. | ## Correct 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
` ## Incorrect number syntax: `
    a =   +1;   // no plus allowed
    a = 2e12.0; // no . after exponent
    a = 2 3e-1; // no spaces
    a = 2,302;  // no commas
` ## 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) { }

    instr bad1(ksig p1) { }

    instr bad2(p1[4]) { }
`

## 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;
    asig d;

    a = 1;

    ksig b,c; // must be at the top

    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];   // must be >= 1
    ksig c[2.0]; // 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];  // mismatch
    imports ksig a;     // 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 {

    asig a;         // no a-rate
    imports ksig c; // no imports
    exports ksig c; // no exports
    ivar d[0];      // width < 1

    }

## 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 usually 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.