136 lines
4.3 KiB
C#
136 lines
4.3 KiB
C#
using FMOD;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Voile.Audio
|
|
{
|
|
public class FmodAudioBackend : AudioBackend
|
|
{
|
|
public override void Initialize()
|
|
{
|
|
CreateSystem();
|
|
_loadedSounds = new Dictionary<string, FMOD.Sound>();
|
|
_channelGroups = new Dictionary<string, ChannelGroup>();
|
|
|
|
CreateBus("Master");
|
|
}
|
|
public override void Update() => _system.update();
|
|
|
|
public override void PlaySound(Sound sound, string bus = "Master", float pitch = 1, float volume = 1)
|
|
{
|
|
int channels = 0;
|
|
|
|
if (sound.Format == SoundFormat.Mono)
|
|
{
|
|
channels = 1;
|
|
}
|
|
else if (sound.Format == SoundFormat.Stereo)
|
|
{
|
|
channels = 2;
|
|
}
|
|
|
|
var channel = PlaySoundFromBuffer(sound.Path, (int)sound.BufferSize, channels, sound.SampleRate, sound.Buffer, GetChannelGroup(bus));
|
|
channel.setVolume(volume);
|
|
channel.setPitch(pitch);
|
|
}
|
|
|
|
public override void CreateBus(string busName)
|
|
{
|
|
ChannelGroup channelGroup;
|
|
_system.createChannelGroup(busName, out channelGroup);
|
|
_channelGroups.Add(busName, channelGroup);
|
|
}
|
|
|
|
public override void SetBusVolume(string busName, float volume)
|
|
{
|
|
var channel = GetChannelGroup(busName);
|
|
channel.setVolume(volume);
|
|
}
|
|
|
|
public override float GetBusVolume(string busName)
|
|
{
|
|
float volume;
|
|
GetChannelGroup(busName).getVolume(out volume);
|
|
return volume;
|
|
}
|
|
|
|
public override void AddBusEffect<T>(T effect, string bus = "Master")
|
|
{
|
|
var channelGroup = GetChannelGroup(bus);
|
|
DSP dsp;
|
|
|
|
switch (effect)
|
|
{
|
|
case AudioEffectReverb:
|
|
dsp = CreateReverbDsp(effect as AudioEffectReverb);
|
|
break;
|
|
default:
|
|
_system.createDSPByType(DSP_TYPE.UNKNOWN, out dsp);
|
|
break;
|
|
}
|
|
|
|
channelGroup.addDSP(0, dsp);
|
|
}
|
|
|
|
protected override void Shutdown()
|
|
{
|
|
|
|
}
|
|
|
|
private DSP CreateReverbDsp(AudioEffectReverb effectReverb)
|
|
{
|
|
DSP dsp;
|
|
_system.createDSPByType(DSP_TYPE.SFXREVERB, out dsp);
|
|
return dsp;
|
|
}
|
|
|
|
private void CreateSystem()
|
|
{
|
|
var result = FMOD.Factory.System_Create(out _system);
|
|
_system.init(128, INITFLAGS.NORMAL, 0);
|
|
}
|
|
|
|
private Channel PlaySoundFromBuffer(string path, int length, int channels, int sampleRate, byte[] buffer, ChannelGroup channelGroup)
|
|
{
|
|
Channel fmodChannel;
|
|
FMOD.Sound fmodSound = IsLoaded(path) ? GetSoundFromLoaded(path) : CreateSound(length, channels, sampleRate, path, buffer);
|
|
|
|
_system.playSound(fmodSound, channelGroup, false, out fmodChannel);
|
|
|
|
return fmodChannel;
|
|
}
|
|
|
|
|
|
private FMOD.Sound GetSoundFromLoaded(string path) => _loadedSounds[path];
|
|
private bool IsLoaded(string path) => _loadedSounds.ContainsKey(path);
|
|
|
|
private FMOD.Sound CreateSound(int length, int channels, int sampleRate, string path, byte[] buffer)
|
|
{
|
|
FMOD.Sound sound;
|
|
CREATESOUNDEXINFO info = new CREATESOUNDEXINFO()
|
|
{
|
|
numchannels = channels,
|
|
defaultfrequency = sampleRate,
|
|
format = SOUND_FORMAT.PCM16,
|
|
length = (uint)length,
|
|
cbsize = Marshal.SizeOf(typeof(CREATESOUNDEXINFO))
|
|
};
|
|
|
|
var result = _system.createSound(buffer, FMOD.MODE.OPENMEMORY | FMOD.MODE.OPENRAW | FMOD.MODE.CREATESAMPLE, ref info, out sound);
|
|
AddToLoaded(path, sound);
|
|
return sound;
|
|
}
|
|
|
|
private void AddToLoaded(string path, FMOD.Sound sound) => _loadedSounds.Add(path, sound);
|
|
|
|
private ChannelGroup GetChannelGroup(string busName)
|
|
{
|
|
return _channelGroups[busName];
|
|
}
|
|
|
|
private FMOD.System _system;
|
|
|
|
// TODO: use a different key for the dictionary, paths are not good :( (waste of memory lol)
|
|
private Dictionary<string, FMOD.Sound> _loadedSounds;
|
|
private Dictionary<string, ChannelGroup> _channelGroups;
|
|
}
|
|
} |