Sorry, I don't speak English (I'm using Google Translate).
I'm very new to Xcode. I'm trying to write an app that can listen to received midi messages and show them in an NSTextField
(just like a midi monitor).
I use CoreMidi
and I am able to connect the app to the desired input and receive Midi messages (I can print them using NSLog
). How I can output these message (the same ones I can read in NSLog
) in an NSTextField
?
I set a property, @synthesize
d it and connected the NSTextField in Interface Builder, but from the midi callback function I can't access it (it says "Undeclared").
Here the code in MyDocument.h
@property (retain,nonatomic) IBOutlet NSTextField *test_messages;
Here the code in MyDocument.m
@synthesize test_messages;
void midiInputCallback (const MIDIPacketList *list, void *procRef, void *srcRef) {
id POOL = [[NSAutoreleasePool alloc] init];
UInt16 nBytes;
NSString *ric;
const MIDIPacket *packet = &list->packet[0];
for (unsigned int i = 0; i < list->numPackets; i++) {
nBytes = packet->length;
UInt16 iByte, size;
iByte = 0;
while (iByte < nBytes) {
size = 0;
unsigned char status = packet->data[iByte];
if (status < 0xC0) {
size = 3;
} else if (status < 0xE0) {
size = 2;
} else if (status < 0xF0) {
size = 3;
} else if (status < 0xF3) {
size = 3;
} else if (status == 0xF3) {
size = 2;
} else {
size = 1;
}
switch (status & 0xF0) {
case 0x80:
ric = @"Note Off";
break;
case 0x90:
ric = @"Note On";
break;
case 0xA0:
ric = @"Aftertouch";
break;
case 0xB0:
ric = @"Control change";
break;
case 0xC0:
ric = @"Program Change";
break;
case 0xD0:
ric = @"Channel Pressure";
break;
case 0xE0:
ric = @"Pitch Wheel";
break;
default:
ric = @"Unk";
break;
}
//TEST HERE
[test_messages setStringValue:@"TEST TEST"]; //THIS GET "test_messages undeclared (first use in this function)"
iByte += size;
}
packet = MIDIPacketNext(packet);
}
[POOL release];
}
int main(int argc, char *argv[]) {
MIDIClientRef midiClient;
MIDIEndpointRef src;
OSStatus result;
result = MIDIClientCreate(CFSTR("MIDI client"), NULL, NULL, &midiClient);
if (result != noErr) {
NSLog(@"Errore : %s - %s",
GetMacOSStatusErrorString(result),
GetMacOSStatusCommentString(result));
return 0;
}
result = MIDIDestinationCreate(midiClient, CFSTR("Porta virtuale"), midiInputCallback, NULL, &src);
if (result != noErr ) {
NSLog(@"Errore : %s - %s",
GetMacOSStatusErrorString(result),
GetMacOSStatusCommentString(result));
return 0;
}
MIDIPortRef inputPort;
result = MIDIInputPortCreate(midiClient, CFSTR("Input"), midiInputCallback, NULL, &inputPort);
ItemCount numOfDevices = MIDIGetNumberOfDevices();
for (int i = 0; i < numOfDevices; i++) {
MIDIDeviceRef midiDevice = MIDIGetDevice(i);
NSDictionary *midiProperties;
MIDIObjectGetProperties(midiDevice, (CFPropertyListRef *)&midiProperties, YES);
MIDIEndpointRef src = MIDIGetSource(i);
MIDIPortConnectSource(inputPort, src, NULL);
}
return NSApplicationMain(argc, (const char **) argv);
}
Thank you in advance for any information that can help me.
The main problem that you're having is that you're assuming that the MIDI callback function "knows" about your
MyDocument
class and is able to access its properties. Unfortunately, that's not the case. C functions have no inherent state information, the only way to pass information to a function is to pass it as an argument.That's what all the
void* refCon
arguments are in the documentation.refCon
is a generic pointer that you can use to pass a reference to some other object to your function.For instance, the docs show the signature for the
MIDIInputPortCreate()
function as follows:In your particular case, you should be passing a reference to your
MyDocument
object as therefCon
parameter. At present you are passingNULL
.Then, in your callback, you can access the document object and therefore its properties:
That should be how it works. However, in your code above you seem to have a
main()
function inside yourMyDocument.m
file. That is completely and totally incorrect. If you are using a Cocoa document-based app, you should not be altering themain()
function at all except in very rare circumstances.Instead, you should do all of your MIDI setup in the
‑windowControllerDidLoadNib:
method ofNSDocument
, which is called when the document's window is loaded and the outlets are guaranteed to be ready.Something like this: