WIP: SoLoud audio system, make Sound be in 16-bit PCM.

This commit is contained in:
2024-10-28 23:13:14 +01:00
parent 99624e152d
commit e51d28ce89
10 changed files with 91 additions and 44 deletions

Binary file not shown.

View File

@@ -34,6 +34,7 @@ public class TestGame : Game
} }
ResourceManager.TryLoad("icon.png", out _icon); ResourceManager.TryLoad("icon.png", out _icon);
ResourceManager.TryLoad("sounds/test_sound_mono.ogg", out _sound);
if (!ResourceManager.TryLoad("fire_effect.toml", out _fireEffect)) if (!ResourceManager.TryLoad("fire_effect.toml", out _fireEffect))
{ {
@@ -52,8 +53,9 @@ public class TestGame : Game
{ {
if (Input.IsActionPressed("reload")) if (Input.IsActionPressed("reload"))
{ {
ResourceManager.Reload(); // ResourceManager.Reload();
_particleSystem!.RestartEmitter(_emitterId); // _particleSystem!.RestartEmitter(_emitterId);
AudioSystem.PlaySound(_sound.Value);
} }
if (Input.KeyboardKeyJustPressed(KeyboardKey.One)) if (Input.KeyboardKeyJustPressed(KeyboardKey.One))
@@ -106,5 +108,6 @@ public class TestGame : Game
private int _emitterId; private int _emitterId;
private ResourceRef<ParticleEmitterSettingsResource> _fireEffect; private ResourceRef<ParticleEmitterSettingsResource> _fireEffect;
private ResourceRef<Font> _font; private ResourceRef<Font> _font;
private ResourceRef<Sound> _sound;
private ResourceRef<Texture2d> _icon; private ResourceRef<Texture2d> _icon;
} }

View File

@@ -1,7 +0,0 @@
namespace Voile
{
public class AudioBus
{
}
}

View File

@@ -1,9 +0,0 @@
namespace Voile
{
public class AudioEffect { }
public class AudioEffectReverb : AudioEffect
{
}
}

View File

@@ -22,7 +22,6 @@ public abstract class AudioSystem : IStartableSystem, IUpdatableSystem, IDisposa
public abstract void SetBusVolume(string busName, float volume); public abstract void SetBusVolume(string busName, float volume);
public abstract float GetBusVolume(string busName); public abstract float GetBusVolume(string busName);
// SOUND
public abstract void PlaySound(Sound sound, float pitch, float volume, string bus = "Master"); 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); 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; return instance;
} }
// EFFECTS
public abstract void AddBusEffect<T>(T effect, string bus = "Master") where T : AudioEffect;
private LehmerRandom _random = new LehmerRandom(); private LehmerRandom _random = new LehmerRandom();
} }

View File

@@ -5,11 +5,6 @@ namespace Voile.Audio
/// </summary> /// </summary>
public class DummyAudioSystem : AudioSystem public class DummyAudioSystem : AudioSystem
{ {
public override void AddBusEffect<T>(T effect, string bus = "Master")
{
return;
}
public override void CreateBus(string busName) public override void CreateBus(string busName)
{ {
return; return;

View File

@@ -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<short> 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;
}

View File

@@ -1,5 +1,6 @@
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Voile.Audio;
using Voile.Input; using Voile.Input;
using Voile.Rendering; using Voile.Rendering;
using Voile.Resources; using Voile.Resources;
@@ -42,6 +43,8 @@ namespace Voile
/// </summary> /// </summary>
protected RenderSystem? Renderer { get; set; } protected RenderSystem? Renderer { get; set; }
protected AudioSystem? AudioSystem { get; set; }
/// <summary> /// <summary>
/// Name of this game. Also used as a default window title. /// Name of this game. Also used as a default window title.
/// </summary> /// </summary>
@@ -113,6 +116,13 @@ namespace Voile
Input = new RaylibInputSystem(); Input = new RaylibInputSystem();
} }
if (AudioSystem is null)
{
AudioSystem = new StandardAudioSystem();
}
AudioSystem.Start();
Input.Start(); Input.Start();
InitializeRenderer(); InitializeRenderer();
} }
@@ -121,6 +131,7 @@ namespace Voile
{ {
Input?.Dispose(); Input?.Dispose();
Renderer?.Dispose(); Renderer?.Dispose();
AudioSystem?.Dispose();
ResourceManager.Dispose(); ResourceManager.Dispose();
} }

View File

@@ -1,4 +1,5 @@
using StbVorbisSharp; using StbVorbisSharp;
using Voile.VFS;
namespace Voile.Resources namespace Voile.Resources
{ {
@@ -6,7 +7,7 @@ namespace Voile.Resources
{ {
public override IEnumerable<string> SupportedExtensions => new string[] public override IEnumerable<string> SupportedExtensions => new string[]
{ {
"ogg" ".ogg"
}; };
protected override Sound LoadResource(string path) protected override Sound LoadResource(string path)
@@ -14,9 +15,11 @@ namespace Voile.Resources
Vorbis vorbis; Vorbis vorbis;
Sound result; Sound result;
var fileBuffer = File.ReadAllBytes(path); using var stream = VirtualFileSystem.Read(path);
vorbis = Vorbis.FromMemory(fileBuffer); byte[] fileBuffer = new byte[stream.Length];
int bytesRead = stream.Read(fileBuffer, 0, fileBuffer.Length);
vorbis = Vorbis.FromMemory(fileBuffer);
vorbis.SubmitBuffer(); vorbis.SubmitBuffer();
if (vorbis.Decoded == 0) if (vorbis.Decoded == 0)
@@ -27,18 +30,9 @@ namespace Voile.Resources
var audioShort = vorbis.SongBuffer; var audioShort = vorbis.SongBuffer;
int length = vorbis.Decoded * vorbis.Channels; int length = vorbis.Decoded * vorbis.Channels;
byte[] audioData = new byte[length * 2];
for (int i = 0; i < length; i++) short[] audioData = new short[length];
{ Array.Copy(audioShort, audioData, length);
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 = new Sound(path, audioData)
{ {

View File

@@ -1,17 +1,17 @@
namespace Voile namespace Voile
{ {
/// <summary> /// <summary>
/// Represents raw audio samples. /// Represents raw audio samples in 16-bit PCM format.
/// </summary> /// </summary>
public class Sound : Resource public class Sound : Resource
{ {
public SoundChannel Channel { get; set; } public SoundChannel Channel { get; set; }
public int SampleRate { 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 long BufferSize { get; set; }
public Sound(string path, byte[] buffer) : base(path) public Sound(string path, short[] buffer) : base(path)
{ {
Buffer = buffer; Buffer = buffer;
} }