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;
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