## NCSA Sound Server Reference Manual

last updated: Camille Goudeseune, 9 November 1999

This is the reference manual for version 3.1 of VSS ("Virtual Sound Server"), developed at NCSA.

## Table of Contents:

1. Introduction
2. Running_VSS
3. Some useful programs in the "util" subdirectory
4. Command-line flags for VSS
5. Writing client applications
6. Using .aud files
7. Limits
8. Not using .aud files
9. Built-in VSS messages
10. Actor messages
    1. Universal messages
    2. Generator actor messages
    3. Handler messages
    4. Actor message reference, by actor
11. Credits

# Introduction

VSS is a platform-independent software package for data-driven sound production controlled from interactive applications.

The original SGI scheduler is based upon HTM, developed by Adrian Freed at the Center for New Music and Audio Technologies, UC Berkeley. HTM is a framework for synthesizing sound in real time while accepting messages over the Internet to modify the sound. VSS lets you control, coordinate, and synchronize sounds produced by direct software synthesis, sample playback, and external synthesizers such as MIDI, Max, and Open Sound Control.

VSS comes in several separate distributions:

- Irix 6.5
- Irix 6.3
- Irix 6.2
- Irix 5.3
- Linux (glibc 2.1+ (e.g., Red Hat 6.0+), OSS drivers; ask about ALSA drivers)
- (Ask about the Windows 95+ / Windows NT 4.0+ distribution.)

