Class Documentation

Name:Audio
Version:1.0
ID:ID_SOUND
Status:Stable
Category:Audio
Date:May 2003
Author:Rocklyte Systems
Copyright:  Rocklyte Systems, 2002-2003. All rights reserved.
Short:  Supports a machine's audio hardware and provides server-style audio management to the developer.



Description

The Audio class provides the heart of Pandora's audio system and is designed around client-server theory. While it is possible to create local audio object's for your own task, system resources are served better if you use a globally allocated audio object. When running Athene, a SystemAudio object is automatically created at boot up for this purpose. This also solves any issues on platforms such as Unix that restrict audio access to one task at a time.

Supported features include 8-bit and 16-bit output in stereo or mono, oversampling, streaming, multiple audio channels, sample sharing and command sequencing. The Audio class is also supported by the Sound and Music classes, so if you only need simple audio playback for your program, it is recommended that you use these classes to your advantage.

Support for audio recording is not currently available.

Actions

The Audio class supports the following actions:

Activate  Enables an audio object's ability to play audio.
Clear  Clears the audio buffers.
Deactivate  Disables an audio object's ability to play or record audio information.
Reset  Resets the audio settings to default values.
SaveToObject  Saves the current audio settings to another object.

Methods

The Audio class implements the following methods:

AddSample  Adds a new sample to an audio object for channel-based playback.
AddStream  Adds a new sample-stream to an Audio object for channel-based playback.
Beep  Beeps the PC audio speaker.
BufferCommand  Sends special audio commands to the channel processor.
CloseChannels  Frees audio channels that have been allocated for sample playback.
OpenChannels  Allocates audio channels that can be used for sample playback.
RemoveSample  Removes a sample from the global sample list and deallocates its memory usage.

Structure

The Audio object consists of the following public fields:

Bass  Sets the amount of bass to use for audio playback.
BitRate  The bit rate affects the overall quality of audio input and output.
Flags  Special audio flags can be set here.
InputRate  Determines the frequency to use when recording audio data.
MasterVolume  The master volume to use for audio playback.
Mute  Mutes all audio output.
OutputRate  Determines the frequency to use for the output of audio data.
Quality  Determines the quality of the audio mixing.
Stereo  Controls stereo and mono audio output.
TotalChannels  Tells you the total number of audio channels that have been allocated.
Treble  Sets the amount of treble to use for audio playback.
Action:Activate
Short:Enables an audio object's ability to play audio.

Before an audio object will play or record audio output, you must call the Activate action in order to enable the audio timer. If you do not call this action, the audio object will appear to function as normal but will remain silent to the user.


Action:Clear
Short:Clears the audio buffers.

You can call this action at any time to clear the internal audio buffers. This will have the effect of temporarily stopping all output until the next audio update occurs.


Action:Deactivate
Short:Disables an audio object's ability to play or record audio information.

Deactivating an audio object will turn off all audio updates and clear the output buffer so that no more audio is being played. The audio object will remain in a suspended state until it is reactivated.


Method:AddSample()
Short:Adds a new sample to an audio object for channel-based playback.
Arguments:
LONG SampleFormat  Indicates the format of the sample data that you are adding.
APTR Data  Points to the address of the sample data.
LONG DataSize  Size of the sample data, in bytes.
*AudioLoop Loop  Points to the sample information that you want to add.
LONG LoopSize  Must be set to sizeof(struct AudioLoop).
LONG Result  The resulting sample handle will be returned in this parameter.

For an audio object to play sound samples, it must have audio samples loaded against it so that it can store them in its own local audio memory. In order to load samples into an audio object you can call either the AddSample or AddStream methods. For small samples under 512k you should use AddSample, while anything over that should be supported through AddStream.

When loading a sample, you need to pay attention to the audio format that is being used for the sample data. While it is important to differentiate between simple things such as 8-bit, 16-bit, mono and stereo, you should also be aware of whether or not the data is little or big endian, and if the sample data consists of signed or unsigned values. Because of the possible variations there are a number of sample formats, as illustrated in the following table:

