audio: Cleanup Ryujinx.Audio and fix OpenAL issue (#1746)

* audio: Cleanup SoundIO and fix OpenAL issue

* fix tabs by spaces

* Fix extra spaces

* Fix SoundIO.cs

* Fix ContainsAudioOutBuffer
This commit is contained in:
Ac_K 2020-11-27 20:55:00 +01:00 committed by GitHub
parent 0108004691
commit 7b66cb0d90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1459 additions and 1322 deletions

View File

@ -1,91 +0,0 @@
namespace Ryujinx.Audio.Adpcm
{
public static class AdpcmDecoder
{
private const int SamplesPerFrame = 14;
private const int BytesPerFrame = 8;
public static int[] Decode(byte[] Buffer, AdpcmDecoderContext Context)
{
int Samples = GetSamplesCountFromSize(Buffer.Length);
int[] Pcm = new int[Samples * 2];
short History0 = Context.History0;
short History1 = Context.History1;
int InputOffset = 0;
int OutputOffset = 0;
while (InputOffset < Buffer.Length)
{
byte Header = Buffer[InputOffset++];
int Scale = 0x800 << (Header & 0xf);
int CoeffIndex = (Header >> 4) & 7;
short Coeff0 = Context.Coefficients[CoeffIndex * 2 + 0];
short Coeff1 = Context.Coefficients[CoeffIndex * 2 + 1];
int FrameSamples = SamplesPerFrame;
if (FrameSamples > Samples)
{
FrameSamples = Samples;
}
int Value = 0;
for (int SampleIndex = 0; SampleIndex < FrameSamples; SampleIndex++)
{
int Sample;
if ((SampleIndex & 1) == 0)
{
Value = Buffer[InputOffset++];
Sample = (Value << 24) >> 28;
}
else
{
Sample = (Value << 28) >> 28;
}
int Prediction = Coeff0 * History0 + Coeff1 * History1;
Sample = (Sample * Scale + Prediction + 0x400) >> 11;
short SaturatedSample = DspUtils.Saturate(Sample);
History1 = History0;
History0 = SaturatedSample;
Pcm[OutputOffset++] = SaturatedSample;
Pcm[OutputOffset++] = SaturatedSample;
}
Samples -= FrameSamples;
}
Context.History0 = History0;
Context.History1 = History1;
return Pcm;
}
public static long GetSizeFromSamplesCount(int SamplesCount)
{
int Frames = SamplesCount / SamplesPerFrame;
return Frames * BytesPerFrame;
}
public static int GetSamplesCountFromSize(long Size)
{
int Frames = (int)(Size / BytesPerFrame);
return Frames * SamplesPerFrame;
}
}
}

View File

@ -1,10 +0,0 @@
namespace Ryujinx.Audio.Adpcm
{
public class AdpcmDecoderContext
{
public short[] Coefficients;
public short History0;
public short History1;
}
}

View File

@ -24,27 +24,31 @@ namespace Ryujinx.Audio
public short Right; public short Right;
} }
private const int Q15Bits = 16; private const int Q15Bits = 16;
private const int RawQ15One = 1 << Q15Bits; private const int RawQ15One = 1 << Q15Bits;
private const int RawQ15HalfOne = (int)(0.5f * RawQ15One); private const int RawQ15HalfOne = (int)(0.5f * RawQ15One);
private const int Minus3dBInQ15 = (int)(0.707f * RawQ15One); private const int Minus3dBInQ15 = (int)(0.707f * RawQ15One);
private const int Minus6dBInQ15 = (int)(0.501f * RawQ15One); private const int Minus6dBInQ15 = (int)(0.501f * RawQ15One);
private const int Minus12dBInQ15 = (int)(0.251f * RawQ15One); private const int Minus12dBInQ15 = (int)(0.251f * RawQ15One);
private static int[] DefaultSurroundToStereoCoefficients = new int[4] private static readonly int[] DefaultSurroundToStereoCoefficients = new int[4]
{ {
RawQ15One, RawQ15One,
Minus3dBInQ15, Minus3dBInQ15,
Minus12dBInQ15, Minus12dBInQ15,
Minus3dBInQ15, Minus3dBInQ15
}; };
private static int[] DefaultStereoToMonoCoefficients = new int[2] private static readonly int[] DefaultStereoToMonoCoefficients = new int[2]
{ {
Minus6dBInQ15, Minus6dBInQ15,
Minus6dBInQ15, Minus6dBInQ15
}; };
private const int SurroundChannelCount = 6;
private const int StereoChannelCount = 2;
private const int MonoChannelCount = 1;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ReadOnlySpan<Channel51FormatPCM16> GetSurroundBuffer(ReadOnlySpan<short> data) private static ReadOnlySpan<Channel51FormatPCM16> GetSurroundBuffer(ReadOnlySpan<short> data)
{ {
@ -72,9 +76,6 @@ namespace Ryujinx.Audio
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static short[] DownMixSurroundToStereo(ReadOnlySpan<int> coefficients, ReadOnlySpan<short> data) private static short[] DownMixSurroundToStereo(ReadOnlySpan<int> coefficients, ReadOnlySpan<short> data)
{ {
const int SurroundChannelCount = 6;
const int StereoChannelCount = 2;
int samplePerChannelCount = data.Length / SurroundChannelCount; int samplePerChannelCount = data.Length / SurroundChannelCount;
short[] downmixedBuffer = new short[samplePerChannelCount * StereoChannelCount]; short[] downmixedBuffer = new short[samplePerChannelCount * StereoChannelCount];
@ -85,7 +86,7 @@ namespace Ryujinx.Audio
{ {
Channel51FormatPCM16 channel = channels[i]; Channel51FormatPCM16 channel = channels[i];
downmixedBuffer[i * 2] = DownMixSurroundToStereo(coefficients, channel.BackLeft, channel.LowFrequency, channel.FrontCenter, channel.FrontLeft); downmixedBuffer[i * 2] = DownMixSurroundToStereo(coefficients, channel.BackLeft, channel.LowFrequency, channel.FrontCenter, channel.FrontLeft);
downmixedBuffer[i * 2 + 1] = DownMixSurroundToStereo(coefficients, channel.BackRight, channel.LowFrequency, channel.FrontCenter, channel.FrontRight); downmixedBuffer[i * 2 + 1] = DownMixSurroundToStereo(coefficients, channel.BackRight, channel.LowFrequency, channel.FrontCenter, channel.FrontRight);
} }
@ -95,9 +96,6 @@ namespace Ryujinx.Audio
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static short[] DownMixStereoToMono(ReadOnlySpan<int> coefficients, ReadOnlySpan<short> data) private static short[] DownMixStereoToMono(ReadOnlySpan<int> coefficients, ReadOnlySpan<short> data)
{ {
const int StereoChannelCount = 2;
const int MonoChannelCount = 1;
int samplePerChannelCount = data.Length / StereoChannelCount; int samplePerChannelCount = data.Length / StereoChannelCount;
short[] downmixedBuffer = new short[samplePerChannelCount * MonoChannelCount]; short[] downmixedBuffer = new short[samplePerChannelCount * MonoChannelCount];

View File

@ -1,16 +0,0 @@
namespace Ryujinx.Audio
{
public static class DspUtils
{
public static short Saturate(int Value)
{
if (Value > short.MaxValue)
Value = short.MaxValue;
if (Value < short.MinValue)
Value = short.MinValue;
return (short)Value;
}
}
}

View File

@ -13,17 +13,13 @@ namespace Ryujinx.Audio
return targetChannelCount; return targetChannelCount;
} }
switch (targetChannelCount) return targetChannelCount switch
{ {
case 6: 6 => SelectHardwareChannelCount(2),
return SelectHardwareChannelCount(2); 2 => SelectHardwareChannelCount(1),
case 2: 1 => throw new ArgumentException("No valid channel configuration found!"),
return SelectHardwareChannelCount(1); _ => throw new ArgumentException($"Invalid targetChannelCount {targetChannelCount}"),
case 1: };
throw new ArgumentException("No valid channel configuration found!");
default:
throw new ArgumentException($"Invalid targetChannelCount {targetChannelCount}");
}
} }
int OpenTrack(int sampleRate, int channels, ReleaseCallback callback) int OpenTrack(int sampleRate, int channels, ReleaseCallback callback)

View File

@ -4,308 +4,383 @@ using System.Runtime.InteropServices;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public class SoundIO : IDisposable public class SoundIO : IDisposable
{ {
Pointer<SoundIo> handle; Pointer<SoundIo> handle;
public SoundIO () public SoundIO()
{ {
handle = Natives.soundio_create (); handle = Natives.soundio_create();
} }
internal SoundIO (Pointer<SoundIo> handle) internal SoundIO(Pointer<SoundIo> handle)
{ {
this.handle = handle; this.handle = handle;
} }
public void Dispose () public void Dispose ()
{ {
foreach (var h in allocated_hglobals) foreach (var h in allocated_hglobals)
Marshal.FreeHGlobal (h); {
Natives.soundio_destroy (handle); Marshal.FreeHGlobal(h);
} }
// Equality (based on handle) Natives.soundio_destroy(handle);
}
public override bool Equals (object other) // Equality (based on handle)
{
var d = other as SoundIO;
return d != null && this.handle == d.handle;
}
public override int GetHashCode () public override bool Equals(object other)
{ {
return (int) (IntPtr) handle; var d = other as SoundIO;
}
public static bool operator == (SoundIO obj1, SoundIO obj2) return d != null && this.handle == d.handle;
{ }
return (object)obj1 == null ? (object)obj2 == null : obj1.Equals (obj2);
}
public static bool operator != (SoundIO obj1, SoundIO obj2) public override int GetHashCode()
{ {
return (object)obj1 == null ? (object)obj2 != null : !obj1.Equals (obj2); return (int)(IntPtr)handle;
} }
// fields public static bool operator == (SoundIO obj1, SoundIO obj2)
{
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
}
// FIXME: this should be taken care in more centralized/decent manner... we don't want to write public static bool operator != (SoundIO obj1, SoundIO obj2)
// this kind of code anywhere we need string marshaling. {
List<IntPtr> allocated_hglobals = new List<IntPtr> (); return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
}
public string ApplicationName { // fields
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 { // FIXME: this should be taken care in more centralized/decent manner... we don't want to write
get { return (SoundIOBackend) Marshal.ReadInt32 (handle, current_backend_offset); } // this kind of code anywhere we need string marshaling.
} List<IntPtr> allocated_hglobals = new List<IntPtr>();
static readonly int current_backend_offset = (int)Marshal.OffsetOf<SoundIo> ("current_backend");
// emit_rtprio_warning public string ApplicationName {
public Action EmitRealtimePriorityWarning { get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, app_name_offset)); }
get { return emit_rtprio_warning; } set
set { {
emit_rtprio_warning = value; unsafe
var ptr = Marshal.GetFunctionPointerForDelegate (on_devices_change); {
Marshal.WriteIntPtr (handle, emit_rtprio_warning_offset, ptr); var existing = Marshal.ReadIntPtr(handle, app_name_offset);
} if (allocated_hglobals.Contains (existing))
} {
static readonly int emit_rtprio_warning_offset = (int)Marshal.OffsetOf<SoundIo> ("emit_rtprio_warning"); allocated_hglobals.Remove(existing);
Action emit_rtprio_warning; Marshal.FreeHGlobal(existing);
}
// jack_error_callback var ptr = Marshal.StringToHGlobalAnsi(value);
public Action<string> JackErrorCallback { Marshal.WriteIntPtr(handle, app_name_offset, ptr);
get { return jack_error_callback; } allocated_hglobals.Add(ptr);
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 static readonly int app_name_offset = (int)Marshal.OffsetOf<SoundIo>("app_name");
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 SoundIOBackend CurrentBackend
public Action<int> OnBackendDisconnect { {
get { return on_backend_disconnect; } get { return (SoundIOBackend)Marshal.ReadInt32(handle, current_backend_offset); }
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 static readonly int current_backend_offset = (int)Marshal.OffsetOf<SoundIo>("current_backend");
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 // emit_rtprio_warning
public Action OnEventsSignal { public Action EmitRealtimePriorityWarning
get { return on_events_signal; } {
set { get { return emit_rtprio_warning; }
on_events_signal = value; set
if (value == null) {
on_events_signal_native = null; emit_rtprio_warning = value;
else
on_events_signal_native = sio => on_events_signal (); var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change);
var ptr = Marshal.GetFunctionPointerForDelegate (on_events_signal_native);
Marshal.WriteIntPtr (handle, on_events_signal_offset, ptr); Marshal.WriteIntPtr(handle, emit_rtprio_warning_offset, ptr);
} }
} }
static readonly int on_events_signal_offset = (int)Marshal.OffsetOf<SoundIo> ("on_events_signal");
Action on_events_signal; static readonly int emit_rtprio_warning_offset = (int)Marshal.OffsetOf<SoundIo>("emit_rtprio_warning");
delegate void on_events_signal_delegate (IntPtr handle);
on_events_signal_delegate on_events_signal_native; 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 // functions
public int BackendCount { public int BackendCount
get { return Natives.soundio_backend_count (handle); } {
} get { return Natives.soundio_backend_count(handle); }
}
public int InputDeviceCount { public int InputDeviceCount
get { return Natives.soundio_input_device_count (handle); } {
} get { return Natives.soundio_input_device_count(handle); }
}
public int OutputDeviceCount { public int OutputDeviceCount
get { return Natives.soundio_output_device_count (handle); } {
} get { return Natives.soundio_output_device_count(handle); }
}
public int DefaultInputDeviceIndex { public int DefaultInputDeviceIndex
get { return Natives.soundio_default_input_device_index (handle); } {
} get { return Natives.soundio_default_input_device_index(handle); }
}
public int DefaultOutputDeviceIndex { public int DefaultOutputDeviceIndex
get { return Natives.soundio_default_output_device_index (handle); } {
} get { return Natives.soundio_default_output_device_index(handle); }
}
public SoundIOBackend GetBackend (int index) public SoundIOBackend GetBackend(int index)
{ {
return (SoundIOBackend) Natives.soundio_get_backend (handle, index); return (SoundIOBackend)Natives.soundio_get_backend(handle, index);
} }
public SoundIODevice GetInputDevice (int index) public SoundIODevice GetInputDevice(int index)
{ {
return new SoundIODevice (Natives.soundio_get_input_device (handle, index)); return new SoundIODevice(Natives.soundio_get_input_device(handle, index));
} }
public SoundIODevice GetOutputDevice (int index) public SoundIODevice GetOutputDevice(int index)
{ {
return new SoundIODevice (Natives.soundio_get_output_device (handle, index)); return new SoundIODevice(Natives.soundio_get_output_device(handle, index));
} }
public void Connect () public void Connect()
{ {
var ret = (SoundIoError) Natives.soundio_connect (handle); var ret = (SoundIoError)Natives.soundio_connect(handle);
if (ret != SoundIoError.SoundIoErrorNone) if (ret != SoundIoError.SoundIoErrorNone)
throw new SoundIOException (ret); {
} throw new SoundIOException(ret);
}
}
public void ConnectBackend (SoundIOBackend backend) public void ConnectBackend(SoundIOBackend backend)
{ {
var ret = (SoundIoError) Natives.soundio_connect_backend (handle, (SoundIoBackend) backend); var ret = (SoundIoError)Natives.soundio_connect_backend(handle, (SoundIoBackend)backend);
if (ret != SoundIoError.SoundIoErrorNone) if (ret != SoundIoError.SoundIoErrorNone)
throw new SoundIOException (ret); {
} throw new SoundIOException(ret);
}
}
public void Disconnect () public void Disconnect()
{ {
Natives.soundio_disconnect (handle); Natives.soundio_disconnect(handle);
} }
public void FlushEvents () public void FlushEvents()
{ {
Natives.soundio_flush_events (handle); Natives.soundio_flush_events(handle);
} }
public void WaitEvents () public void WaitEvents()
{ {
Natives.soundio_wait_events (handle); Natives.soundio_wait_events(handle);
} }
public void Wakeup () public void Wakeup()
{ {
Natives.soundio_wakeup (handle); Natives.soundio_wakeup(handle);
} }
public void ForceDeviceScan () public void ForceDeviceScan()
{ {
Natives.soundio_force_device_scan (handle); Natives.soundio_force_device_scan(handle);
} }
public SoundIORingBuffer CreateRingBuffer (int capacity) public SoundIORingBuffer CreateRingBuffer(int capacity)
{ {
return new SoundIORingBuffer (Natives.soundio_ring_buffer_create (handle, capacity)); return new SoundIORingBuffer(Natives.soundio_ring_buffer_create(handle, capacity));
} }
// static methods // static methods
public static string VersionString { public static string VersionString
get { return Marshal.PtrToStringAnsi (Natives.soundio_version_string ()); } {
} get { return Marshal.PtrToStringAnsi(Natives.soundio_version_string()); }
}
public static int VersionMajor { public static int VersionMajor
get { return Natives.soundio_version_major (); } {
} get { return Natives.soundio_version_major(); }
}
public static int VersionMinor { public static int VersionMinor
get { return Natives.soundio_version_minor (); } {
} get { return Natives.soundio_version_minor(); }
}
public static int VersionPatch { public static int VersionPatch
get { return Natives.soundio_version_patch (); } {
} get { return Natives.soundio_version_patch(); }
}
public static string GetBackendName (SoundIOBackend backend) public static string GetBackendName(SoundIOBackend backend)
{ {
return Marshal.PtrToStringAnsi (Natives.soundio_backend_name ((SoundIoBackend) backend)); return Marshal.PtrToStringAnsi(Natives.soundio_backend_name((SoundIoBackend)backend));
} }
public static bool HaveBackend (SoundIOBackend backend) public static bool HaveBackend(SoundIOBackend backend)
{ {
return Natives.soundio_have_backend ((SoundIoBackend) backend); return Natives.soundio_have_backend((SoundIoBackend)backend);
} }
public static int GetBytesPerSample (SoundIOFormat format) public static int GetBytesPerSample(SoundIOFormat format)
{ {
return Natives.soundio_get_bytes_per_sample ((SoundIoFormat) format); return Natives.soundio_get_bytes_per_sample((SoundIoFormat)format);
} }
public static int GetBytesPerFrame (SoundIOFormat format, int channelCount) public static int GetBytesPerFrame(SoundIOFormat format, int channelCount)
{ {
return Natives.soundio_get_bytes_per_frame ((SoundIoFormat) format, channelCount); return Natives.soundio_get_bytes_per_frame((SoundIoFormat)format, channelCount);
} }
public static int GetBytesPerSecond (SoundIOFormat format, int channelCount, int sampleRate) public static int GetBytesPerSecond(SoundIOFormat format, int channelCount, int sampleRate)
{ {
return Natives.soundio_get_bytes_per_second ((SoundIoFormat) format, channelCount, sampleRate); return Natives.soundio_get_bytes_per_second((SoundIoFormat)format, channelCount, sampleRate);
} }
public static string GetSoundFormatName (SoundIOFormat format) public static string GetSoundFormatName(SoundIOFormat format)
{ {
return Marshal.PtrToStringAnsi (Natives.soundio_format_string ((SoundIoFormat) format)); return Marshal.PtrToStringAnsi(Natives.soundio_format_string((SoundIoFormat)format));
} }
} }
} }

View File

@ -1,15 +1,13 @@
using System; namespace SoundIOSharp
namespace SoundIOSharp
{ {
public enum SoundIOBackend public enum SoundIOBackend
{ {
None = 0, None,
Jack = 1, Jack,
PulseAudio = 2, PulseAudio,
Alsa = 3, Alsa,
CoreAudio = 4, CoreAudio,
Wasapi = 5, Wasapi,
Dummy = 6, Dummy
} }
} }

View File

@ -3,24 +3,28 @@ using System.Runtime.InteropServices;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public struct SoundIOChannelArea public struct SoundIOChannelArea
{ {
internal SoundIOChannelArea (Pointer<SoundIoChannelArea> handle) internal SoundIOChannelArea(Pointer<SoundIoChannelArea> handle)
{ {
this.handle = handle; this.handle = handle;
} }
Pointer<SoundIoChannelArea> handle; Pointer<SoundIoChannelArea> handle;
public IntPtr Pointer { public IntPtr Pointer
get { return Marshal.ReadIntPtr (handle, ptr_offset); } {
set { Marshal.WriteIntPtr (handle, ptr_offset, value); } 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 { static readonly int ptr_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("ptr");
get { return Marshal.ReadInt32 (handle, step_offset); }
} public int Step
static readonly int step_offset = (int)Marshal.OffsetOf<SoundIoChannelArea> ("step"); {
} get { return Marshal.ReadInt32(handle, step_offset); }
}
static readonly int step_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("step");
}
} }

View File

@ -3,31 +3,32 @@ using System.Runtime.InteropServices;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public struct SoundIOChannelAreas public struct SoundIOChannelAreas
{ {
static readonly int native_size = Marshal.SizeOf<SoundIoChannelArea> (); static readonly int native_size = Marshal.SizeOf<SoundIoChannelArea>();
internal SoundIOChannelAreas (IntPtr head, int channelCount, int frameCount) internal SoundIOChannelAreas(IntPtr head, int channelCount, int frameCount)
{ {
this.head = head; this.head = head;
this.channel_count = channelCount; this.channel_count = channelCount;
this.frame_count = frameCount; this.frame_count = frameCount;
} }
IntPtr head; IntPtr head;
int channel_count; int channel_count;
int frame_count; int frame_count;
public bool IsEmpty { public bool IsEmpty
get { return head == IntPtr.Zero; } {
} get { return head == IntPtr.Zero; }
}
public SoundIOChannelArea GetArea (int channel) public SoundIOChannelArea GetArea(int channel)
{ {
return new SoundIOChannelArea (head + native_size * channel); return new SoundIOChannelArea(head + native_size * channel);
} }
public int ChannelCount => channel_count; public int ChannelCount => channel_count;
public int FrameCount => frame_count; public int FrameCount => frame_count;
} }
} }

