diff --git a/DaggerFramework.csproj b/DaggerFramework.csproj
index 4bd54b8..0cef74e 100644
--- a/DaggerFramework.csproj
+++ b/DaggerFramework.csproj
@@ -10,5 +10,6 @@
+
\ No newline at end of file
diff --git a/DaggerFramework.sln b/DaggerFramework.sln
deleted file mode 100644
index bb32f59..0000000
--- a/DaggerFramework.sln
+++ /dev/null
@@ -1,14 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31903.59
-MinimumVisualStudioVersion = 10.0.40219.1
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/Source/Audio/AudioBackend.cs b/Source/Audio/AudioBackend.cs
index 38714dd..9c520e0 100644
--- a/Source/Audio/AudioBackend.cs
+++ b/Source/Audio/AudioBackend.cs
@@ -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 effect, string bus = "Master") where T : AudioEffect;
+ public void Dispose()
+ {
+ Shutdown();
+ }
+
private LehmerRandom _random = new LehmerRandom();
}
}
\ No newline at end of file
diff --git a/Source/Audio/DummyAudioBackend.cs b/Source/Audio/DummyAudioBackend.cs
index 11c7410..fdff592 100644
--- a/Source/Audio/DummyAudioBackend.cs
+++ b/Source/Audio/DummyAudioBackend.cs
@@ -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;
}
diff --git a/Source/Audio/OpenALAudioBackend.cs b/Source/Audio/OpenALAudioBackend.cs
new file mode 100644
index 0000000..d7744e9
--- /dev/null
+++ b/Source/Audio/OpenALAudioBackend.cs
@@ -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 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 _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;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Resources/Loaders/SoundLoader.cs b/Source/Resources/Loaders/SoundLoader.cs
index f5d564b..109ab50 100644
--- a/Source/Resources/Loaders/SoundLoader.cs
+++ b/Source/Resources/Loaders/SoundLoader.cs
@@ -1,15 +1,47 @@
+using StbVorbisSharp;
+
namespace DaggerFramework
{
public class SoundLoader : ResourceLoader
{
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;
}
}
}
\ No newline at end of file
diff --git a/Source/Resources/Sound.cs b/Source/Resources/Sound.cs
index 725f3bf..766d369 100644
--- a/Source/Resources/Sound.cs
+++ b/Source/Resources/Sound.cs
@@ -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
+ }
}
\ No newline at end of file
diff --git a/TestGame/Resources/sounds/test_sound.ogg b/TestGame/Resources/sounds/test_sound.ogg
new file mode 100644
index 0000000..e2d1727
Binary files /dev/null and b/TestGame/Resources/sounds/test_sound.ogg differ
diff --git a/TestGame/TestGame.cs b/TestGame/TestGame.cs
index f98c7a7..9d46673 100644
--- a/TestGame/TestGame.cs
+++ b/TestGame/TestGame.cs
@@ -1,6 +1,7 @@
using DaggerFramework;
using System.Numerics;
using DaggerFramework.Rendering;
+using DaggerFramework.Audio;
public class TestGame : Game
{
@@ -8,18 +9,26 @@ public class TestGame : Game
protected override void OnStart()
{
_renderer = new RaylibRenderer();
+ _audioBackend = new OpenALAudioBackend();
+ _inputHandler = new RaylibInputHandler();
_renderer.CreateAndInitialize(new WindowSettings()
{
Title = "Test Game",
Size = new Vector2(1280, 720)
}, RendererSettings.Default);
+ _renderer.SetTargetFps(60);
+
+ _audioBackend.Initialize();
+
+ _inputHandler.AddInputMapping("play", new InputAction[] { new KeyInputAction(KeyboardKey.Spacebar) });
}
protected override void LoadResources()
{
-
+ _soundLoader = new SoundLoader();
+ _testSound = _soundLoader.Load($"{ResourceRoot}sounds/test_sound.ogg");
}
protected override void MainLoop()
@@ -28,6 +37,12 @@ public class TestGame : Game
{
_renderer.BeginFrame();
_renderer.ClearBackground(Color.Black);
+
+ if (_inputHandler.IsActionJustPressed("play"))
+ {
+ _audioBackend.PlaySoundVariation(_testSound, default, 0.1f);
+ }
+
_renderer.SetTransform(new Vector2(640, 480));
_renderer.DrawCircle(16f, Color.Chocolate);
_renderer.EndFrame();
@@ -39,4 +54,8 @@ public class TestGame : Game
_renderer.Shutdown();
}
private Renderer _renderer;
+ private SoundLoader _soundLoader;
+ private Sound _testSound;
+ private OpenALAudioBackend _audioBackend;
+ private InputHandler _inputHandler;
}
\ No newline at end of file