CoreMidi:将收到的midi消息记录到NSTextField

800*_*464 2 xcode cocoa coremidi

对不起,我不会说英语(我正在使用谷歌翻译).

我对Xcode很新.我正在尝试编写一个应用程序,可以收听收到的midi消息并将其显示在NSTextField(就像midi监视器).

我使用CoreMidi,我能够将应用程序连接到所需的输入并接收Midi消息(我可以使用它打印NSLog).我怎样才能输出这些消息(我能读到的消息NSLog)NSTextField

我设置了一个属性,@synthesize并在接口生成器中连接了NSTextField,但是从midi回调函数我无法访问它(它表示"未声明").

这里是MyDocument.h中的代码

@property (retain,nonatomic) IBOutlet NSTextField *test_messages;
Run Code Online (Sandbox Code Playgroud)

这里是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);
}
Run Code Online (Sandbox Code Playgroud)

提前感谢您提供有助于我的任何信息.

Rob*_*ger 5

您遇到的主要问题是您假设MIDI回调函数"知道"您的MyDocument类并且能够访问其属性.不幸的是,事实并非如此.C函数没有固有的状态信息,将信息传递给函数的唯一方法是将其作为参数传递.

这就是void* refCon文档中所有参数的含义.refCon是一个通用指针,可用于将对其他对象的引用传递给您的函数.

例如,文档显示MIDIInputPortCreate()函数的签名如下:

extern OSStatus MIDIInputPortCreate(
    MIDIClientRef client, 
    CFStringRef portName, 
    MIDIReadProc readProc, 
    void *refCon, 
    MIDIPortRef *outPort ); 
Run Code Online (Sandbox Code Playgroud)

在您的特定情况下,您应该将MyDocument对象的引用作为refCon参数传递.目前你正在路过NULL.

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

然后,在回调中,您可以访问文档对象,从而访问其属性:

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"];
}
Run Code Online (Sandbox Code Playgroud)

这应该是它的工作原理.然而,在你的代码你上面似乎有一个main()函数里面MyDocument.m文件.这完全完全错误的.如果您使用的是基于Cocoa文档的应用程序,main()除非在极少数情况下,否则您不应该更改该功能.

相反,您应该在?windowControllerDidLoadNib:方法中执行所有MIDI设置,该方法在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
Run Code Online (Sandbox Code Playgroud)