View File

@ -1,77 +1,75 @@
using System; namespace SoundIOSharp
namespace SoundIOSharp
{ {
public enum SoundIOChannelId
public enum SoundIOChannelId {
{ Invalid,
Invalid = 0, FrontLeft,
FrontLeft = 1, FrontRight,
FrontRight = 2, FrontCenter,
FrontCenter = 3, Lfe,
Lfe = 4, BackLeft,
BackLeft = 5, BackRight,
BackRight = 6, FrontLeftCenter,
FrontLeftCenter = 7, FrontRightCenter,
FrontRightCenter = 8, BackCenter,
BackCenter = 9, SideLeft,
SideLeft = 10, SideRight,
SideRight = 11, TopCenter,
TopCenter = 12, TopFrontLeft,
TopFrontLeft = 13, TopFrontCenter,
TopFrontCenter = 14, TopFrontRight,
TopFrontRight = 15, TopBackLeft,
TopBackLeft = 16, TopBackCenter,
TopBackCenter = 17, TopBackRight,
TopBackRight = 18, BackLeftCenter,
BackLeftCenter = 19, BackRightCenter,
BackRightCenter = 20, FrontLeftWide,
FrontLeftWide = 21, FrontRightWide,
FrontRightWide = 22, FrontLeftHigh,
FrontLeftHigh = 23, FrontCenterHigh,
FrontCenterHigh = 24, FrontRightHigh,
FrontRightHigh = 25, TopFrontLeftCenter,
TopFrontLeftCenter = 26, TopFrontRightCenter,
TopFrontRightCenter = 27, TopSideLeft,
TopSideLeft = 28, TopSideRight,
TopSideRight = 29, LeftLfe,
LeftLfe = 30, RightLfe,
RightLfe = 31, Lfe2,
Lfe2 = 32, BottomCenter,
BottomCenter = 33, BottomLeftCenter,
BottomLeftCenter = 34, BottomRightCenter,
BottomRightCenter = 35, MsMid,
MsMid = 36, MsSide,
MsSide = 37, AmbisonicW,
AmbisonicW = 38, AmbisonicX,
AmbisonicX = 39, AmbisonicY,
AmbisonicY = 40, AmbisonicZ,
AmbisonicZ = 41, XyX,
XyX = 42, XyY,
XyY = 43, HeadphonesLeft,
HeadphonesLeft = 44, HeadphonesRight,
HeadphonesRight = 45, ClickTrack,
ClickTrack = 46, ForeignLanguage,
ForeignLanguage = 47, HearingImpaired,
HearingImpaired = 48, Narration,
Narration = 49, Haptic,
Haptic = 50, DialogCentricMix,
DialogCentricMix = 51, Aux,
Aux = 52, Aux0,
Aux0 = 53, Aux1,
Aux1 = 54, Aux2,
Aux2 = 55, Aux3,
Aux3 = 56, Aux4,
Aux4 = 57, Aux5,
Aux5 = 58, Aux6,
Aux6 = 59, Aux7,
Aux7 = 60, Aux8,
Aux8 = 61, Aux9,
Aux9 = 62, Aux10,
Aux10 = 63, Aux11,
Aux11 = 64, Aux12,
Aux12 = 65, Aux13,
Aux13 = 66, Aux14,
Aux14 = 67, Aux15
Aux15 = 68, }
}
} }

