Question

I have the following code where I want the function MyMIDINotifyProc to be called to notify me of changes to the midi devices connected to the iOS devices. However, strangely it is never called when i connect or disconnect devices - what could be the problem here?

Thank you. Help much appreciated.

void MyMIDINotifyProc (const MIDINotification  *message, void *refCon) {
    printf("MIDI Notify, messageId=%d,", (int)message->messageID);

}

/* csound MIDI input open callback, sets the device for input */ 
static int MidiInDeviceOpen(CSOUND *csound, void **userData, const char *dev)
{

    int k = 0;
    //6counter++;
    endpoints = 0;

    CFStringRef name = NULL, cname = NULL, pname = NULL;
    CFStringEncoding defaultEncoding = CFStringGetSystemEncoding();
    MIDIClientRef mclient = NULL;
    MIDIPortRef mport = NULL;
    MIDIEndpointRef endpoint;
    MIDIdata *mdata = (MIDIdata *) malloc(DSIZE*sizeof(MIDIdata));
    OSStatus ret;
    cdata *refcon = (cdata *) malloc(sizeof(cdata));
    memset(mdata, 0, sizeof(MIDIdata)*DSIZE);
    refcon->mdata = mdata;
    refcon->p = 0;
    refcon->q = 0;
    refcon->pnot = refcon->pchn = 0;

    cname = CFStringCreateWithCString(NULL, "my client", defaultEncoding);
    ret = MIDIClientCreate(cname, MyMIDINotifyProc, refcon, &mclient);

    if(!ret){
        /* MIDI output port */
        pname = CFStringCreateWithCString(NULL, "outport", defaultEncoding);
        ret = MIDIInputPortCreate(mclient, pname, ReadProc, refcon, &mport);
        if(!ret){
            /* sources, we connect to all available input sources */
            endpoints = MIDIGetNumberOfSources();
            csoundMessage(csound, "midi srcs %d\n", endpoints);
            midiDevicesArray = malloc(endpoints*sizeof(CFStringRef));

            for(k=0; k < endpoints; k++){
                endpoint = MIDIGetSource(k);
                void *srcRefCon = endpoint;
                MIDIPortConnectSource(mport, endpoint, srcRefCon);
                // insert into dictionary instead ?
                midiDevicesArray[k] = ConnectedEndpointName(endpoint);

            }
        }
    }
    refcon->mclient = mclient;
    *userData = (void*) refcon;
    if(name) CFRelease(name);
    if(pname) CFRelease(pname);
    if(cname) CFRelease(cname); 
    /* report success */
    return 0;
}
Was it helpful?

Solution

I just ran into the same problem on Mac OS X. The cause was that i didn't have a run loop in place. The documentation for CoreMIDI isn't quite extensive, but the MIDIClientCreate docs indicate that notifications are dispatched using run loop sources:

Note that notifyProc will always be called on the run loop which was current when MIDIClientCreate was first called. Apple MIDI Services Reference : MIDIClientCreate

So a solution was to call CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) in my custom run loop. Since i created the MIDIClientRef on a secondary thread, i had to add this call to the run loop of my main thread as well (eventually this needs to be done for all parent threads). CFRunLoopRunInMode will process the input sources of the run loop and exits immediately in my case (third parameter is true), but you can also choose to block the thread until the run loop is stopped (CFRunLoopRun), maybe on a new thread, whatever fits your design best.

If you are not familiar with Apple's Core Foundation and Cocoa Run Loops yet, the following guide should be a good introduction: Apple Threading Programming Guide : Run Loops

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top