TypeDescription
SFM_U8BITMONO8-bit mono unsigned sample.
SFM_S16BITMONO16-bit mono signed sample.
SFM_U8BITSTEREO8-bit stereo unsigned sample.
SFM_S16BITSTEREO16-bit stereo signed sample.
SFM_S8BITMONO8-bit mono signed sample.
SFM_U16BITMONO16-bit mono unsigned sample.
SFM_S8BITSTEREO8-bit stereo signed sample.
SFM_U16BITSTEREO16-bit stereo unsigned sample.

By default, all samples are assumed to be in little endian format, as supported by Intel CPU's. If the data is in big endian format, you should OR the SampleFormat value with the flag SFM_BIGENDIAN.

It is also possible to supply loop information with the sample data. The Audio class supports a number of different looping formats, rather than just the 'repeat from the beginning once you reach the end' style of looping that you might normally find in audio systems. The AudioLoop structure illustrates your options:

  struct AudioLoop {
     WORD LoopMode;       Loop mode (single, double)
     BYTE Loop1Type;      First loop type (unidirectional, bidirectional)
     BYTE Loop2Type;      Second loop type (unidirectional, bidirectional)
     LONG Loop1Start;     Start of the first loop
     LONG Loop1End;       End of the first loop
     LONG Loop2Start;     Start of the second loop
     LONG Loop2End;       End of the second loop
  };

There are three types of loop modes that you can specify in the LoopMode field:

   LOOP_SINGLE           Single loop: The sample will continuously loop between Loop1Start and Loop1End.
   LOOP_SINGLE_RELEASE   Release loop: Sample data found after Loop1End will be played when the sample is released.
   LOOP_DOUBLE           Double loop: When the sample is released from playback, playing shifts to the second loop.

The Loop1Type and Loop2Type fields alter the style of the loop. You can set these fields to LTYPE_UNIDIRECTIONAL or LTYPE_BIDIRECTIONAL. Unidirectional looping means that the sample position returns to the byte position specified in the Loop1Start variable. If you choose bidirectional looping, the sample will play in reverse whenever it hits the end marker, and forwards when it hits the start marker.

This method may not be called directly if the audio object in question is located in a foreign task. If you try to grab the audio object and call this method, it will detect the illegal usage and return ERR_IllegalActionAttempt. Thus the only safe way to call this method is to use the ActionMsg() function.

Result
ERR_Okay  The sample was added successfully.
ERR_Args  Invalid arguments were specified.
ERR_IllegalActionAttempt  You attempted to call this method directly using the Action() function. Use ActionMsg() instead.
ERR_ReallocMemory  The existing sample handle array could not be expanded.
ERR_AllocMemory  Failed to allocate enough memory to hold the sample data.

Method:AddStream()
Short:Adds a new sample-stream to an Audio object for channel-based playback.
Arguments:
STRING Location  Refers to the file that contains the sample data, or NULL if you will supply an ObjectID.
OBJECTID ObjectID  Refers to the public object that contains the sample data (if no Location has been specified). The object must support the Read and Seek actions or it will not be possible to stream data from it.
LONG SeekStart  Offset to use when seeking to the start of sample data.
LONG SampleFormat  Indicates the format of the sample data that you are adding.
LONG SampleLength  Total byte-length of the sample data that is being streamed. May be set to zero if the length is infinite or unknown.
LONG BufferLength  Total byte-length of the audio stream buffer that you would like to be allocated internally (large buffers affect timing).
*AudioLoop Loop  Points to the sample information that you want to add.
LONG LoopSize  Must be set to sizeof(struct AudioLoop).
LONG Result  The resulting sample handle will be returned in this parameter.

For an audio object to play sound samples, it must have audio samples loaded against it so that it can store them in its own local audio memory. In order to load samples into an audio object you can call either the AddSample or AddStream methods. For small samples under 512k you should use AddSample, while anything over that should be supported through AddStream.