View File

@ -1,99 +1,116 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public struct SoundIOChannelLayout public struct SoundIOChannelLayout
{ {
public static int BuiltInCount { public static int BuiltInCount
get { return Natives.soundio_channel_layout_builtin_count (); } {
} get { return Natives.soundio_channel_layout_builtin_count(); }
}
public static SoundIOChannelLayout GetBuiltIn (int index) public static SoundIOChannelLayout GetBuiltIn(int index)
{ {
return new SoundIOChannelLayout (Natives.soundio_channel_layout_get_builtin (index)); return new SoundIOChannelLayout(Natives.soundio_channel_layout_get_builtin(index));
} }
public static SoundIOChannelLayout GetDefault (int channelCount) public static SoundIOChannelLayout GetDefault(int channelCount)
{ {
var handle = Natives.soundio_channel_layout_get_default (channelCount); var handle = Natives.soundio_channel_layout_get_default(channelCount);
return new SoundIOChannelLayout (handle);
}
public static SoundIOChannelId ParseChannelId (string name) return new SoundIOChannelLayout (handle);
{ }
var ptr = Marshal.StringToHGlobalAnsi (name);
try {
return (SoundIOChannelId)Natives.soundio_parse_channel_id (ptr, name.Length);
} finally {
Marshal.FreeHGlobal (ptr);
}
}
// instance members public static SoundIOChannelId ParseChannelId(string name)
{
var ptr = Marshal.StringToHGlobalAnsi(name);
internal SoundIOChannelLayout (Pointer<SoundIoChannelLayout> handle) try
{ {
this.handle = handle; return (SoundIOChannelId)Natives.soundio_parse_channel_id(ptr, name.Length);
} }
finally
{
Marshal.FreeHGlobal(ptr);
}
}
readonly Pointer<SoundIoChannelLayout> handle; // instance members
public bool IsNull { internal SoundIOChannelLayout(Pointer<SoundIoChannelLayout> handle)
get { return handle.Handle == IntPtr.Zero; } {
} this.handle = handle;
}
internal IntPtr Handle { readonly Pointer<SoundIoChannelLayout> handle;
get { return handle; }
}
public int ChannelCount { public bool IsNull
get { return IsNull ? 0 : Marshal.ReadInt32 ((IntPtr) handle + channel_count_offset); } {
} get { return handle.Handle == IntPtr.Zero; }
static readonly int channel_count_offset = (int) Marshal.OffsetOf<SoundIoChannelLayout> ("channel_count"); }
public string Name { internal IntPtr Handle
get { return IsNull ? null : Marshal.PtrToStringAnsi (Marshal.ReadIntPtr ((IntPtr) handle + name_offset)); } {
} get { return handle; }
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout> ("name"); }
public IEnumerable<SoundIOChannelId> Channels { public int ChannelCount
get { {
if (IsNull) get { return IsNull ? 0 : Marshal.ReadInt32((IntPtr)handle + channel_count_offset); }
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) static readonly int channel_count_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("channel_count");
{
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 () public string Name
{ {
return handle.GetHashCode (); get { return IsNull ? null : Marshal.PtrToStringAnsi(Marshal.ReadIntPtr((IntPtr)handle + name_offset)); }
} }
public string DetectBuiltInName () static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("name");
{
if (IsNull)
throw new InvalidOperationException ();
return Natives.soundio_channel_layout_detect_builtin (handle) ? Name : null;
}
public int FindChannel (SoundIOChannelId channel) public IEnumerable<SoundIOChannelId> Channels
{ {
if (IsNull) get
throw new InvalidOperationException (); {
return Natives.soundio_channel_layout_find_channel (handle, (SoundIoChannelId) channel); 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);
}
}
} }

View File

@ -4,217 +4,264 @@ using System.Runtime.InteropServices;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public class SoundIODevice public class SoundIODevice
{ {
public static SoundIOChannelLayout BestMatchingChannelLayout (SoundIODevice device1, SoundIODevice device2) public static SoundIOChannelLayout BestMatchingChannelLayout(SoundIODevice device1, SoundIODevice device2)
{ {
var ptr1 = Marshal.ReadIntPtr (device1.handle, layouts_offset); var ptr1 = Marshal.ReadIntPtr(device1.handle, layouts_offset);
var ptr2 = Marshal.ReadIntPtr (device2.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) return new SoundIOChannelLayout(Natives.soundio_best_matching_channel_layout(ptr1, device1.LayoutCount, ptr2, device2.LayoutCount));
{ }
this.handle = handle;
}
readonly Pointer<SoundIoDevice> handle; internal SoundIODevice(Pointer<SoundIoDevice> handle)
{
this.handle = handle;
}
// Equality (based on handle and native func) readonly Pointer<SoundIoDevice> handle;
public override bool Equals (object other) // Equality (based on handle and native func)
{
var d = other as SoundIODevice;
return d != null && (this.handle == d.handle || Natives.soundio_device_equal (this.handle, d.handle));
}
public override int GetHashCode () public override bool Equals(object other)
{ {
return (int) (IntPtr) handle; var d = other as SoundIODevice;
}
public static bool operator == (SoundIODevice obj1, SoundIODevice obj2) return d != null && (this.handle == d.handle || Natives.soundio_device_equal (this.handle, d.handle));
{ }
return (object)obj1 == null ? (object)obj2 == null : obj1.Equals (obj2);
}
public static bool operator != (SoundIODevice obj1, SoundIODevice obj2) public override int GetHashCode()
{ {
return (object)obj1 == null ? (object) obj2 != null : !obj1.Equals (obj2); return (int)(IntPtr)handle;
} }
// fields public static bool operator == (SoundIODevice obj1, SoundIODevice obj2)
{
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
}
public SoundIODeviceAim Aim { public static bool operator != (SoundIODevice obj1, SoundIODevice obj2)
get { return (SoundIODeviceAim) Marshal.ReadInt32 (handle, aim_offset); } {
} return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
static readonly int aim_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("aim"); }
public SoundIOFormat CurrentFormat { // fields
get { return (SoundIOFormat) Marshal.ReadInt32 (handle, current_format_offset); }
}
static readonly int current_format_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("current_format");
public SoundIOChannelLayout CurrentLayout { public SoundIODeviceAim Aim
get { return new SoundIOChannelLayout ((IntPtr) handle + current_layout_offset); {
} get { return (SoundIODeviceAim)Marshal.ReadInt32(handle, aim_offset); }
} }
static readonly int current_layout_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("current_layout");
public int FormatCount { static readonly int aim_offset = (int)Marshal.OffsetOf<SoundIoDevice>("aim");
get { return Marshal.ReadInt32 (handle, format_count_offset); }
}
static readonly int format_count_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("format_count");
public IEnumerable<SoundIOFormat> Formats { public SoundIOFormat CurrentFormat
get { {
var ptr = Marshal.ReadIntPtr (handle, formats_offset); get { return (SoundIOFormat)Marshal.ReadInt32(handle, current_format_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 { static readonly int current_format_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_format");
get { return Marshal.PtrToStringAnsi (Marshal.ReadIntPtr (handle, id_offset)); }
}
static readonly int id_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("id");
public bool IsRaw { public SoundIOChannelLayout CurrentLayout
get { return Marshal.ReadInt32 (handle, is_raw_offset) != 0; } {
} get { return new SoundIOChannelLayout((IntPtr)handle + current_layout_offset); }
static readonly int is_raw_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("is_raw"); }
public int LayoutCount { static readonly int current_layout_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_layout");
get { return Marshal.ReadInt32 (handle, layout_count_offset); }
}
static readonly int layout_count_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("layout_count");
public IEnumerable<SoundIOChannelLayout> Layouts { public int FormatCount
get { {
var ptr = Marshal.ReadIntPtr (handle, layouts_offset); get { return Marshal.ReadInt32(handle, format_count_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 { static readonly int format_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("format_count");
get { return Marshal.PtrToStringAnsi (Marshal.ReadIntPtr (handle, name_offset)); }
}
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("name");
public int ProbeError { public IEnumerable<SoundIOFormat> Formats
get { return Marshal.ReadInt32 (handle, probe_error_offset); } {
} get
static readonly int probe_error_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("probe_error"); {
var ptr = Marshal.ReadIntPtr(handle, formats_offset);
public int ReferenceCount { for (int i = 0; i < FormatCount; i++)
get { return Marshal.ReadInt32 (handle, ref_count_offset); } {
} yield return (SoundIOFormat)Marshal.ReadInt32(ptr, i);
static readonly int ref_count_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("ref_count"); }
}
}
public int SampleRateCount { static readonly int formats_offset = (int)Marshal.OffsetOf<SoundIoDevice>("formats");
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 { public string Id
get { {
var ptr = Marshal.ReadIntPtr (handle, sample_rates_offset); get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, id_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 { static readonly int id_offset = (int)Marshal.OffsetOf<SoundIoDevice>("id");
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 { public bool IsRaw
get { return MarshalEx.ReadDouble (handle, software_latency_min_offset); } {
set { MarshalEx.WriteDouble (handle, software_latency_min_offset, value); } get { return Marshal.ReadInt32(handle, is_raw_offset) != 0; }
} }
static readonly int software_latency_min_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("software_latency_min");
public double SoftwareLatencyMax { static readonly int is_raw_offset = (int)Marshal.OffsetOf<SoundIoDevice>("is_raw");
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 { public int LayoutCount
get { return new SoundIO (Marshal.ReadIntPtr (handle, soundio_offset)); } {
} get { return Marshal.ReadInt32(handle, layout_count_offset); }
static readonly int soundio_offset = (int)Marshal.OffsetOf<SoundIoDevice> ("soundio"); }
// functions static readonly int layout_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layout_count");
public void AddReference () public IEnumerable<SoundIOChannelLayout> Layouts
{ {
Natives.soundio_device_ref (handle); get
} {
var ptr = Marshal.ReadIntPtr (handle, layouts_offset);
public void RemoveReference () for (int i = 0; i < LayoutCount; i++)
{ {
Natives.soundio_device_unref (handle); yield return new SoundIOChannelLayout(ptr + i * Marshal.SizeOf<SoundIoChannelLayout>());
} }
}
}
public void SortDeviceChannelLayouts () static readonly int layouts_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layouts");
{
Natives.soundio_device_sort_channel_layouts (handle);
}
public static readonly SoundIOFormat S16NE = BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE; public string Name
public static readonly SoundIOFormat U16NE = BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE; {
public static readonly SoundIOFormat S24NE = BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE; get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
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) static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoDevice>("name");
{
return Natives.soundio_device_supports_format (handle, (SoundIoFormat) format);
}
public bool SupportsSampleRate (int sampleRate) public int ProbeError
{ {
return Natives.soundio_device_supports_sample_rate (handle, sampleRate); get { return Marshal.ReadInt32(handle, probe_error_offset); }
} }
public bool SupportsChannelCount(int channelCount) static readonly int probe_error_offset = (int)Marshal.OffsetOf<SoundIoDevice>("probe_error");
{
return Natives.soundio_device_supports_layout(handle, SoundIOChannelLayout.GetDefault(channelCount).Handle);
}
public int GetNearestSampleRate (int sampleRate) public int ReferenceCount
{ {
return Natives.soundio_device_nearest_sample_rate (handle, sampleRate); get { return Marshal.ReadInt32(handle, ref_count_offset); }
} }
public SoundIOInStream CreateInStream () static readonly int ref_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("ref_count");
{
return new SoundIOInStream (Natives.soundio_instream_create (handle));
}
public SoundIOOutStream CreateOutStream () public int SampleRateCount
{ {
return new SoundIOOutStream (Natives.soundio_outstream_create (handle)); 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));
}
}
} }

View File

@ -1,9 +1,8 @@
using System; namespace SoundIOSharp
namespace SoundIOSharp
{ {
public enum SoundIODeviceAim // soundio.h (228, 6) public enum SoundIODeviceAim // soundio.h (228, 6)
{ {
Input = 0, Input,
Output = 1, Output
} }
} }

View File

@ -3,11 +3,8 @@ using System.Runtime.InteropServices;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public class SoundIOException : Exception public class SoundIOException : Exception
{ {
internal SoundIOException (SoundIoError errorCode) internal SoundIOException(SoundIoError errorCode) : base (Marshal.PtrToStringAnsi(Natives.soundio_strerror((int) errorCode))) { }
: base (Marshal.PtrToStringAnsi (Natives.soundio_strerror ((int) errorCode))) }
{
}
}
} }

View File

@ -1,26 +1,25 @@
using System; namespace SoundIOSharp
namespace SoundIOSharp
{ {
public enum SoundIOFormat public enum SoundIOFormat
{ {
Invalid = 0, Invalid,
S8 = 1, S8,
U8 = 2, U8,
S16LE = 3, S16LE,
S16BE = 4, S16BE,
U16LE = 5, U16LE,
U16BE = 6, U16BE,
S24LE = 7, S24LE,
S24BE = 8, S24BE,
U24LE = 9, U24LE,
U24BE = 10, U24BE,
S32LE = 11, S32LE,
S32BE = 12, S32BE,
U32LE = 13, U32LE,
U32BE = 14, U32BE,
Float32LE = 15, Float32LE,
Float32BE = 16, Float32BE,
Float64LE = 17, Float64LE,
Float64BE = 18, Float64BE
} }
} }

View File

@ -4,225 +4,290 @@ using System.Runtime.InteropServices;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public class SoundIOInStream : IDisposable public class SoundIOInStream : IDisposable
{ {
internal SoundIOInStream (Pointer<SoundIoInStream> handle) internal SoundIOInStream(Pointer<SoundIoInStream> handle)
{ {
this.handle = handle; this.handle = handle;
} }
Pointer<SoundIoInStream> handle; Pointer<SoundIoInStream> handle;
public void Dispose () public void Dispose()
{ {
Natives.soundio_instream_destroy (handle); Natives.soundio_instream_destroy(handle);
} }
// Equality (based on handle) // Equality (based on handle)
public override bool Equals (object other) public override bool Equals(object other)
{ {
var d = other as SoundIOInStream; var d = other as SoundIOInStream;
return d != null && (this.handle == d.handle);
}
public override int GetHashCode () return d != null && (this.handle == d.handle);
{ }
return (int)(IntPtr)handle;
}
public static bool operator == (SoundIOInStream obj1, SoundIOInStream obj2) public override int GetHashCode()
{ {
return (object)obj1 == null ? (object)obj2 == null : obj1.Equals (obj2); return (int)(IntPtr)handle;
} }
public static bool operator != (SoundIOInStream obj1, SoundIOInStream obj2) public static bool operator == (SoundIOInStream obj1, SoundIOInStream obj2)
{ {
return (object)obj1 == null ? (object)obj2 != null : !obj1.Equals (obj2); return obj1 is null ? obj2 is null : obj1.Equals(obj2);
} }
// fields public static bool operator != (SoundIOInStream obj1, SoundIOInStream obj2)
{
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
}
public SoundIODevice Device { // fields
get { return new SoundIODevice (Marshal.ReadIntPtr (handle, device_offset)); }
}
static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoInStream> ("device");
public SoundIOFormat Format { public SoundIODevice Device
get { return (SoundIOFormat) Marshal.ReadInt32 (handle, format_offset); } {
set { Marshal.WriteInt32 (handle, format_offset, (int) value); } get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); }
} }
static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoInStream> ("format");
public int SampleRate { static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoInStream>("device");
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 { public SoundIOFormat Format
get { return new SoundIOChannelLayout ((IntPtr) handle + layout_offset); } {
set { get { return (SoundIOFormat)Marshal.ReadInt32(handle, format_offset); }
unsafe { set { Marshal.WriteInt32(handle, format_offset, (int) value); }
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");
static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoInStream>("format");
public double SoftwareLatency { public int SampleRate
get { return MarshalEx.ReadDouble (handle, software_latency_offset); } {
set { MarshalEx.WriteDouble (handle, software_latency_offset, value); } get { return Marshal.ReadInt32(handle, sample_rate_offset); }
} set { Marshal.WriteInt32(handle, sample_rate_offset, value); }
static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoInStream> ("software_latency"); }
// error_callback static readonly int sample_rate_offset = (int)Marshal.OffsetOf<SoundIoInStream>("sample_rate");
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 SoundIOChannelLayout Layout
public Action<int,int> ReadCallback { {
get { return read_callback; } get { return new SoundIOChannelLayout ((IntPtr) handle + layout_offset); }
set { set
read_callback = value; {
read_callback_native = (_, minFrameCount, maxFrameCount) => read_callback (minFrameCount, maxFrameCount); unsafe
var ptr = Marshal.GetFunctionPointerForDelegate (read_callback_native); {
Marshal.WriteIntPtr (handle, read_callback_offset, ptr); Buffer.MemoryCopy((void*)((IntPtr)handle + layout_offset), (void*)value.Handle, Marshal.SizeOf<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
} }
} }
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 static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoInStream>("layout");
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 public double SoftwareLatency
// this kind of code anywhere we need string marshaling. {
List<IntPtr> allocated_hglobals = new List<IntPtr> (); get { return MarshalEx.ReadDouble(handle, software_latency_offset); }
set { MarshalEx.WriteDouble(handle, software_latency_offset, value); }
}
public string Name { static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoInStream>("software_latency");
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 { // error_callback
get { return Marshal.ReadInt32 (handle, non_terminal_hint_offset) != 0; } public Action ErrorCallback
} {
static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoInStream> ("non_terminal_hint"); get { return error_callback; }
set
{
error_callback = value;
error_callback_native = _ => error_callback();
public int BytesPerFrame { var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native);
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 { Marshal.WriteIntPtr(handle, error_callback_offset, ptr);
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 { static readonly int error_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("error_callback");
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 Action error_callback;
delegate void error_callback_delegate(IntPtr handle);
error_callback_delegate error_callback_native;
public void Open () // read_callback
{ public Action<int,int> ReadCallback
var ret = (SoundIoError) Natives.soundio_instream_open (handle); {
if (ret != SoundIoError.SoundIoErrorNone) get { return read_callback; }
throw new SoundIOException (ret); set
} {
read_callback = value;
read_callback_native = (_, minFrameCount, maxFrameCount) => read_callback(minFrameCount, maxFrameCount);
public void Start () var ptr = Marshal.GetFunctionPointerForDelegate(read_callback_native);
{
var ret = (SoundIoError)Natives.soundio_instream_start (handle);
if (ret != SoundIoError.SoundIoErrorNone)
throw new SoundIOException (ret);
}
public SoundIOChannelAreas BeginRead (ref int frameCount) Marshal.WriteIntPtr(handle, read_callback_offset, ptr);
{ }
IntPtr ptrs = default (IntPtr); }
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 () static readonly int read_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("read_callback");
{
var ret = (SoundIoError) Natives.soundio_instream_end_read (handle);
if (ret != SoundIoError.SoundIoErrorNone)
throw new SoundIOException (ret);
}
public void Pause (bool pause) Action<int, int> read_callback;
{ delegate void read_callback_delegate(IntPtr handle, int min, int max);
var ret = (SoundIoError) Natives.soundio_instream_pause (handle, pause); read_callback_delegate read_callback_native;
if (ret != SoundIoError.SoundIoErrorNone)
throw new SoundIOException (ret);
}
public double GetLatency () // overflow_callback
{ public Action OverflowCallback
unsafe { {
double* dptr = null; get { return overflow_callback; }
IntPtr p = new IntPtr (dptr); set
var ret = (SoundIoError) Natives.soundio_instream_get_latency (handle, p); {
if (ret != SoundIoError.SoundIoErrorNone) overflow_callback = value;
throw new SoundIOException (ret); overflow_callback_native = _ => overflow_callback();
dptr = (double*) p;
return *dptr; 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;
}
}
}
} }

View File

@ -4,251 +4,328 @@ using System.Runtime.InteropServices;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public class SoundIOOutStream : IDisposable public class SoundIOOutStream : IDisposable
{ {
internal SoundIOOutStream (Pointer<SoundIoOutStream> handle) internal SoundIOOutStream (Pointer<SoundIoOutStream> handle)
{ {
this.handle = handle; this.handle = handle;
} }
Pointer<SoundIoOutStream> handle; Pointer<SoundIoOutStream> handle;
public void Dispose () public void Dispose ()
{ {
Natives.soundio_outstream_destroy (handle); Natives.soundio_outstream_destroy (handle);
} }
// Equality (based on handle) // Equality (based on handle)
public override bool Equals (object other) public override bool Equals (object other)
{ {
var d = other as SoundIOOutStream; var d = other as SoundIOOutStream;
return d != null && (this.handle == d.handle);
}
public override int GetHashCode () return d != null && (this.handle == d.handle);
{ }
return (int)(IntPtr)handle;
}
public static bool operator == (SoundIOOutStream obj1, SoundIOOutStream obj2) public override int GetHashCode ()
{ {
return (object)obj1 == null ? (object)obj2 == null : obj1.Equals (obj2); return (int)(IntPtr)handle;
} }
public static bool operator != (SoundIOOutStream obj1, SoundIOOutStream obj2) public static bool operator == (SoundIOOutStream obj1, SoundIOOutStream obj2)
{ {
return (object)obj1 == null ? (object)obj2 != null : !obj1.Equals (obj2); return obj1 is null ? obj2 is null : obj1.Equals(obj2);
} }
// fields public static bool operator != (SoundIOOutStream obj1, SoundIOOutStream obj2)
{
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
}
public SoundIODevice Device { // fields
get { return new SoundIODevice (Marshal.ReadIntPtr (handle, device_offset)); }
}
static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("device");
public SoundIOFormat Format { public SoundIODevice Device
get { return (SoundIOFormat) Marshal.ReadInt32 (handle, format_offset); } {
set { Marshal.WriteInt32 (handle, format_offset, (int) value); } get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); }
} }
static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("format");
public int SampleRate { static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("device");
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 SoundIOFormat Format
{
get { return (SoundIOFormat) Marshal.ReadInt32(handle, format_offset); }
set { Marshal.WriteInt32(handle, format_offset, (int) value); }
}
public SoundIOChannelLayout Layout { static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("format");
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 { public int SampleRate
get { return MarshalEx.ReadDouble (handle, software_latency_offset); } {
set { MarshalEx.WriteDouble (handle, software_latency_offset, value); } get { return Marshal.ReadInt32(handle, sample_rate_offset); }
} set { Marshal.WriteInt32(handle, sample_rate_offset, value); }
static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("software_latency"); }
public float Volume { static readonly int sample_rate_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("sample_rate");
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 SoundIOChannelLayout Layout
public Action ErrorCallback { {
get { return error_callback; } get { unsafe { return new SoundIOChannelLayout((IntPtr) (void*)((IntPtr)handle + layout_offset)); } }
set { set
error_callback = value; {
if (value == null) unsafe
error_callback_native = null; {
else Buffer.MemoryCopy((void*)value.Handle, (void*)((IntPtr)handle + layout_offset), Marshal.SizeOf<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
error_callback_native = stream => error_callback (); }
var ptr = Marshal.GetFunctionPointerForDelegate (error_callback_native); }
Marshal.WriteIntPtr (handle, error_callback_offset, ptr); }
} static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("layout");
}
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 double SoftwareLatency
public Action<int, int> WriteCallback { {
get { return write_callback; } get { return MarshalEx.ReadDouble (handle, software_latency_offset); }
set { set { MarshalEx.WriteDouble (handle, software_latency_offset, value); }
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 static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("software_latency");
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 public float Volume
// this kind of code anywhere we need string marshaling. {
List<IntPtr> allocated_hglobals = new List<IntPtr> (); get { return MarshalEx.ReadFloat(handle, volume_offset); }
set { MarshalEx.WriteFloat(handle, volume_offset, value); }
}
public string Name { static readonly int volume_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("volume");
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 { // error_callback
get { return Marshal.ReadInt32 (handle, non_terminal_hint_offset) != 0; } public Action ErrorCallback
} {
static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("non_terminal_hint"); get { return error_callback; }
set
{
error_callback = value;
if (value == null)
{
error_callback_native = null;
}
else
{
error_callback_native = stream => error_callback();
}
public int BytesPerFrame { var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native);
get { return Marshal.ReadInt32 (handle, bytes_per_frame_offset); } Marshal.WriteIntPtr(handle, error_callback_offset, ptr);
} }
static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("bytes_per_frame"); }
public int BytesPerSample { static readonly int error_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("error_callback");
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 { Action error_callback;
get { delegate void error_callback_delegate (IntPtr handle);
var code = (SoundIoError) Marshal.ReadInt32 (handle, layout_error_offset); error_callback_delegate error_callback_native;
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 // 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);
}
public void Open () var ptr = Marshal.GetFunctionPointerForDelegate (write_callback_native);
{ Marshal.WriteIntPtr (handle, write_callback_offset, ptr);
var ret = (SoundIoError) Natives.soundio_outstream_open (handle); }
if (ret != SoundIoError.SoundIoErrorNone) }
throw new SoundIOException (ret);
}
public void Start () static readonly int write_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("write_callback");
{
var ret = (SoundIoError)Natives.soundio_outstream_start (handle);
if (ret != SoundIoError.SoundIoErrorNone)
throw new SoundIOException (ret);
}
public SoundIOChannelAreas BeginWrite (ref int frameCount) Action<int, int> write_callback;
{ delegate void write_callback_delegate(IntPtr handle, int min, int max);
IntPtr ptrs = default (IntPtr); write_callback_delegate write_callback_native;
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 () // underflow_callback
{ public Action UnderflowCallback
var ret = (SoundIoError) Natives.soundio_outstream_end_write (handle); {
if (ret != SoundIoError.SoundIoErrorNone) get { return underflow_callback; }
throw new SoundIOException (ret); set
} {
underflow_callback = value;
if (value == null)
{
underflow_callback_native = null;
}
else
{
underflow_callback_native = h => underflow_callback();
}
public void ClearBuffer () var ptr = Marshal.GetFunctionPointerForDelegate (underflow_callback_native);
{ Marshal.WriteIntPtr (handle, underflow_callback_offset, ptr);
Natives.soundio_outstream_clear_buffer (handle); }
} }
public void Pause (bool pause) static readonly int underflow_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("underflow_callback");
{
var ret = (SoundIoError) Natives.soundio_outstream_pause (handle, pause);
if (ret != SoundIoError.SoundIoErrorNone)
throw new SoundIOException (ret);
}
public double GetLatency () Action underflow_callback;
{ delegate void underflow_callback_delegate(IntPtr handle);
unsafe { underflow_callback_delegate underflow_callback_native;
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) // 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.
var ret = (SoundIoError) Natives.soundio_outstream_set_volume (handle, volume); List<IntPtr> allocated_hglobals = new List<IntPtr>();
if (ret != SoundIoError.SoundIoErrorNone)
throw new SoundIOException (ret); 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);
}
}
}
} }

View File

@ -1,61 +1,58 @@
using System; using System;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public class SoundIORingBuffer : IDisposable public class SoundIORingBuffer : IDisposable
{ {
internal SoundIORingBuffer (IntPtr handle) internal SoundIORingBuffer(IntPtr handle)
{ {
this.handle = handle; this.handle = handle;
} }
IntPtr handle; IntPtr handle;
public int Capacity { public int Capacity
get { return Natives.soundio_ring_buffer_capacity (handle); } {
} get { return Natives.soundio_ring_buffer_capacity(handle); }
}
public void Clear () public void Clear()
{ {
Natives.soundio_ring_buffer_clear (handle); Natives.soundio_ring_buffer_clear(handle);
} }
public void Dispose () public void Dispose()
{ {
Natives.soundio_ring_buffer_destroy (handle); Natives.soundio_ring_buffer_destroy(handle);
} }
public int FillCount { public int FillCount
get { {
return Natives.soundio_ring_buffer_fill_count (handle); get { return Natives.soundio_ring_buffer_fill_count(handle); }
} }
}
public int FreeCount { public int FreeCount
get { {
return Natives.soundio_ring_buffer_free_count (handle); get { return Natives.soundio_ring_buffer_free_count(handle); }
} }
}
public IntPtr ReadPointer { public IntPtr ReadPointer
get { {
return Natives.soundio_ring_buffer_read_ptr (handle); get { return Natives.soundio_ring_buffer_read_ptr(handle); }
} }
}
public IntPtr WritePointer { public IntPtr WritePointer
get { {
return Natives.soundio_ring_buffer_write_ptr (handle); get { return Natives.soundio_ring_buffer_write_ptr(handle); }
} }
}
public void AdvanceReadPointer (int count) public void AdvanceReadPointer(int count)
{ {
Natives.soundio_ring_buffer_advance_read_ptr (handle, count); Natives.soundio_ring_buffer_advance_read_ptr(handle, count);
} }
public void AdvanceWritePointer (int count) public void AdvanceWritePointer(int count)
{ {
Natives.soundio_ring_buffer_advance_write_ptr (handle, count); Natives.soundio_ring_buffer_advance_write_ptr(handle, count);
} }
} }
} }

View File

@ -1,15 +1,15 @@
using System; using System;
namespace SoundIOSharp namespace SoundIOSharp
{ {
public struct SoundIOSampleRateRange public struct SoundIOSampleRateRange
{ {
internal SoundIOSampleRateRange (int min, int max) internal SoundIOSampleRateRange(int min, int max)
{ {
Min = min; Min = min;
Max = max; Max = max;
} }
public readonly int Min; public readonly int Min;
public readonly int Max; public readonly int Max;
} }
} }

View File

@ -367,7 +367,7 @@ namespace Ryujinx.Audio
{ {
lock (track) lock (track)
{ {
return track.Volume; return track.GetVolume();
} }
} }

View File

@ -11,7 +11,6 @@ namespace Ryujinx.Audio
public int SampleRate { get; private set; } public int SampleRate { get; private set; }
public ALFormat Format { get; private set; } public ALFormat Format { get; private set; }
public PlaybackState State { get; set; } public PlaybackState State { get; set; }
public float Volume { get; private set; }
public int HardwareChannels { get; } public int HardwareChannels { get; }
public int VirtualChannels { get; } public int VirtualChannels { get; }
@ -151,9 +150,14 @@ namespace Ryujinx.Audio
public void SetVolume(float volume) public void SetVolume(float volume)
{ {
Volume = volume; AL.Source(SourceId, ALSourcef.Gain, volume);
}
AL.Source(SourceId, ALSourcef.Gain, Volume); public float GetVolume()
{
AL.GetSource(SourceId, ALSourcef.Gain, out float volume);
return volume;
} }
public void Dispose() public void Dispose()

View File

@ -1,6 +1,5 @@
using Ryujinx.Audio.SoundIo; using Ryujinx.Audio.SoundIo;
using SoundIOSharp; using SoundIOSharp;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Audio namespace Ryujinx.Audio

View File

@ -85,16 +85,16 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
{ {
long tag = context.RequestData.ReadInt64(); long tag = context.RequestData.ReadInt64();
context.ResponseData.Write(_audioOut.ContainsBuffer(_track, tag) ? 1 : 0); context.ResponseData.Write(_audioOut.ContainsBuffer(_track, tag));
return 0; return ResultCode.Success;
} }
[Command(7)] // 3.0.0+ [Command(7)] // 3.0.0+
// AppendAudioOutBufferAuto(u64 tag, buffer<nn::audio::AudioOutBuffer, 0x21>) // AppendAudioOutBufferAuto(u64 tag, buffer<nn::audio::AudioOutBuffer, 0x21>)
public ResultCode AppendAudioOutBufferAuto(ServiceCtx context) public ResultCode AppendAudioOutBufferAuto(ServiceCtx context)
{ {
(long position, long size) = context.Request.GetBufferType0x21(); (long position, _) = context.Request.GetBufferType0x21();
return AppendAudioOutBufferImpl(context, position); return AppendAudioOutBufferImpl(context, position);
} }
@ -103,9 +103,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
{ {
long tag = context.RequestData.ReadInt64(); long tag = context.RequestData.ReadInt64();
AudioOutData data = MemoryHelper.Read<AudioOutData>( AudioOutData data = MemoryHelper.Read<AudioOutData>(context.Memory, position);
context.Memory,
position);
// NOTE: Assume PCM16 all the time, change if new format are found. // NOTE: Assume PCM16 all the time, change if new format are found.
short[] buffer = new short[data.SampleBufferSize / sizeof(short)]; short[] buffer = new short[data.SampleBufferSize / sizeof(short)];

View File

@ -20,10 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
// ListAudioOuts() -> (u32 count, buffer<bytes, 6>) // ListAudioOuts() -> (u32 count, buffer<bytes, 6>)
public ResultCode ListAudioOuts(ServiceCtx context) public ResultCode ListAudioOuts(ServiceCtx context)
{ {
return ListAudioOutsImpl( return ListAudioOutsImpl(context, context.Request.ReceiveBuff[0].Position, context.Request.ReceiveBuff[0].Size);
context,
context.Request.ReceiveBuff[0].Position,
context.Request.ReceiveBuff[0].Size);
} }
[Command(1)] [Command(1)]
@ -31,12 +28,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio
// -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object<nn::audio::detail::IAudioOut>, buffer<bytes, 6> name_out) // -> (u32 sample_rate, u32 channel_count, u32 pcm_format, u32, object<nn::audio::detail::IAudioOut>, buffer<bytes, 6> name_out)
public ResultCode OpenAudioOut(ServiceCtx context) public ResultCode OpenAudioOut(ServiceCtx context)
{ {
return OpenAudioOutImpl( return OpenAudioOutImpl(context, context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size,
context, context.Request.ReceiveBuff[0].Position, context.Request.ReceiveBuff[0].Size);
context.Request.SendBuff[0].Position,
context.Request.SendBuff[0].Size,
context.Request.ReceiveBuff[0].Position,
context.Request.ReceiveBuff[0].Size);
} }
[Command(2)] // 3.0.0+ [Command(2)] // 3.0.0+
@ -56,12 +49,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
(long sendPosition, long sendSize) = context.Request.GetBufferType0x21(); (long sendPosition, long sendSize) = context.Request.GetBufferType0x21();
(long recvPosition, long recvSize) = context.Request.GetBufferType0x22(); (long recvPosition, long recvSize) = context.Request.GetBufferType0x22();
return OpenAudioOutImpl( return OpenAudioOutImpl(context, sendPosition, sendSize, recvPosition, recvSize);
context,
sendPosition,
sendSize,
recvPosition,
recvSize);
} }
private ResultCode ListAudioOutsImpl(ServiceCtx context, long position, long size) private ResultCode ListAudioOutsImpl(ServiceCtx context, long position, long size)
@ -88,10 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
private ResultCode OpenAudioOutImpl(ServiceCtx context, long sendPosition, long sendSize, long receivePosition, long receiveSize) private ResultCode OpenAudioOutImpl(ServiceCtx context, long sendPosition, long sendSize, long receivePosition, long receiveSize)
{ {
string deviceName = MemoryHelper.ReadAsciiString( string deviceName = MemoryHelper.ReadAsciiString(context.Memory, sendPosition, sendSize);
context.Memory,
sendPosition,
sendSize);
if (deviceName == string.Empty) if (deviceName == string.Empty)
{ {