Each distribution includes the reference manual. The most recent version of the reference manual is always here, and the most recent version of the tutorial is always here. (Tutorials are no longer included with the VSS distribution because they've become too large.)

A client first makes a connection to VSS. It then requests the server to make a sound, whereupon the server does so and replies with a "handle" for the sound. The client can then send further messages using this sound handle to modify the sound and eventually delete it. Finally the client breaks the connection with the server.

Interaction between the client and sounds in VSS is coordinated through entities in VSS called actors. Actors are requested by the client and manipulated using actor handles, in similar manner to sounds. Actors are classified by the types of actions they perform, including the types of sound synthesis being used to generate the sounds. As with an object-oriented class hierarchy, in the actor hierarchy, an actor may control several related sounds, so that they all may be manipulated at once with a single command to the actor. An actor accepts messages from VSS clients or from other actors, and can send messages to other actors. Some actors process real-time input and generate real-time output in various formats, primarily audio and MIDI.

# Running VSS

Run VSS on an SGI computer with audio hardware and IRIX 5.3 or later, by typing "vss" at your shell prompt. Run your client on the same machine or a different machine accessible to the server machine over the network. If you run on a different machine, tell the client where to find VSS with a command like "setenv SOUNDSERVER 141.142.220.61" (csh), where 141.142.220.61 is the IP address of the machine running VSS. You can also use "setenv SOUNDSERVER mymachine.foo.edu".

Run only one copy of VSS per machine. If one is already running when you get to a machine, you can choose to go ahead and use it, or if you must run your own copy, use the command vsskill to terminate the previously running VSS process.

If connection cannot be established with the server, the client will time out after a few seconds and will print an error message.

When VSS exits, it emails to audio@ncsa.uiuc.edu a report consisting of which actors were loaded and how many of each. (This is so only for the licensed, non-demo versions.) These reports help the VSS team set priorities on which features to add, what code is really worth optimizing, and so on. If you prefer not to have these reports sent, set the environment variable VSSMAIL to "0" (in csh, "setenv VSSMAIL 0"). If you "setenv VSSMAIL foo@bar.com", the email will be copied to that address.

### Some useful programs in the "util" subdirectory

vssping
  Ping VSS to see if it's running.
vssflush
  Reset VSS (by deleting all actors).
vsskill
  Terminate any running copy of VSS on this computer.
audtest
  Read and execute a .aud file, optionally running message groups from the command line.
audpanel
  Read and execute a .aud file, with sliders and presets and scaling and buttons. Probably fancy enough to be a mock-up for your own application.

### Command-line flags for VSS

-srate n
  set sampling rate (8000, 11025, 16000, 22050, 32000, 44100, 48000 Hz)
  default is 22050 (44100 on Linux and Windows)
-chans n
  set number of channels (1, 2, 4, or 8; default 1 (2 on Windows))
  (Note that 8-channel mode on SGI requires Irix 6.3 or greater, an ADAT fiber optic output such as those found on Octanes or Onyxes, a hardware device to convert the fiber to eight analog audio jacks, and apanel's default output to be set to "adat".)
-chans nintom:a,b,c,...
  set number of channels computed by VSS to n;
  set number of channels actually played by the computer to m;
  assign channel numbers a,b,c,... (m of them) to be the ones played.
  Note that this usage of -chans uses more CPU than plain old "-chans n".
  You can use this for tricks like:
  - swapping left and right: -chans 2into2:1,0
  - hearing individual channels of an 8-channel sound on a 2-channel machine: -chans 8into2:6,7
    (or loosely build up an 8-channel mix from several 2-channel machines!)
  - custom mapping from 2-channel to 4-channel (left -> front, right -> rear): -chans 2into4:0,0,1,1
-input [n]
  enable input of sound (to analysis actors).
  The optional number n sets the number of channels of input, which defaults to 1.
-graphoutput
  (Irix only:) display graph of output signal
-graphspectrum
  (Irix only:) display graph of output spectrum (thanks to Xavier Rodet, CNMAT, for the code this is based on)
-mmio
  (Windows only:) Use low-level MMIO audio instead of DirectSound. Useful if your soundcard has no DirectSound driver, or if you need to output more than 2 channels.
-hog n
  set cpu-hogging behavior (if running as root in Irix):
  0 - normal
  1 - prevent swapping out
  2 - nondegrading highest-priority process

  As root on Linux, vss runs niced -10 and locked into memory (technically, setpriority(PRIO_PROCESS, 0, -10) and mlockall(MCL_FUTURE)).

-lowlatency
  reduce input-to-output latency (on IRIX, recommended in combination with locking VSS to a CPU by a program like mplockpid)
-latency lwm hwm
  precisely specify latency by setting the low- and high-water mark, in samples (if you don't know what this is, don't ask)
-antidropout x
  increase resistance to audio dropouts from cpu starvation, to a duration of x milliseconds (only for Linux OSS at the moment)
-soft
  enable soft clipping
-limit
  absolutely prevent hard clipping
-nopanel
  don't show the graphical control panel
-silent
  disable sound playback (if you want only output to a sound file and no sound from the speakers).

## Writing Client Applications

## The Trivial Client

        #include "vssClient.h"     /* must do this */

        main()
        {
            /* Connect to the server */
            if (!BeginSoundServer()) {
                printf("UDP connection to sound server failed\n");
                exit(2);
            }

            /* Break connection */
            EndSoundServer();
        }

To build this client, set the directories in which to find vssClient.h and libsnd.a. For example:

        CC -c foo.c -IVssIncludeDir -fullwarn
        CC -o foo foo.o -LVssLibDir -lsnd -ll -lm

or

        CC foo.c -IVssIncludeDir -LVssLibDir -lsnd -ll -lm -fullwarn

(at NCSA:)

        CC foo.c -I/afs/ncsa/packages/vss/6.2 -L/afs/ncsa/packages/vss/6.2 \
    		-lsnd -ll -lm -fullwarn

### Recommendations

#### Compiling and Linking

On Irix, the Mipspro C and C++ compilers work well for compiling VSS clients. On all platforms, gcc and g++ work well.

Do not link with "cc" or "ld". Link with either "CC" or with "cc -lC". Otherwise you'll get mysterious link errors like __vec_new and __nw__FUi. We recommend CC over -lC. With some compilers/linkers, -lC causes peculiar run-time errors.

#### Verifying VSS component versions

    const char* GetVssLibVersion(void);

  Returns a string indicating the current version of libsnd.a (e.g., "2.1").

    const char* GetVssLibDate(void);

  Returns a string indicating when libsnd.a was built (e.g., "Apr 18 1995, 13:26:31").

Question: "How do I know if libsnd.a, vssClient.h, and VSS are all compatible?" Some places (like NCSA) have several versions of VSS sitting around, and so their components can often end up out of synch. Should this occur (despite valiant efforts to avoid them), here is how to reconcile versions among VSS components:

- VSS : reports its build time/date and version number on startup.

- vssClient.h : A line at the top of the file indicates when it was built (much more definitive than the UNIX file date).

- libsnd.a : The command "`strings libsnd.a | grep Version`" will show you what version of VSS that libsnd.a is compatible with. Compare this with the version number reported by VSS at startup. Note that the client calls to GetVssLibVersion() and GetVssLibDate() as described above provide the "formal" way to perform this checking.

Take as a good sign that version numbers match and dates match to within a few days.

## Using .aud files

The .aud file provides an interface through which the bulk of an application's audio code may be isolated from the compiled code. While the events which may trigger sound originate from within the client application, the specific way in which those events ultimately map to sound are described through the .aud file. This interface then allows the sound to be tweaked independently of the application, e.g. without recompiling the application, thereby simplifying the development and the debugging of the complete, sonified application. The interface will also help trivialize the process of porting the audio component of the app to other apps or platforms.

The client-side interface to the .aud file is implemented through three main functions:

    int AUDinit(const char *filename);

  Initialize. "filename" is the name of the .aud file, e.g. "../AUDFILES/foo.aud".

    float AUDupdate(int handle, char *msgGroupName,
                   int numFloats, float *floatArray);

  Do interaction with commands in .aud file referenced by "handle", where "handle" is as returned by AUDinit(). Send an array of float data "floatArray" with number of elements "numFloats" to the Message Group "msgGroupName". (For trigger and flag-type events, "numFloats" may be zero and "floatArray" NULL.)

  (Typically you can ignore the float return value. But if you know that the message group `*msgGroupName` contains a `BeginSound` statement, the return value will be a handle to that sound (the last one, if there are several). This is useful if you don't know at compile time how many sounds you'll need simultaneously.)

    void AUDterminate(int handle);

  Clean up, using the handle returned by AUDinit().

An alternative form of AUDupdate():

    float AUDupdateFloats(int handle, char *msgGroupName,
                   int numFloats, float f1, float f2, ...);

  Just like AUDupdate(), but put the arguments right in the function call.
  Advantage: you don't need to declare an array "floatArray" and stuff it with the arguments. Convenient when you have just a few floats to pass.
  Disadvantages: unwieldy for very large numbers of arguments (though it'll take up to a thousand); the arguments must be explicitly of type float or double (if you pass an int like 42 instead of 42.0 then garbage data will result).

(There are a few other functions (`AUDreset(), AUDupdateTwo(), AUDupdateMany(), AUDqueue(), AUDflushQueue()`) which can be used in special circumstances.)

The following example client code builds upon the previous example, using these three functions in context:

    #include "vssClient.h"

    void UpdateState(float *data)
    {
        /* generate three numbers between 0 and 1 */
        data[0] = drand48();
        data[1] = drand48();
        data[2] = drand48();

       /* rescale two numbers */
        data[1] *= 20;
        data[2] *= 20;
    }

    void main()
    {
        int     i;
        int     handle;
        float   data[3];

        if (!BeginSoundServer()) {
            printf("UDP connection to sound server failed\n");
            exit(2);
        }

        handle = AUDinit("example.aud");
        if (handle < 0) {
    	printf("Failed to load audfile example.aud\n");
    	exit(3);
        }

        /* Send state messages to VSS */
        for (i=0; i<10; i++)
            {
            UpdateState(data);                    /* run my simulation */
            AUDupdate(handle, "Whack", 3, data);  /* send message group 0 */
            sleep(1);                             /* wait a sec */
            AUDupdate(handle, "Clang", 3, data);  /* send message group 1 */
            sleep(2);

            /* data[] maps to the "*" parameters in the .aud file
             * (see "Commands in .aud files" below).
    	 * In the .aud file immediately below, the first element of
    	 * data[] is used to set the amplitudes of sounds in all three
    	 * BeginSound messages; data[1] and data [2] are used to set
    	 * the tone color of sounds in two BeginSound messages
    	 * that are synchronized.
             */
            }

        AUDterminate(handle);
        EndSoundServer();
    }

The client first establishes connection with the server, and then calls AUDinit(), which reads the .aud file "example.aud" (shown below), parses out the command strings, and then sends the commands to the server. The server also returns a file handle for referencing the .aud file, and to do interaction with actors which the .aud file caused to be created.

The client then updates the state of a data array, in this case 3 randomized floats, and then makes successive calls to AUDupdate(). Each call passes new data values to each of the two Message Groups named "Whack" and "Clang". The Message Groups are created from commands within the .aud file. (Note, the details of .aud file commands are given later below.)

Here is the corresponding example .aud file, "example.aud":

    // Have the server echo messages

       SetPrintCommands 1;

    // Load the DSOs that we will need

       LoadDSO msgGroup.so;
       LoadDSO marimba.so;
       LoadDSO tubebell.so;

    // Create two Message Groups

       Whack = Create MessageGroup;
       Clang = Create MessageGroup;

    // Create generator actors for the message
    //    groups to route messages to

       Woody = Create MarimbaActor;
       Belly = Create TubeBellActor;

    // Create list of messages for "Whack"

       AddMessage Whack BeginSound Woody SetAmp *0, SetStickHardness 3.0;

    // Create list of messages for "Clang"

        AddMessage Clang BeginSound Belly SetAmp *0, SetModIndex *1;
        AddMessage Clang BeginSound Belly SetAmp *0, SetModIndex *2;

Again, .aud file commands are detailed below; only certain aspects will be pointed out here.

Dynamically Shared Objects (DSOs) are loaded with the LoadDSO command. A DSO contains the code for one or more actors used by VSS, so it must be loaded before these actors can be used. Therefore, LoadDSO commands are usually placed near the top of the .aud file.

The Message Groups are then created. The names of the Message Groups within the .aud file must match the names used in the client's AUDupdate() calls: these names are the interface between client and server.

Messages are then added to each Message Group. The messages define the group of actions to be taken by VSS when a particular Message Group is triggered by a client-side AUDupdate(). In this case, the message "Whack", upon receipt by the server, will begin a marimba sound with stick-harness of 3.0; the message "Clang" will begin two Tubular Bell sounds with two different degrees of tonal brightness. The set of actions taken by a given Message Group occur in the order in which they appear in the .aud file.

Through this grouping of messages, one AUDupdate() can trigger many, possibly diverse, actions. Diversity of actions is accomodated by allowing an array of data values to be passed through the call to AUDupdate(). From within the Message Group, individual elements of the array may then be referenced and used, say, to set different sound parameters. For example, in the line

       AddMessage Whack BeginSound Woody SetAmp *0, SetStickHardness 3.0;

the element array[0] is referenced through the notation *0 (generally, array[N] is referenced through *N) to set the amplitude value of the Marimba sound to be played.

A .aud file has no variables per se, no "scope". All the state of a running .aud file is hidden inside its actors. Therefore, at first blush if you use BeginSound from inside a message group

    	AddMessage Clang BeginSound Belly;

then there's no way to get at the handle returned by BeginSound (if you want to modify or end that sound). The following doesn't work:

    	AddMessage Clang myBell = BeginSound Belly;   // "myBell =" is illegal
    	AddMessage Clang SetAmp myBell 0.1;

Message Groups have a special syntax to handle this case, where you want a message group to itself begin a sound instead of modifying an already existing sound. The syntax is similar to *0 *1 etc.: "*?" stands for the handle to the most recent BeginSound. So the previous example becomes, correctly:

    	AddMessage Clang BeginSound Belly;
    	AddMessage Clang SetAmp *? 0.1;

You can modify the note at some point in the future by using the LaterActor, as follows (read the LaterActor reference to see what's going on here):

    	myLaterActor = Create LaterActor;
    	...

    	AddMessage Clang BeginSound Belly SetAmp 0.1;   // (Might as well put the SetAmp in the same line.)
    	AddMessage Clang AddMessage myLaterActor 0.5 SetModIndex *? *1; // Wait 0.5 seconds, then SetModIndex.
    	AddMessage Clang AddMessage myLaterActor 1.5 SetModIndex *? *2; // Do it again, 1 more second later.
    	AddMessage Clang AddMessage myLaterActor 5.0 Delete *?;         // End the sound after 5 seconds.

### Using only one .aud file ("1040-EZ" syntax)

If your C program uses only a single .aud file, it can use a simplified form of the C functions AUDinit(), AUDupdate()/AUDupdateFloats(), and AUDterminate(), as follows:

- Ignore the return value provided by AUDinit(). (If you like, at least test that the return value is nonnegative to ensure that the .aud file itself was valid.)
- Leave out the first "handle" argument to AUDupdate(), and call AUDupdateSimple() instead.
- Ditto for AUDupdateFloats(): Leave out the first "handle" argument and call AUDupdateSimpleFloats() instead.
- Don't bother calling AUDterminate() -- it will get called for you when you call EndSoundServer().

So a simple client using this syntax is:

    #include "vssClient.h"
    main()
    {
    	if (!BeginSoundServer())               /* connect to VSS */
    		return -1;
    	AUDinit("foo.aud");                    /* start making a sound */
    	AUDupdateSimpleFloats("foo", 1, 42.0); /* change the sound */
    	  sginap(1000);                        /* wait 10 seconds */
    	AUDupdateSimple("bar", 0, NULL);       /* change the sound again */
    	  sginap(1000);                        /* wait 10 seconds */
    	EndSoundServer();                      /* disconnect from VSS */
    }

### Basic .aud File Command (Message) Syntax

- Command syntax in .aud files adhere to one of the following forms:

         name = command, arg1, arg2, arg3,... ;

         command, arg1, arg2, arg3,... ;

- All statements in .aud files end in a semicolon (";"). If a syntax error occurs upon AUDinit(), look for missing semicolons near the line with the reported error.
- Commas are always optional. Use them if they clarify structure, leave them out if it looks cluttered.

- Both `/*C*/` and `//C++` style comments work in a .aud file.

- A .aud file is comprised of six parts:
  1. Load the DSOs corresponding to the actors needed.
  2. Create and name the actors to whom the messages will be sent.
  3. Create and name the empty Message Groups.
  4. Send setup messages to these actors.
  5. Add a list of messages to each Message Group.
  6. In the message arguments, use the "*_" syntax to indicate numbers that are indexes into the array being passed with the Message Group. This defines a mapping from the data array passed in AUDupdate() to message arguments in the Message Group.

### Using Text Preprocessors with .aud Files

If you're trying to manage very large .aud files, the following technique may prove useful to you. It is not recommended if you aren't yet comfortable with the basics outlined above.

In Irix, you can use filter programs to modify a .aud file before it gets parsed. A filter is any executable file which reads text on its standard input and produces (modified) text on its output. Examples of these are the C preprocessor, perl, m4, and handwritten C programs. To invoke a filter, the first line of the .aud file should read
`//pragma filter "myprogramname"`
where myprogramname is the name of the filter (technically, anything that /bin/sh will parse). The C preprocessor, for example:
`//pragma filter "/usr/lib/cpp -P"`
Note that the .aud file parser is intolerant of leading or trailing whitespace, or trailing comments, on the //pragma line. Also note that the filtered output text isn't stored anywhere, so if you have syntax errors the line numbers will probably be off if your filter is even slightly intelligent.

#### Miscellaneous Limits

- Up to 100 .aud files can be used simultaneously by a client. (However, if you keep track of the order in which you open the .aud files, and then close them in the reverse order in which you opened them, a client can sequentially open an arbitrary number of .aud files.)
- There is no limit to the number of actors you can create in VSS.
- The name of an actor can be at most 49 characters.
- The name of a Message Group can be up to 30 characters.
- A single message (with arguments) sent to a message group can be at most 5120 characters.
- A client can call AUDqueue() at most 32 times between calls to AUDflushQueue().

## Not using .aud files

In special circumstances you may want to call C functions directly from your VSS client application, instead of using a .aud file. Here are some of the functions you can use then (these are the same functions which are called by the parser of .aud files). It's a lot easier to make subtle errors, though, so beware. And this fragment of documentation doesn't pretend to be an adequate explanation of this interface, partially out of laziness and partially out of discouraging its use.

    	int   BeginSoundServer(void);
    	int   BeginSoundServerAt(char * hostName);
    	void  EndSoundServer(void);
    	int   PingSoundServer(void);

    	void  actorMessage(char* messagename);
    	void  actorMessageF(char* messagename, float);
    	void  actorMessageFD(char* messagename, float, int);
    	void  actorMessageFDD(char* messagename, float, int, int);
    	float actorMessageRetval(char* messagename);

    	void  MsgsendObj(OBJ obj, struct sockaddr_in *paddr, mm* pmm);
    	OBJ   BgnMsgsend(char *szHostname, int channel);
    	void  Msgsend(struct sockaddr_in *paddr, mm* pmm);
    	void  MsgsendArgs1(struct sockaddr_in *paddr, mm* pmm, const char* msg, float z0);
    	void  MsgsendArgs2(struct sockaddr_in *paddr, mm* pmm, const char* msg, float z0, float z1);
    	void  clientMessageCall(char* Message);

    	float actorGetReply(void);
    	float createActor(const char* actorType);
    	void  deleteActor(const float actorHandle);
    	void  setActorActive(const float actorHandle, const int active);
    	float beginSound(const float hactor);
    	void  killSoundServer();

## VSS Message Reference

## Built-in VSS messages

These messages are handled by the VSS message receiver, independent of whatever actors have been created.

Create actorName
  Create an actor of type actorName.
DumpAll
  (For debugging:) send the Dump message to all actors.
KillServer
  Terminate VSS immediately (even if other clients are connected to it!).
LoadDSO dsoName
  Load a DSO into VSS. The only way to get an actor into VSS. dsoName should refer to a file in, or path/file relative to,
  1. the server launch directory (".");
  2. the directory $SOUNDSERVER_DSO (in csh, "setenv SOUNDSERVER_DSO myDsoDir" on server machine);
  3. the directory containing the executable file `vss`;
  4. /lib or /usr/lib.
  VSS will search these directories in this order. LoadDSO will fail if the dso is not in one of these directories.
  In Windows environments, DSO's (actually, DLL's) will be searched for in the following directories, in this order:
  1. The directory where vss is located.
  2. The directory where vss was run from.
  3. The Windows system directory.
  4. The Windows directory.
  5. The directories listed in the PATH environment variable.
  Note that the LIBPATH environment variable is not used.
Ping
  Ping VSS, wait for acknowledgement that VSS is running.
SetPrintCommands level
  When level = 1, cause VSS to print out all the messages it receives from clients (in green).
  When level = 2 or more, cause VSS to print out all the messages any actor receives from any other actor (in blue).
  When level = 0 or less, cause VSS to do none of the above.
EnableOfile 1 "filename"
  Start logging the output of VSS into a raw audio file.
  Appends to the file if it already exists (say, from a previous EnableOfile).
  (The filename can begin with a path, if you want the file to be put in a particular directory instead of where VSS was launched from.)
EnableOfile 0
  Stop logging. (To convert the file into an aiff file, use the (csh) command
  `sfconvert filename.raw filename.aiff -i rate 44100 int 16 2 chan 2 end format aiff`
  where `44100` is the sampling rate VSS was running at, and the number `2` after `chan` is the number of channels VSS was running at.)
  (A "filename" can optionally follow the 0. This filename is ignored, but it is allowed for convenience of use with tools like audpanel.)
SetGear gear
  Change the "gear" VSS is running in, by analogy with a car transmission. gear can be one of three values: PRNDL_Parked, PRNDL_Low, PRNDL_Drive. PRNDL_Parked suspends computation of samples, and is appropriate during initialization (often the bulk of a .aud file, creating actors and sequences). PRNDL_Low is VSS's default behavior. PRNDL_Drive is appropriate when the app is running smoothly and sending only parameter-update messages. PRNDL_Drive handles too-rapid sending of messages more gracefully than PRNDL_Low.

The following look like messages when written in a .aud file, but in fact do not cause any message to be sent to the VSS server. They only change behavior of the VSS client which loaded the .aud file. (Therefore, it makes no sense to put them in a message group; they are not messages, are not "sent" to any actor, are not "sent" to VSS. They therefore happen only during AUDinit(); AUDupdate()'s will never see them. So they're useful only during the initialization part of a .aud file.)

ClientSleep `duration`
  Pause the client application for `duration` seconds. ("Sleep" and "sleep" are synonyms for "ClientSleep", for historical reasons.)
ClientSetTimeout `duration`
  Let the client wait for `duration` seconds before timing out and assuming that VSS isn't running, when expecting a handle back from VSS as a result of a BeginSound or Create message. `duration` is initially 2.5 seconds when the VSS client starts up. `duration` must be greater than 0, and not more than 3600 (one hour).

  In some cases you may want the client to wait until VSS has completed a task which does not return a handle but might take a long time, such as a few LoadFile commands sent to a SampleActor when the files aren't on a local disk. You can accomplish this as follows:
  `ClientSetTimeout 60;
  LoadFile ... ; LoadFile ... ; LoadFile ... ;
  dummy = Create SampleActor; Delete dummy;
  ClientSetTimeout 2.5;`
  or with any similar Create or BeginSound command whose sole purpose is to force VSS to send something back to the client.

ClientPrint "`string`"
  Simply print a notice to the standard error (for debugging and tracing purposes).

## Actor messages

Actors are built up inside VSS according to a class hierarchy. Actors respond to messages at different levels, depending upon the actor type and the functionality needed. The levels are, from top to bottom, the Actor Level, the Handler Level, and the Algorithm Level. Governed at the Actor Level are such top-level behaviors as the creation/deletion of actors and the passing of messages and data from one actor to another. Governed at the Handler Level are the creation/deletion and modification of individual sound-making objects, called "sounds". At the Algorithm Level, only low-level tasks are performed, such as keeping track of the internal state of generators for each sound, and producing the sound output for the sounds. No direct external interface is available at the Algorithm Level; any needed interface is provided through messages at the Handler level.

Actors fall into three primary types: Control Actors, Generator Actors, and Processor Actors. Control Actors generate or manipulate control-rate messages, then pass the resulting messages to other actors. As such, Control Actors only operate at the top Actor Level. Generator Actors respond to control messages and produce sounds, and so they operate at all three levels, Actor, Handler, and Algorithm. Processor Actors operate on audio data, modifying the sound output of Generator Actors or other Processor Actors in response to control messages. Even so, they do not generate sound on their own, so they also only operate at the top Actor Level.

Two simple actor examples will help explain these concepts. First, we show a basic Control Actor:

An instance of the LaterActor is created by VSS when the Create command is issued. A handle act_handle1 is returned so that further messages may refer to that particular instance. During usage, we may desire to delay, say by 0.5 seconds, the sending of a message message to an instance act_handle2 of the generator actor FMActor. We may accomplish this by issuing an AddMessage command using act_handle1, where the message contents use act_handle2. Thus, the LaterActor passes the contents of message from where it originated (e.g. the client or another top-level actor) to another actor, in this case a generator actor. So, the LaterActor is a top-level-only actor.

On the other hand, the FMActor is a Generator Actor and operates at all three levels:

Here we have instance act_handle2 of the FMActor, produced by VSS upon the appropriate Create. Two sounds are begun using the BeginSound command and act_handle2. This invokes the FMHandler, creating the two sound instances sound_handle1 and sound_handle2. For these sounds, the FM synthesis algorithm is used with default parameters. The internal state information for the sound synthesis is contained privately within each existing sound, so that the sound generation may proceed independently among all sounds. (Each sound can then be called a child of its referring actor instance, or parent actor.)

Messages may then be sent to existing instances of the Actor or Handler, with the different levels of interaction resulting in differing behavior. For example,

    	SetAllAmp act_handle2 0.5;

in this case will set the amplitudes of both sounds sound_handle1 and sound_handle2 to the value 0.5, but

    	SetAmp sound_handle2 0.5;

will set only the amplitude of sound_handle2 to 0.5.

### Universal messages

The following messages are understood by all actors.

Active `hActor bool`
  Activate/Deactivate this actor. An actor is active when bool=1 (default). (This means that its `act()` method is being called. Certain uses of the EnvelopeActor require the Active message to be sent manually.) This message is used internally by VSS, typically to "silence" an actor just prior to deleting it.
Debug `hActor x`
  Set this actor's debug level to `x`. It's up to individual actors to use this value as they see fit.
Delete `hActor`
  Delete this actor. Removes it from VSS memory.
Dump `hActor`
  For debugging only. Print out the contents of this actor.

### Generator actor messages

In addition to the messages understood by all actors, generator actors understand the following messages. Arguments in italics are optional; without them, default values will prevail. Note, [params] can be any number of parameter-setting messages appropriate to that actor:

BeginSound `hActor` [params]
  Create a new instance of the synthesis algorithm and handler corresponding to this actor. Returns the handler's handle to the client.
BeginSoundPaused `hActor` [params]
  Create a new instance, return a handle, and leave it in the paused state (inactive, not generating samples).
SetAmp `hActor x`
  Set the default amplitude for all future handlers created by this actor to `x` (0 = silence, unity = nominal).
SetAllAmp `hActor x time`
  Set the amplitude for all of this actor's handlers (its children) to `x` and set the default amplitude for all future handlers. If `time` is specified, handlers will modulate to the new value over the specified duration. The default value is always set immediately regardless of `time`.
SetGain `hActor x`
  Set the default amplitude in decibels for all future handlers created by this actor to `x` (-100 or less = silence, 0 = nominal).
SetPan `hActor x`
  Set the default pan position for all future handlers created by this actor to `x` (-1 = hard left, 0 = centered, +1 = hard right).
SetElev `hActor x`
  Set the default elevation for all future handlers created by this actor to `x` (-1 = hard down, 0 = level, +1 = hard up). Use +1 to give your sounds a subtle aura of impecuniosity.
SetDistance `hActor x`
  Set the default distance for all future handlers created by this actor to `x` (in feet).
SetDistanceHorizon `hActor x`
  Set the default horizon distance for all future handlers created by this actor to `x` (in feet), if you need to tweak how the distance cues work.
SetXYZ `hActor x y z`
  Set the default position for all future handlers created by this actor to `(x,y,z)` (in feet, standard cave-coords).
InvertAmp `hActor fInvert`
  By default, invert the signal (multiply amplitude by -1) for all future handlers created by this actor if `fInvert` is true.
SetAllGain `hActor x time`
  By analogy with SetAllAmp.
SetAllPan `hActor x time`
  By analogy with SetAllAmp.
SetAllElev `hActor x time`
  By analogy with SetAllAmp.
SetAllDistance `hActor x time`
  By analogy with SetAllAmp.
SetAllDistanceHorizon `hActor x time`
  By analogy with SetAllAmp.
SetAllXYZ `hActor x time`
  By analogy with SetAllAmp.
InvertAllAmp `hActor fInvert`
  By analogy with SetAllAmp.
SetLinearEnv `hActor bool`
  Cause amplitudes to be interpolated linearly (pre-vss3.1 behavior) instead of exponentially, if bool=1 (default=1). (If a generator actor receives no SetLinearEnv message, it defaults to exponential interpolation.)

Extra messages understood by processor actors (generator actors which accept audio input):

SetInputAmp `hActor x`
  Set the default input scaling for all future handlers created by this actor to `x` (0 = silence, unity = nominal). Default is nominal.
SetInputGain `hActor x`
  Set the default input scaling in decibels for all future handlers created by this actor to `x` (-100 or less = silence, 0 = nominal). Default is nominal.
SetAllInputAmp `hActor x time`
  By analogy with SetAllAmp.
SetAllInputGain `hActor x time`
  By analogy with SetAllAmp.

### Handler messages

In addition to the messages understood by all actors, handlers understand the following messages: (arguments in italics are optional)

SetAmp `hSound x time`
  Set the amplitude for this sound to `x`. If time is specified, modulate to the new value over the specified duration.
ScaleAmp `hSound x time`
  Set the secondary amplitude for this handler to `x`. THe secondary amplitude defaults to unity. It is provided if you need to control amplitude in a separate way from the main amplitude.
SetGain `hSound x time`
  Set the amplitude in decibels for this sound to `x`. If time is specified, modulate to the new value over the specified duration.
ScaleGain `hSound x time`
  Set the secondary amplitude in decibels for this handler to `x`. The secondary amplitude defaults to +0 dB.
SetPan `hSound x time`
  Set the pan position for this sound to `x`. If time is specified, modulate to the new value over the specified duration. Pan from hard left to hard right as x varies from -1 to 1. In 4-channel mode, hard left and hard right meet directly behind the listener, and mod-2 arithmetic is used (-3 is also directly behind; 2 is also directly in front). Panning over a time interval in 4-channel mode is done "the shortest way around the circle". 8-channel is analogous to 4-channel.
SetElev `hSound x time`
  Set the elevation for this sound to `x`. If time is specified, modulate to the new value over the specified duration. Move from "hard down" to "hard up" as x varies from -1 to 1. This command has an audible effect only if VSS is running with 8 channels.
SetDistance `hSound x time`
  Set the distance for this sound to `x` feet. If time is specified, modulate to the new value over the specified duration.
SetDistanceHorizon `hSound x`
  Set the horizon distance for this sound to `x` feet. No time may be specified here.
SetXYZ `hSound x y z time`
  Set the position for this sound to `(x,y,z)` feet, in standard cave-coords. If time is specified, modulate to the new value over the specified duration.
  Note that SetXYZ is implemented in terms of SetPan SetElev SetDistance SetDistanceHorizon. This means that, for a given handler, you can use either SetXYZ or these other four. If you combine SetXYZ with these other four, the acoustic result is undefined (though probably entertaining). You may use SetXYZ for some sounds you wish to localize in threespace, and use SetPan etc. to position other sounds to taste, with no problems.
InvertAmp `hSound fInvert`
  Invert the signal (multiply amplitude by -1) if `fInvert` is true.
SetMute `hSound bool`
  Mute/Unmute this sound. Sound is muted when bool=1 (default=0). Muted algorithms continue to generate samples and store them in their internal buffer, but these samples are not sent to the VSS main outputs. Muting is analogous to temporarily setting the amplitude of a handler to zero.
SetPause `hSound bool`
  Pause/Unpause this sound. Sound is paused when bool=1 (default=0). Paused algorithms do not generate samples. Pausing is analogous to temporarily removing an algorithm from the VSS scheduler's list of synthesis processes.
SetLinearEnv `hSound bool`
  Cause amplitudes to be interpolated linearly (pre-vss3.1 behavior) instead of exponentially, if bool=1 (default=1). (If a handler receives no SetLinearEnv message, it uses the linear-or-exponential interpolation behavior of its parent actor.)
SetNumChans `hSound numchans`
  Set the number of channels of audio computed by this handler to `numchans`, which should be 1, 2, 4, or 8. (8 requires Irix 6.3 or later; Windows works with only 1 or 2.) Most handlers default to 1, or the number of channels of their input if they accept audio input with SetInput. Note that the number of channels of a particular handler can differ from the number of channels VSS itself is running at. It is doubtfully useful, and somewhat inefficient, to run a handler with more channels than VSS is running.
SetChannel `hSound n`
  Override any SetPan/SetElev/SetDistance for this sound, and simply assign it to channel number `n`. The value of `n` should range from zero to one less than the number of channels VSS is running at. This is useful if the loudspeakers aren't arranged in a spatial array and need to be addressed individually.
SetChannelAmps `hSound [amp0 amp1 ...]`
  Override any SetPan/SetElev/SetDistance for this sound, and set the amount of sound to be sent to each speaker individually (0 = silence, 1 = nominal). The number of amplitudes specified in the array must equal the number of channels VSS is running at. This command is useful if you want to implement your own spatialization algorithms or have unusual speaker locations.

Extra messages understood by handlers for processor actors:

SetInputAmp `hActor x time`
  Set the default input scaling to `x` (0 = silence, unity = nominal). Default is nominal. If time is specified, modulate to the new value over the specified duration.
SetInputGain `hActor x time`
  Set the default input scaling in decibels to `x` (-100 or less = silence, 0 = nominal). Default is nominal. If time is specified, modulate to the new value over the specified duration.

These messages are summarized in the following slightly obsolete diagram, which is drawn to resemble an audio mixing console.

Every "sound", i.e., handler of a generator actor, runs unless it got a SetPause message (as if it was taking a union break during a rehearsal). If it's not paused, it normally outputs to the "main bus" of VSS. But this can be interrupted with the SetMute message, for instance if you want to use only the "side" output which other actors (processor actors, typically) can grab with a SetInput message. Two independent gain controls are provided, so you can for example control them independently from two message groups. Finally, SetPan (and SetElev) sets the relative levels going to each channel of VSS's audio output (the "main bus"). The number of channels here can be one, two or four, set by the "-chans" command-line argument or from the control panel.

Speaker placement for 2, 4, and 8-channel output

- 2-channel: left; right.
- 4-channel: front left; front right; rear left; rear right.
- 8-channel: top front left; top front right; top rear left; top rear right; bottom front left; bottom front right; bottom rear left; bottom rear right.

### Actor message reference, by actor

Messages for particular actors are documented on separate pages outlining the functionality of those actors.

- Control Actors
  - BasicActor (BASIC language)
  - EnvelopeActor (apply envelope to a sound)
  - LaterActor (delay)
  - MappingActors
  - MessageGroup
  - SeqActor (sequencer)
  - ThresholdActor (trigger when threshold is crossed)
  - SwitchActor (trigger on boolean expressions, obsolete)
  - LoopActor (loops)
  - BasicIterator (loops, obsolete)
  - PentaActor (pentatonic windchimes)
  - PrintfActor (debugging)
  - LedActor (parallel-port RGB LED driver)
  - Midi Actors
    - MidiInputActor (drive VSS from a keyboard)
    - MidiOutputActor (drive a tone module from VSS)
    - MidiGenerator (emit low-level midi messages)
    - MidiSequencer (play SMF files)
- Generator Actors
  - AddActor (additive synthesis)
  - ChantActor (IRCAM's singing)
  - ChuaActor (Chua's Circuit)
  - FmActor (good old FM)
  - Granulator (granular synthesis)
  - InputActor (for real-time input)
  - SampleActor (play soundfiles)
  - NoiseActor (noise bands)
  - PseudoNoiseActor (noise bands)
  - ShimmerActor (random harmonic spectra)
  - Tb303Actor (classic techno bass synth)
  - From Perry Cook's STK Toolkit (physical modelling):
    - AgogoBelActor
    - BowedActor
    - BrassActor
    - ClarinetActor
    - FluteActor
    - FMVoicesActor
    - MandolinActor
    - MarimbaActor
    - ShakerActor
    - TubebellActor
    - VibraphnActor
    - VoicFormActor
  - StkActor (updated STK Toolkit)
- Processor Actors
  - ProcessActor (generic example)
  - DelayActor (echo, or a train of echos)
  - Filter Actors (1st-order and biquad)
  - MixerActor (combine n sounds into 1)
  - ReverbActor (fancy reverberation)
  - RingModActor (ring modulation)
  - SocketActor (streaming audio i/o)
  - StereoActor (fancy stereo pan)

# Credits

Sumit Das wrote the original VSS Sound Server Manual (6/24/94) and the original actor hierarchy. Camille Goudeseune HTMLized the manual some time after that, for VSS 2.2. Kelly Fitz and Camille Goudeseune wrote many words after that. Other contributors include Carlos Ricci and Geoffrey Hua.