diff --git a/TestGame/Resources/sounds/test_sound_mono.ogg b/TestGame/Resources/sounds/test_sound_mono.ogg new file mode 100644 index 0000000..0ac7c52 Binary files /dev/null and b/TestGame/Resources/sounds/test_sound_mono.ogg differ diff --git a/TestGame/TestGame.cs b/TestGame/TestGame.cs index 803edf1..12d2478 100644 --- a/TestGame/TestGame.cs +++ b/TestGame/TestGame.cs @@ -34,6 +34,7 @@ public class TestGame : Game } ResourceManager.TryLoad("icon.png", out _icon); + ResourceManager.TryLoad("sounds/test_sound_mono.ogg", out _sound); if (!ResourceManager.TryLoad("fire_effect.toml", out _fireEffect)) { @@ -52,8 +53,9 @@ public class TestGame : Game { if (Input.IsActionPressed("reload")) { - ResourceManager.Reload(); - _particleSystem!.RestartEmitter(_emitterId); + // ResourceManager.Reload(); + // _particleSystem!.RestartEmitter(_emitterId); + AudioSystem.PlaySound(_sound.Value); } if (Input.KeyboardKeyJustPressed(KeyboardKey.One)) @@ -106,5 +108,6 @@ public class TestGame : Game private int _emitterId; private ResourceRef _fireEffect; private ResourceRef _font; + private ResourceRef _sound; private ResourceRef _icon; } \ No newline at end of file diff --git a/Voile/Source/Audio/AudioBus.cs b/Voile/Source/Audio/AudioBus.cs deleted file mode 100644 index c27fded..0000000 --- a/Voile/Source/Audio/AudioBus.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Voile -{ - public class AudioBus - { - - } -} \ No newline at end of file diff --git a/Voile/Source/Audio/AudioEffect.cs b/Voile/Source/Audio/AudioEffect.cs deleted file mode 100644 index 8deec24..0000000 --- a/Voile/Source/Audio/AudioEffect.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Voile -{ - public class AudioEffect { } - - public class AudioEffectReverb : AudioEffect - { - - } -} \ No newline at end of file diff --git a/Voile/Source/Audio/AudioSystem.cs b/Voile/Source/Audio/AudioSystem.cs index 3195ea4..e0d3eda 100644 --- a/Voile/Source/Audio/AudioSystem.cs +++ b/Voile/Source/Audio/AudioSystem.cs @@ -22,7 +22,6 @@ public abstract class AudioSystem : IStartableSystem, IUpdatableSystem, IDisposa public abstract void SetBusVolume(string busName, float volume); public abstract float GetBusVolume(string busName); - // SOUND public abstract void PlaySound(Sound sound, float pitch, float volume, string bus = "Master"); public void PlaySound(Sound sound, string bus = "Master") => PlaySound(sound, 1.0f, 1.0f, bus); @@ -32,9 +31,6 @@ public abstract class AudioSystem : IStartableSystem, IUpdatableSystem, IDisposa return instance; } - // EFFECTS - public abstract void AddBusEffect(T effect, string bus = "Master") where T : AudioEffect; - private LehmerRandom _random = new LehmerRandom(); } \ No newline at end of file diff --git a/Voile/Source/Audio/DummyAudioSystem.cs b/Voile/Source/Audio/DummyAudioSystem.cs index f7b1d21..323b0e4 100644 --- a/Voile/Source/Audio/DummyAudioSystem.cs +++ b/Voile/Source/Audio/DummyAudioSystem.cs @@ -5,11 +5,6 @@ namespace Voile.Audio /// public class DummyAudioSystem : AudioSystem { - public override void AddBusEffect(T effect, string bus = "Master") - { - return; - } - public override void CreateBus(string busName) { return; diff --git a/Voile/Source/Audio/StandardAudioSystem.cs b/Voile/Source/Audio/StandardAudioSystem.cs new file mode 100644 index 0000000..e99209a --- /dev/null +++ b/Voile/Source/Audio/StandardAudioSystem.cs @@ -0,0 +1,64 @@ +using System.Runtime.CompilerServices; +using Raylib_cs; +using SoLoud; + +namespace Voile.Audio; + +public class StandardAudioSystem : AudioSystem +{ + public StandardAudioSystem() + { + _engine = new Soloud(); + } + protected override void Initialize() + { + _engine.init(); + } + + public override void CreateBus(string busName) + { + throw new NotImplementedException(); + } + + public override float GetBusVolume(string busName) + { + throw new NotImplementedException(); + } + + public override void PlaySound(Sound sound, float pitch, float volume, string bus = "Master") + { + PlayUnsafe(sound.Buffer, sound.BufferSize, sound.SampleRate, sound.Channel); + } + + public override void SetBusVolume(string busName, float volume) + { + throw new NotImplementedException(); + } + + protected override void Shutdown() + { + _engine!.deinit(); + } + + protected override void Update() + { + + } + + private void PlayUnsafe(ReadOnlyMemory soundBuffer, long length, int sampleRate, SoundChannel channels) + { + var wav = new Wav(); + + int channelCount = channels == SoundChannel.Stereo ? 2 : 1; + + unsafe + { + nint ptr = (nint)soundBuffer.Pin().Pointer; + wav.loadRawWave16(ptr, (uint)length, sampleRate, (uint)channelCount); + } + + _engine.play(wav); + } + + private Soloud _engine; +} \ No newline at end of file diff --git a/Voile/Source/Game.cs b/Voile/Source/Game.cs index b4b4102..4599f06 100644 --- a/Voile/Source/Game.cs +++ b/Voile/Source/Game.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Voile.Audio; using Voile.Input; using Voile.Rendering; using Voile.Resources; @@ -42,6 +43,8 @@ namespace Voile /// protected RenderSystem? Renderer { get; set; } + protected AudioSystem? AudioSystem { get; set; } + /// /// Name of this game. Also used as a default window title. /// @@ -113,6 +116,13 @@ namespace Voile Input = new RaylibInputSystem(); } + if (AudioSystem is null) + { + AudioSystem = new StandardAudioSystem(); + } + + AudioSystem.Start(); + Input.Start(); InitializeRenderer(); } @@ -121,6 +131,7 @@ namespace Voile { Input?.Dispose(); Renderer?.Dispose(); + AudioSystem?.Dispose(); ResourceManager.Dispose(); } diff --git a/Voile/Source/Resources/Loaders/SoundLoader.cs b/Voile/Source/Resources/Loaders/SoundLoader.cs index 1729d4e..56e92f7 100644 --- a/Voile/Source/Resources/Loaders/SoundLoader.cs +++ b/Voile/Source/Resources/Loaders/SoundLoader.cs @@ -1,4 +1,5 @@ using StbVorbisSharp; +using Voile.VFS; namespace Voile.Resources { @@ -6,7 +7,7 @@ namespace Voile.Resources { public override IEnumerable SupportedExtensions => new string[] { - "ogg" + ".ogg" }; protected override Sound LoadResource(string path) @@ -14,9 +15,11 @@ namespace Voile.Resources Vorbis vorbis; Sound result; - var fileBuffer = File.ReadAllBytes(path); - vorbis = Vorbis.FromMemory(fileBuffer); + using var stream = VirtualFileSystem.Read(path); + byte[] fileBuffer = new byte[stream.Length]; + int bytesRead = stream.Read(fileBuffer, 0, fileBuffer.Length); + vorbis = Vorbis.FromMemory(fileBuffer); vorbis.SubmitBuffer(); if (vorbis.Decoded == 0) @@ -27,18 +30,9 @@ namespace Voile.Resources 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; - } + short[] audioData = new short[length]; + Array.Copy(audioShort, audioData, length); result = new Sound(path, audioData) { diff --git a/Voile/Source/Resources/Sound.cs b/Voile/Source/Resources/Sound.cs index f3433c5..cd18555 100644 --- a/Voile/Source/Resources/Sound.cs +++ b/Voile/Source/Resources/Sound.cs @@ -1,17 +1,17 @@ namespace Voile { /// - /// Represents raw audio samples. + /// Represents raw audio samples in 16-bit PCM format. /// public class Sound : Resource { public SoundChannel Channel { get; set; } public int SampleRate { get; set; } - public byte[]? Buffer { get; private set; } + public short[]? Buffer { get; private set; } public long BufferSize { get; set; } - public Sound(string path, byte[] buffer) : base(path) + public Sound(string path, short[] buffer) : base(path) { Buffer = buffer; }