Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
"source.fixAll.dotnet": "explicit"
},
"[csharp]": {
"editor.defaultFormatter": "ms-dotnettools.csharp"
"editor.defaultFormatter": "csharpier.csharpier-vscode"
}
}
1 change: 1 addition & 0 deletions samples/pong/Game.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using rasdaq;
using rasdaq.Audio;
using rasdaq.Core.ECS;
using rasdaq.Graphics;
using rasdaq.Resources;
Expand Down
29 changes: 27 additions & 2 deletions samples/pong/Soldier.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
using rasdaq;
using OpenTK.Audio.OpenAL;
using rasdaq;
using rasdaq.Audio;
using rasdaq.Core.ECS;
using rasdaq.Graphics;
using rasdaq.Inputs;
using rasdaq.Logging;
using rasdaq.Resources;
using rasdaq.Transformations;

namespace pong;

internal class Soldier : Component
{
AudioSource _audioSource;

public override void Start()
{
base.Start();

Audio audio1 = ResourceManager.Load<Audio>("assets/laser.wav");
AudioSource source = new();
// source.Handle = audio1.Handle;
source.SetAudio(audio1);
_audioSource = source;
Entity.AddComponent(source);
}

public override void Update(double deltaTime)
{
base.Update(deltaTime);

}

public override void FrameUpdate(double deltaTime)
Expand All @@ -29,6 +40,16 @@ public override void FrameUpdate(double deltaTime)
Entity.Transform.RotateFromPoint(new Vector2(800, 200), 90);
}

if (Input.IsKeyPressed(Keys.Space))
{
_audioSource.Play();
}

if (Input.IsKeyPressed(Keys.LeftShift))
{
_audioSource.Stop();
}

PhysicsBody? body = Entity?.GetComponent<PhysicsBody>();

if (Input.IsKeyDown(Keys.W))
Expand Down Expand Up @@ -70,6 +91,10 @@ public override void FrameUpdate(double deltaTime)
var x = Entity?.Transform.position.X - (Application.WindowSize?.X / 2) ?? 0;
var y = Entity?.Transform.position.Y - (Application.WindowSize?.Y / 2) ?? 0;
Renderer.Instance.Camera.SetPosition(x, y);
if (Input.IsKeyDown(Keys.W))
{
ALContext context = ALC.GetCurrentContext();
Comment thread
Thrill12 marked this conversation as resolved.
}
}
}
}
Binary file added samples/pong/assets/laser.wav
Binary file not shown.
15 changes: 10 additions & 5 deletions src/rasdaq/Application.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using OpenTK.Graphics.OpenGL4;
using OpenTK.Windowing.Common;
Comment thread
Thrill12 marked this conversation as resolved.
using OpenTK.Windowing.Desktop;

using rasdaq.Audio;
using rasdaq.Core.ECS;
using rasdaq.Graphics;
using rasdaq.Inputs;
Expand All @@ -20,17 +22,13 @@ public class Application : IDisposable
/// <summary>
/// The <c>Application</c> instance is created after <c>Run</c> is called.
/// </summary>
private static Application? _instance;
public static Application Instance
{
get => _instance ?? throw new InvalidOperationException("Application not started. Call Run() first.");
private set => _instance = value;
}
private static Application? _instance;
public static Vector2? WindowSize => Instance._gameWindow?.Size;
/// <summary>
/// Return list of instantiated <c>Worlds</c>.
/// </summary>
public List<World> Worlds => _worlds.Objects;

private InputManager? _inputManager;
internal InputManager InputManager
Expand All @@ -39,7 +37,13 @@ internal InputManager InputManager
private set => _inputManager = value;
}

public AudioManager AudioManager { get; private set; }

private FlushEnumerable<World> _worlds = new();
/// <summary>
/// Return list of instantiated <c>Worlds</c>.
/// </summary>
public List<World> Worlds => _worlds.Objects;

private GameWindow? _gameWindow;
internal GameWindow GameWindow
Expand Down Expand Up @@ -86,6 +90,7 @@ public void Run(int width, int height, string title)
GameWindow.FramebufferResize += OnFramebufferResize;

InputManager = new InputManager(new GameWindowWrapper(GameWindow));
AudioManager = new AudioManager();

InputManager.SetEventListeners();
GameWindow.Run();
Expand Down
28 changes: 28 additions & 0 deletions src/rasdaq/Audio/Audio.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using OpenTK.Audio.OpenAL;
using rasdaq.Logging;

namespace rasdaq.Audio;

