yun
yun

Reputation: 1283

Debugging MIDI in iOS app

I'm trying to implement CoreMIDI in my iOS app and I'm having trouble trying to debug it right now. Currently I have a UILabel that updates whenever the my MIDI callback is called. However, my UILabel never updates! I am not sure why this is happening and I'm guessing it's either how I'm defining something in my MIDI initialization or how I'm calling the UILabel. I'm still trying to figure this out but is there a better way to debug MIDI on an iOS app (as iOS devices only have one port and can only use the port for either connecting to computer or a MIDI controller at a given time).

How I'm creating the MIDI client:

Check(MIDIClientCreate(CFSTR("Yun Client"), NULL, NULL , &client));
Check(MIDIOutputPortCreate(client, CFSTR("Yun Output Port"), &outputPort));
Check(MIDIInputPortCreate(client, CFSTR("Yun Input Port"), MIDIInputCallback, 
                         (__bridge void *)self, &inputPort));
unsigned long sourceCount = MIDIGetNumberOfSources();

CFStringRef endpointName;
for (int i = 0; i < sourceCount; ++i) {
    MIDIEndpointRef endPoint = MIDIGetSource(i);
    endpointName = NULL;
    Check(MIDIObjectGetStringProperty(endPoint, kMIDIPropertyName, &endpointName));
    Check(MIDIPortConnectSource(inputPort, endPoint, NULL));
    [param addToMIDIInputsArray:[NSString stringWithFormat:@"%@", endpointName]];
}

My MIDI callback:

// MIDI receiver callback
static void MIDIInputCallback(const MIDIPacketList *pktlist, 
                              void *refCon, void *connRefCon) {
    SynthViewController *vc = (__bridge SynthViewController*)refCon;

    MIDIPacket *packet = (MIDIPacket *)pktlist->packet;

    Byte midiCommand = packet->data[0] >> 4;
    NSInteger command = midiCommand;

    Byte noteByte = packet->data[1] & 0x7F;
    NSInteger note = noteByte;

    Byte velocityByte = packet->data[2] & 0x7F;
    float velocity = [[NSNumber numberWithInt:velocityByte] floatValue];

    // Note On event
    if (command == 9 && velocity > 0) {
        [vc midiKeyDown:(note+4) withVelocity:velocity];
    } 
    // Note off event
    else if ((command == 9 || command == 8) && velocity == 0) {
        [vc midiKeyUp:(note+4)];
    }

    [vc.logLabel addLogLine:[NSString stringWithFormat:@"%lu - %lu - %lu", 
                            (long)command, (long)note, (long)velocityByte]];
}

addLogLine method:

- (void)addLogLine:(NSString *)line {
    NSString *str = [NSString stringWithFormat:@"%d - %@", _cnt++, line];
    _logLabel.text = str;
}

Any help is great! Thanks

Upvotes: 0

Views: 338

Answers (1)

Kurt Revis
Kurt Revis

Reputation: 27984

The header documentation for MIDIInputPortCreate says:

readProc will be called on a separate high-priority thread owned by CoreMIDI.

You must update UIKit on the main thread only.

Use dispatch_async to transfer control to the main thread, after you've parsed the incoming MIDI data.

static void MIDIInputCallback(const MIDIPacketList *pktlist, 
                          void *refCon, void *connRefCon) {
    SynthViewController *vc = (__bridge SynthViewController*)refCon;
    // ...

    dispatch_async(dispatch_get_main_queue(), ^{
        // Note On event
        if (command == 9 && velocity > 0) {
           [vc midiKeyDown:(note+4) withVelocity:velocity];
        } 
        // Note off event
        else if ((command == 9 || command == 8) && velocity == 0) {
           [vc midiKeyUp:(note+4)];
        }

        [vc.logLabel addLogLine:[NSString stringWithFormat:@"%lu - %lu - %lu", (long)command, (long)note, (long)velocityByte]];
    });
}

Upvotes: 2

Related Questions