The data source used for a stream can be located either at an accessible file location (through the Location argument), or you can supply a reference to a public object that has stored the data (through the ObjectID argument). You also need to set the SeekStart argument, which refers to the byte position at which the audio data starts within the stream source. The SampleLength argument must also refer to the byte-length of the entire audio stream.

When creating a new stream, you need to pay attention to the audio format that is being used for the sample data. While it is important to differentiate between simple things such as 8-bit, 16-bit, mono and stereo, you should also be aware of whether or not the data is little or big endian, and if the sample data consists of signed or unsigned values. Because of the possible variations there are a number of sample formats, as illustrated in the following table:

TypeDescription
SFM_U8BITMONO8-bit mono unsigned sample.
SFM_S16BITMONO16-bit mono signed sample.
SFM_U8BITSTEREO8-bit stereo unsigned sample.
SFM_S16BITSTEREO16-bit stereo signed sample.
SFM_S8BITMONO8-bit mono signed sample.
SFM_U16BITMONO16-bit mono unsigned sample.
SFM_S8BITSTEREO8-bit stereo signed sample.
SFM_U16BITSTEREO16-bit stereo unsigned sample.

By default, all samples are assumed to be in little endian format, as supported by Intel CPU's. If the data is in big endian format, you should OR the SampleFormat value with the flag SFM_BIGENDIAN.

It is also possible to supply loop information with the stream. The Audio class supports a number of different looping formats, rather than just the 'repeat from the beginning once you reach the end' style of looping that you might normally find in audio systems. The AudioLoop structure illustrates your options:

  struct AudioLoop {
     WORD LoopMode;       Loop mode (single, double)
     BYTE Loop1Type;      First loop type (unidirectional, bidirectional)
     BYTE Loop2Type;      Second loop type (unidirectional, bidirectional)
     LONG Loop1Start;     Start of the first loop
     LONG Loop1End;       End of the first loop
     LONG Loop2Start;     Start of the second loop
     LONG Loop2End;       End of the second loop
  };

There are three types of loop modes that you can specify in the LoopMode field:

   LOOP_SINGLE           Single loop: The sample will continuously loop between Loop1Start and Loop1End.
   LOOP_SINGLE_RELEASE   Release loop: Sample data found after Loop1End will be played when the sample is released.
   LOOP_DOUBLE           Double loop: When the sample is released from playback, playing shifts to the second loop.

The Loop1Type and Loop2Type fields normally determine the style of the loop, however only unidirectional looping is currently supported for streams. For that reason, set the type variables to either NULL or LTYPE_UNIDIRECTIONAL.

This method may not be called directly if the audio object in question is located in a foreign task. If you try to grab the audio object and call this method, it will detect the illegal usage and return ERR_IllegalActionAttempt. Thus the only safe way to call this method is to use the ActionMsg() function.

Result
ERR_Okay  The stream was created successfully.
ERR_Args  Invalid arguments were specified.
ERR_IllegalActionAttempt  You attempted to call this method directly using the Action() function. Use ActionMsg() instead.
ERR_ReallocMemory  The existing sample handle array could not be expanded.
ERR_AllocMemory  Failed to allocate the stream buffer.
ERR_CreateObject  Failed to create a file object based on the supplied Location.

Method:Beep()
Short:Beeps the PC audio speaker.
Arguments:
LONG Pitch  The pitch of the beep.
LONG Duration  The duration of the beep.
LONG Volume  The volume of the beep.

This method will beep the PC audio speaker for you. You can set the pitch, duration and volume of the beep according to your requirements.

Result
ERR_Okay  The beep was played successfully.
ERR_Args  Invalid arguments were specified.
ERR_NoSupport  PC speaker support is not available.

