Audio playback with FMOD Audio
Besides the simple and low-performance TGorillaAudioManager, Gorilla3D introduces an interface for usage of the professional audio lowlevel library FMOD.
Notice
If your development budget is under $500k or you’re not doing it for the money, go ahead and start creating. Simply register for a free license and include our logo in your game, before it is released to the world:
FMOD allows many different formats on all platforms. It supports 3D positioning of sound sources. It guarantees high performance and high quality playback even with a large number of samples. By usage of sound- and channelgroups you can easily manage your audio files.
FMOD provides a few common sound effects, like: panning, volume, reverb, … By the geometry API you are able to implement even complex sound effects within a 3D world with obstacles, doppler-effect and reverb. FMOD allows DSP plugins to create your own native sound effects.
Supported file formats: AIFF, ASF, ASX, DLS, FLAC, FSB (FMOD's sample bank format), IT, M3U, MIDI, MOD, MP2, MP3, Ogg Vorbis, PLS, S3M, VAG (PS2/PSP format), WAV, WAX (Windows Media Audio Redirector), WMA, XM, XMA (only on the Xbox 360), as well as raw audio data.
Supported platforms: Microsoft Windows (x86 and x86-64), macOS, iOS, Linux (x86 and x86-64), Android, BlackBerry, Wii, Wii U, 3DS, Nintendo Switch, Xbox, Xbox 360, Xbox One, PlayStation 2, PlayStation 3, PlayStation 4, PlayStation Portable, PlayStation Vita, and Google Native Client.
Units
Gorilla3D provides the low level header declarations in Gorilla.Audio.FMOD.Lib.* units.
Gorilla.Audio.FMOD.Lib.API Gorilla.Audio.FMOD.Lib.Codec Gorilla.Audio.FMOD.Lib.Common Gorilla.Audio.FMOD.Lib.DSP.Effects Gorilla.Audio.FMOD.Lib.DSP Gorilla.Audio.FMOD.Lib.Errors Gorilla.Audio.FMOD.Lib.Output Gorilla.Audio.FMOD.Lib.Types
To simplify usage of the massive amount of functions, Gorilla3D provides higher level structure declarations in Gorilla.Audio.FMOD.Intf.* and Gorilla.Audio.FMOD.* units.
Gorilla.Audio.FMOD.Intf.System Gorilla.Audio.FMOD.Intf.Channel Gorilla.Audio.FMOD.Intf.ChannelGroup Gorilla.Audio.FMOD.Intf.DSP Gorilla.Audio.FMOD.Intf.Sound Gorilla.Audio.FMOD.Intf.SoundGroup Gorilla.Audio.FMOD.Intf.Reverb3D Gorilla.Audio.FMOD.Intf.Geometry
Gorilla.Audio.FMOD.System Gorilla.Audio.FMOD.Custom Gorilla.Audio.FMOD.Channel Gorilla.Audio.FMOD.ChannelGroup Gorilla.Audio.FMOD.DSP Gorilla.Audio.FMOD.Sound Gorilla.Audio.FMOD.SoundGroup Gorilla.Audio.FMOD.Reverb3D Gorilla.Audio.FMOD.Geometry
On the highest level Gorilla3D provides a component for quick usage by IDE. You can find the TGorillaFMODAudioManager in:
Gorilla.Audio.FMOD
Remarks: The higher level structures are based on a interface-class architecture, so you need to take care of reference counting. In your application you should only use the interfaces!
Examples
To load an audio file at runtime
- Form1.pas
uses Gorilla.Audio.FMOD, Gorilla.Audio.FMOD.Sound; var FFMOD : TGorillaFMODAudioManager; procedure TForm1.FormShow(Sender: TObject); var LPath : String; LSound : IGorillaFMODSound; begin FFMOD := TGorillaFMODAudioManager.Create(Self); FFMOD.Parent := Form1; LPath := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'demo.mp3'; LSound := FFMOD.LoadSoundFromFile(LPath); FFMOD.PlaySound(LSound, nil, false, 0); end; procedure TForm1.Timer1Timer(Sender: TObject); begin // Timer1.Interval := 33; FFMOD.Update(); end;
Output playback position
- Form1.pas
uses Gorilla.Audio.FMOD, Gorilla.Audio.FMOD.Intf.Sound, Gorilla.Audio.FMOD.Intf.Channel; procedure TForm1.Timer1Timer(Sender: TObject); var LSound : IGorillaFMODSound; LMS, LLenMS : UInt32; begin {...} LMS := FChannel.Position[FMOD_TIMEUNIT_MS]; LSound := LChannel.GetCurrentSound() as IGorillaFMODSound; if Assigned(LSound) then begin LLenMS := LSound.Length[FMOD_TIMEUNIT_MS]; Self.Caption := Format('sound #%s %d / %d', [IntToHex(NativeInt(LSound), 16), LMS, LLenMS]); end; end;
Add a FadePoint
- Form1.pas
uses Gorilla.Audio.FMOD, Gorilla.Audio.FMOD.Sound, Gorilla.Audio.FMOD.Channel; procedure TForm1.FormShow(Sender: TObject); var LSound : IGorillaFMODSound; LChannel : IGorillaFMODChannel; LClock, LPClock : UInt64; begin {...} LChannel := FFMOD.PlaySound(LSound, nil, false, 0); if Assigned(LChannel) then begin LChannel.GetDSPClock(LClock, LPClock); LChannel.AddFadePoint(LPClock, 0.0); LChannel.AddFadePoint(LPClock + 48000, 1.0); end; end;
Set 3D Listener Position
- Form1.pas
uses Gorilla.Audio.FMOD, Gorilla.Audio.FMOD.Sound, Gorilla.Audio.FMOD.Channel, Gorilla.Audio.FMOD.System; var FFMOD : TGorillaFMODAudioManager; FListenerPos : TFMOD_Vector; FListenerInc : Single; procedure TForm1.FormShow(Sender: TObject); begin {...} F3DListener := TGorillaFMOD3DListenerAttr.Create(FListenerPos); end; procedure TForm1.Timer1Timer(Sender: TObject); begin {...} // update 3d listener position : listener rotating around // soundsource = (0, 0, 0) FListenerInc := FListenerInc + 0.1; FListenerPos.X := Sin(FListenerInc) + 3; FListenerPos.Z := Cos(FListenerInc) + 3; F3DListener.Pos := FListenerPos; FFMOD.Set3DListener(F3DListener); end;
Loop sample
- Form1.pas
uses Gorilla.Audio.FMOD, Gorilla.Audio.FMOD.Sound, Gorilla.Audio.FMOD.Lib.Common; procedure TForm1.FormShow(Sender: TObject); var LSound : IGorillaFMODSound; begin {...} LSound := LFMOD.LoadSoundFromFile('drumloop.wav'); LSound.Mode := FMOD_LOOP_NORMAL; end;
Apply a DSP effect to a channel
FMOD offers a large number of sound effects, f.e. echo, oscillator, distortion, …
FMOD_DSP_TYPE = ( FMOD_DSP_TYPE_UNKNOWN, { This unit was created via a non FMOD plugin so has an unknown purpose. } FMOD_DSP_TYPE_MIXER, { This unit does nothing but take inputs and mix them together then feed the result to the soundcard unit. } FMOD_DSP_TYPE_OSCILLATOR, { This unit generates sine/square/saw/triangle or noise tones. } FMOD_DSP_TYPE_LOWPASS, { This unit filters sound using a high quality, resonant lowpass filter algorithm but consumes more CPU time. Deprecated and will be removed in a future release (see FMOD_DSP_LOWPASS remarks for alternatives). } FMOD_DSP_TYPE_ITLOWPASS, { This unit filters sound using a resonant lowpass filter algorithm that is used in Impulse Tracker, but with limited cutoff range (0 to 8060hz). } FMOD_DSP_TYPE_HIGHPASS, { This unit filters sound using a resonant highpass filter algorithm. Deprecated and will be removed in a future release (see FMOD_DSP_HIGHPASS remarks for alternatives). } FMOD_DSP_TYPE_ECHO, { This unit produces an echo on the sound and fades out at the desired rate. } FMOD_DSP_TYPE_FADER, { This unit pans and scales the volume of a unit. } FMOD_DSP_TYPE_FLANGE, { This unit produces a flange effect on the sound. } FMOD_DSP_TYPE_DISTORTION, { This unit distorts the sound. } FMOD_DSP_TYPE_NORMALIZE, { This unit normalizes or amplifies the sound to a certain level. } FMOD_DSP_TYPE_LIMITER, { This unit limits the sound to a certain level. } FMOD_DSP_TYPE_PARAMEQ, { This unit attenuates or amplifies a selected frequency range. Deprecated and will be removed in a future release (see FMOD_DSP_PARAMEQ remarks for alternatives). } FMOD_DSP_TYPE_PITCHSHIFT, { This unit bends the pitch of a sound without changing the speed of playback. } FMOD_DSP_TYPE_CHORUS, { This unit produces a chorus effect on the sound. } FMOD_DSP_TYPE_VSTPLUGIN, { This unit allows the use of Steinberg VST plugins } FMOD_DSP_TYPE_WINAMPPLUGIN, { This unit allows the use of Nullsoft Winamp plugins } FMOD_DSP_TYPE_ITECHO, { This unit produces an echo on the sound and fades out at the desired rate as is used in Impulse Tracker. } FMOD_DSP_TYPE_COMPRESSOR, { This unit implements dynamic compression (linked/unlinked multichannel, wideband) } FMOD_DSP_TYPE_SFXREVERB, { This unit implements SFX reverb } FMOD_DSP_TYPE_LOWPASS_SIMPLE, { This unit filters sound using a simple lowpass with no resonance, but has flexible cutoff and is fast. Deprecated and will be removed in a future release (see FMOD_DSP_LOWPASS_SIMPLE remarks for alternatives). } FMOD_DSP_TYPE_DELAY, { This unit produces different delays on individual channels of the sound. } FMOD_DSP_TYPE_TREMOLO, { This unit produces a tremolo / chopper effect on the sound. } FMOD_DSP_TYPE_LADSPAPLUGIN, { Unsupported / Deprecated. } FMOD_DSP_TYPE_SEND, { This unit sends a copy of the signal to a return DSP anywhere in the DSP tree. } FMOD_DSP_TYPE_RETURN, { This unit receives signals from a number of send DSPs. } FMOD_DSP_TYPE_HIGHPASS_SIMPLE, { This unit filters sound using a simple highpass with no resonance, but has flexible cutoff and is fast. Deprecated and will be removed in a future release (see FMOD_DSP_HIGHPASS_SIMPLE remarks for alternatives). } FMOD_DSP_TYPE_PAN, { This unit pans the signal, possibly upmixing or downmixing as well. } FMOD_DSP_TYPE_THREE_EQ, { This unit is a three-band equalizer. } FMOD_DSP_TYPE_FFT, { This unit simply analyzes the signal and provides spectrum information back through getParameter. } FMOD_DSP_TYPE_LOUDNESS_METER, { This unit analyzes the loudness and true peak of the signal. } FMOD_DSP_TYPE_ENVELOPEFOLLOWER, { This unit tracks the envelope of the input/sidechain signal. Deprecated and will be removed in a future release. } FMOD_DSP_TYPE_CONVOLUTIONREVERB, { This unit implements convolution reverb. } FMOD_DSP_TYPE_CHANNELMIX, { This unit provides per signal channel gain, and output channel mapping to allow 1 multichannel signal made up of many groups of signals to map to a single output signal. } FMOD_DSP_TYPE_TRANSCEIVER, { This unit 'sends' and 'receives' from a selection of up to 32 different slots. It is like a send/return but it uses global slots rather than returns as the destination. It also has other features. Multiple transceivers can receive from a single channel, or multiple transceivers can send to a single channel, or a combination of both. } FMOD_DSP_TYPE_OBJECTPAN, { This unit sends the signal to a 3d object encoder like Dolby Atmos. Supports a subset of the FMOD_DSP_TYPE_PAN parameters. } FMOD_DSP_TYPE_MULTIBAND_EQ, { This unit is a flexible five band parametric equalizer. } FMOD_DSP_TYPE_MAX, { Maximum number of pre-defined DSP types. } FMOD_DSP_TYPE_FORCEINT = 65536 { Makes sure this enum is signed 32bit. } );
You can attach an effect easily onto a channel, but not directly to a sound instance.
uses Gorilla.Audio.FMOD, Gorilla.Audio.FMOD.Custom, Gorilla.Audio.FMOD.Lib.DSP.Effects, Gorilla.Audio.FMOD.Intf.Channel, Gorilla.Audio.FMOD.Intf.DSP; [..] /// CAUTION: For applying multiple effects, the AIndex argument has to start at zero and needs /// to increase continously without gaps! procedure TForm1.AttachEffect(AChannel : IGorillaFMODChannel; AIndex : Integer; AEffect : TFMOD_DSPType); var LDSPEffect : IGorillaFMODDSP; LWetDryMix : TGorillaFMODWetDryMix; begin // Access the system object of FMOD API LDSPEffect := GorillaFMODAudioManager1.SystemObject.CreateDSPByType(AEffect); // Activate the effect LDSPEffect.Active := true; // Setup the wet-dry mix record LWetDryMix.PreWet := 0.75; LWetDryMix.PostWet := 0.75; LWetDryMix.Dry := 0.25; // Apply it to the dsp effect LDSPEffect.WetDryMix := LWetDryMix; // Finally attach the dsp effect to our channel, where we play a sound AChannel.AddDSP(AIndex, LDSPEffect); end; [...] // Let's add some kind of echo AttachEffect(FChannel, 0, FMOD_DSP_TYPE_ECHO);
Android
Using FMOD in Android needs some additional configuration. Because on Android the FMOD engine uses a Java library (fmod.jar), we need to attach those to our project.
To allow correct loading of this FMOD Java library, we created an extra Java library (Gorilla.jar). This library loads the FMOD library in the right context.
Go to your project tree and select Android as destination platform. Then enter the library section and add these 2 files: fmod.jar, Gorilla.jar to your project. You can find them in the “lib” folder of your package download.
Next step: AssetsManager
Remarks
It is not allowed to release FMOD interfaces when the TGorillaFMODAudioManager component, especially the IGorillaFMODSystem interface inside of it, is already destroyed. In this case you will receive an AccessViolation, because FMOD can not destroy the internal handle anymore.
WRONG:
var LFMOD : TGorillaFMODAudioManager; LSound : IGorillaFMODSound; [...] LFMOD := TGorillaFMODAudioManager.Create(nil); try LSound := LFMOD.LoadSoundFromFile(Common_MediaPathRaw('drumloop.wav')); finally FreeAndNil(LFMOD); LSound := nil; // <<< WRONG! end;
CORRECT:
var LFMOD : TGorillaFMODAudioManager; LSound : IGorillaFMODSound; [...] LFMOD := TGorillaFMODAudioManager.Create(nil); try LSound := LFMOD.LoadSoundFromFile(Common_MediaPathRaw('drumloop.wav')); finally LSound := nil; // !!! CORRECT! FreeAndNil(LFMOD); end;
Next step: Assets Manager