-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
134 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
using Spectere.SdlKit.Interop; | ||
using Spectere.SdlKit.Interop.LibC; | ||
|
||
namespace Spectere.SdlKit; | ||
|
||
/// <summary> | ||
/// Provides a means for an application to play audio via SDL. | ||
/// </summary> | ||
public class Audio { | ||
/// <summary> | ||
/// The audio buffer that the application should fill in for us. | ||
/// </summary> | ||
private float[] _buffer = Array.Empty<float>(); | ||
|
||
/// <summary> | ||
/// A field that will point to the audio callback function in this class. | ||
/// </summary> | ||
private Interop.Sdl.Audio.SdlAudioCallback _callback; | ||
|
||
/// <summary> | ||
/// Raised when the audio subsystem is ready to receive more audio. | ||
/// </summary> | ||
public delegate void AudioRequestedEventHandler(object sender, int samplesRequested, ref float[] buffer); | ||
|
||
/// <summary> | ||
/// Raised when the audio subsystem is ready to receive more audio. | ||
/// </summary> | ||
public event AudioRequestedEventHandler? AudioRequested; | ||
|
||
/// <summary> | ||
/// If this is set to <c>true</c>, the audio buffer will be initialized to 0 when passed to the application. If | ||
/// this is <c>false</c>, the buffer will not be initialized and may contain stale data. This defaults to | ||
/// <c>false</c>. | ||
/// </summary> | ||
public bool ClearBufferOnCallback { get; set; } | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public Audio() { | ||
LibraryResolver.SetSdlKitLibraryResolver(); // Required for memset. | ||
|
||
_callback = SdlCallback; | ||
} | ||
|
||
/// <summary> | ||
/// The SDL audio callback function. | ||
/// </summary> | ||
/// <param name="userdata">Custom user data. This is not used by SdlKit.</param> | ||
/// <param name="stream">A pointer to the audio stream that should be filled by the application.</param> | ||
/// <param name="len">The amount of data to fill the stream with, in bytes.</param> | ||
private unsafe void SdlCallback(IntPtr userdata, IntPtr stream, int len) { | ||
if(AudioRequested is null) { | ||
// No subscriber. Fill the stream with silence. | ||
CMemory.Memset(stream.ToPointer(), 0, (nuint)len); | ||
return; | ||
} | ||
|
||
var samples = 0; // TODO: Get the number of samples that need filled. Resize the buffer array if necessary. | ||
AudioRequested(this, samples, ref _buffer); | ||
|
||
// TODO: Convert the audio stream from float to the desired format, then copy to 'stream'. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System.Runtime.InteropServices; | ||
|
||
namespace Spectere.SdlKit.Interop.LibC; | ||
|
||
/// <summary> | ||
/// Contains C library functions related to memory. | ||
/// </summary> | ||
internal class CMemory { | ||
/// <summary> | ||
/// Fill memory with a constant byte. | ||
/// </summary> | ||
/// <param name="s">A pointer to the memory area to fill.</param> | ||
/// <param name="c">The character to fill the block of memory with.</param> | ||
/// <param name="n">The number of bytes to fill.</param> | ||
/// <returns>A pointer to the memory area <paramref name="s"/>.</returns> | ||
// Possible caveat: nuint isn't always equal to size_t. | ||
[DllImport(Lib.LibC, EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl)] | ||
internal static extern unsafe void* Memset(void* s, int c, nuint n); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
using System.Reflection; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace Spectere.SdlKit.Interop; | ||
|
||
/// <summary> | ||
/// Contains helper methods related to native library resolution. | ||
/// </summary> | ||
internal static class LibraryResolver { | ||
/// <summary> | ||
/// If this is <c>true</c>, the custom resolver has already been set. Future calls to | ||
/// <see cref="SetSdlKitLibraryResolver"/> will immediately return. | ||
/// </summary> | ||
private static bool _resolverSet; | ||
|
||
/// <summary> | ||
/// Configures the .NET runtime to use SDLKit's native library resolver. This must be called prior to calling any | ||
/// native functions that are marked as requiring this resolver. | ||
/// </summary> | ||
internal static void SetSdlKitLibraryResolver() { | ||
if(_resolverSet) { | ||
return; | ||
} | ||
|
||
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), SdlKitDllImportResolver); | ||
_resolverSet = true; | ||
} | ||
|
||
/// <summary> | ||
/// SDLKit's custom DllImport resolver. This is required to handle cases where required libraries are named | ||
/// differently on different operating systems (for example, the C runtime being called "msvcrt" on Windows and | ||
/// "libc" on Linux/Unix systems. | ||
/// </summary> | ||
/// <param name="libraryName">The name of the native library to load.</param> | ||
/// <param name="assembly">The assembly loading the native library.</param> | ||
/// <param name="searchPath">The search path.</param> | ||
/// <returns>The OS handle for the loaded library.</returns> | ||
private static IntPtr SdlKitDllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) { | ||
if(libraryName == "c") { | ||
// libc is "msvcrt" on Windows. | ||
if(OperatingSystem.IsWindows()) { | ||
return NativeLibrary.Load("msvcrt", assembly, searchPath); | ||
} | ||
} | ||
|
||
// Fall back to the default resolver. | ||
return IntPtr.Zero; | ||
} | ||
} |