Method:BufferCommand()
Short:Sends special audio commands to the channel processor.
Arguments:
LONG CommandID  The ID of the command that you want to execute.
LONG Handle  Refers to the channel that the command is to be executed against.
LONG Data  Special data value relevant to the command being executed.

The BufferCommand method is provided so that you can send commands to an audio object, where they can either be executed immediately or stored in a sequencing buffer for progressive execution. The method that you use depends on the style of playback that you need for your program. If you are simply playing an audio sample, immediate execution is appropriate. If you are writing a music player or need to execute audio commands at very precise intervals during playback, you need to use command sequencing.

Immediate execution is enabled by default. This involves calling the BufferCommand method whenever you please and the commands will be immediately executed for you. You need to supply the ID of the command that you wish to execute, indicate the channel that the command is to be executed against, and provide a special data parameter according to the type of command being executed. The following commands are available:

CommandDescription
CMD_SetSampleSets a new sample against a channel. You are required to supply the sample handle (as obtained from AddSample or AddStream) in the Data argument. The sample will not play until you use the Play command.
CMD_SetVolumeSets a new channel volume. The Data argument indicates the new volume and must be in the range of 0 - 500% (100% is normal volume, 0% is silence).
CMD_SetPanSets a channel's panning position. The Data argument indicates the new pan and must be in the range of -100 to +100. A setting of zero plays the sound at an equal level between both speakers. If output is in mono, panning has no effect.
CMD_SetFrequencySets the current playback frequency of a channel.
CMD_StopImmediately stops a channel from playing any audio until the next Play command.
CMD_StopLoopingTells the channel to stop performing any more audio loops related to the currently playing sample. This command does nothing if the current sample has no associated loop information.
CMD_SetPositionSets the playback position within a channel's currently associated sample (measured in bytes). Useful for starting playback from a preset position.
CMD_PlayPlays the sample associated with the channel. You are required to set the playback frequency in the Data argument. This command does nothing if the channel does not have a sample loaded against it.
CMD_FadeInFades a channel in from zero to the current volume (as previously determined by the SetVolume command).
CMD_FadeOutFades a channel from the current volume down to zero.
CMD_MuteMutes the channel so that no further audio will play until you unmute it. The Data argument needs to be set to either TRUE or FALSE to indicate the required mute status.

Command sequencing is enabled only when you open a channel set with a large number of command buffers (refer to OpenChannel for details). You also need to organise your code so that it sends commands to the audio object in batches rather than drip-feeding commands. Each batch of commands will be executed at a predetermined rate, as defined by you (e.g. every 125 milliseconds). This allows the audio object to process the command sets at regular intervals. This has the effect of clearing the command buffers, so you will need to keep feeding it information to make sure that there are no pauses in the audio playback.

To send command batches, you need to call the BufferCommand method with CMD_StartSequence, then send the instructions before terminating with CMD_EndSequence. You can do this as many times as you like until the command buffers are full. The following code illustrates how you might do this:

   if (AccessObject(AudioID, 4, &audio) IS ERR_Okay) {
      cycles = 0;
      while ((ActionTags(MT_BufferCommand, audio, CMD_StartSequence,
         Self->Channels, NULL) IS ERR_Okay) AND (cycles < MAX_CYCLES)) {

      	 // Add buffered commands in this area.
      	 // ...

         ActionTags(MT_BufferCommand, Self->Audio, CMD_EndSequence, Self->Channels, NULL);
         cycles++;
      }
      ReleaseObject(Self->Audio);
   }

To set the command sequencing rate, you need to send the CMD_SetRate instruction. The amount of milliseconds that you specify in the Data argument will determine the rate at which the command sets are executed. For instance, if you set a rate of 200ms then a new sequence will be executed five times every second.

Result
ERR_Okay  The command was successfully buffered or executed.
ERR_Args  Invalid arguments were specified.
ERR_BufferOverflow  The command buffer is full.
ERR_NoSupport  The CommandID is not supported.

