2012-01-09 6 views
2

Извините, я не говорю по-английски (я использую Google Translate).CoreMidi: протоколирование полученных сообщений midi на NSTextField

Я очень новичок в Xcode. Я пытаюсь написать приложение, которое может прослушать полученные сообщения midi и показать их в NSTextField (точно так же, как монитор midi).

Я использую CoreMidi, и я могу подключить приложение к желаемому входу и получать сообщения Midi (я могу распечатать их, используя NSLog). Как я могу вывести это сообщение (те же, что я могу прочитать в NSLog) в NSTextField?

Я установил свойство, @synthesize d и подключил NSTextField в Interface Builder, но из функции обратного вызова midi я не могу получить к ней доступ (он говорит «Undeclared»).

Здесь код в MyDocument.h

@property (retain,nonatomic) IBOutlet NSTextField *test_messages; 

Вот код в 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); 
} 

Заранее спасибо за любую информацию, которая может помочь мне.

+0

Вы можете разместить код, который вы используете для регистрации обратного вызова и саму функцию обратного вызова? –

+0

Большое спасибо за чтение меня :) Код добавлен (надеется на правильный путь) – 8003130124464

ответ

5

Основная проблема, с которой вы сталкиваетесь, заключается в том, что вы считаете, что функция обратного вызова MIDI «знает» о вашем классе MyDocument и имеет доступ к ее свойствам. К сожалению, это не так. Функции C не имеют неотъемлемой информации о состоянии, единственный способ передать информацию функции - передать ее в качестве аргумента.

Вот что все аргументы void* refCon содержатся в документации. refCon - это общий указатель, который вы можете использовать для передачи ссылки на какой-либо другой объект вашей функции.

Например, документы показывают подписи для функции MIDIInputPortCreate() следующим образом:

extern OSStatus MIDIInputPortCreate(
    MIDIClientRef client, 
    CFStringRef portName, 
    MIDIReadProc readProc, 
    void *refCon, 
    MIDIPortRef *outPort); 

В вашем конкретном случае, вы должны передать ссылку на ваш MyDocument объект в качестве параметра refCon. В данный момент вы проходите NULL.

MIDIPortRef inputPort; 
result = MIDIInputPortCreate(midiClient, 
    CFSTR("Input"), 
    midiInputCallback, 
    myDocument, //note the change 
    &inputPort); 

Тогда в обратном вызове, вы можете получить доступ к объекту документа и поэтому его свойству:

void midiInputCallback (const MIDIPacketList *list, void *procRef, void *srcRef) 
{ 
    //do some MIDI stuff here 

    //get a reference to your document by casting the void* pointer 
    MyDocument* myDocument = (MyDocument*)procRef; 
    //log the message to the text field 
    [myDocument.test_messages setStringValue:@"TEST TEST"]; 
} 

Это должно быть, как это работает. Однако в вашем коде выше у вас есть main() функция внутри ваш MyDocument.m файл. То есть полностью и полностью неверно. Если вы используете приложение на основе документа Cocoa, вы не должны изменять функцию main() вообще, за исключением очень редких случаев.

Вместо этого вы должны выполнить всю свою настройку MIDI в ‑windowControllerDidLoadNib: методе NSDocument, который вызывается, когда окно документа загружено, и выходы гарантированно будут готовы.

Что-то вроде этого:

@implementation MyDocument 
@synthesize test_messages; 

void midiInputCallback (const MIDIPacketList *list, void *procRef, void *srcRef) 
{ 
    //do some MIDI stuff here 

    //get a reference to your document by casting the void* pointer 
    MyDocument* myDocument = (MyDocument*)procRef; 
    //log the message to the text field 
    [myDocument.test_messages setStringValue:@"TEST TEST"]; 
}  

‑ (void)windowControllerDidLoadNib:(NSWindowController*)windowController 
{ 
    //set up midi input 
    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; 
    } 

    //note the use of "self" to send the reference to this document object 
    result = MIDIDestinationCreate(midiClient, CFSTR("Porta virtuale"), midiInputCallback, self, &src); 
    if (result != noErr) { 
     NSLog(@"Errore : %s - %s", 
       GetMacOSStatusErrorString(result), 
       GetMacOSStatusCommentString(result)); 
     return 0; 
    } 

    MIDIPortRef inputPort; 
    //and again here 
    result = MIDIInputPortCreate(midiClient, CFSTR("Input"), midiInputCallback, self, &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); 
    } 
} 

@end 
+0

Это прекрасно! Спасибо вам большое: D – 8003130124464

+0

Он работает? MIDIGetNumberOfDevices возвращает количество всех устройств (источник и пункт назначения), но MIDIGetSource должен работать в диапазоне 0..MIDIGetNumberOfSources-1. И почему вы все равно получаете MIDIObjectGetProperties? –