Conversely, a single application can make sound with several copies of VSS (one copy of VSS per computer), by connecting to them individually with int BeginSoundServerAt(char* hostname). Sending a message simultaneously to all these copies of VSS will produce a synchronized result (to within a few centiseconds if network load and CPU load isn't heavy).
A single client connected to a single copy of VSS can load several .aud files. This design may be useful if your sound description falls into several disjoint components which are controlled by different parts of your application. But then you have to remember the value each AUDinit() returns, and pass that value to AUDupdate...() and AUDterminate().
In rare cases it may work better to weave the entire sound description into your application in the form of dozens of C function calls, instead of calling AUDinit("foo.aud"). We encourage the use of .aud files because this puts the sound description in one place and lets you unit-test the sound without the entire application (using audpanel). But if this isn't working for you, see this section of the VSS reference manual.
A .aud file is merely a sequence of messages. But certain structures are worth mentioning. This is a useful format:
The message BeginSound is special in the kind of arguments it takes. It accepts name-value pairs. The next two examples are equivalent:
sFoo = BeginSound aFoo, SetAmp 0.99, SetPan -1;and
sFoo = BeginSound aFoo; SetAmp sFoo 0.99; SetPan sFoo -1;Well, they're almost equivalent. VSS runs in real time, so what the second example would do is begin sound sFoo with a default amplitude and pan position, and a few milliseconds later change sFoo's amplitude and pan position. If you wanted the sound to being silently (change 0.99 to 0 here), you'd get a blip of sound before SetAmp sFoo 0 was sent to VSS. The next two examples are truly equivalent:
sFoo = BeginSound aFoo, SetAmp 0.99, SetPan -1;and
sFoo = BeginSoundPaused aFoo; SetAmp sFoo 0.99; SetPan sFoo -1; SetPause sFoo 0;A paused sound has its computation suspended, so BeginSoundPaused will not let any sound be heard until SetPause 0 unpauses the sound.
You put stuff into a message group with the AddMessage command (illustrated in many of the examples shown already).
When you invoke a message group, you pass it an array of (floating-point) values. To get at these values, use the special syntax *0 *1 *2 ... in your AddMessage commands. These are expanded into the zeroth, first, second,... elements of this array. (Think of argv[0], argv[1],... in C.)
You invoke a message group in one of two ways. Most commonly, your application calls one of the AUDupdate...() C functions (illustrated in many of the examples shown already). But if you want to call a message group foo from within your .aud file, use the SendData command. The following two fragments do the same thing:
s = BeginSound ... ; m = Create MessageGroup; AddMessage m SetFoo s *0; AddMessage m SetBar s *1; ... SendData m [ 300 20 ];and
s = BeginSound ... ; ... SetFoo s 300; SetBar s 20;
Here's a .aud file which sends white noise through a filter,
so you hear only the filtered sound and not the original.
Note the phrase SetInput sNoise, which connects the filter
to its source.
LoadDSO noise.so; LoadDSO filter.so; aNoise = Create NoiseActor; sNoise = BeginSound aNoise SetCutoff 5000 SetOrder 1; sleep 2; // Now we hear unfiltered noise. aFilter = Create Order1FilterActor; sFilter = BeginSound aFilter SetInput sNoise; sleep 2; // Now we hear unfiltered AND filtered noise. SetMute sNoise 1; sleep 2; // Now we hear only filtered noise.
Here you can adjust how loud the original and the modified sounds are:
LoadDSO noise.so; LoadDSO filter.so; aNoise = Create NoiseActor; sNoise = BeginSound aNoise SetCutoff 5000 SetOrder 1; aFilter = Create Order1FilterActor; sFilter = BeginSound aFilter SetInput sNoise; SetAmp sNoise .1; SetAmp sFilter .9; // mostly filtered sleep 2; SetAmp sNoise .2; SetAmp sFilter .8; // mostly unfiltered sleep 2; SetAmp sNoise 0; SetAmp sFilter 0; // silent sleep 2; SetAmp sNoise .6; SetAmp sFilter .6; // both, but too loud! sleep 2;
The last setting will probably result in clipping, because .6 + .6 > 1.
Finally, a chain of processors (FM into a filter into a delay into a reverb). In a chain you'll usually want to mute all but the last processor.
LoadDSO fm.so; LoadDSO filter.so; LoadDSO delay.so; LoadDSO reverb.so; aFM = Create FmActor; sFM = BeginSound aFM SetMute 1; aFilter = Create Order1FilterActor; sFilter = BeginSound aFilter SetInput sFM SetMute 1; aDelay = Create DelayActor; sDelay = BeginSound aDelay SetInput sFilter SetMute 1; aReverb = Create ReverbActor; sReverb = BeginSound aReverb SetInput sDelay; // No SetMute here!
Back: Ambient sound.
Back: Parambient sound.
Back: Sonifying your data.