Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
MIDIDestinationCreateWithProtocol/MIDISourceCreateWithProtocol/MIDIIn…
…putPortCreateWithProtocol
  • Loading branch information
rolfbjarne committed Jun 4, 2025
commit f2208d750ee9755e45d437836b6b15db5e4a1a07
175 changes: 134 additions & 41 deletions src/CoreMidi/MidiServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -625,11 +625,18 @@ public class MidiClient : MidiObject {
[SupportedOSPlatform ("ios")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[ObsoletedOSPlatform ("macos11.0")]
[ObsoletedOSPlatform ("ios14.0")]
[ObsoletedOSPlatform ("maccatalyst14.0")]
[ObsoletedOSPlatform ("macos11.0", "Call 'MIDISourceCreateWithProtocol' instead.")]
[ObsoletedOSPlatform ("ios14.0", "Call 'MIDISourceCreateWithProtocol' instead.")]
[ObsoletedOSPlatform ("maccatalyst14.0", "Call 'MIDISourceCreateWithProtocol' instead.")]
[DllImport (Constants.CoreMidiLibrary)]
unsafe extern static int /* OSStatus = SInt32 */ MIDISourceCreate (MidiObjectRef handle, IntPtr name, MidiObjectRef* endpoint);
unsafe extern static int /* OSStatus = SInt32 */ MIDISourceCreate (MidiObjectRef handle, IntPtr name, MidiEndpointRef* endpoint);

[SupportedOSPlatform ("ios14.0")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[UnsupportedOSPlatform ("tvos")]
[DllImport (Constants.CoreMidiLibrary)]
unsafe extern static OSStatus MIDISourceCreateWithProtocol (MidiClientRef client, IntPtr /* CFStringRef */ name, MidiProtocolId protocol, MidiEndpointRef* outSrc);

GCHandle gch;

Expand Down Expand Up @@ -683,45 +690,59 @@ public override string ToString ()
return Name;
}

/// <param name="name">To be added.</param>
/// <param name="statusCode">To be added.</param>
/// <summary>To be added.</summary>
/// <returns>To be added.</returns>
/// <remarks>To be added.</remarks>
/// <summary>Create a virtual source for this client.</summary>
/// <param name="name">The name for the virtual source.</param>
/// <param name="statusCode">A status code that describes the result of this operation. This will be <see cref="MidiError.Ok" /> in case of success.</param>
/// <returns>A newly created <see cref="MidiEndpoint" /> if successful, otherwise null.</returns>
[SupportedOSPlatform ("ios")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[ObsoletedOSPlatform ("macos11.0")]
[ObsoletedOSPlatform ("ios14.0")]
[ObsoletedOSPlatform ("maccatalyst14.0")]
[ObsoletedOSPlatform ("macos11.0", "Call 'CreateVirtualSource (string, MidiProtocolId, out MidiError)' instead.")]
[ObsoletedOSPlatform ("ios14.0", "Call 'CreateVirtualSource (string, MidiProtocolId, out MidiError)' instead.")]
[ObsoletedOSPlatform ("maccatalyst14.0", "Call 'CreateVirtualSource (string, MidiProtocolId, out MidiError)' instead.")]
public MidiEndpoint? CreateVirtualSource (string name, out MidiError statusCode)
{
using (var nsstr = new NSString (name)) {
MidiObjectRef ret;
int code;
unsafe {
code = MIDISourceCreate (handle, nsstr.Handle, &ret);
}
if (code != 0) {
statusCode = (MidiError) code;
return null;
}
statusCode = MidiError.Ok;
return new MidiEndpoint (ret, true);
using var namePtr = new TransientCFString (name);
var handle = default (MidiEndpointRef);
unsafe {
statusCode = (MidiError) MIDISourceCreate (handle, namePtr, &handle);
}
if (handle == MidiObject.InvalidRef)
return null;
return new MidiEndpoint (handle, true);
}

/// <param name="name">To be added.</param>
/// <param name="status">To be added.</param>
/// <summary>To be added.</summary>
/// <returns>To be added.</returns>
/// <remarks>To be added.</remarks>
/// <summary>Create a virtual source for this client.</summary>
/// <param name="name">The name for the virtual source.</param>
/// <param name="protocol">The MIDI protocol for the data this source will produce.</param>
/// <param name="status">A status code that describes the result of this operation. This will be <see cref="MidiError.Ok" /> in case of success.</param>
/// <returns>A newly created <see cref="MidiEndpoint" /> if successful, otherwise null.</returns>
[SupportedOSPlatform ("ios14.0")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[UnsupportedOSPlatform ("tvos")]
public MidiEndpoint? CreateVirtualSource (string name, MidiProtocolId protocol, out MidiError status)
{
using var namePtr = new TransientCFString (name);
var handle = default (MidiEndpointRef);
unsafe {
status = (MidiError) MIDISourceCreateWithProtocol (GetCheckedHandle (), namePtr, protocol, &handle);
}
if (handle == MidiObject.InvalidRef)
return null;
return new MidiEndpoint (handle, true);
}

/// <summary>Create a virtual destination for this client.</summary>
/// <param name="name">The name for the virtual destination.</param>
/// <param name="status">A status code that describes the result of this operation. This will be <see cref="MidiError.Ok" /> in case of success.</param>
/// <returns>A newly created <see cref="MidiEndpoint" /> if successful, otherwise null.</returns>
[SupportedOSPlatform ("ios")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[ObsoletedOSPlatform ("macos11.0")]
[ObsoletedOSPlatform ("ios14.0")]
[ObsoletedOSPlatform ("maccatalyst14.0")]
[ObsoletedOSPlatform ("macos11.0", "Call the other 'CreateVirtualDestination' overload instead.")]
[ObsoletedOSPlatform ("ios14.0", "Call the other 'CreateVirtualDestination' overload instead.")]
[ObsoletedOSPlatform ("maccatalyst14.0", "Call the other 'CreateVirtualDestination' overload instead.")]
public MidiEndpoint? CreateVirtualDestination (string name, out MidiError status)
{
var m = new MidiEndpoint (this, name, out status);
Expand All @@ -732,6 +753,32 @@ public override string ToString ()
return null;
}

/// <summary>Create a virtual destination for this client.</summary>
/// <param name="name">The name for the virtual destination.</param>
/// <param name="protocol">The MIDI protocol for the data this destination will receive.</param>
/// <param name="readBlock">The callback that will be called when the destination receives MIDI data.</param>
/// <param name="status">A status code that describes the result of this operation. This will be <see cref="MidiError.Ok" /> in case of success.</param>
/// <returns>A newly created <see cref="MidiEndpoint" /> if successful, otherwise null.</returns>
/// <remarks> FIXME: ADD BETTER DOCS HERE </remarks>
public unsafe MidiEndpoint? CreateVirtualDestination (string name, MidiProtocolId protocol, delegate* unmanaged<void*,void*,void> readBlock, out MidiError status)
{
using var namePtr = new TransientCFString (name);
var handle = default (MidiEndpointRef);
unsafe {
status = (MidiError) MIDIDestinationCreateWithProtocol (GetCheckedHandle (), namePtr, protocol, &handle, readBlock);
}
if (handle == MidiObject.InvalidRef)
return null;
return new MidiEndpoint (handle, name, true);
}

[SupportedOSPlatform ("ios14.0")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[UnsupportedOSPlatform ("tvos")]
[DllImport (Constants.CoreMidiLibrary)]
unsafe extern static OSStatus MIDIDestinationCreateWithProtocol (MidiClientRef client, IntPtr /* CFStringRef */ name, MidiProtocolId protocol, MidiEndpointRef* outSrc, delegate* unmanaged<void * /* const MIDIEventList * */, void * /* __nullable srcConnRefCon */, void> readBlock);

/// <param name="name">name for the input port.</param>
/// <summary>Creates a new MIDI input port.</summary>
/// <returns>
Expand All @@ -752,6 +799,41 @@ public MidiPort CreateOutputPort (string name)
return new MidiPort (this, name, false);
}

[SupportedOSPlatform ("ios14.0")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[UnsupportedOSPlatform ("tvos")]
[DllImport (Constants.CoreMidiLibrary)]
unsafe extern static OSStatus MIDIInputPortCreateWithProtocol (
MidiClientRef client,
IntPtr /* CFStringRef */ name,
MidiProtocolId protocol,
MidiPortRef* outPort,
delegate* unmanaged<void * /* const MIDIEventList * */, void * /* __nullable srcConnRefCon */, void> receiveBlock);

/// <summary>Create a input port for this client.</summary>
/// <param name="name">The name for the port.</param>
/// <param name="protocol">The MIDI protocol for the data this port will receive.</param>
/// <param name="readBlock">The callback that will be called when the port receives MIDI data.</param>
/// <param name="status">A status code that describes the result of this operation. This will be <see cref="MidiError.Ok" /> in case of success.</param>
/// <returns>A newly created <see cref="MidiEndpoint" /> if successful, otherwise null.</returns>
/// <remarks> FIXME: ADD BETTER DOCS HERE </remarks>
[SupportedOSPlatform ("ios14.0")]
[SupportedOSPlatform ("maccatalyst")]
[SupportedOSPlatform ("macos")]
[UnsupportedOSPlatform ("tvos")]
public unsafe MidiPort? CreateInputPort (string name, MidiProtocolId protocol, delegate* unmanaged<void*,void*,void> readBlock, out MidiError status)
{
using var namePtr = new TransientCFString (name);
var handle = default (MidiEndpointRef);
unsafe {
status = (MidiError) MIDIInputPortCreateWithProtocol (GetCheckedHandle (), namePtr, protocol, &handle, readBlock);
}
if (handle == MidiObject.InvalidRef)
return null;
return new MidiPort (handle, true, this, name);
}

public event EventHandler? SetupChanged;
public event EventHandler<ObjectAddedOrRemovedEventArgs>? ObjectAdded;
public event EventHandler<ObjectAddedOrRemovedEventArgs>? ObjectRemoved;
Expand Down Expand Up @@ -1134,6 +1216,13 @@ public class MidiPort : MidiObject {
GCHandle gch;
bool input;

internal MidiPort (MidiPortRef handle, bool owns, MidiClient client, string portName)
: base (handle, owns)
{
Client = client;
PortName = portName;
}

internal MidiPort (MidiClient client, string portName, bool input)
{
using (var nsstr = new NSString (portName)) {
Expand Down Expand Up @@ -2824,17 +2913,21 @@ internal MidiEndpoint (MidiEndpointRef handle, string endpointName, bool owns) :
return new MidiEndpoint (h, "Destination" + destinationIndex, false);
}

internal MidiEndpoint (MidiClient client, string name, out MidiError code)
internal MidiEndpoint (MidiClient client, string name, out MidiError status)
{
using (var nsstr = new NSString (name)) {
GCHandle gch = GCHandle.Alloc (this);
unsafe {
MidiEndpointRef tempHandle;
code = MIDIDestinationCreate (client.handle, nsstr.Handle, &Read, GCHandle.ToIntPtr (gch), &tempHandle);
handle = tempHandle;
}
EndpointName = name;
EndpointName = name;

using var namePtr = new TransientCFString (name);
var handle = default (MidiEndpointRef);
gch = GCHandle.Alloc (this);
unsafe {
status = (MidiError) MIDIDestinationCreate (client.GetCheckedHandle (), namePtr, &Read, GCHandle.ToIntPtr (gch), &handle);
}
if (handle == MidiObject.InvalidRef) {
gch.Free ();
return;
}
this.handle = handle;
}

/// <include file="../../docs/api/CoreMidi/MidiEndpoint.xml" path="/Documentation/Docs[@DocId='M:CoreMidi.MidiEndpoint.Dispose(System.Boolean)']/*" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
# There's no need to bind this P/Invoke, we bind/use 'MIDIClientCreate' which provide the exact same capabilities.
!missing-pinvoke! MIDIClientCreateWithBlock is not bound

# same as the above, we should bind all of them, these have been added on Xcode 12 beta 2
# https://github.com/dotnet/macios/issues/4452#issuecomment-660220392
!missing-pinvoke! MIDIDestinationCreateWithProtocol is not bound
!missing-pinvoke! MIDIInputPortCreateWithProtocol is not bound
!missing-pinvoke! MIDISourceCreateWithProtocol is not bound
6 changes: 0 additions & 6 deletions tests/xtro-sharpie/api-annotations-dotnet/iOS-CoreMIDI.ignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
# There's no need to bind this P/Invoke, we bind/use 'MIDIClientCreate' which provide the exact same capabilities.
!missing-pinvoke! MIDIClientCreateWithBlock is not bound

# same as the above, we should bind all of them, these have been added on Xcode 12 beta 2
# https://github.com/dotnet/macios/issues/4452#issuecomment-660220392
!missing-pinvoke! MIDIDestinationCreateWithProtocol is not bound
!missing-pinvoke! MIDIInputPortCreateWithProtocol is not bound
!missing-pinvoke! MIDISourceCreateWithProtocol is not bound
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
# There's no need to bind this P/Invoke, we bind/use 'MIDIClientCreate' which provide the exact same capabilities.
!missing-pinvoke! MIDIClientCreateWithBlock is not bound

# same as the above, we should bind all of them, these have been added on Xcode 12 beta 2
# https://github.com/dotnet/macios/issues/4452#issuecomment-660220392
!missing-pinvoke! MIDIDestinationCreateWithProtocol is not bound
!missing-pinvoke! MIDIInputPortCreateWithProtocol is not bound
!missing-pinvoke! MIDISourceCreateWithProtocol is not bound