For the past few weeks I have been working on the new audio engine.
The
SDL_Mixer is a great library and I just love its simplicity and straightforward API code. However there is one significant feature missing. It is 3D sound support. Off course it could be faked, but I decided to give
OpenAL a try.
The library itself is a well-known standard right now for 3D Sound audio and
allot of new games are using it for their audio support.
The library itself is fairly low level. Its API is somewhat similar to the
OpenGL. The API has 3 major parts:
1. Device2. Buffer3. SourceThe device is an output device that is available on the machine. On my machine there are 2 devices:
1. Software1. HardwareIt is possible to select either of them. On some other machines another devices are available. Usually device can have additional features included, which can be requested through the extension system. Quite similar to
OpenGL.
When the device is created the
OpenAL allows you to request sources to be played on that device. Source is like a point in space where sound is playing. It is possible to specify allot of different properties to the source such as position , velocity , volume (Gain) and more. There is also a
Listener it is exactly what it is named like . There can be only one
Listener and this
Listener is who can "hear" the sounds.
The sound itself is loaded into buffer or multiple buffers, which are then assigned to the source and
OpenAL starts playing them.
This is probably all it can generally do. But the best part off course is the 3d positioning and the doppler shift. The extensions are also one cool thing as it allows to create plenty effects to simulate different audio environments.
For the audio file I decided to use
ogg/vorbis. It is royalty free audio format which has become quite popular now. I decided to use ogg instead of regular .wav files to save memory space. Off course it would add additional impact on the processor but this wouldn't be so hard I think.
So generally I have integrated all of this into one easy to use and intuitive audio engine.
The following flow chart or class structure illustrates the whole picture:

There is one singleton factory called
AudioManager class. Its primary job is to manage all the audio data, creation and destruction. Throught it sources and streams are requested.
The
AudioManager contains the
StreamList class which is collection of
Streams.
Each
Stream represents Ogg file (either in the loaded memory or on the local hard drive).
Stream itself allows to read from this file and contains reference counter to automatically destroy itself when required.
There is also an
AudioThread. Its primary job is to continuously stream the Ogg files fill the Audio buffers to the source.
AudioThread manages 4 lists :
1. List of Passive 3d sources
2. List of Active 3d sources
3. List of Passive 1d sources
4. List of Active 1d sourcesGenerally when the application starts a fixed number of sources is created. Usually 1-4 of 1D sources and 5-20 of 3D sources.
Now when any sound request the source for playing, then audio thread requests source from passive sources and if successful, puts it to the active sources and returns reference to the source. If not well it ignores the command then.
All the active sources are walked through by the
AudioThread and get streamed.
The most important part is that only the
AudioThread can change any of the list. So the requests are synchronized with a mutex.
Now about user Interface.
There are only 3 classes available :
1. Sound1D
2. Sound3D
3. MusicSound1D is used for the stereo sounds, such as playing GUI elements or videos in the game. It contains all the required basic operation : Loading , Playing , Stopping , Pausing and so on. Each sound contains
StreamReader. The
StreamReader just holds the position on the stream that gets streamed. This is used to assure that any 2 sounds that are playing the same
Stream wouldn't interfer with each other.
Sound3D is used for the in-game 3d sounds. It is important that the sounds used is mono. Otherwise it wouldn't play or cause not desirable side effects.
Sound3D has the same functions as the
Sound1D , but also has additional functions that specify position in the 3D space and velocity. I am also planning to add a binding option so it would automatically synchronize itself with physical engine.
Music is a singleton class. It is actually available only by calling through the
AudioManager. Generally it holds
Sound1D inside itself and calls its functions. The only difference is the volume control, that allows music to have different volume then just sounds.
This is not all the stuff that is implemented, but I just explained general idea, and saved it for my own future reference.
P.S. I am using gliffy for this diagram. Check it out, its cool !Labels: Audio, Audio Thread, Buffer, Engine, Ogg, OpenAL, OpenGL, SDL_Mixer, Sound, Source, Stream, Vorbis