Miles Sound System SDK 7.2a

AIL_sample_buffer_available

The function AIL_sample_buffer_available checks to see if any of the buffers associated with a sample handle are ready to be filled with new audio data by the AIL_load_sample_buffer function.

S32 AIL_sample_buffer_available(
  HSAMPLE S
);

In Parameters

S
indicates the sample handle to check.

Returns

Zero if none of the sample's low-level streaming buffers require service, or nonzero if additional audio data can be submitted.

Discussion

There are three ways to play digital audio data with MSS. One method assumes that the entire audio sample to be played is resident in memory during playback. With this technique, the application calls AIL_set_sample_address to specify the location and size of the sample data, followed by a call to AIL_start_sample to begin playback of the audio data. Various functions such as AIL_set_sample_volume_pan and others allow the application to control various aspects of sample playback, before and during playback. The number of available sample handles determines how many independent samples may be played at once.

The second method is to simply use the high-level streaming services described in the "Digital Audio Streaming Services" chapter. These services allow you to stream or spool data off a hard drive or CD-ROM.

The final method, called low-level streaming, also allows full control over a sample's playback characteristics, and also permits as many samples to be played simultaneously as there are available handles. It differs from the first method in only one important way: the audio data to be played is passed to MSS in small, manageable chunks. With low-level streaming, the entire audio data sample does not need to fit into memory, so samples of any size can be played. The high-level streaming services were written using the low-level streaming calls, in fact.

First, two or more sound data buffers are allocated by the application from system memory. The application allocates a sample handle with AIL_allocate_sample_handle, initializes it with AIL_init_sample, and sets its playback rate with AIL_set_sample_playback_rate, exactly as would be done under the first method mentioned above. However, instead of using AIL_set_sample_address prior to the beginning of playback, an application which makes use of low-level streaming would open the file containing the desired sample data, and begin repeatedly executing a small loop of the form:


while (AIL_sample_buffer_available(sample))
{
S32 len = read(file,buf[n],size);
AIL_load_sample_buffer(sample,
MSS_BUFFER_HEAD,
buf[n],
len);
n = (n + 1) % 2; // (2 sample buffers by default)
if (len == 0)
{
break;
}
}
AIL_start_sample(sample);

to begin transferring data from the file into the two buffers associated with each sample handle.

By default, all HSAMPLE handles are created with a ring of two buffer pointers. (Additional buffer pointers may be allocated through the use of the AIL_set_sample_buffer_count function.) Normally, the second sample buffer is disabled by AIL_init_sample; it cannot be accessed by the application except through the two API calls associated with low-level streaming, AIL_sample_buffer_available and AIL_load_sample_buffer. Low-level streaming mode is enabled automatically for a sample handle when either of these calls are used by the application, and it will remain in effect until the next AIL_init_sample call for that sample handle.

Assuming that the HSAMPLE has two buffer pointers, the first two calls to AIL_sample_buffer_available will return nonzero values to indicate that both buffers should be filled. Normally, this is done by calling AIL_load_sample_buffer with the constant MSS_BUFFER_HEAD, to place incoming data at the head of the buffer list. Once both buffers have been filled with sample data, subsequent calls to AIL_sample_buffer_available will return zero, meaning that neither buffer needs to be filled with audio data ("serviced") for the moment.

As soon as the first buffer finishes playing, MSS will immediately switch to the second buffer, whose contents have presumably been updated by the application since the last time it was played.

Low-level streaming playback stops when a function such as AIL_stop_sample or AIL_end_sample is used, or when a buffer of length 0 is reached (this occurs at end-of-file when read is used in the example above). From the foregoing discussion, it should be apparent that the application must check the buffers' status with AIL_sample_buffer_available frequently enough to avoid buffer "starvation", a condition in which playback stops because new data has not been provided in a timely fashion. In general, the application should call its serve_sample routine, or perform a similar action, at a rate of better than half of either buffer's playback period. The playback period in seconds for a given buffer is equal to the buffer's size in bytes divided by the playback rate in samples per second. This period must be further divided by the number of bytes per sample (4 for stereo 16-bit samples, 1 for mono 8-bit samples, and so forth).

At first glance, the loop above would seem an ideal candidate for an MSS background timer service client. Under Win32, Win64 and MacOS X, this would work fine, but it will stall timer services for the duration of the I/O routine. Worse, under DOS, the C read function must call DOS (and the DOS extender) to read audio data from the sample file. While it is theoretically possible to perform DOS file access from a timer-based interrupt handler, doing so requires techniques which are beyond the scope of this documentation or any MSS example program. These techniques may or may not be usable with certain DOS extenders, so any attempt at DOS access from a timer callback function is made entirely at the programmer's risk. Although it is customary that all of a sample's ring buffers be the same size, it is not mandatory. The buffers may be of different sizes if desired, and their sizes may be changed "on the fly." (This normally happens when the very last chunk of audio data is read from the sample file unless the sample file's size happens to be an integer multiple of the buffer size.) It is important that the size of each individual buffer (except the last) be equal to or larger than the value returned by the AIL_minimum_sample_buffer_size function, since the application's buffers cannot be smaller than the hardware-level buffers (see below).

Low-level streaming audio data is often stored in raw form, but formats such as Ogg Vorbis and MP3 are also usable, along with other compressed formats used for applications such as video playback and VoIP. .VOC or .WAV files may not be passed to the low-level streaming routines, unless the application itself assumes responsibility for seeking past the header and terminator blocks in these files. (.VOC or .WAV files may be converted to raw data with the Miles Sound Studio utility, or with the RAD Video Tools which are available at our website. The AIL_set_sample_file function may be helpful in parsing .VOC and .WAV files as well.)

It is possible to mix streamed samples and conventional memory-resident samples freely. However, it may not be advisable to play more than one streaming sample at once, because the system overhead required to continually stream data from two separate files may give rise to sound dropouts, depending on the data rates involved. Experimentation and careful testing are recommended in such cases.

To loop a low-level streaming sample, it is necessary to trap the end-of-file condition (zero bytes read) and seek back to the file's beginning to re-execute the read call. The AIL_set_sample_loop_count function is not applicable to streaming samples, since it can be used only when the entire sample is resident in memory. If used, it will cause only the currently playing buffer to loop, which is not likely to be the desired result.

On MacOS, you should use the system file-reading function, PBRead, which provides asynchronous data-reading functionality.

Beginning with MSS version 7, applications that use AIL_load_sample_buffer must call AIL_start_sample themselves. Low-level streaming samples are no longer started automatically as soon as the first buffer is loaded. It's not necessary to check the status of a low-level streaming sample before calling AIL_start_sample -- if it's already playing, the call will be ignored.

Most applications should use MSS's higher-level streaming functions instead -- they remove a lot of complexity from the picture! See the "Digital Audio Streaming Services" chapter for more information.

Example files that use this function: DBTEST.C


Group: Digital Audio Services
Related Functions: AIL_allocate_sample_handle, AIL_end_sample, AIL_init_sample, AIL_load_sample_buffer, AIL_minimum_sample_buffer_size, AIL_sample_buffer_available, AIL_sample_buffer_count, AIL_sample_buffer_info, AIL_set_sample_address, AIL_set_sample_buffer_count, AIL_set_sample_file, AIL_set_sample_loop_count, AIL_set_sample_playback_rate, AIL_set_sample_volume_pan, AIL_start_sample, AIL_stop_sample
Related Basic Types: HSAMPLE, S32

For technical support, e-mail Miles3@radgametools.com
© Copyright 1991-2007 RAD Game Tools, Inc. All Rights Reserved.