gpt4 book ai didi

xcode - 核心MIDI : logging received midi messages to an NSTextField

转载 作者:行者123 更新时间:2023-12-03 16:27:16 25 4
gpt4 key购买 nike

抱歉,我不会说英语(我正在使用 Google 翻译)。

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

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

我设置了一个属性,@synthesize对其进行了编辑,并在 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);
}

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

最佳答案

您遇到的主要问题是您假设 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-windowControllerDidLoadNib: 方法中完成所有 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

关于xcode - 核心MIDI : logging received midi messages to an NSTextField,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8795749/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com