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:

https://www.fmod.com/

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