Skip to content
Draft
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
5 changes: 5 additions & 0 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;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should add something in the pong sample to show using audio

using OpenTK.Windowing.Desktop;

using rasdaq.Audio;
using rasdaq.Core.ECS;
using rasdaq.Graphics;
using rasdaq.Inputs;
Expand All @@ -22,6 +24,8 @@ public sealed class Application : IDisposable
public static Application? Instance { get; private set; }
internal InputManager InputManager { get; set; }

public AudioManager AudioManager { get; private set; }

private List<World> _worlds = new();
private GameWindow _gameWindow;

Expand Down Expand Up @@ -57,6 +61,7 @@ public Application(int width, int height, string title)
_gameWindow.FramebufferResize += OnFramebufferResize;

InputManager = new InputManager(new GameWindowWrapper(_gameWindow));
AudioManager = new AudioManager();
}

internal void RegisterWorld(World world)
Expand Down
29 changes: 29 additions & 0 deletions src/rasdaq/Audio/Audio.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using OpenTK.Audio.OpenAL;

using rasdaq.Logging;

namespace rasdaq.Audio;

public class Audio : IDisposable
{
public 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);
}
}
159 changes: 159 additions & 0 deletions src/rasdaq/Audio/AudioManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
using OpenTK.Audio.OpenAL;

using rasdaq.Logging;

namespace rasdaq.Audio;

public class AudioManager
{
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);
}
}

private 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>
public 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>
public 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>
public void PlaySource(AudioSource audioSource)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it not make sense to have the Play function be directly on the AudioSource component? Then you can do something like

Entity.GetComponent().Play()

{
AL.SourcePlay(audioSource.Handle);
CheckALError();
}

/// <summary>
/// Stop playback of an audio source.
/// </summary>
/// <param name="source"></param>
public void StopSource(AudioSource audioSource)
{
AL.SourceStop(audioSource.Handle);
CheckALError();
}
}
29 changes: 29 additions & 0 deletions src/rasdaq/Audio/AudioSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using OpenTK.Audio.OpenAL;

using rasdaq.Logging;

namespace rasdaq.Audio;

public class AudioSource : IDisposable
{
public int Handle;

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

Log.Error(err);
throw new Exception("OpenAL error while trying to create audio source: " + error);
}
}

public void Dispose()
{
AL.DeleteSource(Handle);
}
}
Loading
Loading