Appendix B - Apple Sound Manager

Description

The Sound manager allows for a very simple and high level interface for sound generation on Macintosh computers and is capable of generating sounds defined by using Square Wave data, Sampled sound data and Wave table data as described below.   (Only square wave data was  used for this project).

Square Wave Data

Square Wave data can be used to generate a sound based on a sine wave described by three factors: The frequency (or pitch) of a sound is the number of cycles per second of the sound.  Frequency is specified as one of the 128 (0 - 127) MIDI notes containing a frequency range of 8.176Hz to 12,543.827Hz. As with a piano keyboard, the MIDI notes follow the scale of equal temperament in which every octave (a 2:1 change in frequency), is divided into 12 equal intervals allowing for the frequency of adjacent notes to differ by a factor of 1.05946 (twelfth root of two). As shown in shaded region of the figure B1 below, the range of MIDI notes includes the five octaves of the piano keyboard (shaded region).
 

 
Figure B1
Range of Midi Notes

The amplitude of a sound is the loudness the sound is being output.  Amplitude values may range from 0  (non - audible to 255 (fairly loud) and it has been observed amplitude values below approximately 35 are barely audible.  The duration of a sound is the length of time the sound is being output.

Optionally, the wave's timbre may also be altered allowing for either a clear (low timbre) or buzzing (high timbre) sound.

Wave-Table Data

Wave table data is based on a description of a single sine wave cycle (called a wave table) and is
represented as an array of bytes which describe the wave's amplitudes at fixed intervals.  When playing a  wave table description of a sound, the sound manager loops through the wave table for the duration of
the sound. [X].

Sampled Sound Data

Sampled sound data are sounds that have been digitally recorded or computed (possibly at run time). For example sampled sounds are usually used to output speech and special sound effects.  Sampled sound  data must be in one two formats, either a sound resource or an AIFF (or AIFF-C) format file.  The  sound manager uses the information provided in the header of each sampled sound to generate and output  the sound.  The header contains information pertaining to the sample including the original sampling  rate, sample duration etc.

Using the Sound Manager

Sound Commands and Sound Channels

"A sound command is an instruction to produce sound, modify sound or otherwise assist in the overall process of sound production by  a sound channel.  For example the ampCmd sound command changes the amplitude of a sound" (Inside Macintosh).  All sound generation/manipulation is achieved by issuing a sound command to a particular sound channel .  A sound channel contains information about the sounds it will output (e.g. amplitude, timbre) and also contains a queue used to hold the sound commands issued using the SndDoCommand (explained below).

All commands issued to a channel are placed in the channel's queue and from there sent one by one to the sound manager to be implemented.  Alternatively, to bypass the queue,  a command may be issued using the SndDoImmediate command in which case the command will be implemented immediately even if there are previously issued commands awaiting processing in the queue.  Sound commands are defined using the following data type:

struct SndCommand{

   int    cmd                          /* command number. */
   int    param2                     /* first parameter. */
   long  param2                    /* second parameter. */

}

The fist varaible 'cmd' represents the command type while the other two variables are used to specify any of the options available with the particular sound command.  Depending on the sound command, param1 and param2 may be interpreted differently or may not be used at all.  A list of all available commands as well as the options they require may be found in Inside Macintosh [X].

Sounds are output synchronously by default however, an asynchronous option exists in which other processing may be taking place while the sound is output.  For the purpose of this project, all sound output was synchronous as there was no processing necessary between the output of notes.

Prior to outputting any sound, a sound channel must be allocated using the SndNewChannel function illustrated below.

SndChannelPtr   chan1 = NULL
SndNewChannel(*SndChannelPtr chan, int synth, long init,  SndCallBackProcPtr routine)

SndChannelPtr chan
A pointer to the actual sound channel.  This parameter should be explicitly set to 'NULL' prior to passing it to SndNewChannell().

int synth
Indicates which one of the three types of data to be output by the channel.  Square wave data may be specified with the system variable 'squareWaveSynth', Wave table data using 'waveTableSynth' and sampled data using the variable 'sampledSynth'.

long init
Specifies the initialization parameters required for this channel.  For example, the channel may be used to produce stereo sound, mono sound etc.  A value of '0' allows for the default mono output.

SndCallBackProcPtr routine
This parameter is a pointer to a function (callback routine), used when the channel output is asynchronously or when the calling procedure needs to know when the sound has completed playing.   Passing a value of 'NULL' indicates there is no callback routine associated with this channel (e.g. output is asynchronous).

For our purposes, the channel was initialized as shown below, allowing for square wave data, asynchronous mono data.

SndChannelPtr   chan1 = NULL
SndNewChannel(&chan1,  squareWaveSynth, 0,  NULL)

Once the channel has been initialized, it is ready to receive sound commands.  The code segment below illustrates how commands are issued to the channel.

SndCommand      cmd1;
SndChannelPtr   chan1;

SndNewChannel(&chan1,  squareWaveSynth, 0,  NULL)

cmd1.cmd = ampCmd;      /* Command to alter the amplitude of the channel. */
cmd1.param1 = 100;          /* Amplitude value. */
cmd1.param2 = 0;             /* This parameter is not needed for this command - assign it 0. */

/* Send the command to the channel thereby altering the amplitude. */
SndDoCommand(chan1, &cmd1, FALSE)

cmd1.cmd = freqDurationCmd;   /* Command to alter the timbre of the channel. */
cmd1.param1 = 1000;                  /* Duration of sound in 1/2 milliseconds. */
cmd1.param2 = 60;                     /* Midi note value of sound to be output.*/

/* Send the command to the channel thereby altering the amplitude. */
SndDoImmediate(chan1, &cmd1)

As shown above, a channel is first declared and then initialized (using the SndNewChannel routine) according to the specified characteristics.  Once the channel has been initialized, sound commands may be issued to the channel.  The first command issued above is the amplitude command 'ampCmd' which will set the amplitude of the channel for all subsequent output.  This command is issued using the SndDoCommand (explained below), thereby placing the command in the channel's queue for processing once all other commands in the queue have been processed.  The second command 'freqDurationCmd' is used to cause the output of a sound (Midi note).  For this command, the parameter 'param1' is used to specify the duration of the sound in half milliseconds.  For example, to output a sound for 1 second (1000 milliseconds), param1 should be set to 2000.  The parameter 'param2' specifies the Midi note to output.  In the above segment, Midi note 60 specifies Middle C (261.625Hz).  The second command is issued to the channel using the SndDoImmediate command thereby bypassing the queue and processed immediately by the channel regardless of the commands in the queue.  In this project, all channel initialization was performed using the SndDoCommand however, all freqDurationCmd commands were sent to the channel using SndDoImmediate.  Since range measurements were constantly being obtained and mapped to a Midi note, sending the command immediately ensured that when a reading was obtained and processed, the sound associated with it was output immediately thereby producing no "backlog" of sounds in the queue.  Such a backlog may result in the wrong sound being output for a particular range reading.  In addition, the immediate output of sound allowed for a simple implementation of having a continuous sound output.  In this case, the duration of the note was set to a value higher then the rate at which the range measurements are being taken.  Since commands are sent immediately, a new freqDurationCmd will automatically stop the old one.

OSErr SndDoCommand(SndChannelPtr chan, SndCommand cmd, int noWait)

SndChannelPtr
Valid channel pointer.

SndCommand cmd
Command to be sent to the channel.

int noWait
Indicates the action to be taken by the Sound Manager in the case the queue is full.  A value of FALSE (0), will cause the Sound Manager to wait until there is room in the queue while a value of TRUE (1) will cause the Sound Manager to return without placing the command in the queue.  Due to the limited number of sound commands issued using SndDoCommand, the channel buffer will not become full in any implementation used for this project.

The sound manager allows for many sound channels to be declared.  In addition, using the asynchronous feature, multiple channels may output sound simultaneously.

Finally, when the channel is no longer required, it should be de-allocated using the following routine:

SndDisposeChannel(SndChannelPtr chan, int booleanValue)

SndChannelPtr chan
The channel that is to be disposed.

int booleanValue
Indicates whether the channel should be flushed prior to being disposed (booleanValue = 1), thereby stopping any sound which may be playing and removes any sound commands from the queue.  When the channel is not to be flushed (booleanValue = 0), the channel will be disposed of only when all commands in the queue have been processed.

NOTE:
A complete description of the Sound Manager is beyond the scope of this report.  Only information relevant to the project is given above.  Further information may be found in "Inside Macintosh - Sound".