OpenAL sound implementation.

This commit is contained in:
2023-06-17 00:56:17 +02:00
parent 7d5c5f822b
commit 36eae40926
9 changed files with 211 additions and 30 deletions

View File

@@ -1,29 +1,35 @@
namespace DaggerFramework.Audio
{
public abstract class AudioBackend
public abstract class AudioBackend : IDisposable
{
public abstract void Initialize();
public abstract void Update();
public abstract void Shutdown();
// BUS
public abstract void CreateBus(string busName);
public abstract void SetBusVolume(string busName, float volume);
public abstract float GetBusVolume(string busName);
// SOUND
protected abstract void PlaySound(Sound sound, string bus = "Master", float pitch = 1.0f, float volume = 1.0f);
public void PlaySound(Sound sound, string bus = "Master") => PlaySound(sound, bus, sound.PitchScale, sound.Volume);
public void PlaySoundVariation(Sound sound, string bus = "Master", float pitchVariation = 0.1f)
public abstract void PlaySound(Sound sound, string bus = "Master", float pitch = 1.0f, float volume = 1.0f);
public void PlaySound(Sound sound, string bus = "Master") => PlaySound(sound, bus, default, default);
public void PlaySoundVariation(Sound sound, string bus = "Master", float pitchVariation = 0.1f, float volume = 1.0f)
{
var maxPitch = sound.PitchScale + pitchVariation;
var minPitch = sound.PitchScale - pitchVariation;
var maxPitch = 1.0f + pitchVariation;
var minPitch = 1.0f - pitchVariation;
var pitch = (float)_random.NextDouble() * (maxPitch - minPitch) + minPitch;
PlaySound(sound, bus, pitch, sound.Volume);
PlaySound(sound, bus, pitch, volume);
}
// EFFECTS
public abstract void AddBusEffect<T>(T effect, string bus = "Master") where T : AudioEffect;
public void Dispose()
{
Shutdown();
}
private LehmerRandom _random = new LehmerRandom();
}
}

View File

@@ -27,12 +27,17 @@ namespace DaggerFramework.Audio
return;
}
public override void Shutdown()
{
return;
}
public override void Update()
{
return;
}
protected override void PlaySound(Sound sound, string bus = "Master", float pitch = 1, float volume = 1)
public override void PlaySound(Sound sound, string bus = "Master", float pitch = 1, float volume = 1)
{
return;
}

View File

@@ -0,0 +1,125 @@
using Silk.NET.OpenAL;
namespace DaggerFramework.Audio
{
public class OpenALAudioBackend : AudioBackend
{
public unsafe override void Initialize()
{
_alc = ALContext.GetApi();
_al = AL.GetApi();
_alDevice = _alc.OpenDevice("");
_context = _alc.CreateContext(_alDevice, null);
_alc.MakeContextCurrent(_context);
}
public override void Update()
{
}
public unsafe override void Shutdown()
{
_alc.CloseDevice(_alDevice);
_al.Dispose();
_alc.Dispose();
}
public override void AddBusEffect<T>(T effect, string bus = "Master")
{
throw new NotImplementedException();
}
public override void CreateBus(string busName)
{
throw new NotImplementedException();
}
public override float GetBusVolume(string busName)
{
throw new NotImplementedException();
}
public override void SetBusVolume(string busName, float volume)
{
throw new NotImplementedException();
}
public override void PlaySound(Sound sound, string bus = "Master", float pitch = 1, float volume = 1)
{
ALSound alSound;
if (_alSoundsForDaggerSounds.ContainsKey(sound))
{
alSound = _alSoundsForDaggerSounds[sound];
PlayALSound(alSound, pitch);
return;
}
alSound = CreateALSound(sound);
_alSoundsForDaggerSounds.Add(sound, alSound);
PlayALSound(alSound, pitch);
}
private void PlayALSound(ALSound sound, float pitch, float volume = 1.0f)
{
_al.SetSourceProperty(sound.SourceHandle, SourceFloat.Pitch, pitch);
// TODO: Add gain.
// _al.SetSourceProperty(sound.SourceHandle, SourceFloat.Gain, 0.0f);
_al.SourcePlay(sound.SourceHandle);
}
private unsafe ALSound CreateALSound(Sound sound)
{
ALSound result;
uint source = _al.GenSource();
uint buffer = _al.GenBuffer();
fixed (byte* pData = sound.Buffer)
{
BufferFormat bufferFormat = BufferFormat.Stereo16;
if (sound.Format == SoundFormat.Mono)
{
bufferFormat = BufferFormat.Mono16;
}
else if (sound.Format == SoundFormat.Stereo)
{
bufferFormat = BufferFormat.Stereo16;
}
_al.BufferData(buffer, bufferFormat, pData, sound.BufferSize, sound.BufferSize);
}
result = new ALSound(buffer, source);
_al.SetSourceProperty(source, SourceInteger.Buffer, buffer);
return result;
}
private void DeleteALSound(ALSound sound)
{
_al.DeleteSource(sound.SourceHandle);
_al.DeleteBuffer(sound.BufferHandle);
}
private Dictionary<Sound, ALSound> _alSoundsForDaggerSounds = new();
private ALContext _alc;
private AL _al;
private unsafe Device* _alDevice;
private unsafe Context* _context;
private struct ALSound
{
public uint BufferHandle { get; set; }
public uint SourceHandle { get; set; }
public ALSound(uint bufferHandle, uint sourceHandle)
{
BufferHandle = bufferHandle;
SourceHandle = sourceHandle;
}
}
}
}

View File

@@ -1,15 +1,47 @@
using StbVorbisSharp;
namespace DaggerFramework
{
public class SoundLoader : ResourceLoader<Sound>
{
public override Sound Load(string path)
{
// TODO
// var data = File.ReadAllBytes(path);
var sound = new Sound(path, new byte[] { });
sound.Path = path;
Vorbis vorbis;
Sound result;
return sound;
var fileBuffer = File.ReadAllBytes(path);
vorbis = Vorbis.FromMemory(fileBuffer);
vorbis.SubmitBuffer();
if (vorbis.Decoded == 0)
{
vorbis.Restart();
vorbis.SubmitBuffer();
}
var audioShort = vorbis.SongBuffer;
int length = vorbis.Decoded * vorbis.Channels;
byte[] audioData = new byte[length * 2];
for (int i = 0; i < length; i++)
{
if (i * 2 >= audioData.Length) break;
var b1 = (byte)(audioShort[i] >> 8);
var b2 = (byte)(audioShort[i] & 256);
audioData[i * 2] = b2;
audioData[i * 2 + 1] = b1;
}
result = new Sound(path, audioData);
result.Format = (SoundFormat)vorbis.Channels - 1;
result.SampleRate = vorbis.SampleRate;
result.BufferSize = length;
vorbis.Dispose();
return result;
}
}
}

View File

@@ -2,11 +2,18 @@ namespace DaggerFramework
{
public class Sound : Resource
{
public float PitchScale { get; set; } = 1.0f;
public float Volume { get; set; } = 1.0f;
public SoundFormat Format { get; set; }
public int SampleRate { get; set; }
public int BufferSize { get; set; }
public Sound(string path, byte[] buffer) : base(path, buffer)
{
}
}
public enum SoundFormat
{
Mono,
Stereo
}
}