Method:CloseChannels()
Short:Frees audio channels that have been allocated for sample playback.
Arguments:
LONG Handle  Must refer to a channel handle returned from the OpenChannels method.

Use the CloseChannels method when you want to destroy a group of channels that you have previously allocated through the OpenChannels method. Any audio commands buffered against the channels will be cleared instantly. Any audio data that has already been mixed into the output buffer will remain until it plays out during the next 1 - 2 seconds, so do not assume that stoppage will be instant.

Result
ERR_Okay  The channel set was successfully removed.
ERR_Args  Invalid arguments were supplied to this method.

Method:OpenChannels()
Short:Allocates audio channels that can be used for sample playback.
Arguments:
LONG Amount  Amount of channels to allocate.
LONG Key  Special key to associate with the channel allocation (optional).
LONG Commands  The total number of command buffers to allocate for real-time processing.
LONG Result  The resulting channel handle is returned in this parameter.

Use the OpenChannels method when you need to open audio channels for sample playback. Channels are allocated in sets that can lie between a range of 1 and 64. There are global limits as to how many channel sets can be open at any one time, so it is recommended that you never call this function more than once for your task.

When opening a new channel set, you can provide your own special key if your code is written in such a way that being able to reopen channel sets at later stages is of benefit to you. To do this, provide a randomised number in the Key parameter. The next time you call OpenChannels with the same key and number of channels, it will return the same allocation handle rather than creating a new set of channels. An internal open counter will also be incremented, so multiple calls to CloseChannels will be required in order to destroy the channel allocation.

You may also indicate to this method how many command sequencing buffers you would like to allocate for your channels. This is particularly useful if you are writing a digital music sequencer, or if you want to process a number of real-time channel adjustments with precision timing. You can allocate a maximum of 1024 command buffers at a cost of approximately eight bytes each.

The resulting handle returned from this method is an integer consisting of two parts. The upper word uniquely identifies the channel set that has been provided to you, while the lower word is used to refer to specific channel numbers. With this in mind, if you need to refer to specific channels when using certain functions, you can do so with the formula "Channel = (Handle & 0xffff0000) | ChannelNo".

To destroy an allocated channel set, use the CloseChannels method.

Result
ERR_Okay  The channels were allocated successfully.
ERR_OutOfRange  The amount of requested channels or commands is outside of acceptable range.
ERR_AllocMemory  Memory for the audio channels could not be allocated.
ERR_ArrayFull  The maximum number of available channel sets is currently exhausted.

Method:RemoveSample()
Short:Removes a sample from the global sample list and deallocates its memory usage.
Arguments:
Handle  The handle of the sample that you want to remove.

You can remove an allocated sample at any time by calling the RemoveSample method. Once a sample is removed it is permanently deleted from the audio server and it is not possible to reallocate the sample against the same handle number.

This method may not be called directly if the audio object in question is located in a foreign task. If you try to grab the audio object and call this method, it will detect the illegal usage and return ERR_IllegalActionAttempt. Thus the only safe way to call this method is to use the ActionMsg() function.

Over time, the continued allocation of audio samples will mean that freed handle numbers will become available again through the AddSample and AddStream methods. For this reason, you should clear all references to the sample handle after removing it.

Result
ERR_Okay  The sample was removed.
ERR_Args  Invalid arguments were specified.
ERR_OutOfRange  The provided sample handle is not within the valid range.
ERR_IllegalActionAttempt  You attempted to call this method directly using the Action() function. Use ActionMsg() instead.

Field:Bass
Short:Sets the amount of bass to use for audio playback.
Type:FLOAT
Status:Read/Set

The Bass field controls the amount of bass that is applied when audio is played back over the user's speakers. Not all platforms support bass adjustment.

The normal setting for bass is a value of 50, minimum bass is 0 and maximum bass is 100.


Field:BitRate
Short:The bit rate affects the overall quality of audio input and output.
Type:LONG
Status:Get/Set

