# Operating the Sound File Player

A task uses the sound file player by making Music library calls. This section of the chapter describes how each of those calls works in the process of sound file player operation.

## Creating a Sound File Player

The first step in using the sound file player is to create a sound file player. This is a process that creates a `SoundFilePlayer` data structure, sets initial values for the structure's fields, and, optionally, creates the sound buffers to go with the player. To create a sound file player, use this call:

  `SoundFilePlayer *CreateSoundFilePlayer( int32 NumBuffers, int32 BufSize, void *Buffers[] )`

The call accepts three arguments. The first, `NumBuffers`, is the number of buffers set up for use with the sound file player; the second is the size in bytes of a buffer. (Remember that all of a sound file player's buffers must be the same size.) The third, `*Buffers[]`, is an array of pointers, one for each player buffer. Each pointer in the array points to the buffer's beginning location in memory. This is not the location of the sample item that uses this memory, but of the memory used to store the sampled sound data for the buffer.

When a task creates a sound file player, it can ask the Music library to create the buffers for it. To do so, it passes a NULL for the `*Buffers[]` argument. `CreateSoundFilePlayer()` then uses the `NumBuffers` and `BufSize` values to allocate the proper amount of memory and to create sample items and `SoundFileBuffer` data structures for each buffer. It sets the appropriate `SoundFilePlayer` values to refer to those data structures.

If a task wants to allocate its own memory for sound file buffers, it first allocates the memory and then sets the appropriate pointers in the `*Buffers[]` array. (It is important to remember that all buffers must be the same size.) When `CreateSoundFilePlayer()` executes, it creates sound file buffers using the allocated memory and includes the buffers in the buffer array of the `SoundFilePlayer` data structure. If you use this option, be sure to set `NumBuffers` and `BufSize` to values that match the buffers you point to. When you allocate memory for sound buffers, specify the memory type MEMTYPE_AUDIO.

When it executes, `CreateSoundFilePlayer()` creates a `SoundFilePlayer` data structure and sets its field values to default values. If requested, it allocates memory for sound buffers. It creates a `SoundFileBuffer` data structure for each buffer, then sets the appropriate buffer values in the `SoundFilePlayer` data structure. If successful, this call returns a pointer to the newly created `SoundFilePlayer` data structure. If unsuccessful, it returns a NULL.

## Preloading a Sound File

Once a sound file player is created, a task specifies which AIFF file to play and asks the sound file player to preload the file using this call:

  `int32 LoadSoundFile( SoundFilePlayer *sfp, char *FileName )`

The call accepts two arguments: `*sfp`, which is a pointer to the `SoundFilePlayer` data structure controlling playback; and *FileName, which is a pointer to a null terminated string containing the pathname to the AIFF file.

When executed, `LoadSoundFile()` preloads as much of the specified AIFF file's sample data as fits into the sound buffers and sends them to the sound spooler. It also determines the sampled sound instrument most appropriate to play back the sampled sound, loads that instrument, attaches it to the sound buffers, and connects the instrument's output to an output mixer. The call then sets SoundFilePlayer values to store the item number of the specified AIFF file, the item number of the sampled sound instrument. `LoadSoundFile()` also creates an `IOReq` item to read the AIFF file, and stores its item number in the `SoundFilePlayer` data structure.

If successful, `LoadSoundFile()` returns 0. If unsuccessful, it returns an error code (a negative value).

## Creating a Sound File Player and Preloading a File

If you want to combine the process of creating a sound file player and preloading a sound file, you can use this convenience call:

  `SoundFilePlayer *OpenSoundFile( char *FileName, int32 NumBuffers, int32 BufSize )`

The call accepts three arguments: `*FileName`, which is a pointer to a null terminated string containing the pathname to the AIFF file; `NumBuffers`, which is the number of buffers desired for the sound file player; and `BufSize`, which is the size in bytes of each sound buffer.

When it executes, `StartSoundFile()` instructs the sound spooler to begin playing the preloaded sound buffers. Playback starts in the first preloaded buffer, and continues sequentially through the successive buffers. The sound file player stops after playing the last filled buffer if the sound file player is not serviced (see below) before then.

Note that `OpenSoundFile()` does not allow you to specify existing sound buffers. If you want to create your own buffers or reuse existing buffers, use `CreateSoundFilePlayer()` and `LoadSoundFile()` instead.

## Specifying an Output Mixer

Whenever a task uses `LoadSoundFile()` or `OpenSoundFile()` to specify and preload an AIFF file, the sound file player, by default, loads a `directout.dsp` output mixer and connects the sampled sound instrument output to the mixer. If you want to send the sampled sound output to a different mixer or to an effects instrument, you must set to true the SFP_NO_DIRECTOUT flag in the `sfp_Flags` field of the `SoundFilePlayer` data structure before calling `LoadSoundFile()`. (Be careful not to unset other flags in the field when you do.) When true, the flag tells the sound file player not to automatically load and connect a `directout.dsp` mixer. The calling task is then responsible for connecting the sound file player's sampled sound instrument to an existing mixer or effects instrument. It is also responsible for deleting the connection when the sound file player is deleted.

## Starting Sound File Playback

Once a sound file player is set up and a sound file is preloaded, a task can start sound playback using this call:

  `int32 StartSoundFile( SoundFilePlayer *sfp, int32 Amplitude )`

The call accepts the argument `*sfp`, a pointer to the `SoundFilePlayer` data structure used to control sound playback; and the argument `Amplitude`, a value from 0 to 0x7FFF that controls the amplitude of the sound's playback. Use the amplitude value to limit playback amplitude so that it does not overload the system amplitude. (For details, see Preparing Instruments.)

When executed, `StartSoundFile()` begins playing back the contents of the first sound buffer, feeding them to the SoundFilePlayer specified sampled sound instrument. The instrument feeds its output to the specified output mixer. When the first buffer finishes playback, the spooler uses the buffer's cue to send a signal to the playback calling task, and then starts playing the contents of the next sound buffer. As each buffer finishes playback, the spooler sends the buffer's signal to the calling task. When the spooler finishes playing the last buffer in the buffer array, it starts playback at the beginning of the first buffer, and the playback cycle begins again. Playback does not stop until the task calls `StopSoundFile()` or dies.

If successful, `StartSoundFile()` returns 0. If unsuccessful, it returns an error code (a negative value).

## Servicing a Sound File

To keep fresh sound file data loaded in the sound buffers ahead of playback, a task must constantly service the sound file. To do so, it must use a loop. The task should ideally be a high priority task or thread so that it is not interrupted in its file service.

Within the service loop, the task checks to see what buffers it must wait for. It then enters wait state until it receives a signal from one or more of those buffers, signifying that the buffer has finished playing. The task then exits wait state, asks the sound file player to spool more of the AIFF sample data into the free buffer (or buffers), and checks again to see what buffers it must wait for.

The key call within such a loop is this:

  `int32 ServiceSoundFile( SoundFilePlayer *sfp, int32 SignalIn, int32 *SignalNeeded )`

The call accepts three arguments: `*sfp`, a pointer to the `SoundFilePlayer` data structure used for playback; `SignalIn`, a signal mask containing a bit set for each buffer to which the sound file player should write; and `*SignalNeeded`, a pointer to a signal mask where the sound file player writes the signal bits of each buffer for which the calling task should wait. The sound file player writes 0 to `SignalNeeded` when it finishes spooling the sound file to the buffers.

When `ServiceSoundFile()` executes, it performs an input service and an output service. Its input service is to read the signal bits specified by the calling task in `SignalIn`, to find the corresponding sound buffers, and to read sampled sound data from disc into those buffers. Its output service is to write a signal mask to `SignalNeeded` that contains a signal bit set for each buffer the task should wait for. The task should use this signal mask whenever it enters wait state. If the task needs to wait for other signals as well, it can logically OR the `SignalNeeded` signal mask with another signal mask before entering wait state. If `SignalNeeded` comes back 0, the task knows that spooling is finished, and can exit its service loop.

If successful, `ServiceSoundFile()` returns 0. If unsuccessful, it returns an error code (a negative value).

Note: When `ServiceSoundFile()` executes, it calls `ReadSoundFile()` to help the spooler keep its place in the AIFF file and in the buffers it uses to play the file. Although `ReadSoundFile()` is described in the 3DO Music and Audio Programmer's Reference, your tasks should not use it directly; it can mix up the sound file player's playback.

### The File Service Loop

When a task uses `ServiceSoundFile()` to service a file, it might use a loop such as the one defined in the following code fragment:

Example 1: Servicing a file.

``

    int32 Result;
    SoundFilePlayer *sfp;
    int32 SignalIn, SignalsNeeded;
    SignalIn = 0;
    do {
        Result = ServiceSoundFile(sfp, SignalIn, &SignalsNeeded);
        if (SignalsNeeded) SignalIn = WaitSignal(SignalsNeeded);
    } while (SignalsNeeded)

Going into the loop, the task sets to 0 `SignalIn`, the mask it uses to tell `ServiceSoundFile()` which buffers the spooler should write to. The second mask, `SignalsNeeded`, is used by `ServiceSoundFile()` to receive the signals the task should wait for.

The first statement in the loop, which calls `ServiceSoundFile()`, specifies no buffers to write to (`SignalIn` = 0), so the call does not spool any of the AIFF file to the buffers. It only reports the buffers that the task should wait for, which it does by writing the buffers' signals in the `SignalsNeeded` signal mask.

The second statement in the loop checks to see if there are buffers for which the task should wait. If so, it calls `WaitSignal()`. The task supplies `WaitSignal()` with the signal mask specifying the buffers to wait for. The task enters wait state until it receives a signal from any one of these buffers, that tells the task which buffer has played. (If buffers have already played before the task enters wait state, then the task immediately gets the buffers' signals when it enters wait state. This means that the task can receive more than one signal at this point.) Once the task has received one or more buffer signals, it exits wait state and proceeds to the end of the loop.

The end of the loop checks the `SignalsNeeded` mask to see if it is set to 0. If it is, the AIFF file has finished playing, and the loop exits.

## Stopping Sound File Playback

A task can stop sound file playback at any point, but it usually does so when `ServiceSoundFile()` informs it that the AIFF file has finished playing. To stop playback, use the following call:

  `int32 StopSoundFile( SoundFilePlayer *sfp )`

The call accepts a single argument: `*sfp`, which is a pointer to the `SoundFilePlayer` data structure controlling playback. When `StopSoundFile()` executes, it stops buffer playback so that no sample data is fed to the sampled sound instrument. As a consequence, no buffer signals are sent as each buffer finishes playback.

`StopSoundFile()` returns 0 if successful, or an error code (a negative value) if unsuccessful.

## Rewinding a Sound File Player

To rewind a sound file player so that it is ready to play its AIFF file from the beginning once again, use this call:

  `int32 RewindSoundFile( SoundFilePlayer *sfp )`

The call accepts a single argument: `*sfp`, which is a pointer to the `SoundFilePlayer` data structure controlling playback. When it executes, `RewindSoundFile()` resets all of the appropriate playback progress values in the `SoundFilePlayer` data structure to the beginning of the AIFF file. It also preloads the beginning of the file into the sound buffers. When playback is turned back on with a `StartSoundFile()` call, the AIFF sound file begins playback from its beginning.

Note: This call does not provide seamless looping.

`RewindSoundFile()` returns 0 if successful, or an error code (a negative value) if unsuccessful.

## Cleaning Up After Playback

Once a task finishes playing a sound file and no longer needs the sound file player, it should clean up by freeing any associated items such as the playback instrument, attachment, and output mixer. It should then delete the `SoundFilePlayer` data structure and any associated sound buffers.

To free associated items, use this call:

  `int32 UnloadSoundFile( SoundFilePlayer *sfp )`

It accepts a pointer to the `SoundFilePlayer` data structure that you want to clean up for. When it executes, the call closes the AIFF file used for spooling, deletes the `IOReq` item used to read the file, detaches the buffers from the sampled sound instrument by deleting the attachment items, and frees the sampled sound instrument. If the sound file player created a `directout.dsp` mixer for sampled sound playback, that mixer is freed as well. `UnloadSoundFile()` is, in essence, the reverse of the `LoadSoundFile()` with one exception: it does not clear the buffers of sample data, but leaves it in place.

`UnloadSoundFile()` returns 0 if successful, or an error code (a negative value) if unsuccessful.

Calling `UnloadSoundFile()` is necessary if you want to play a new AIFF file on an existing sound file player. The call cleans up the existing AIFF setup so that calling `LoadSoundFile()` arranges a new AIFF setup for playback.

To delete a `SoundFilePlayer` data structure when you're finished with it, use this call:

  `int32 DeleteSoundFilePlayer( SoundFilePlayer *sfp )`

The call accepts a pointer to the `SoundFilePlayer` data structure you want to delete. When it executes, it deletes the data structure and cleans up anything else created by `CreateSoundFilePlayer()`. If sound buffers were created automatically for the sound player, their `SoundFileBuffer` data structures are deleted, and the memory used for them is freed. If the buffers were not created automatically, then `DeleteSoundFilePlayer()` does not delete them; the task must delete them itself.

`DeleteSoundFilePlayer()` returns 0 if successful, or an error code (a negative value) if unsuccessful.

If you want to use a convenience call to combine `UnloadSoundFile()` and `DeleteSoundFilePlayer()`, use this call:

  `int32 CloseSoundFile( SoundFilePlayer *sfp )`

It accepts a pointer to the `SoundFilePlayer` data structure you want to delete. When executed, it calls `UnloadSoundFile()` to clean up any items associated with the player and then calls `DeleteSoundFilePlayer()` to delete the specified data structure.

`CloseSoundFile()` returns 0 if successful, or an error code (a negative value) if unsuccessful.

Note that `CloseSoundFilePlayer()` does not delete custom allocated buffers. You should not use it on a sound file player with custom buffers. If you do, you need to free those buffers yourself.

## Typical Calling Sequences

A single sound file player can play back a sound file once, play back a sound file repeatedly, or play back a series of sound files. To do so, it can use the following calling sequences for playback.

### Playing a Sound File Once

`

    CreateSoundFilePlayer()
    LoadSoundFile()
    StartSoundFile()
    loop{
        ServiceSoundFile()
    }is file finished?
    StopSoundFile()
    UnloadSoundFile()
    DeleteSoundFilePlayer()

`

### Playing a Sound File Repeatedly

`

    CreateSoundFilePlayer()
    LoadSoundFile()
    loop{
        StartSoundFile()
        loop{
            ServiceSoundFile()
        }is file finished?
        StopSoundFile()
        RewindSoundFile()
    }has file played specified number of times?
    UnloadSoundFile()
    DeleteSoundFilePlayer()

`

### Playing a Series of Sound Files Any Number of Times

`

    CreateSoundFilePlayer()
    loop{
        LoadSoundFile()
        loop{
            StartSoundFile()
            loop{
                ServiceSoundFile()
            }is file finished?
            StopSoundFile()
            RewindSoundFile()
        }has file played specified number of times?
        UnloadSoundFile()
    }is there another file to play?
    DeleteSoundFilePlayer()

` Note that in this calling sequence, the outer loop checks to see if there is another file to play. If there is, it specifies the new file's pathname when it reenters the loop.