Quick Start
Important: You must call FMEx.StartUp prior to using any classes or methods that manipulate audio or query the mixing engine. Also don't forget to call FMEx.ShutDown to ensure the library and the classes clean up after themselves.
Tip: The download archive contains heavily commented example projects that demonstrate many useful features and techniques.
Loading & Playing Sounds
The FMExAudioPlayer and related classes work in a similar fashion to REALbasic's built in Sound class. They have familiar play, stop, pan, and volume methods and properties, but they aren't tied to one particular audio sample. Instead, an FMExAudio object is passed to a player's constructor or when calling one of the play methods. The FMExAudioPlayer's properties are applied to that audio sample from there on in, until a play method is called using a different sample. The FMExAudio instance itself isn't affected in the slightest - a dozen FMExAudioPlayer (or FMExAudioPlayer3D) objects can play the exact same FMExAudio instance at the same time, using different volume, pan, pitch (etc.) values as required.
Any audio file format supported by the FMOD Ex library can be loaded into an FMExAudio object. An extension to the FolderItem class (FolderItem.OpenAsFMExAudio) is provided to make this relatively painless:
Dim myAudio As FMExAudio Dim f As FolderItem f = GetFolderItem("mysound.wav") myAudio = f.OpenAsFMExAudio
Once an FMExAudio object is created, it can be played back from any FMExAudioPlayer object:
' myPlayer is declared as FMExAudioPlayer elsewhere myPlayer = New FMExAudioPlayer myPlayer.Play(myAudio)
Important: FMExAudioPlayer objects must remain in scope while they are being used (i.e. while playing back audio). Declaring these as properties of a window or of another persistent class or module is usually the easiest way to ensure they stick around. FMExAudioPlayer objects keep a reference to the last audio sample played however, so you can safely allow FMExAudio objects to go out of scope if they are no longer needed.
Loading & Playing Streaming Audio
When loading sounds into an FMExAudio object, the audio data is decoded entirely into RAM. This is fine for short or uncompressed audio samples and provides optimal playback performance, but long compressed sounds such as music encoded in Ogg Vorbis format may end up using gobs of RAM and take several seconds to fully decode. The FMExStream class is preferable for long-format compressed audio since it only stores the compressed data, decoding small chunks as needed during playback.
Although a distinction is made between the audio data and the playback mechanism when loading sounds into the FMExAudio class, the FMExStream class works more like REALbasic's built-in Sound class - it wraps a single sound source and doubles as a player. Note that as with FMExAudioPlayer, you must retain a reference to the FMExStream object while it is in use. FMExStream (and FMExAudioPlayer/FMExAudioPlayer3D) objects will simply stop playing when they go out of scope.
' myStream is declared as FMExStream elsewhere Dim f As FolderItem f = GetFolderItem("mymusic.mod") myStream = f.OpenAsFMExStream myStream.Play
Note: Uncompressed audio formats will gain no advantage by streaming. These classes do not yet provide disk or network streaming but those features are under consideration for future releases.
Restarting FMOD Ex
First, a little background; The FMOD Ex API supports multiple concurrent "system" objects which may map to multiple audio devices installed on the same machine. Consequentially, all sounds, channels, and effects are "owned" by a single system object and can not be shared. When a system object is destroyed, all of its sounds, channels, etc. become invalidated - attempting to use these invalid object handles will generate errors, or worse...
To simplify this situation within the REALbasic environment, these classes essentially wrap single FMOD Ex system object. Under normal circumstances this should not cause any grief - you call FMEx.StartUp when your application is launched, load your audio samples, create player objects, etc., then call FMEx.ShutDown when your application quits and all will be fine. If you ever have a need to restart FMOD Ex however, all existing FMExAudio, FMExStream, FMExStreamSentence, and FMExSubMixer instances will contain invalid handles. There is error checking in place to avoid crashes if this situation should arise, but for various reasons those handles can not be re-generated automatically. In order to properly restart FMOD Ex you should follow these guidelines:
- Prior to shutting down FMOD Ex, call the FMExChannel.Stop method for any channels that are currently playing or paused, In other words, stop playback on all FMExAudioPlayer, FMExAudioPlayer3D, FMExStream, and FMExStreamSentence instances (they're all FMExChannel subclasses). You do not have to dispose of these objects, but calling stop ensures the internal channel reference is reset.
- Once all channels are stopped, restart FMOD Ex by calling FMEx.ShutDown followed by FMEx.StartUp. At this point, any existing FMExAudio, FMExStream, FMExStreamSentence, and FMExSubMixer instances will need to either be disposed of (e.g. set to Nil) and re-created from scratch, or "reinitialized" (more on that below).
- The process for reinitializing playback objects differs for each type. By necessity, streams keep a local cache of their audio data so you can simply call FMExStream.Reinitialize and they will refresh the internal FMOD handles without any further work. FMExAudio instances do not keep a local cache, but the FMEx module provides "ByRef" methods to load external audio data into an existing FMExAudio instance (FolderItem.OpenAsFMExAudio and FMEx.CreateAudio). This allows you to refresh the internal FMOD handle and data without disposing of the REALbasic object instance - meaning any and all classes that reference that particular FMExAudio instance won't need any further tweaking.
- Lastly, you'll need to recreate any FMExSubMixer instances. Here again the FMEx module provides a "ByRef" method overload, FMEx.CreateSubMixer. There are a couple caveats however - you may need to manually specify the ignoreMaster parameter each time you recreate a sub-mixer, and you'll also need to manually re-route all players previously assigned to the mixer using the FMExChannel.RouteToSubMixer method.
Restarting FMOD Ex can seem somewhat daunting, but there are plans to ease this process (particularly for sub-mixers) in future releases of these classes. With the introduction of weak references in REALbasic 2007r2 it may even be possible to automate this process entirely, however this still remains a non-trivial task. For the time being, it can help to store references of the affected classes in Dictionary objects using appropriate keys (e.g. matching up FolderItems to FMExAudio instances) to centralize the reloading process.