This field manages the bit rate for audio objects. Valid bit rates are 8 and 16, with 16 being the recommended value for CD quality playback.


Field:Flags
Short:Special audio flags can be set here.
Type:LONG
Status:Read/Set

The audio class supports a number of special flags that affect internal behaviour. The following table illustrates the publicly available flags:

FlagDescription
ADF_OVERSAMPLINGEnables oversampling for higher quality at the cost of slower mixing.
ADF_MUTEIndicates that the audio is muted (to change the mute status, set the Mute field).
ADF_FILTERLOWEnables low-level output filtering to minimise distortion.
ADF_FILTERHIGHEnables high-level output filtering to minimise distortion.
ADF_STEREOEnables stereo output (set by default if the platform supports stereo). If not set, output is in mono.
ADF_16BITEnables 16 bit output (set by default if the platform supports 16 bit). If not set, output is in 8 bit.
ADF_VOLRAMPINGEnables volume ramping - this gives softer playback when a sample is played multiple times (enabled by default).

It is not possible to set any of the available audio flags after initialisation.


Field:InputRate
Short:Determines the frequency to use when recording audio data.
Type:LONG
Status:Read/Set

The InputRate determines the frequency to use when recording audio data from a Line-In connection or microphone. In most cases, this value should be set to 44100 for CD quality audio.

The InputRate can only be set prior to initialisation, further attempts to set the field will be ignored. On some platforms, it may not be possible to set an InputRate that is different to the OutputRate. In such a case, the value of the InputRate shall be ignored.


Field:MasterVolume
Short:The master volume to use for audio playback.
Type:FLOAT
Status:Read/Set

The MasterVolume field controls the amount of volume applied to all of the audio channels. Volume is expressed as a percentage, with 0% being no volume and 100% being normal volume.

Amplification is supported up to 10 times the normal volume (1000%). Please note that high levels of amplification will produce distortion to a level that is proportional to the amount of amplification applied.


Field:Mute
Short:Mutes all audio output.
Type:LONG
Status:Get/Set

You can mute all audio output by setting this field to TRUE. To restart audio output after muting, set the field to FALSE. Muting does not disable the audio system - to do that you should use the Deactivate action.


Field:OutputRate
Short:Determines the frequency to use for the output of audio data.
Type:LONG
Status:Read/Init

The OutputRate determines the frequency of the audio data that will be output to the audio speakers. In most cases, this value should be set to 44100 for CD quality audio.

The OutputRate can only be set prior to initialisation, further attempts to set the field will be ignored.


Field:Quality
Short:Determines the quality of the audio mixing.
Type:LONG
Status:Read/Set

You can alter the quality of internal audio mixing by adjusting the Quality field. You can set any value between 0 (low quality) and 100 (high quality). A setting between 70 and 80 is the recommended value. Setting the Quality field results in the following flags being automatically adjusted in the audio object: ADF_FILTERLOW, ADF_FILTERHIGH and ADF_OVERSAMPLING.

Generally speaking, the only time when low quality modes should be used are when you do not want the audio output to be extensively modified, or if the CPU is considered to be very slow.


Field:Stereo
Short:Controls stereo and mono audio output.
Type:LONG
Status:Get/Set

The Stereo field controls audio output, allowing stereo and mono modes to be selected dynamically. Set this field to TRUE to enable stereo output or FALSE to enable mono output.


Field:TotalChannels
Short:Tells you the total number of audio channels that have been allocated.
Type:LONG
Status:Get

If you need to know the total number of audio channels that have been allocated against an audio object, you can read this field to get the exact value. The total includes channels that have been allocated by your task as well as other tasks that have used the object.


Field:Treble
Short:Sets the amount of treble to use for audio playback.
Type:FLOAT
Status:Read/Set

The Treble field controls the amount of treble that is applied when audio is played back over the user's speakers. Not all platforms support treble adjustment.

The normal setting for treble is a value of 50, minimum treble is 0 and maximum treble is 100.