The s3eAudio API

Let's start with the quickest and easiest way of allowing our games to stop being the strong, silent type.

The s3eAudio API allows us to play compressed music formats such as MP3 and AAC. Some devices may also allow us to play other formats, such as MIDI files. Marmalade makes use of whichever audio codecs a particular device may have built-in rather than decoding the audio itself, so be sure to check that your chosen audio format is supported by all the devices you wish to target.

Note

Due to its ubiquity, it is recommended that you use MP3 as your format of choice. There are very few devices (if any) that can't play an MP3 file and the format itself allows you a wide variety of bit rates so you can trade-off between audio quality and file size.

Let's now take a look at how we can get an audio track playing and what other functionality the s3eAudio API provides for us. There is nothing we need to add to our MKB file in order to allow us to use s3eAudio, as it is one of the low level APIs of Marmalade that is always available for use. All we need to do is include the header file s3eAudio.h in any source file that needs access to s3eAudio functions.

Starting audio playback

There are two ways of starting the playback of an audio track. The first allows us to specify the filename of the audio track we want to play and the number of times we would like the track to repeat, and looks like this:

s3eAudioPlay("music.mp3", aRepeatCount);

The filename is just a standard C, null-terminated string and is relative to the data directory when run from Windows or the application install directory on the device. Specifying a number for the repeat count will cause the audio track to play that many times, while setting it to zero will cause the track to loop continuously.

The other method is to play the audio track from an area of memory as follows:

s3eAudioPlayFromBuffer(apBuffer, aBufferLength, aRepeatCount);

The parameters apBuffer and aBufferLength provide the memory location where the audio track resides and the length of audio data in bytes. The repeat count is specified in the same manner as with s3eAudioPlay.

In most cases we will find that the first method is good enough since it is easy to use and doesn't require us to allocate blocks of memory and fill it with data. You may find that the buffer method provides slightly faster initial playback if you have preloaded the audio data, but on most recent devices the difference is negligible.

If you make a call to either of these functions while an audio track is currently playing, that track will be stopped and the new track will begin playing.

Pausing, resuming, and stopping playback

Once an audio track is playing, we can pause playback by calling the s3eAudioPause function. The audio can be started again from the point at which it was paused by calling s3eAudioResume. Finally, to stop playback completely just call s3eAudioStop.

All three of these functions take no parameters and will return S3E_RESULT_SUCCESS when no errors occur. An error is raised if any of these functions are called when it makes no sense to do so, for example calling s3eAudioPause when there is no audio playing.

Changing volume

Like most of the low level APIs in Marmalade, s3eAudio features a pair of functions called s3eAudioGetInt and s3eAudioSetInt that are used to change attributes related to that API. In s3eAudio, one of the things we use these functions for is to change the volume of audio playback.

To set the playback volume we can make the following call:

s3eAudioSetInt(S3E_AUDIO_VOLUME, S3E_AUDIO_MAX_VOLUME / 2);

In the aforementioned example we set the volume to half of S3E_AUDIO_MAX_VOLUME, which is the maximum allowed volume.

To determine the current volume we use this code:

int32 lVolume = s3eAudioGetInt(S3E_AUDIO_VOLUME);

We can also request the default volume for audio by passing in the value S3E_AUDIO_VOLUME_DEFAULT. This is the default volume level for playing audio and has been chosen by the Marmalade SDK so as to provide a fairly consistent volume level across all devices.

Other audio queries

The s3eAudioGetInt function allows us to make several other queries regarding audio playback. The following table shows which properties can be specified:

Property

Description

S3E_AUDIO_STATUS

Returns current audio status—one of S3E_AUDIO_STOPPED, S3E_AUDIO_PLAYING, S3E_AUDIO_PAUSED, or S3E_AUDIO_FAILED.

S3E_AUDIO_POSITION

Returns the current position in the audio track in milliseconds, or 0 if no track is playing. Note that not all platforms support this feature.

S3E_AUDIO_CHANNEL

Returns the currently selected audio channel. This property can also be used in s3eAudioSetInt to select which audio channel the future audio commands will be applied to. See the following property for more on audio channels.

S3E_AUDIO_NUM_CHANNELS

Returns the number of audio channels available. On most platforms this will return 1 since most devices only allow a single audio track to be played at any time. Some devices provide more than one channel, meaning more than one audio track can be played simultaneously.

S3E_AUDIO_MUTES_S3ESOUND

Returns 1 if the hardware is not capable of outputting sound through both s3eAudio and s3eSound at the same time. In this instance playing an audio track will cause s3eSound processing to continue, but without actually producing any output.

S3E_AUDIO_DURATION

Returns the length, in milliseconds, of the track currently playing.

S3E_AUDIO_PLAYBACK_FROM_HTTP_AVAILABLE

Returns 1 if the hardware is able to play an audio track by streaming from a URL.

End of track notification

There are two methods we can use to determine when an audio track has finished. One is to use a polled approach, the other is to make use of a callback.

To poll whether an audio track has completed or not, we can do the following:

if (s3eAudioIsPlaying() == S3E_FALSE)
{
  // Audio is not playing!
}

This function returns S3E_TRUE if the audio is currently playing, or S3E_FALSE if it is stopped or paused. This function is actually just a shortcut for calling s3eAudioGetInt with the property S3E_AUDIO_STATUS.

The callback approach is also very simple to use, as the following code snippet shows:

int32 AudioFinished(s3eAudioCallbackData* apAudioData,
void* apUserData)
{
  // apAudioData->m_ChannelID identifies the audio channel that
  // has completed.
  // s3eCallback functions must return a value, but in case of
  // audio callback the value returned does not matter.
  return 0;
}

// Use the following line to set up the audio callback
s3eAudioRegister(S3E_AUDIO_STOP, (s3eCallback) AudioFinished, NULL);

// And this line to remove the callback function
s3eAudioUnRegister(S3E_AUDIO_STOP, (s3eCallback) AudioFinished);

The callback function will be called whenever an audio track finishes and will pass the pointer to user data supplied as the last parameter in the s3eAudioRegister call by using the apUserData argument. It will not be called if we have asked the audio track to be looped unless it is the last repetition. The function will also be called if the audio is stopped due to an error, such as a corrupted track. We can determine whether completion was caused due to error by calling the s3eAudioGetError function, which returns an error code of the enumerated type s3eAudioError. A complete list of error codes can be found in s3eAudio.h.

The decision of whether to use the polling or callback-based approach depends on your application, and indeed quite often in games we don't even really care that much about when an audio track has finished as we often just want the same track to loop forever until a new piece of audio is required. If you are just waiting for a jingle to finish during a splash screen, the polled method is probably adequate, but if you want to join several tracks together one after the other, the callback approach would probably lead to a clean solution.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.37.191