public class Audio : IDisposable
{
internal int Handle;

public Audio()
{
Handle = AL.GenBuffer();
// Check for errors
ALError error = AL.GetError();
if (error != ALError.NoError)
{
string err = $"OpenAL error while trying to create audio buffer: {error}";

Log.Error(err);
throw new Exception(err);
}
}

public void Dispose()
{
AL.DeleteBuffer(Handle);
}
}
13 changes: 13 additions & 0 deletions src/rasdaq/Audio/AudioLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using OpenTK.Audio.OpenAL;
using rasdaq.Logging;
using rasdaq.Resources;

namespace rasdaq.Audio;

public class AudioLoader : IResourceLoader
{
public object Load(string path)
{
return AudioManager.Instance.LoadAudio(path);
}
}
176 changes: 176 additions & 0 deletions src/rasdaq/Audio/AudioManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
using OpenTK.Audio.OpenAL;
using rasdaq.Logging;

namespace rasdaq.Audio;

public class AudioManager
{
public static AudioManager Instance
{
get
{
if (_instance == null)
{
_instance = new();
}

return _instance;
}
}

private static AudioManager _instance;

private static void CheckALCError(ALDevice device)
{
AlcError error = ALC.GetError(device);
if (error != AlcError.NoError)
{
string err = $"OpenAL error: {error}";
Log.Error(err);
throw new Exception(err);
}
}

public static void CheckALError()
{
ALError error = AL.GetError();
if (error != ALError.NoError)
{
string err = $"OpenAL error: {error}";
Log.Error(err);
throw new Exception(err);
}
}

/// <summary>
/// Initialize Audio for the Application, using the default audio device.
/// </summary>
/// <exception cref="Exception"></exception>
public AudioManager()
{
// Open the default audio device.
ALDevice device = ALC.OpenDevice(null);
if (device == ALDevice.Null)
{
string err = "Failed to open the default audio device.";
Log.Error(err);
throw new Exception(err);
}

// Create a context for the device.
ALContext context = ALC.CreateContext(
device,
new ALContextAttributes(null, null, null, null, null)
);
if (context == ALContext.Null)
{
ALC.CloseDevice(device);
string err = "Failed to create an OpenAL context.";
Log.Error(err);
throw new Exception(err);
}

// Check if we have any errors.
AlcError error = ALC.GetError(device);
CheckALCError(device);
// If no errors, make the context current.
ALC.MakeContextCurrent(context);
}

/// <summary>
/// Load a WAV file that contains PCM data only.
/// </summary>
/// <param name="path">Path to WAV file</param>
/// <returns>A integer handle referring to the loaded audio</returns>
/// <exception cref="Exception"></exception>
internal Audio LoadAudio(string path)
{
// Create an OpenAL buffer for the data to go in.
Audio audio = new Audio();

// Load the WAV file
WAVLoader.WAVData wavData = WAVLoader.LoadWav(path);

// Discern the format of the audio data based on number of channels and bits per sample.
ALFormat format;
if (wavData.Format.NumChannels == 1)
{
if (wavData.Format.BitsPerSample == 8)
{
format = ALFormat.Mono8;
}
else if (wavData.Format.BitsPerSample == 16)
{
format = ALFormat.Mono16;
}
else
{
string err = $"Unsupported bits per sample: {wavData.Format.BitsPerSample}";
Log.Error(err);
throw new Exception(err);
}
}
else if (wavData.Format.NumChannels == 2)
{
if (wavData.Format.BitsPerSample == 8)
{
format = ALFormat.Stereo8;
}
else if (wavData.Format.BitsPerSample == 16)
{
format = ALFormat.Stereo16;
}
else
{
string err = $"Unsupported bits per sample: {wavData.Format.BitsPerSample}";
Log.Error(err);
throw new Exception(err);
}
}
else
{
string err = $"Unsupported number of channels: {wavData.Format.NumChannels}";
Log.Error(err);
throw new Exception(err);
}

// Load the audio data into the OpenAL buffer.
AL.BufferData(audio.Handle, format, wavData.Data.Data, (int)wavData.Format.SampleRate);

// Check if we have any errors from trying to load the audio data.
CheckALError();

return audio;
}

/// <summary>
/// Add a loaded audio file to an audio source, so that it can be played.
/// </summary>
/// <param name="audio">Audio file</param>
/// <param name="audioSource">Audio source</param>
internal void AttachAudioToSource(Audio audio, AudioSource audioSource)
{
AL.Source(audioSource.Handle, ALSourcei.Buffer, audio.Handle);
CheckALError();
}

/// <summary>
/// Play back an audio source that has audio attached to it.
/// </summary>
/// <param name="source"></param>
internal void PlaySource(AudioSource audioSource)
{
AL.SourcePlay(audioSource.Handle);
CheckALError();
}

/// <summary>
/// Stop playback of an audio source.
/// </summary>
/// <param name="source"></param>
internal void StopSource(AudioSource audioSource)
{
AL.SourceStop(audioSource.Handle);
CheckALError();
}
}
Loading