1

Apple recently deprecated the MIDIDestinationCreate method and replaced it with a MidiDestinationCreateWithProtocol (MIDIDestinationCreate)

The old method required to pass a simple callback method 'MIDIReadProc' which from C# could be done by creating the following delegate signature, then creating a delegate and assigning a method as the callback. We declare the delegate signature:

internal delegate void MIDIReadProc(MIDIPacketListPtr pktlist, IntPtr readProcRefCon, IntPtr srcConnRefCon);

Create a delegate to assign our callback method to:

private CoreMidiInterop.NativeMethods.MIDIReadProc m_readProcDelegate; 

Assign a method to the delegate we created:

m_readProcDelegate = CallMessageReceived;

Create a callback method, that should receive MIDI messages from macOS Core MIDI:

private void CallMessageReceived(MIDIPacketListPtr pktlist, IntPtr readProcRefCon, IntPtr srcConnRefCon)
{
   ...
}

Eventually pass this delegate to the apple Core MIDI method:

CoreMidiInterop.NativeMethods
                .MIDIDestinationCreate(m_clientRef, CoreFoundationUtils.ToCFStringRef(name), m_readProcDelegate, CFStringRef.Zero, out MIDIEndpointRef destinationRef);

This all works as expected.

That's now deprecated and no longer works on macOS Big Sur. The new method "MidiDestinationCreateWithProtocol" requires an apple block to use as the callback param (called MIDIReceiveBlock readBlock):

OSStatus MIDIDestinationCreateWithProtocol(MIDIClientRef client, CFStringRef name, MIDIProtocolID protocol, MIDIEndpointRef *outDest, MIDIReceiveBlock readBlock);

The documentation here: MIDIReceiveBlock

How is it possible to create an apple block with C# code? I've been searching for examples but cannot find any. I did start looking at the underlying implementation of apple blocks here:

Block Implementation Specification

It's no simple thing, so any help/example of how to do this in C# would be really helpful.

Simon Bosley
  • 1,114
  • 3
  • 18
  • 41
  • Did you solve the problem? – Maxim Jul 15 '21 at 14:09
  • Hi @Maxim I ended up creating a C++ 'shimmy' dynamic library between the C# and Apple code. Using the clang compiler I can create apple blocks in C++, to communicate with the CoreMIDI services, then I use my C# interop code to call to my C++ code. The feedback I received from Apple was that they don't support C# and offered no help at all. – Simon Bosley Jul 15 '21 at 15:31
  • Hi @simon-bosley Yes, I do intermediate layer too (but in plain C). But how do you pass block from C#? From what I've known on the web, we can just pass delegate to block parameter, can't we? – Maxim Jul 15 '21 at 17:30
  • Hi @Maxim, from my investigation I learnt that Apple Blocks is a language feature that only exists in Apple supported languages (C, Obj-C, Swift etc), which would require the Clang complier as far as I remember. I created a dynamic library using Clang (actually it may have been written in C), that creates the Apple Block and simply calls back using a supplied pointer. This way my C# code calls my dynamic library with a traditional callback pointer, my dynamic library creates the 'Apple Block' which is like a lamda that just calls my callback pointer. You cannot create an Apple Block in C# – Simon Bosley Jul 16 '21 at 08:50
  • In [this question](https://stackoverflow.com/questions/5823770/objective-c-code-blocks-equivalent-in-c-sharp) I see that we can just pass delegate/method to a block parameter. So you didn't try this? – Maxim Jul 16 '21 at 16:18
  • That post is just explaining what the language equivalent of an Apple Block is in C#, not that the two can be used interchangeably via interop code. I tried all these things though in the hope it would work but it didn't. You can read more about them here: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html#:~:text=Blocks%20are%20a%20language%2Dlevel,collections%20like%20NSArray%20or%20NSDictionary%20. – Simon Bosley Jul 18 '21 at 14:14
  • @Maxim if you look at the implementation specification of Apple Blocks, you'll see how they are implemented: https://clang.llvm.org/docs/Block-ABI-Apple.html I expect it's possible to provide a C# implementation of Apple Blocks with the correct memory layout, however that was way beyond the scope of what I needed. – Simon Bosley Jul 18 '21 at 14:20
  • Thank you! Well, it seems I need to define blocks in an intermediate layer too and call provided .NET callbacks inside those blocks. – Maxim Jul 18 '21 at 14:34

1 Answers1

0

First, I feel that Apple is being inconsistent with their use of the word "deprecate". Since these new functions involving the words "WithProtocol" are only valid for Big Sur at this time, I don't see how all previous code can be deprecated until the previous versions of the operating system are no longer supported. See https://bradleyross.github.io/ObjectiveC-Examples/Documentation/BRossTools/FunctionalArea.html.

See https://bradleyross.github.io/ObjectiveC-Examples/Documentation/BRossTools/CoreMidi.html#MIDIDestinationCreateWithBlock MIDIDestinationCreate should indeed be deprecated, but MIDIDestinationCreateWithProtocol is only for BigSur. In addition the "WithProtocol" functions are to support MIDI 2.0, and the full specifications for MIDI 2.0 have not yet been released to the general public. I would therefore prefer to use MIDIDestinationCreateWithBlock. See the Xcode project BRossTools in the GitHub project at https://github.com/BradleyRoss/ObjectiveC-Examples. You can search this repository for the names of the CoreMIDI functions you are looking for and it may help. You might also want to look at https://github.com/mixedinkey-opensource/MIKMIDI. Part of the problem is that the functions ending with "WithBlock" and most of the functions ending with "WithProtocol" use closures (another name for blocks). I'm not sure how C# closures and CLANG closures (used in Objective-C) compare. Try to look for information on C# closures.

Bradley Ross
  • 445
  • 2
  • 8
  • Hi, unfortunately from my investigations I found that the Apple Blocks feature is only supported by Apple languages such as C, Obj-C, Swift etc. These require the Clang compiler that uses that feature. Unfortunately this means we cannot create Apple Blocks or equivalents to use in C#. The only way around is to have C# code call some 'C' dynamic library (compiled by clang) to do that job for us. – Simon Bosley Jul 16 '21 at 08:54