Skip to content

Instantly share code, notes, and snippets.

@GlaireDaggers
Created April 16, 2023 19:21
Show Gist options
  • Save GlaireDaggers/51f2062ca25cca4b15a1e91ff6f3c239 to your computer and use it in GitHub Desktop.
Save GlaireDaggers/51f2062ca25cca4b15a1e91ff6f3c239 to your computer and use it in GitHub Desktop.
Audio manager class from unfinished FNA game using FMOD
using System.Diagnostics;
using System.Runtime.InteropServices;
public class AudioManager
{
public readonly VESGame game;
private FMOD.Studio.System _studioSystem;
private FMOD.Studio.Bank _master;
private FMOD.Studio.Bank _master_strings;
private FMOD.Studio.Bank _music;
private FMOD.Studio.Bank _sfx;
private FMOD.Studio.EventInstance _song;
private GCHandle _masterBankStream;
private GCHandle _masterStringsBankStream;
private GCHandle _musicBankStream;
private GCHandle _sfxBankStream;
private FMOD.Studio.BANK_INFO _masterBankData;
private FMOD.Studio.BANK_INFO _masterStringsBankData;
private FMOD.Studio.BANK_INFO _musicBankData;
private FMOD.Studio.BANK_INFO _sfxBankData;
public AudioManager(VESGame game)
{
this.game = game;
AssertFMODResult(FMOD.Studio.System.create(out _studioSystem));
AssertFMODResult(_studioSystem.initialize(32, FMOD.Studio.INITFLAGS.NORMAL, FMOD.INITFLAGS.NORMAL, IntPtr.Zero));
_masterBankData = BankFromStream(game.Resources.Open("content/audio/Master.bank"), out _masterBankStream);
_masterStringsBankData = BankFromStream(game.Resources.Open("content/audio/Master.strings.bank"), out _masterStringsBankStream);
_musicBankData = BankFromStream(game.Resources.Open("content/audio/Music.bank"), out _musicBankStream);
_sfxBankData = BankFromStream(game.Resources.Open("content/audio/SFX.bank"), out _sfxBankStream);
// load audio banks
AssertFMODResult(_studioSystem.loadBankCustom(_masterBankData, FMOD.Studio.LOAD_BANK_FLAGS.NORMAL, out _master));
AssertFMODResult(_studioSystem.loadBankCustom(_masterStringsBankData, FMOD.Studio.LOAD_BANK_FLAGS.NORMAL, out _master_strings));
AssertFMODResult(_studioSystem.loadBankCustom(_musicBankData, FMOD.Studio.LOAD_BANK_FLAGS.NORMAL, out _music));
AssertFMODResult(_studioSystem.loadBankCustom(_sfxBankData, FMOD.Studio.LOAD_BANK_FLAGS.NORMAL, out _sfx));
Console.WriteLine("FMOD initialized");
}
public void Update()
{
AssertFMODResult(_studioSystem.update());
}
public void Dispose()
{
AssertFMODResult(_studioSystem.release());
((Stream)_masterBankStream.Target).Dispose();
((Stream)_masterStringsBankStream.Target).Dispose();
((Stream)_musicBankStream.Target).Dispose();
((Stream)_sfxBankStream.Target).Dispose();
_masterBankStream.Free();
_masterStringsBankStream.Free();
_musicBankStream.Free();
_sfxBankStream.Free();
}
public FMOD.Studio.EventInstance CreateEvent(string path)
{
AssertFMODResult(_studioSystem.getEvent(path, out var eventDesc));
AssertFMODResult(eventDesc.createInstance(out var eventInstance));
return eventInstance;
}
public void PlaySong(string path)
{
if (_song.isValid())
{
_song.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
_song.release();
}
_song = CreateEvent(path);
_song.start();
}
private void AssertFMODResult(FMOD.RESULT result)
{
Debug.Assert(result == FMOD.RESULT.OK, FMOD.Error.String(result));
}
private FMOD.Studio.BANK_INFO BankFromStream(Stream stream, out GCHandle handle)
{
handle = GCHandle.Alloc(stream);
var bankInfo = new FMOD.Studio.BANK_INFO();
bankInfo.userdata = GCHandle.ToIntPtr(handle);
bankInfo.opencallback = OpenFile;
bankInfo.closecallback = CloseFile;
bankInfo.readcallback = ReadFile;
bankInfo.seekcallback = SeekFile;
bankInfo.userdatalength = 0;
return bankInfo;
}
private static FMOD.RESULT OpenFile(IntPtr name, ref uint filesize, ref IntPtr handle, IntPtr userdata)
{
Stream stream = (Stream)GCHandle.FromIntPtr(userdata).Target;
filesize = (uint)stream.Length;
return FMOD.RESULT.OK;
}
private static FMOD.RESULT CloseFile(IntPtr handle, IntPtr userdata)
{
//Stream stream = (Stream)GCHandle.FromIntPtr(userdata).Target;
//stream.Close();
return FMOD.RESULT.OK;
}
private static unsafe FMOD.RESULT ReadFile(IntPtr handle, IntPtr buffer, uint sizebytes, ref uint bytesread, IntPtr userdata)
{
Stream stream = (Stream)GCHandle.FromIntPtr(userdata).Target;
byte[] buf = new byte[sizebytes];
bytesread = (uint)stream.Read(buf, 0, buf.Length);
fixed (void* src = buf)
{
Buffer.MemoryCopy(src, (void*)buffer, sizebytes, bytesread);
}
return FMOD.RESULT.OK;
}
private static FMOD.RESULT SeekFile(IntPtr handle, uint pos, IntPtr userdata)
{
Stream stream = (Stream)GCHandle.FromIntPtr(userdata).Target;
stream.Seek(pos, SeekOrigin.Begin);
return FMOD.RESULT.OK;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment