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

Xcode CoreMidi:将收到的midi消息记录到NSTextField,xcode,cocoa,coremidi,Xcode,Cocoa,Coremidi,对不起,我不会说英语(我在用谷歌翻译) 我对Xcode非常陌生。我正在尝试编写一个应用程序,它可以监听收到的midi消息,并将它们显示在NSTextField(就像midi监视器一样) 我使用CoreMidi,我能够将应用程序连接到所需的输入并接收Midi消息(我可以使用NSLog打印它们)。如何在NSTextField中输出这些消息(与我在NSLog中读取的消息相同) 我设置了一个属性,@synthesisd,并连接了Interface Builder中的NSTextField,但从midi回

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

我对Xcode非常陌生。我正在尝试编写一个应用程序,它可以监听收到的midi消息,并将它们显示在
NSTextField
(就像midi监视器一样)

我使用
CoreMidi
,我能够将应用程序连接到所需的输入并接收Midi消息(我可以使用
NSLog
打印它们)。如何在
NSTextField
中输出这些消息(与我在
NSLog
中读取的消息相同)

我设置了一个属性,
@synthesis
d,并连接了Interface Builder中的NSTextField,但从midi回调函数中我无法访问它(它显示“未声明”)

这里是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);
}
@合成测试消息;
void midiInputCallback(const MIDIPacketList*list,void*procRef,void*srcRef){
id POOL=[[NSAutoreleasePool alloc]init];
UInt16毫字节;
NSString*ric;
const MIDIPacket*packet=&list->packet[0];
对于(无符号整数i=0;inumPackets;i++){
n字节=数据包->长度;
UInt16 iByte,大小;
iByte=0;
而(iByte数据[iByte];
如果(状态<0xC0){
尺寸=3;
}否则如果(状态<0xE0){
尺寸=2;
}否则如果(状态<0xF0){
尺寸=3;
}否则如果(状态<0xF3){
尺寸=3;
}否则如果(状态==0xF3){
尺寸=2;
}否则{
尺寸=1;
}
开关(状态&0xF0){
案例0x80:
ric=@“注意事项”;
打破
案例0x90:
ric=@“关于”的说明;
打破
案例0xA0:
ric=@“后触摸”;
打破
案例0xB0:
ric=@“控制变更”;
打破
案例0xC0:
ric=@“程序变更”;
打破
案例0xD0:
ric=@“通道压力”;
打破
案例0xE0:
ric=@“变桨轮”;
打破
违约:
ric=@“Unk”;
打破
}
//在这里测试
[test_messages setStringValue:@“test test”];//此获取“未声明的test_messages(首次在此函数中使用)”
iByte+=尺寸;
}
packet=MIDIPacketNext(packet);
}
[池释放];
}
int main(int argc,char*argv[]){
MIDIClientRef midiClient;
middiref-src;
骨状态结果;
结果=midclientcreate(CFSTR(“MIDI客户机”)、NULL、NULL和midclient;
如果(结果!=noErr){
NSLog(@“错误:%s-%s”,
GetMacOSStatusErrorString(结果),
GetMacOSStatusCommentString(结果));
返回0;
}
结果=MIDIDestinationCreate(midiClient、CFSTR(“Porta virtuale”)、midiInputCallback、NULL和src);
如果(结果!=noErr){
NSLog(@“错误:%s-%s”,
GetMacOSStatusErrorString(结果),
GetMacOSStatusCommentString(结果));
返回0;
}
MIDIPortRef输入端口;
结果=MIDIInputPortCreate(midiClient、CFSTR(“输入”)、midiInputCallback、NULL和inputPort);
ItemCount numOfDevices=MIDIGetNumberOfDevices();
对于(int i=0;i

提前感谢您提供的任何可以帮助我的信息。

您遇到的主要问题是,您假设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"];
}
这应该是它的工作原理。但是,在上面的代码中,
MyDocument.m
文件中似乎有一个
main()
函数。这是完全不正确的。如果您使用的是基于Cocoa文档的应用程序,那么除了极少数情况外,您根本不应该更改
main()
函数

相反,您应该在
NSDocument
-windowcontrolleridloadnib:
方法中完成所有MIDI设置,该方法在加载文档的窗口并确保输出准备就绪时调用

大概是这样的:

@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
@实现MyDocument
@综合测试信息;
void midiInputCallback(const MIDIPacketList*list,void*procRef,void*srcRef)
{
//在这里做一些MIDI的东西
//通过强制转换void*指针获取对文档的引用
MyDocument*MyDocument=(MyDocument*)procRef;
//将消息记录到文本字段
[myDocument.test_messages setString值:@“test test”];
}    
‑(无效)WindowControllerIDloadNib:(NSWindowController*)windowController
{
//设置midi输入
MIDIClientRef midiClient;
middiref-src;
骨状态结果;
结果=midclientcreate(CFSTR(“MIDI客户机”)、NULL、NULL和midclient;
如果