aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Audio.Backends.SoundIo/Native/libsoundio')
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs38
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs386
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs13
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs30
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs34
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs75
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs116
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs267
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs8
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs10
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs25
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs293
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs331
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs58
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs15
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.dllbin0 -> 85504 bytes
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.dylibbin0 -> 54976 bytes
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.sobin0 -> 88584 bytes
-rw-r--r--Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs643
19 files changed, 2342 insertions, 0 deletions
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs
new file mode 100644
index 00000000..5e86263e
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public static class MarshalEx
+ {
+ public static double ReadDouble(IntPtr handle, int offset = 0)
+ {
+ return BitConverter.Int64BitsToDouble(Marshal.ReadInt64(handle, offset));
+ }
+
+ public static void WriteDouble(IntPtr handle, double value)
+ {
+ WriteDouble(handle, 0, value);
+ }
+
+ public static void WriteDouble(IntPtr handle, int offset, double value)
+ {
+ Marshal.WriteInt64(handle, offset, BitConverter.DoubleToInt64Bits(value));
+ }
+
+ public static float ReadFloat(IntPtr handle, int offset = 0)
+ {
+ return BitConverter.Int32BitsToSingle(Marshal.ReadInt32(handle, offset));
+ }
+
+ public static void WriteFloat(IntPtr handle, float value)
+ {
+ WriteFloat(handle, 0, value);
+ }
+
+ public static void WriteFloat(IntPtr handle, int offset, float value)
+ {
+ Marshal.WriteInt32(handle, offset, BitConverter.SingleToInt32Bits(value));
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs
new file mode 100644
index 00000000..c4ce1887
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs
@@ -0,0 +1,386 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public class SoundIO : IDisposable
+ {
+ Pointer<SoundIo> handle;
+
+ public SoundIO()
+ {
+ handle = Natives.soundio_create();
+ }
+
+ internal SoundIO(Pointer<SoundIo> handle)
+ {
+ this.handle = handle;
+ }
+
+ public void Dispose ()
+ {
+ foreach (var h in allocated_hglobals)
+ {
+ Marshal.FreeHGlobal(h);
+ }
+
+ Natives.soundio_destroy(handle);
+ }
+
+ // Equality (based on handle)
+
+ public override bool Equals(object other)
+ {
+ var d = other as SoundIO;
+
+ return d != null && this.handle == d.handle;
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)(IntPtr)handle;
+ }
+
+ public static bool operator == (SoundIO obj1, SoundIO obj2)
+ {
+ return obj1 is null ? obj2 is null : obj1.Equals(obj2);
+ }
+
+ public static bool operator != (SoundIO obj1, SoundIO obj2)
+ {
+ return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
+ }
+
+ // fields
+
+ // FIXME: this should be taken care in more centralized/decent manner... we don't want to write
+ // this kind of code anywhere we need string marshaling.
+ List<IntPtr> allocated_hglobals = new List<IntPtr>();
+
+ public string ApplicationName {
+ get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, app_name_offset)); }
+ set
+ {
+ unsafe
+ {
+ var existing = Marshal.ReadIntPtr(handle, app_name_offset);
+ if (allocated_hglobals.Contains (existing))
+ {
+ allocated_hglobals.Remove(existing);
+ Marshal.FreeHGlobal(existing);
+ }
+
+ var ptr = Marshal.StringToHGlobalAnsi(value);
+ Marshal.WriteIntPtr(handle, app_name_offset, ptr);
+ allocated_hglobals.Add(ptr);
+ }
+ }
+ }
+
+ static readonly int app_name_offset = (int)Marshal.OffsetOf<SoundIo>("app_name");
+
+ public SoundIOBackend CurrentBackend
+ {
+ get { return (SoundIOBackend)Marshal.ReadInt32(handle, current_backend_offset); }
+ }
+
+ static readonly int current_backend_offset = (int)Marshal.OffsetOf<SoundIo>("current_backend");
+
+ // emit_rtprio_warning
+ public Action EmitRealtimePriorityWarning
+ {
+ get { return emit_rtprio_warning; }
+ set
+ {
+ emit_rtprio_warning = value;
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change);
+
+ Marshal.WriteIntPtr(handle, emit_rtprio_warning_offset, ptr);
+ }
+ }
+
+ static readonly int emit_rtprio_warning_offset = (int)Marshal.OffsetOf<SoundIo>("emit_rtprio_warning");
+
+ Action emit_rtprio_warning;
+
+ // jack_error_callback
+ public Action<string> JackErrorCallback
+ {
+ get { return jack_error_callback; }
+ set
+ {
+ jack_error_callback = value;
+ if (value == null)
+ {
+ jack_error_callback = null;
+ }
+ else
+ {
+ jack_error_callback_native = msg => jack_error_callback(msg);
+ }
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(jack_error_callback_native);
+ Marshal.WriteIntPtr(handle, jack_error_callback_offset, ptr);
+ }
+ }
+
+ static readonly int jack_error_callback_offset = (int)Marshal.OffsetOf<SoundIo>("jack_error_callback");
+
+ Action<string> jack_error_callback;
+ delegate void jack_error_delegate(string message);
+ jack_error_delegate jack_error_callback_native;
+
+ // jack_info_callback
+ public Action<string> JackInfoCallback
+ {
+ get { return jack_info_callback; }
+ set
+ {
+ jack_info_callback = value;
+ if (value == null)
+ {
+ jack_info_callback = null;
+ }
+ else
+ {
+ jack_info_callback_native = msg => jack_info_callback(msg);
+ }
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(jack_info_callback_native);
+ Marshal.WriteIntPtr(handle, jack_info_callback_offset, ptr);
+ }
+ }
+
+ static readonly int jack_info_callback_offset = (int)Marshal.OffsetOf<SoundIo>("jack_info_callback");
+
+ Action<string> jack_info_callback;
+ delegate void jack_info_delegate(string message);
+ jack_info_delegate jack_info_callback_native;
+
+ // on_backend_disconnect
+ public Action<int> OnBackendDisconnect
+ {
+ get { return on_backend_disconnect; }
+ set
+ {
+ on_backend_disconnect = value;
+ if (value == null)
+ {
+ on_backend_disconnect_native = null;
+ }
+ else
+ {
+ on_backend_disconnect_native = (sio, err) => on_backend_disconnect(err);
+ }
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(on_backend_disconnect_native);
+ Marshal.WriteIntPtr(handle, on_backend_disconnect_offset, ptr);
+ }
+ }
+
+ static readonly int on_backend_disconnect_offset = (int)Marshal.OffsetOf<SoundIo>("on_backend_disconnect");
+
+ Action<int> on_backend_disconnect;
+ delegate void on_backend_disconnect_delegate(IntPtr handle, int errorCode);
+ on_backend_disconnect_delegate on_backend_disconnect_native;
+
+ // on_devices_change
+ public Action OnDevicesChange
+ {
+ get { return on_devices_change; }
+ set
+ {
+ on_devices_change = value;
+ if (value == null)
+ {
+ on_devices_change_native = null;
+ }
+ else
+ {
+ on_devices_change_native = sio => on_devices_change();
+ }
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change_native);
+ Marshal.WriteIntPtr(handle, on_devices_change_offset, ptr);
+ }
+ }
+
+ static readonly int on_devices_change_offset = (int)Marshal.OffsetOf<SoundIo>("on_devices_change");
+
+ Action on_devices_change;
+ delegate void on_devices_change_delegate(IntPtr handle);
+ on_devices_change_delegate on_devices_change_native;
+
+ // on_events_signal
+ public Action OnEventsSignal
+ {
+ get { return on_events_signal; }
+ set
+ {
+ on_events_signal = value;
+ if (value == null)
+ {
+ on_events_signal_native = null;
+ }
+ else
+ {
+ on_events_signal_native = sio => on_events_signal();
+ }
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(on_events_signal_native);
+ Marshal.WriteIntPtr(handle, on_events_signal_offset, ptr);
+ }
+ }
+
+ static readonly int on_events_signal_offset = (int)Marshal.OffsetOf<SoundIo>("on_events_signal");
+
+ Action on_events_signal;
+ delegate void on_events_signal_delegate(IntPtr handle);
+ on_events_signal_delegate on_events_signal_native;
+
+
+ // functions
+
+ public int BackendCount
+ {
+ get { return Natives.soundio_backend_count(handle); }
+ }
+
+ public int InputDeviceCount
+ {
+ get { return Natives.soundio_input_device_count(handle); }
+ }
+
+ public int OutputDeviceCount
+ {
+ get { return Natives.soundio_output_device_count(handle); }
+ }
+
+ public int DefaultInputDeviceIndex
+ {
+ get { return Natives.soundio_default_input_device_index(handle); }
+ }
+
+ public int DefaultOutputDeviceIndex
+ {
+ get { return Natives.soundio_default_output_device_index(handle); }
+ }
+
+ public SoundIOBackend GetBackend(int index)
+ {
+ return (SoundIOBackend)Natives.soundio_get_backend(handle, index);
+ }
+
+ public SoundIODevice GetInputDevice(int index)
+ {
+ return new SoundIODevice(Natives.soundio_get_input_device(handle, index));
+ }
+
+ public SoundIODevice GetOutputDevice(int index)
+ {
+ return new SoundIODevice(Natives.soundio_get_output_device(handle, index));
+ }
+
+ public void Connect()
+ {
+ var ret = (SoundIoError)Natives.soundio_connect(handle);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public void ConnectBackend(SoundIOBackend backend)
+ {
+ var ret = (SoundIoError)Natives.soundio_connect_backend(handle, (SoundIoBackend)backend);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public void Disconnect()
+ {
+ Natives.soundio_disconnect(handle);
+ }
+
+ public void FlushEvents()
+ {
+ Natives.soundio_flush_events(handle);
+ }
+
+ public void WaitEvents()
+ {
+ Natives.soundio_wait_events(handle);
+ }
+
+ public void Wakeup()
+ {
+ Natives.soundio_wakeup(handle);
+ }
+
+ public void ForceDeviceScan()
+ {
+ Natives.soundio_force_device_scan(handle);
+ }
+
+ public SoundIORingBuffer CreateRingBuffer(int capacity)
+ {
+ return new SoundIORingBuffer(Natives.soundio_ring_buffer_create(handle, capacity));
+ }
+
+ // static methods
+
+ public static string VersionString
+ {
+ get { return Marshal.PtrToStringAnsi(Natives.soundio_version_string()); }
+ }
+
+ public static int VersionMajor
+ {
+ get { return Natives.soundio_version_major(); }
+ }
+
+ public static int VersionMinor
+ {
+ get { return Natives.soundio_version_minor(); }
+ }
+
+ public static int VersionPatch
+ {
+ get { return Natives.soundio_version_patch(); }
+ }
+
+ public static string GetBackendName(SoundIOBackend backend)
+ {
+ return Marshal.PtrToStringAnsi(Natives.soundio_backend_name((SoundIoBackend)backend));
+ }
+
+ public static bool HaveBackend(SoundIOBackend backend)
+ {
+ return Natives.soundio_have_backend((SoundIoBackend)backend);
+ }
+
+ public static int GetBytesPerSample(SoundIOFormat format)
+ {
+ return Natives.soundio_get_bytes_per_sample((SoundIoFormat)format);
+ }
+
+ public static int GetBytesPerFrame(SoundIOFormat format, int channelCount)
+ {
+ return Natives.soundio_get_bytes_per_frame((SoundIoFormat)format, channelCount);
+ }
+
+ public static int GetBytesPerSecond(SoundIOFormat format, int channelCount, int sampleRate)
+ {
+ return Natives.soundio_get_bytes_per_second((SoundIoFormat)format, channelCount, sampleRate);
+ }
+
+ public static string GetSoundFormatName(SoundIOFormat format)
+ {
+ return Marshal.PtrToStringAnsi(Natives.soundio_format_string((SoundIoFormat)format));
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs
new file mode 100644
index 00000000..fd105804
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs
@@ -0,0 +1,13 @@
+namespace SoundIOSharp
+{
+ public enum SoundIOBackend
+ {
+ None,
+ Jack,
+ PulseAudio,
+ Alsa,
+ CoreAudio,
+ Wasapi,
+ Dummy
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs
new file mode 100644
index 00000000..c15fb744
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public struct SoundIOChannelArea
+ {
+ internal SoundIOChannelArea(Pointer<SoundIoChannelArea> handle)
+ {
+ this.handle = handle;
+ }
+
+ Pointer<SoundIoChannelArea> handle;
+
+ public IntPtr Pointer
+ {
+ get { return Marshal.ReadIntPtr(handle, ptr_offset); }
+ set { Marshal.WriteIntPtr(handle, ptr_offset, value); }
+ }
+
+ static readonly int ptr_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("ptr");
+
+ public int Step
+ {
+ get { return Marshal.ReadInt32(handle, step_offset); }
+ }
+
+ static readonly int step_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("step");
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs
new file mode 100644
index 00000000..e0f375b9
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public struct SoundIOChannelAreas
+ {
+ static readonly int native_size = Marshal.SizeOf<SoundIoChannelArea>();
+
+ internal SoundIOChannelAreas(IntPtr head, int channelCount, int frameCount)
+ {
+ this.head = head;
+ this.channel_count = channelCount;
+ this.frame_count = frameCount;
+ }
+
+ IntPtr head;
+ int channel_count;
+ int frame_count;
+
+ public bool IsEmpty
+ {
+ get { return head == IntPtr.Zero; }
+ }
+
+ public SoundIOChannelArea GetArea(int channel)
+ {
+ return new SoundIOChannelArea(head + native_size * channel);
+ }
+
+ public int ChannelCount => channel_count;
+ public int FrameCount => frame_count;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs
new file mode 100644
index 00000000..002669dc
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs
@@ -0,0 +1,75 @@
+namespace SoundIOSharp
+{
+ public enum SoundIOChannelId
+ {
+ Invalid,
+ FrontLeft,
+ FrontRight,
+ FrontCenter,
+ Lfe,
+ BackLeft,
+ BackRight,
+ FrontLeftCenter,
+ FrontRightCenter,
+ BackCenter,
+ SideLeft,
+ SideRight,
+ TopCenter,
+ TopFrontLeft,
+ TopFrontCenter,
+ TopFrontRight,
+ TopBackLeft,
+ TopBackCenter,
+ TopBackRight,
+ BackLeftCenter,
+ BackRightCenter,
+ FrontLeftWide,
+ FrontRightWide,
+ FrontLeftHigh,
+ FrontCenterHigh,
+ FrontRightHigh,
+ TopFrontLeftCenter,
+ TopFrontRightCenter,
+ TopSideLeft,
+ TopSideRight,
+ LeftLfe,
+ RightLfe,
+ Lfe2,
+ BottomCenter,
+ BottomLeftCenter,
+ BottomRightCenter,
+ MsMid,
+ MsSide,
+ AmbisonicW,
+ AmbisonicX,
+ AmbisonicY,
+ AmbisonicZ,
+ XyX,
+ XyY,
+ HeadphonesLeft,
+ HeadphonesRight,
+ ClickTrack,
+ ForeignLanguage,
+ HearingImpaired,
+ Narration,
+ Haptic,
+ DialogCentricMix,
+ Aux,
+ Aux0,
+ Aux1,
+ Aux2,
+ Aux3,
+ Aux4,
+ Aux5,
+ Aux6,
+ Aux7,
+ Aux8,
+ Aux9,
+ Aux10,
+ Aux11,
+ Aux12,
+ Aux13,
+ Aux14,
+ Aux15
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs
new file mode 100644
index 00000000..cff6114f
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public struct SoundIOChannelLayout
+ {
+ public static int BuiltInCount
+ {
+ get { return Natives.soundio_channel_layout_builtin_count(); }
+ }
+
+ public static SoundIOChannelLayout GetBuiltIn(int index)
+ {
+ return new SoundIOChannelLayout(Natives.soundio_channel_layout_get_builtin(index));
+ }
+
+ public static SoundIOChannelLayout GetDefault(int channelCount)
+ {
+ var handle = Natives.soundio_channel_layout_get_default(channelCount);
+
+ return new SoundIOChannelLayout (handle);
+ }
+
+ public static SoundIOChannelId ParseChannelId(string name)
+ {
+ var ptr = Marshal.StringToHGlobalAnsi(name);
+
+ try
+ {
+ return (SoundIOChannelId)Natives.soundio_parse_channel_id(ptr, name.Length);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(ptr);
+ }
+ }
+
+ // instance members
+
+ internal SoundIOChannelLayout(Pointer<SoundIoChannelLayout> handle)
+ {
+ this.handle = handle;
+ }
+
+ readonly Pointer<SoundIoChannelLayout> handle;
+
+ public bool IsNull
+ {
+ get { return handle.Handle == IntPtr.Zero; }
+ }
+
+ internal IntPtr Handle
+ {
+ get { return handle; }
+ }
+
+ public int ChannelCount
+ {
+ get { return IsNull ? 0 : Marshal.ReadInt32((IntPtr)handle + channel_count_offset); }
+ }
+
+ static readonly int channel_count_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("channel_count");
+
+ public string Name
+ {
+ get { return IsNull ? null : Marshal.PtrToStringAnsi(Marshal.ReadIntPtr((IntPtr)handle + name_offset)); }
+ }
+
+ static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("name");
+
+ public IEnumerable<SoundIOChannelId> Channels
+ {
+ get
+ {
+ if (IsNull) yield break;
+
+ for (int i = 0; i < 24; i++)
+ {
+ yield return (SoundIOChannelId)Marshal.ReadInt32((IntPtr)handle + channels_offset + sizeof(SoundIoChannelId) * i);
+ }
+ }
+ }
+
+ static readonly int channels_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("channels");
+
+ public override bool Equals(object other)
+ {
+ if (!(other is SoundIOChannelLayout)) return false;
+
+ var s = (SoundIOChannelLayout) other;
+
+ return handle == s.handle || Natives.soundio_channel_layout_equal(handle, s.handle);
+ }
+
+ public override int GetHashCode()
+ {
+ return handle.GetHashCode();
+ }
+
+ public string DetectBuiltInName()
+ {
+ if (IsNull) throw new InvalidOperationException();
+
+ return Natives.soundio_channel_layout_detect_builtin(handle) ? Name : null;
+ }
+
+ public int FindChannel(SoundIOChannelId channel)
+ {
+ if (IsNull) throw new InvalidOperationException();
+
+ return Natives.soundio_channel_layout_find_channel(handle, (SoundIoChannelId)channel);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs
new file mode 100644
index 00000000..6e7c4964
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs
@@ -0,0 +1,267 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public class SoundIODevice
+ {
+ public static SoundIOChannelLayout BestMatchingChannelLayout(SoundIODevice device1, SoundIODevice device2)
+ {
+ var ptr1 = Marshal.ReadIntPtr(device1.handle, layouts_offset);
+ var ptr2 = Marshal.ReadIntPtr(device2.handle, layouts_offset);
+
+ return new SoundIOChannelLayout(Natives.soundio_best_matching_channel_layout(ptr1, device1.LayoutCount, ptr2, device2.LayoutCount));
+ }
+
+ internal SoundIODevice(Pointer<SoundIoDevice> handle)
+ {
+ this.handle = handle;
+ }
+
+ readonly Pointer<SoundIoDevice> handle;
+
+ // Equality (based on handle and native func)
+
+ public override bool Equals(object other)
+ {
+ var d = other as SoundIODevice;
+
+ return d != null && (this.handle == d.handle || Natives.soundio_device_equal (this.handle, d.handle));
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)(IntPtr)handle;
+ }
+
+ public static bool operator == (SoundIODevice obj1, SoundIODevice obj2)
+ {
+ return obj1 is null ? obj2 is null : obj1.Equals(obj2);
+ }
+
+ public static bool operator != (SoundIODevice obj1, SoundIODevice obj2)
+ {
+ return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
+ }
+
+ // fields
+
+ public SoundIODeviceAim Aim
+ {
+ get { return (SoundIODeviceAim)Marshal.ReadInt32(handle, aim_offset); }
+ }
+
+ static readonly int aim_offset = (int)Marshal.OffsetOf<SoundIoDevice>("aim");
+
+ public SoundIOFormat CurrentFormat
+ {
+ get { return (SoundIOFormat)Marshal.ReadInt32(handle, current_format_offset); }
+ }
+
+ static readonly int current_format_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_format");
+
+ public SoundIOChannelLayout CurrentLayout
+ {
+ get { return new SoundIOChannelLayout((IntPtr)handle + current_layout_offset); }
+ }
+
+ static readonly int current_layout_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_layout");
+
+ public int FormatCount
+ {
+ get { return Marshal.ReadInt32(handle, format_count_offset); }
+ }
+
+ static readonly int format_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("format_count");
+
+ public IEnumerable<SoundIOFormat> Formats
+ {
+ get
+ {
+ var ptr = Marshal.ReadIntPtr(handle, formats_offset);
+
+ for (int i = 0; i < FormatCount; i++)
+ {
+ yield return (SoundIOFormat)Marshal.ReadInt32(ptr, i);
+ }
+ }
+ }
+
+ static readonly int formats_offset = (int)Marshal.OffsetOf<SoundIoDevice>("formats");
+
+ public string Id
+ {
+ get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, id_offset)); }
+ }
+
+ static readonly int id_offset = (int)Marshal.OffsetOf<SoundIoDevice>("id");
+
+ public bool IsRaw
+ {
+ get { return Marshal.ReadInt32(handle, is_raw_offset) != 0; }
+ }
+
+ static readonly int is_raw_offset = (int)Marshal.OffsetOf<SoundIoDevice>("is_raw");
+
+ public int LayoutCount
+ {
+ get { return Marshal.ReadInt32(handle, layout_count_offset); }
+ }
+
+ static readonly int layout_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layout_count");
+
+ public IEnumerable<SoundIOChannelLayout> Layouts
+ {
+ get
+ {
+ var ptr = Marshal.ReadIntPtr (handle, layouts_offset);
+
+ for (int i = 0; i < LayoutCount; i++)
+ {
+ yield return new SoundIOChannelLayout(ptr + i * Marshal.SizeOf<SoundIoChannelLayout>());
+ }
+ }
+ }
+
+ static readonly int layouts_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layouts");
+
+ public string Name
+ {
+ get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
+ }
+
+ static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoDevice>("name");
+
+ public int ProbeError
+ {
+ get { return Marshal.ReadInt32(handle, probe_error_offset); }
+ }
+
+ static readonly int probe_error_offset = (int)Marshal.OffsetOf<SoundIoDevice>("probe_error");
+
+ public int ReferenceCount
+ {
+ get { return Marshal.ReadInt32(handle, ref_count_offset); }
+ }
+
+ static readonly int ref_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("ref_count");
+
+ public int SampleRateCount
+ {
+ get { return Marshal.ReadInt32(handle, sample_rate_count_offset); }
+ }
+
+ static readonly int sample_rate_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("sample_rate_count");
+
+ public IEnumerable<SoundIOSampleRateRange> SampleRates
+ {
+ get
+ {
+ var ptr = Marshal.ReadIntPtr(handle, sample_rates_offset);
+
+ for (int i = 0; i < SampleRateCount; i++)
+ {
+ yield return new SoundIOSampleRateRange(Marshal.ReadInt32(ptr, i * 2), Marshal.ReadInt32(ptr, i * 2 + 1));
+ }
+ }
+ }
+
+ static readonly int sample_rates_offset = (int)Marshal.OffsetOf<SoundIoDevice>("sample_rates");
+
+ public double SoftwareLatencyCurrent
+ {
+ get { return MarshalEx.ReadDouble(handle, software_latency_current_offset); }
+ set { MarshalEx.WriteDouble(handle, software_latency_current_offset, value); }
+ }
+
+ static readonly int software_latency_current_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_current");
+
+ public double SoftwareLatencyMin
+ {
+ get { return MarshalEx.ReadDouble(handle, software_latency_min_offset); }
+ set { MarshalEx.WriteDouble(handle, software_latency_min_offset, value); }
+ }
+
+ static readonly int software_latency_min_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_min");
+
+ public double SoftwareLatencyMax
+ {
+ get { return MarshalEx.ReadDouble(handle, software_latency_max_offset); }
+ set { MarshalEx.WriteDouble(handle, software_latency_max_offset, value); }
+ }
+
+ static readonly int software_latency_max_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_max");
+
+ public SoundIO SoundIO
+ {
+ get { return new SoundIO(Marshal.ReadIntPtr(handle, soundio_offset)); }
+ }
+
+ static readonly int soundio_offset = (int)Marshal.OffsetOf<SoundIoDevice>("soundio");
+
+ // functions
+
+ public void AddReference()
+ {
+ Natives.soundio_device_ref(handle);
+ }
+
+ public void RemoveReference()
+ {
+ Natives.soundio_device_unref(handle);
+ }
+
+ public void SortDeviceChannelLayouts()
+ {
+ Natives.soundio_device_sort_channel_layouts(handle);
+ }
+
+ public static readonly SoundIOFormat S16NE = BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE;
+ public static readonly SoundIOFormat U16NE = BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE;
+ public static readonly SoundIOFormat S24NE = BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE;
+ public static readonly SoundIOFormat U24NE = BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE;
+ public static readonly SoundIOFormat S32NE = BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE;
+ public static readonly SoundIOFormat U32NE = BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE;
+ public static readonly SoundIOFormat Float32NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE;
+ public static readonly SoundIOFormat Float64NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE;
+ public static readonly SoundIOFormat S16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE;
+ public static readonly SoundIOFormat U16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE;
+ public static readonly SoundIOFormat S24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE;
+ public static readonly SoundIOFormat U24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE;
+ public static readonly SoundIOFormat S32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE;
+ public static readonly SoundIOFormat U32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE;
+ public static readonly SoundIOFormat Float32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE;
+ public static readonly SoundIOFormat Float64FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE;
+
+ public bool SupportsFormat(SoundIOFormat format)
+ {
+ return Natives.soundio_device_supports_format(handle, (SoundIoFormat)format);
+ }
+
+ public bool SupportsSampleRate(int sampleRate)
+ {
+ return Natives.soundio_device_supports_sample_rate(handle, sampleRate);
+ }
+
+ public bool SupportsChannelCount(int channelCount)
+ {
+ return Natives.soundio_device_supports_layout(handle, SoundIOChannelLayout.GetDefault(channelCount).Handle);
+ }
+
+ public int GetNearestSampleRate(int sampleRate)
+ {
+ return Natives.soundio_device_nearest_sample_rate(handle, sampleRate);
+ }
+
+ public SoundIOInStream CreateInStream()
+ {
+ return new SoundIOInStream(Natives.soundio_instream_create(handle));
+ }
+
+ public SoundIOOutStream CreateOutStream()
+ {
+ return new SoundIOOutStream(Natives.soundio_outstream_create(handle));
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs
new file mode 100644
index 00000000..1e596127
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs
@@ -0,0 +1,8 @@
+namespace SoundIOSharp
+{
+ public enum SoundIODeviceAim // soundio.h (228, 6)
+ {
+ Input,
+ Output
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs
new file mode 100644
index 00000000..537b6cde
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public class SoundIOException : Exception
+ {
+ internal SoundIOException(SoundIoError errorCode) : base (Marshal.PtrToStringAnsi(Natives.soundio_strerror((int) errorCode))) { }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs
new file mode 100644
index 00000000..df1b71c6
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs
@@ -0,0 +1,25 @@
+namespace SoundIOSharp
+{
+ public enum SoundIOFormat
+ {
+ Invalid,
+ S8,
+ U8,
+ S16LE,
+ S16BE,
+ U16LE,
+ U16BE,
+ S24LE,
+ S24BE,
+ U24LE,
+ U24BE,
+ S32LE,
+ S32BE,
+ U32LE,
+ U32BE,
+ Float32LE,
+ Float32BE,
+ Float64LE,
+ Float64BE
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs
new file mode 100644
index 00000000..df97d653
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs
@@ -0,0 +1,293 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public class SoundIOInStream : IDisposable
+ {
+ internal SoundIOInStream(Pointer<SoundIoInStream> handle)
+ {
+ this.handle = handle;
+ }
+
+ Pointer<SoundIoInStream> handle;
+
+ public void Dispose()
+ {
+ Natives.soundio_instream_destroy(handle);
+ }
+
+ // Equality (based on handle)
+
+ public override bool Equals(object other)
+ {
+ var d = other as SoundIOInStream;
+
+ return d != null && (this.handle == d.handle);
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)(IntPtr)handle;
+ }
+
+ public static bool operator == (SoundIOInStream obj1, SoundIOInStream obj2)
+ {
+ return obj1 is null ? obj2 is null : obj1.Equals(obj2);
+ }
+
+ public static bool operator != (SoundIOInStream obj1, SoundIOInStream obj2)
+ {
+ return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
+ }
+
+ // fields
+
+ public SoundIODevice Device
+ {
+ get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); }
+ }
+
+ static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoInStream>("device");
+
+ public SoundIOFormat Format
+ {
+ get { return (SoundIOFormat)Marshal.ReadInt32(handle, format_offset); }
+ set { Marshal.WriteInt32(handle, format_offset, (int) value); }
+ }
+
+ static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoInStream>("format");
+
+ public int SampleRate
+ {
+ get { return Marshal.ReadInt32(handle, sample_rate_offset); }
+ set { Marshal.WriteInt32(handle, sample_rate_offset, value); }
+ }
+
+ static readonly int sample_rate_offset = (int)Marshal.OffsetOf<SoundIoInStream>("sample_rate");
+
+ public SoundIOChannelLayout Layout
+ {
+ get { return new SoundIOChannelLayout ((IntPtr) handle + layout_offset); }
+ set
+ {
+ unsafe
+ {
+ Buffer.MemoryCopy((void*)((IntPtr)handle + layout_offset), (void*)value.Handle, Marshal.SizeOf<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
+ }
+ }
+ }
+
+ static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoInStream>("layout");
+
+ public double SoftwareLatency
+ {
+ get { return MarshalEx.ReadDouble(handle, software_latency_offset); }
+ set { MarshalEx.WriteDouble(handle, software_latency_offset, value); }
+ }
+
+ static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoInStream>("software_latency");
+
+ // error_callback
+ public Action ErrorCallback
+ {
+ get { return error_callback; }
+ set
+ {
+ error_callback = value;
+ error_callback_native = _ => error_callback();
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native);
+
+ Marshal.WriteIntPtr(handle, error_callback_offset, ptr);
+ }
+ }
+
+ static readonly int error_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("error_callback");
+
+ Action error_callback;
+ delegate void error_callback_delegate(IntPtr handle);
+ error_callback_delegate error_callback_native;
+
+ // read_callback
+ public Action<int,int> ReadCallback
+ {
+ get { return read_callback; }
+ set
+ {
+ read_callback = value;
+ read_callback_native = (_, minFrameCount, maxFrameCount) => read_callback(minFrameCount, maxFrameCount);
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(read_callback_native);
+
+ Marshal.WriteIntPtr(handle, read_callback_offset, ptr);
+ }
+ }
+
+ static readonly int read_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("read_callback");
+
+ Action<int, int> read_callback;
+ delegate void read_callback_delegate(IntPtr handle, int min, int max);
+ read_callback_delegate read_callback_native;
+
+ // overflow_callback
+ public Action OverflowCallback
+ {
+ get { return overflow_callback; }
+ set
+ {
+ overflow_callback = value;
+ overflow_callback_native = _ => overflow_callback();
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(overflow_callback_native);
+
+ Marshal.WriteIntPtr(handle, overflow_callback_offset, ptr);
+ }
+ }
+ static readonly int overflow_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("overflow_callback");
+
+ Action overflow_callback;
+ delegate void overflow_callback_delegate(IntPtr handle);
+ overflow_callback_delegate overflow_callback_native;
+
+ // FIXME: this should be taken care in more centralized/decent manner... we don't want to write
+ // this kind of code anywhere we need string marshaling.
+ List<IntPtr> allocated_hglobals = new List<IntPtr>();
+
+ public string Name
+ {
+ get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
+ set
+ {
+ unsafe
+ {
+ var existing = Marshal.ReadIntPtr(handle, name_offset);
+ if (allocated_hglobals.Contains(existing))
+ {
+ allocated_hglobals.Remove(existing);
+ Marshal.FreeHGlobal(existing);
+ }
+
+ var ptr = Marshal.StringToHGlobalAnsi(value);
+ Marshal.WriteIntPtr(handle, name_offset, ptr);
+ allocated_hglobals.Add(ptr);
+ }
+ }
+ }
+
+ static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoInStream>("name");
+
+ public bool NonTerminalHint
+ {
+ get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; }
+ }
+
+ static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoInStream>("non_terminal_hint");
+
+ public int BytesPerFrame
+ {
+ get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); }
+ }
+
+ static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf<SoundIoInStream>("bytes_per_frame");
+
+ public int BytesPerSample
+ {
+ get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); }
+ }
+
+ static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf<SoundIoInStream>("bytes_per_sample");
+
+ public string LayoutErrorMessage
+ {
+ get
+ {
+ var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset);
+
+ return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code));
+ }
+ }
+
+ static readonly int layout_error_offset = (int)Marshal.OffsetOf<SoundIoInStream>("layout_error");
+
+ // functions
+
+ public void Open()
+ {
+ var ret = (SoundIoError)Natives.soundio_instream_open(handle);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public void Start()
+ {
+ var ret = (SoundIoError)Natives.soundio_instream_start(handle);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public SoundIOChannelAreas BeginRead(ref int frameCount)
+ {
+ IntPtr ptrs = default;
+ int nativeFrameCount = frameCount;
+
+ unsafe
+ {
+ var frameCountPtr = &nativeFrameCount;
+ var ptrptr = &ptrs;
+ var ret = (SoundIoError)Natives.soundio_instream_begin_read(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr);
+
+ frameCount = *frameCountPtr;
+
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+
+ return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount);
+ }
+ }
+
+ public void EndRead()
+ {
+ var ret = (SoundIoError)Natives.soundio_instream_end_read(handle);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public void Pause(bool pause)
+ {
+ var ret = (SoundIoError)Natives.soundio_instream_pause(handle, pause);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public double GetLatency()
+ {
+ unsafe
+ {
+ double* dptr = null;
+ IntPtr p = new IntPtr(dptr);
+
+ var ret = (SoundIoError)Natives.soundio_instream_get_latency(handle, p);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+
+ dptr = (double*)p;
+
+ return *dptr;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs
new file mode 100644
index 00000000..432ca42b
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs
@@ -0,0 +1,331 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace SoundIOSharp
+{
+ public class SoundIOOutStream : IDisposable
+ {
+ internal SoundIOOutStream (Pointer<SoundIoOutStream> handle)
+ {
+ this.handle = handle;
+ }
+
+ Pointer<SoundIoOutStream> handle;
+
+ public void Dispose ()
+ {
+ Natives.soundio_outstream_destroy (handle);
+ }
+ // Equality (based on handle)
+
+ public override bool Equals (object other)
+ {
+ var d = other as SoundIOOutStream;
+
+ return d != null && (this.handle == d.handle);
+ }
+
+ public override int GetHashCode ()
+ {
+ return (int)(IntPtr)handle;
+ }
+
+ public static bool operator == (SoundIOOutStream obj1, SoundIOOutStream obj2)
+ {
+ return obj1 is null ? obj2 is null : obj1.Equals(obj2);
+ }
+
+ public static bool operator != (SoundIOOutStream obj1, SoundIOOutStream obj2)
+ {
+ return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
+ }
+
+ // fields
+
+ public SoundIODevice Device
+ {
+ get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); }
+ }
+
+ static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("device");
+
+ public SoundIOFormat Format
+ {
+ get { return (SoundIOFormat) Marshal.ReadInt32(handle, format_offset); }
+ set { Marshal.WriteInt32(handle, format_offset, (int) value); }
+ }
+
+ static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("format");
+
+ public int SampleRate
+ {
+ get { return Marshal.ReadInt32(handle, sample_rate_offset); }
+ set { Marshal.WriteInt32(handle, sample_rate_offset, value); }
+ }
+
+ static readonly int sample_rate_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("sample_rate");
+
+ public SoundIOChannelLayout Layout
+ {
+ get { unsafe { return new SoundIOChannelLayout((IntPtr) (void*)((IntPtr)handle + layout_offset)); } }
+ set
+ {
+ unsafe
+ {
+ Buffer.MemoryCopy((void*)value.Handle, (void*)((IntPtr)handle + layout_offset), Marshal.SizeOf<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
+ }
+ }
+ }
+ static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("layout");
+
+ public double SoftwareLatency
+ {
+ get { return MarshalEx.ReadDouble (handle, software_latency_offset); }
+ set { MarshalEx.WriteDouble (handle, software_latency_offset, value); }
+ }
+
+ static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("software_latency");
+
+ public float Volume
+ {
+ get { return MarshalEx.ReadFloat(handle, volume_offset); }
+ set { MarshalEx.WriteFloat(handle, volume_offset, value); }
+ }
+
+ static readonly int volume_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("volume");
+
+ // error_callback
+ public Action ErrorCallback
+ {
+ get { return error_callback; }
+ set
+ {
+ error_callback = value;
+ if (value == null)
+ {
+ error_callback_native = null;
+ }
+ else
+ {
+ error_callback_native = stream => error_callback();
+ }
+
+ var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native);
+ Marshal.WriteIntPtr(handle, error_callback_offset, ptr);
+ }
+ }
+
+ static readonly int error_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("error_callback");
+
+ Action error_callback;
+ delegate void error_callback_delegate (IntPtr handle);
+ error_callback_delegate error_callback_native;
+
+ // write_callback
+ public Action<int, int> WriteCallback
+ {
+ get { return write_callback; }
+ set
+ {
+ write_callback = value;
+ if (value == null)
+ {
+ write_callback_native = null;
+ }
+ else
+ {
+ write_callback_native = (h, frame_count_min, frame_count_max) => write_callback(frame_count_min, frame_count_max);
+ }
+
+ var ptr = Marshal.GetFunctionPointerForDelegate (write_callback_native);
+ Marshal.WriteIntPtr (handle, write_callback_offset, ptr);
+ }
+ }
+
+ static readonly int write_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("write_callback");
+
+ Action<int, int> write_callback;
+ delegate void write_callback_delegate(IntPtr handle, int min, int max);
+ write_callback_delegate write_callback_native;
+
+ // underflow_callback
+ public Action UnderflowCallback
+ {
+ get { return underflow_callback; }
+ set
+ {
+ underflow_callback = value;
+ if (value == null)
+ {
+ underflow_callback_native = null;
+ }
+ else
+ {
+ underflow_callback_native = h => underflow_callback();
+ }
+
+ var ptr = Marshal.GetFunctionPointerForDelegate (underflow_callback_native);
+ Marshal.WriteIntPtr (handle, underflow_callback_offset, ptr);
+ }
+ }
+
+ static readonly int underflow_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("underflow_callback");
+
+ Action underflow_callback;
+ delegate void underflow_callback_delegate(IntPtr handle);
+ underflow_callback_delegate underflow_callback_native;
+
+ // FIXME: this should be taken care in more centralized/decent manner... we don't want to write
+ // this kind of code anywhere we need string marshaling.
+ List<IntPtr> allocated_hglobals = new List<IntPtr>();
+
+ public string Name {
+ get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
+ set
+ {
+ unsafe
+ {
+ var existing = Marshal.ReadIntPtr(handle, name_offset);
+ if (allocated_hglobals.Contains(existing))
+ {
+ allocated_hglobals.Remove(existing);
+ Marshal.FreeHGlobal(existing);
+ }
+
+ var ptr = Marshal.StringToHGlobalAnsi(value);
+ Marshal.WriteIntPtr(handle, name_offset, ptr);
+ allocated_hglobals.Add(ptr);
+ }
+ }
+ }
+
+ static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("name");
+
+ public bool NonTerminalHint
+ {
+ get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; }
+ }
+
+ static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("non_terminal_hint");
+
+ public int BytesPerFrame
+ {
+ get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); }
+ }
+
+ static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("bytes_per_frame");
+
+ public int BytesPerSample
+ {
+ get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); }
+ }
+
+ static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("bytes_per_sample");
+
+ public string LayoutErrorMessage
+ {
+ get
+ {
+ var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset);
+
+ return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code));
+ }
+ }
+
+ static readonly int layout_error_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("layout_error");
+
+ // functions
+
+ public void Open ()
+ {
+ var ret = (SoundIoError)Natives.soundio_outstream_open(handle);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public void Start ()
+ {
+ var ret = (SoundIoError)Natives.soundio_outstream_start(handle);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public SoundIOChannelAreas BeginWrite(ref int frameCount)
+ {
+ IntPtr ptrs = default;
+ int nativeFrameCount = frameCount;
+
+ unsafe
+ {
+ var frameCountPtr = &nativeFrameCount;
+ var ptrptr = &ptrs;
+ var ret = (SoundIoError)Natives.soundio_outstream_begin_write(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr);
+
+ frameCount = *frameCountPtr;
+
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+
+ return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount);
+ }
+ }
+
+ public void EndWrite ()
+ {
+ var ret = (SoundIoError)Natives.soundio_outstream_end_write(handle);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public void ClearBuffer ()
+ {
+ _ = Natives.soundio_outstream_clear_buffer(handle);
+ }
+
+ public void Pause (bool pause)
+ {
+ var ret = (SoundIoError)Natives.soundio_outstream_pause(handle, pause);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+
+ public double GetLatency ()
+ {
+ unsafe
+ {
+ double* dptr = null;
+ IntPtr p = new IntPtr(dptr);
+
+ var ret = (SoundIoError)Natives.soundio_outstream_get_latency(handle, p);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+
+ dptr = (double*)p;
+
+ return *dptr;
+ }
+ }
+
+ public void SetVolume (double volume)
+ {
+ var ret = (SoundIoError)Natives.soundio_outstream_set_volume(handle, volume);
+ if (ret != SoundIoError.SoundIoErrorNone)
+ {
+ throw new SoundIOException(ret);
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs
new file mode 100644
index 00000000..7530da72
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs
@@ -0,0 +1,58 @@
+using System;
+namespace SoundIOSharp
+{
+ public class SoundIORingBuffer : IDisposable
+ {
+ internal SoundIORingBuffer(IntPtr handle)
+ {
+ this.handle = handle;
+ }
+
+ IntPtr handle;
+
+ public int Capacity
+ {
+ get { return Natives.soundio_ring_buffer_capacity(handle); }
+ }
+
+ public void Clear()
+ {
+ Natives.soundio_ring_buffer_clear(handle);
+ }
+
+ public void Dispose()
+ {
+ Natives.soundio_ring_buffer_destroy(handle);
+ }
+
+ public int FillCount
+ {
+ get { return Natives.soundio_ring_buffer_fill_count(handle); }
+ }
+
+ public int FreeCount
+ {
+ get { return Natives.soundio_ring_buffer_free_count(handle); }
+ }
+
+ public IntPtr ReadPointer
+ {
+ get { return Natives.soundio_ring_buffer_read_ptr(handle); }
+ }
+
+ public IntPtr WritePointer
+ {
+ get { return Natives.soundio_ring_buffer_write_ptr(handle); }
+ }
+
+ public void AdvanceReadPointer(int count)
+ {
+ Natives.soundio_ring_buffer_advance_read_ptr(handle, count);
+ }
+
+ public void AdvanceWritePointer(int count)
+ {
+ Natives.soundio_ring_buffer_advance_write_ptr(handle, count);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs
new file mode 100644
index 00000000..e01ec2bd
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs
@@ -0,0 +1,15 @@
+using System;
+namespace SoundIOSharp
+{
+ public struct SoundIOSampleRateRange
+ {
+ internal SoundIOSampleRateRange(int min, int max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public readonly int Min;
+ public readonly int Max;
+ }
+}
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.dll b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.dll
new file mode 100644
index 00000000..48804312
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.dll
Binary files differ
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.dylib b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.dylib
new file mode 100644
index 00000000..10171f4f
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.dylib
Binary files differ
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.so b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.so
new file mode 100644
index 00000000..87c8b506
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libs/libsoundio.so
Binary files differ
diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs
new file mode 100644
index 00000000..5377582f
--- /dev/null
+++ b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs
@@ -0,0 +1,643 @@
+// This source file is generated by nclang PInvokeGenerator.
+using System;
+using System.Runtime.InteropServices;
+using delegate0 = SoundIOSharp.Delegates.delegate0;
+using delegate1 = SoundIOSharp.Delegates.delegate1;
+using delegate2 = SoundIOSharp.Delegates.delegate2;
+using delegate3 = SoundIOSharp.Delegates.delegate3;
+using delegate4 = SoundIOSharp.Delegates.delegate4;
+using delegate5 = SoundIOSharp.Delegates.delegate5;
+using delegate6 = SoundIOSharp.Delegates.delegate6;
+using delegate7 = SoundIOSharp.Delegates.delegate7;
+using delegate8 = SoundIOSharp.Delegates.delegate8;
+using delegate9 = SoundIOSharp.Delegates.delegate9;
+
+namespace SoundIOSharp
+{
+ enum SoundIoError // soundio.h (72, 6)
+ {
+ SoundIoErrorNone = 0,
+ SoundIoErrorNoMem = 1,
+ SoundIoErrorInitAudioBackend = 2,
+ SoundIoErrorSystemResources = 3,
+ SoundIoErrorOpeningDevice = 4,
+ SoundIoErrorNoSuchDevice = 5,
+ SoundIoErrorInvalid = 6,
+ SoundIoErrorBackendUnavailable = 7,
+ SoundIoErrorStreaming = 8,
+ SoundIoErrorIncompatibleDevice = 9,
+ SoundIoErrorNoSuchClient = 10,
+ SoundIoErrorIncompatibleBackend = 11,
+ SoundIoErrorBackendDisconnected = 12,
+ SoundIoErrorInterrupted = 13,
+ SoundIoErrorUnderflow = 14,
+ SoundIoErrorEncodingString = 15,
+ }
+
+ enum SoundIoChannelId // soundio.h (106, 6)
+ {
+ SoundIoChannelIdInvalid = 0,
+ SoundIoChannelIdFrontLeft = 1,
+ SoundIoChannelIdFrontRight = 2,
+ SoundIoChannelIdFrontCenter = 3,
+ SoundIoChannelIdLfe = 4,
+ SoundIoChannelIdBackLeft = 5,
+ SoundIoChannelIdBackRight = 6,
+ SoundIoChannelIdFrontLeftCenter = 7,
+ SoundIoChannelIdFrontRightCenter = 8,
+ SoundIoChannelIdBackCenter = 9,
+ SoundIoChannelIdSideLeft = 10,
+ SoundIoChannelIdSideRight = 11,
+ SoundIoChannelIdTopCenter = 12,
+ SoundIoChannelIdTopFrontLeft = 13,
+ SoundIoChannelIdTopFrontCenter = 14,
+ SoundIoChannelIdTopFrontRight = 15,
+ SoundIoChannelIdTopBackLeft = 16,
+ SoundIoChannelIdTopBackCenter = 17,
+ SoundIoChannelIdTopBackRight = 18,
+ SoundIoChannelIdBackLeftCenter = 19,
+ SoundIoChannelIdBackRightCenter = 20,
+ SoundIoChannelIdFrontLeftWide = 21,
+ SoundIoChannelIdFrontRightWide = 22,
+ SoundIoChannelIdFrontLeftHigh = 23,
+ SoundIoChannelIdFrontCenterHigh = 24,
+ SoundIoChannelIdFrontRightHigh = 25,
+ SoundIoChannelIdTopFrontLeftCenter = 26,
+ SoundIoChannelIdTopFrontRightCenter = 27,
+ SoundIoChannelIdTopSideLeft = 28,
+ SoundIoChannelIdTopSideRight = 29,
+ SoundIoChannelIdLeftLfe = 30,
+ SoundIoChannelIdRightLfe = 31,
+ SoundIoChannelIdLfe2 = 32,
+ SoundIoChannelIdBottomCenter = 33,
+ SoundIoChannelIdBottomLeftCenter = 34,
+ SoundIoChannelIdBottomRightCenter = 35,
+ SoundIoChannelIdMsMid = 36,
+ SoundIoChannelIdMsSide = 37,
+ SoundIoChannelIdAmbisonicW = 38,
+ SoundIoChannelIdAmbisonicX = 39,
+ SoundIoChannelIdAmbisonicY = 40,
+ SoundIoChannelIdAmbisonicZ = 41,
+ SoundIoChannelIdXyX = 42,
+ SoundIoChannelIdXyY = 43,
+ SoundIoChannelIdHeadphonesLeft = 44,
+ SoundIoChannelIdHeadphonesRight = 45,
+ SoundIoChannelIdClickTrack = 46,
+ SoundIoChannelIdForeignLanguage = 47,
+ SoundIoChannelIdHearingImpaired = 48,
+ SoundIoChannelIdNarration = 49,
+ SoundIoChannelIdHaptic = 50,
+ SoundIoChannelIdDialogCentricMix = 51,
+ SoundIoChannelIdAux = 52,
+ SoundIoChannelIdAux0 = 53,
+ SoundIoChannelIdAux1 = 54,
+ SoundIoChannelIdAux2 = 55,
+ SoundIoChannelIdAux3 = 56,
+ SoundIoChannelIdAux4 = 57,
+ SoundIoChannelIdAux5 = 58,
+ SoundIoChannelIdAux6 = 59,
+ SoundIoChannelIdAux7 = 60,
+ SoundIoChannelIdAux8 = 61,
+ SoundIoChannelIdAux9 = 62,
+ SoundIoChannelIdAux10 = 63,
+ SoundIoChannelIdAux11 = 64,
+ SoundIoChannelIdAux12 = 65,
+ SoundIoChannelIdAux13 = 66,
+ SoundIoChannelIdAux14 = 67,
+ SoundIoChannelIdAux15 = 68,
+ }
+
+ enum SoundIoChannelLayoutId // soundio.h (189, 6)
+ {
+ SoundIoChannelLayoutIdMono = 0,
+ SoundIoChannelLayoutIdStereo = 1,
+ SoundIoChannelLayoutId2Point1 = 2,
+ SoundIoChannelLayoutId3Point0 = 3,
+ SoundIoChannelLayoutId3Point0Back = 4,
+ SoundIoChannelLayoutId3Point1 = 5,
+ SoundIoChannelLayoutId4Point0 = 6,
+ SoundIoChannelLayoutIdQuad = 7,
+ SoundIoChannelLayoutIdQuadSide = 8,
+ SoundIoChannelLayoutId4Point1 = 9,
+ SoundIoChannelLayoutId5Point0Back = 10,
+ SoundIoChannelLayoutId5Point0Side = 11,
+ SoundIoChannelLayoutId5Point1 = 12,
+ SoundIoChannelLayoutId5Point1Back = 13,
+ SoundIoChannelLayoutId6Point0Side = 14,
+ SoundIoChannelLayoutId6Point0Front = 15,
+ SoundIoChannelLayoutIdHexagonal = 16,
+ SoundIoChannelLayoutId6Point1 = 17,
+ SoundIoChannelLayoutId6Point1Back = 18,
+ SoundIoChannelLayoutId6Point1Front = 19,
+ SoundIoChannelLayoutId7Point0 = 20,
+ SoundIoChannelLayoutId7Point0Front = 21,
+ SoundIoChannelLayoutId7Point1 = 22,
+ SoundIoChannelLayoutId7Point1Wide = 23,
+ SoundIoChannelLayoutId7Point1WideBack = 24,
+ SoundIoChannelLayoutIdOctagonal = 25,
+ }
+
+ enum SoundIoBackend // soundio.h (218, 6)
+ {
+ SoundIoBackendNone = 0,
+ SoundIoBackendJack = 1,
+ SoundIoBackendPulseAudio = 2,
+ SoundIoBackendAlsa = 3,
+ SoundIoBackendCoreAudio = 4,
+ SoundIoBackendWasapi = 5,
+ SoundIoBackendDummy = 6,
+ }
+
+ enum SoundIoDeviceAim // soundio.h (228, 6)
+ {
+ SoundIoDeviceAimInput = 0,
+ SoundIoDeviceAimOutput = 1,
+ }
+
+ enum SoundIoFormat // soundio.h (235, 6)
+ {
+ SoundIoFormatInvalid = 0,
+ SoundIoFormatS8 = 1,
+ SoundIoFormatU8 = 2,
+ SoundIoFormatS16LE = 3,
+ SoundIoFormatS16BE = 4,
+ SoundIoFormatU16LE = 5,
+ SoundIoFormatU16BE = 6,
+ SoundIoFormatS24LE = 7,
+ SoundIoFormatS24BE = 8,
+ SoundIoFormatU24LE = 9,
+ SoundIoFormatU24BE = 10,
+ SoundIoFormatS32LE = 11,
+ SoundIoFormatS32BE = 12,
+ SoundIoFormatU32LE = 13,
+ SoundIoFormatU32BE = 14,
+ SoundIoFormatFloat32LE = 15,
+ SoundIoFormatFloat32BE = 16,
+ SoundIoFormatFloat64LE = 17,
+ SoundIoFormatFloat64BE = 18,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct SoundIoChannelLayout // soundio.h (306, 8)
+ {
+ [CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
+ public int @channel_count;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
+ [CTypeDetails("ConstArrayOf<SoundIoChannelId>")] public SoundIoChannelId[] @channels;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct SoundIoSampleRateRange // soundio.h (313, 8)
+ {
+ public int @min;
+ public int @max;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct SoundIoChannelArea // soundio.h (319, 8)
+ {
+ [CTypeDetails("Pointer<byte>")] public System.IntPtr @ptr;
+ public int @step;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct SoundIo // soundio.h (328, 8)
+ {
+ [CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
+ [CTypeDetails("Pointer<void (SoundIo *)>")] public delegate0 @on_devices_change;
+ [CTypeDetails("Pointer<void (SoundIo *, int)>")] public delegate1 @on_backend_disconnect;
+ [CTypeDetails("Pointer<void (SoundIo *)>")] public Delegates.delegate0 @on_events_signal;
+ public SoundIoBackend @current_backend;
+ [CTypeDetails("Pointer<byte>")] public System.IntPtr @app_name;
+ [CTypeDetails("Pointer<void ()>")] public delegate2 @emit_rtprio_warning;
+ [CTypeDetails("Pointer<void (const char *)>")] public delegate3 @jack_info_callback;
+ [CTypeDetails("Pointer<void (const char *)>")] public Delegates.delegate3 @jack_error_callback;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct SoundIoDevice // soundio.h (387, 8)
+ {
+ [CTypeDetails("Pointer<SoundIo>")] public System.IntPtr @soundio;
+ [CTypeDetails("Pointer<byte>")] public System.IntPtr @id;
+ [CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
+ public SoundIoDeviceAim @aim;
+ [CTypeDetails("Pointer<SoundIoChannelLayout>")] public System.IntPtr @layouts;
+ public int @layout_count;
+ public SoundIoChannelLayout @current_layout;
+ [CTypeDetails("Pointer<SoundIoFormat>")] public System.IntPtr @formats;
+ public int @format_count;
+ public SoundIoFormat @current_format;
+ [CTypeDetails("Pointer<SoundIoSampleRateRange>")] public System.IntPtr @sample_rates;
+ public int @sample_rate_count;
+ public int @sample_rate_current;
+ public double @software_latency_min;
+ public double @software_latency_max;
+ public double @software_latency_current;
+ public bool @is_raw;
+ public int @ref_count;
+ public int @probe_error;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct SoundIoOutStream // soundio.h (497, 8)
+ {
+ [CTypeDetails("Pointer<SoundIoDevice>")] public System.IntPtr @device;
+ public SoundIoFormat @format;
+ public int @sample_rate;
+ public SoundIoChannelLayout @layout;
+ public double @software_latency;
+ public float @volume;
+ [CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
+ [CTypeDetails("Pointer<void (SoundIoOutStream *, int, int)>")] public delegate4 @write_callback;
+ [CTypeDetails("Pointer<void (SoundIoOutStream *)>")] public delegate5 @underflow_callback;
+ [CTypeDetails("Pointer<void (SoundIoOutStream *, int)>")] public delegate6 @error_callback;
+ [CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
+ public bool @non_terminal_hint;
+ public int @bytes_per_frame;
+ public int @bytes_per_sample;
+ public int @layout_error;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct SoundIoInStream // soundio.h (600, 8)
+ {
+ [CTypeDetails("Pointer<SoundIoDevice>")] public System.IntPtr @device;
+ public SoundIoFormat @format;
+ public int @sample_rate;
+ public SoundIoChannelLayout @layout;
+ public double @software_latency;
+ [CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
+ [CTypeDetails("Pointer<void (SoundIoInStream *, int, int)>")] public delegate7 @read_callback;
+ [CTypeDetails("Pointer<void (SoundIoInStream *)>")] public delegate8 @overflow_callback;
+ [CTypeDetails("Pointer<void (SoundIoInStream *, int)>")] public delegate9 @error_callback;
+ [CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
+ public bool @non_terminal_hint;
+ public int @bytes_per_frame;
+ public int @bytes_per_sample;
+ public int @layout_error;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct SoundIoRingBuffer // soundio.h (1170, 8)
+ {
+ }
+
+ partial class Natives
+ {
+ const string LibraryName = "libsoundio";
+ // function soundio_version_string - soundio.h (682, 28)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_version_string();
+
+ // function soundio_version_major - soundio.h (684, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_version_major();
+
+ // function soundio_version_minor - soundio.h (686, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_version_minor();
+
+ // function soundio_version_patch - soundio.h (688, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_version_patch();
+
+ // function soundio_create - soundio.h (694, 32)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_create();
+
+ // function soundio_destroy - soundio.h (695, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_destroy([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_connect - soundio.h (705, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_connect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_connect_backend - soundio.h (717, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_connect_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, SoundIoBackend @backend);
+
+ // function soundio_disconnect - soundio.h (718, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_disconnect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_strerror - soundio.h (721, 28)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_strerror(int @error);
+
+ // function soundio_backend_name - soundio.h (723, 28)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_backend_name(SoundIoBackend @backend);
+
+ // function soundio_backend_count - soundio.h (726, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_backend_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_get_backend - soundio.h (729, 36)
+ [DllImport(LibraryName)]
+ internal static extern SoundIoBackend soundio_get_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
+
+ // function soundio_have_backend - soundio.h (732, 21)
+ [DllImport(LibraryName)]
+ internal static extern bool soundio_have_backend(SoundIoBackend @backend);
+
+ // function soundio_flush_events - soundio.h (756, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_flush_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_wait_events - soundio.h (760, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_wait_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_wakeup - soundio.h (763, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_wakeup([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_force_device_scan - soundio.h (780, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_force_device_scan([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_channel_layout_equal - soundio.h (787, 21)
+ [DllImport(LibraryName)]
+ internal static extern bool soundio_channel_layout_equal([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @b);
+
+ // function soundio_get_channel_name - soundio.h (791, 28)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_get_channel_name(SoundIoChannelId @id);
+
+ // function soundio_parse_channel_id - soundio.h (795, 38)
+ [DllImport(LibraryName)]
+ internal static extern SoundIoChannelId soundio_parse_channel_id([CTypeDetails("Pointer<byte>")]System.IntPtr @str, int @str_len);
+
+ // function soundio_channel_layout_builtin_count - soundio.h (798, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_channel_layout_builtin_count();
+
+ // function soundio_channel_layout_get_builtin - soundio.h (803, 51)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_channel_layout_get_builtin(int @index);
+
+ // function soundio_channel_layout_get_default - soundio.h (806, 51)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_channel_layout_get_default(int @channel_count);
+
+ // function soundio_channel_layout_find_channel - soundio.h (809, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_channel_layout_find_channel([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout, SoundIoChannelId @channel);
+
+ // function soundio_channel_layout_detect_builtin - soundio.h (814, 21)
+ [DllImport(LibraryName)]
+ internal static extern bool soundio_channel_layout_detect_builtin([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
+
+ // function soundio_best_matching_channel_layout - soundio.h (819, 51)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_best_matching_channel_layout([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @preferred_layouts, int @preferred_layout_count, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @available_layouts, int @available_layout_count);
+
+ // function soundio_sort_channel_layouts - soundio.h (824, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_sort_channel_layouts([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layouts, int @layout_count);
+
+ // function soundio_get_bytes_per_sample - soundio.h (830, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_get_bytes_per_sample(SoundIoFormat @format);
+
+ // function soundio_get_bytes_per_frame - soundio.h (833, 19)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_get_bytes_per_frame(SoundIoFormat @format, int @channel_count);
+
+ // function soundio_get_bytes_per_second - soundio.h (838, 19)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_get_bytes_per_second(SoundIoFormat @format, int @channel_count, int @sample_rate);
+
+ // function soundio_format_string - soundio.h (845, 29)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_format_string(SoundIoFormat @format);
+
+ // function soundio_input_device_count - soundio.h (861, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_input_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_output_device_count - soundio.h (864, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_output_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_get_input_device - soundio.h (870, 38)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_get_input_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
+
+ // function soundio_get_output_device - soundio.h (875, 38)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_get_output_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
+
+ // function soundio_default_input_device_index - soundio.h (880, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_default_input_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_default_output_device_index - soundio.h (885, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_default_output_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
+
+ // function soundio_device_ref - soundio.h (888, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_device_ref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
+
+ // function soundio_device_unref - soundio.h (891, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_device_unref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
+
+ // function soundio_device_equal - soundio.h (895, 21)
+ [DllImport(LibraryName)]
+ internal static extern bool soundio_device_equal([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @b);
+
+ // function soundio_device_sort_channel_layouts - soundio.h (900, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_device_sort_channel_layouts([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
+
+ // function soundio_device_supports_format - soundio.h (904, 21)
+ [DllImport(LibraryName)]
+ internal static extern bool soundio_device_supports_format([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, SoundIoFormat @format);
+
+ // function soundio_device_supports_layout - soundio.h (909, 21)
+ [DllImport(LibraryName)]
+ internal static extern bool soundio_device_supports_layout([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
+
+ // function soundio_device_supports_sample_rate - soundio.h (914, 21)
+ [DllImport(LibraryName)]
+ internal static extern bool soundio_device_supports_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
+
+ // function soundio_device_nearest_sample_rate - soundio.h (919, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_device_nearest_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
+
+ // function soundio_outstream_create - soundio.h (929, 41)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_outstream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
+
+ // function soundio_outstream_destroy - soundio.h (931, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_outstream_destroy([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
+
+ // function soundio_outstream_open - soundio.h (954, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_outstream_open([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
+
+ // function soundio_outstream_start - soundio.h (965, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_outstream_start([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
+
+ // function soundio_outstream_begin_write - soundio.h (997, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_outstream_begin_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
+
+ // function soundio_outstream_end_write - soundio.h (1009, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_outstream_end_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
+
+ // function soundio_outstream_clear_buffer - soundio.h (1024, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_outstream_clear_buffer([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
+
+ // function soundio_outstream_pause - soundio.h (1045, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_outstream_pause([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, bool @pause);
+
+ // function soundio_outstream_get_latency - soundio.h (1058, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_outstream_get_latency([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
+
+ // function soundio_outstream_set_volume - soundio.h (1061, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_outstream_set_volume([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, double @volume);
+
+ // function soundio_instream_create - soundio.h (1071, 40)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_instream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
+
+ // function soundio_instream_destroy - soundio.h (1073, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_instream_destroy([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
+
+ // function soundio_instream_open - soundio.h (1093, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_instream_open([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
+
+ // function soundio_instream_start - soundio.h (1102, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_instream_start([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
+
+ // function soundio_instream_begin_read - soundio.h (1133, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_instream_begin_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
+
+ // function soundio_instream_end_read - soundio.h (1143, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_instream_end_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
+
+ // function soundio_instream_pause - soundio.h (1156, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_instream_pause([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, bool @pause);
+
+ // function soundio_instream_get_latency - soundio.h (1166, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_instream_get_latency([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
+
+ // function soundio_ring_buffer_create - soundio.h (1181, 42)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_ring_buffer_create([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @requested_capacity);
+
+ // function soundio_ring_buffer_destroy - soundio.h (1182, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_ring_buffer_destroy([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
+
+ // function soundio_ring_buffer_capacity - soundio.h (1186, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_ring_buffer_capacity([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
+
+ // function soundio_ring_buffer_write_ptr - soundio.h (1189, 22)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_ring_buffer_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
+
+ // function soundio_ring_buffer_advance_write_ptr - soundio.h (1191, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_ring_buffer_advance_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
+
+ // function soundio_ring_buffer_read_ptr - soundio.h (1194, 22)
+ [DllImport(LibraryName)]
+ internal static extern System.IntPtr soundio_ring_buffer_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
+
+ // function soundio_ring_buffer_advance_read_ptr - soundio.h (1196, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_ring_buffer_advance_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
+
+ // function soundio_ring_buffer_fill_count - soundio.h (1199, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_ring_buffer_fill_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
+
+ // function soundio_ring_buffer_free_count - soundio.h (1202, 20)
+ [DllImport(LibraryName)]
+ internal static extern int soundio_ring_buffer_free_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
+
+ // function soundio_ring_buffer_clear - soundio.h (1205, 21)
+ [DllImport(LibraryName)]
+ internal static extern void soundio_ring_buffer_clear([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
+
+ }
+
+ class Delegates
+ {
+ public delegate void delegate0(System.IntPtr p0);
+ public delegate void delegate1(System.IntPtr p0, int p1);
+ public delegate void delegate2();
+ public delegate void delegate3(System.IntPtr p0);
+ public delegate void delegate4(System.IntPtr p0, int p1, int p2);
+ public delegate void delegate5(System.IntPtr p0);
+ public delegate void delegate6(System.IntPtr p0, int p1);
+ public delegate void delegate7(System.IntPtr p0, int p1, int p2);
+ public delegate void delegate8(System.IntPtr p0);
+ public delegate void delegate9(System.IntPtr p0, int p1);
+ }
+
+ public struct Pointer<T>
+ {
+ public IntPtr Handle;
+ public static implicit operator IntPtr(Pointer<T> value) { return value.Handle; }
+ public static implicit operator Pointer<T>(IntPtr value) { return new Pointer<T>(value); }
+
+ public Pointer(IntPtr handle)
+ {
+ Handle = handle;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is Pointer<T> && this == (Pointer<T>)obj;
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)Handle;
+ }
+
+ public static bool operator ==(Pointer<T> p1, Pointer<T> p2)
+ {
+ return p1.Handle == p2.Handle;
+ }
+
+ public static bool operator !=(Pointer<T> p1, Pointer<T> p2)
+ {
+ return p1.Handle != p2.Handle;
+ }
+ }
+ public struct ArrayOf<T> { }
+ public struct ConstArrayOf<T> { }
+ public class CTypeDetailsAttribute : Attribute
+ {
+ public CTypeDetailsAttribute(string value)
+ {
+ Value = value;
+ }
+
+ public string Value { get; set; }
+ }
+
+}