0

I will program an inter App MIDI In Port in my Arranger App, that can be accessed by other MIDI App's. I would appreciate very much to get some sample code. I built a virtual MIDI In port like this, but how to make it visible for other App's:

MIDIClientRef virtualMidi;
result = MIDIClientCreate(CFSTR("Virtual Client"), MyMIDINotifyProc, NULL, &virtualMidi);
סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
Walter Schurter
  • 997
  • 9
  • 14
  • creation of Virtual Midi Ports (Destination and Source) is in most circumstances better than relaying on OSX IAC driver Midi host. IAC has higher latency cause of its nature and users have to know how to setup the IAC midi host, as well the filtering setup of IAC can lead to unexpected results for your users. Your own virtual host has a lot more reliability about features and needs to make work what you want to. And the same applies to Cross Platform Solutions where IAC is not existent. – Ol Sen Oct 14 '20 at 15:11

2 Answers2

0

You need to use MIDIDestinationCreate, which will be visible to other MIDI Clients. You need to provide a MIDIReadProc callback that will be notified when a MIDI event arrives to your MIDI Destination. You may create another MIDI Input Port as well, with the same callback, that you can connect yourself from within your own program to an external MIDI Source.

Here is an example (in C++):

void internalCreate(CFStringRef name)
{
    OSStatus result = noErr;
    result = MIDIClientCreate( name , nullptr, nullptr, &m_client );
    if (result != noErr) {
        qDebug() << "MIDIClientCreate() err:" << result;
        return;
    }
    result = MIDIDestinationCreate ( m_client, name, MacMIDIReadProc, (void*) this, &m_endpoint );
    if (result != noErr) {
        qDebug() << "MIDIDestinationCreate() err:" << result;
        return;
    }
    result = MIDIInputPortCreate( m_client, name, MacMIDIReadProc, (void *) this,  &m_port );
    if (result != noErr) {
        qDebug() << "MIDIInputPortCreate() error:" << result;
        return;
    }
}

Another example, in ObjectiveC from symplesynth

- (id)initWithName:(NSString*)newName
{
    PYMIDIManager*  manager = [PYMIDIManager sharedInstance];
    MIDIEndpointRef newEndpoint;
    OSStatus        error;
    SInt32          newUniqueID;

    // This makes sure that we don't get notified about this endpoint until after
    // we're done creating it.
    [manager disableNotifications];

    MIDIDestinationCreate ([manager midiClientRef], (CFStringRef)newName, midiReadProc, self, &newEndpoint);

    // This code works around a bug in OS X 10.1 that causes
    // new sources/destinations to be created without unique IDs.
    error = MIDIObjectGetIntegerProperty (newEndpoint, kMIDIPropertyUniqueID, &newUniqueID);
    if (error == kMIDIUnknownProperty) {
        newUniqueID = PYMIDIAllocateUniqueID();
        MIDIObjectSetIntegerProperty (newEndpoint, kMIDIPropertyUniqueID, newUniqueID);
    }

    MIDIObjectSetIntegerProperty (newEndpoint, CFSTR("PYMIDIOwnerPID"), [[NSProcessInfo processInfo] processIdentifier]);

    [manager enableNotifications];

    self = [super initWithMIDIEndpointRef:newEndpoint];

    ioIsRunning = NO;

    return self;
}
Former contributor
  • 2,466
  • 2
  • 10
  • 15
  • Thanks very much for the fast answer. Does this code contain also the necessary steps to make the MIDI In port visible for other MIDI App's. MIDI In and MIDI Out worked in my App's, but when I will connect from other App's to my MIDI In, then the port is not visible as "software" MIDI in. – Walter Schurter Nov 21 '19 at 20:24
  • A previous question: I've edited the question flags to include coremidi and also macos. Are them right? Is your program for mac or for ios? – Former contributor Nov 21 '19 at 20:42
  • Answering now your question: Yes, MIDIDestinationCreate() creates a destination visible by other programs, and other programs will be able to connect to your virtual destination. But both samples are for coremidi macOS programs, and I didn't test them on iOS. – Former contributor Nov 21 '19 at 20:49
  • Thanks again. I need the code for iOS. I will try if I can get it work. – Walter Schurter Nov 22 '19 at 09:44
  • Sorry, I do capitulate, I am too stupid and too old to check it. Also I don't know if all frameworks are included in Xcode or if I must use third party frameworks. – Walter Schurter Nov 22 '19 at 10:11
  • I tried this, but the virtual port is still not visible for other App's: – Walter Schurter Nov 22 '19 at 15:02
  • Please excuse me, I was not able to format the text as code in "comments": – Walter Schurter Nov 22 '19 at 15:03
  • MIDIClientRef virtualMidi2; result = MIDIClientCreate(CFSTR("Virtual Client"), MyMIDINotifyProc, NULL, &virtualMidi2); MIDIEndpointRef destMIDI2; result = MIDIDestinationCreate(virtualMidi2, CFSTR("Virtual Destination"), MyMIDIReadProc2, NULL, &destMIDI2); MIDIPortRef inputPort2 = 0; result = MIDIInputPortCreate(virtualMidi2, CFSTR("Virtual Input"), MyMIDIReadProc2, NULL, &inputPort2); MIDIEndpointRef sourceMIDI2; sourceMIDI2 = MIDIGetSource(0); s = MIDIPortConnectSource(inputPort2, sourceMIDI2, NULL); – Walter Schurter Nov 22 '19 at 15:03
  • Sorry, I know nothing about iOS. The samples I provided where for macOS. The documentation says that CoreMIDI is a framework available for macOS and iOS: https://developer.apple.com/documentation/coremidi/1495347-mididestinationcreate – Former contributor Nov 22 '19 at 15:05
  • See also: https://stackoverflow.com/questions/15743150/get-ios-core-midi-client-name-to-show-in-list-of-devices – Former contributor Nov 22 '19 at 15:43
0

Ports can't be discovered from the API, but sources and destinations can. You want to create a MIDISource or MIDIDestination so that MIDI clients can call MIDIGetNumberOfDestinations/MIDIGetDestination or MIDIGetNumberOfSources/MIDIGetSource and discover it.

FYI, there is no need to do what you are planning to do on macOS because the IAC driver already does it. If this is for iOS, these are the steps to follow:

  1. Create at least one MIDI Client.
  2. Create a MIDIInputPort with a read block for I/O.
  3. Use MIDIPortConnectSource to attach the input port to every MIDI Source of interest. [From now, every MIDI message received by the source will come to your read block.]

If you want to resend this data to a different destination, you'll need to have created a MIDIOutputPort as well. Use MIDISend with that port to the desired MIDI Destination.

MIDIWalker
  • 41
  • 3