任何人都可以告诉我如何在iOS上使用CoreMIDI?

我一直无法find关于iOS的CoreMIDI的很多信息。 是否可以通过向设备发送消息来播放MIDI声音。 iPhone或iPad是否安装了MIDI设备,或者是否必须连接一个设备连接到?

你应该看看pete goodliffe的博客 ,他慷慨提供一个示例项目。 它帮助我开始编程CoreMIDI。

现在关于您的问题,在iOS上,大多数使用CoreMIDInetworking会话。 同一个“networking会话”的参与者向对方发送消息。

例如,您可以在Mac上configurationnetworking会话(使用audioMIDI设置工具),并且可以将iOS设备连接到它。 这样,您可以将消息从iOS发送到您的OSX主机,反之亦然。

CoreMIDInetworking会话依靠RTP协议传输MIDI消息和Bonjour来发现主机。

除此之外,CoreMIDI还可以处理连接到系统的MIDI接口,但iOS设备默认没有物理MIDI接口。 如果要直接将iPhone连接到合成器,则必须购买外部硬件。 但是,iPad可以通过相机套件连接到兼容USB类的Midi接口。

另外,在独立的iOS设备上,您可以使用本地CoreMIDI会话向其他CoreMIDI兼容应用程序发送或接收消息。

这已经晚了两年了,但它可能会帮助其他人帮助我。 本网站帮助我从外部MIDI键盘读取MIDI数据。 连接是最棘手的部分,但本教程将引导您通过它。

这是我创build的课程。

MIDIController.h

#import <Foundation/Foundation.h> @interface MIDIController : NSObject @property NSMutableArray *notes; @end 

MIDIController.m

 #import "MIDIController.h" #include <CoreFoundation/CoreFoundation.h> #import <CoreMIDI/CoreMIDI.h> #define SYSEX_LENGTH 1024 #define KEY_ON 1 #define KEY_OFF 0 @implementation MIDIController - (id)init { if (self = [super init]) { _notes = [[NSMutableArray alloc] init]; [self setupMidi]; } return self; } - (void) setupMidi { MIDIClientRef midiClient; checkError(MIDIClientCreate(CFSTR("MIDI client"), NULL, NULL, &midiClient), "MIDI client creation error"); MIDIPortRef inputPort; checkError(MIDIInputPortCreate(midiClient, CFSTR("Input"), midiInputCallback, (__bridge_retained void *)self, &inputPort), "MIDI input port error"); checkError(connectMIDIInputSource(inputPort), "connect MIDI Input Source error"); } OSStatus connectMIDIInputSource(MIDIPortRef inputPort) { unsigned long sourceCount = MIDIGetNumberOfSources(); for (int i = 0; i < sourceCount; ++i) { MIDIEndpointRef endPoint = MIDIGetSource(i); CFStringRef endpointName = NULL; checkError(MIDIObjectGetStringProperty(endPoint, kMIDIPropertyName, &endpointName), "String property not found"); checkError(MIDIPortConnectSource(inputPort, endPoint, NULL), "MIDI not connected"); } return noErr; } void midiInputCallback(const MIDIPacketList *list, void *procRef, void *srcRef) { MIDIController *midiController = (__bridge MIDIController*)procRef; UInt16 nBytes; const MIDIPacket *packet = &list->packet[0]; //gets first packet in list for(unsigned int i = 0; i < list->numPackets; i++) { nBytes = packet->length; //number of bytes in a packet handleMIDIStatus(packet, midiController); packet = MIDIPacketNext(packet); } } void handleMIDIStatus(const MIDIPacket *packet, MIDIController *midiController) { int status = packet->data[0]; //unsigned char messageChannel = status & 0xF; //16 possible MIDI channels switch (status & 0xF0) { case 0x80: updateKeyboardButtonAfterKeyPressed(midiController, packet->data[1], KEY_OFF); break; case 0x90: //data[2] represents the velocity of a note if (packet->data[2] != 0) { updateKeyboardButtonAfterKeyPressed(midiController, packet->data[1], KEY_ON); }//note off also occurs if velocity is 0 else { updateKeyboardButtonAfterKeyPressed(midiController, packet->data[1], KEY_OFF); } break; default: //NSLog(@"Some other message"); break; } } void updateKeyboardButtonAfterKeyPressed(MIDIController *midiController, int key, bool keyStatus) { NSMutableArray *notes = [midiController notes]; //key is being pressed if(keyStatus) { [notes addObject:[NSNumber numberWithInt:key]]; } else {//key has been released for (int i = 0; i < [notes count]; i++) { if ([[notes objectAtIndex:i] integerValue] == key) { [notes removeObjectAtIndex:i]; } } } } void checkError(OSStatus error, const char* task) { if(error == noErr) return; char errorString[20]; *(UInt32 *)(errorString + 1) = CFSwapInt32BigToHost(error); if(isprint(errorString[1]) && isprint(errorString[2]) && isprint(errorString[3]) && isprint(errorString[4])) { errorString[0] = errorString[5] = '\''; errorString[6] = '\0'; } else sprintf(errorString, "%d", (int)error); fprintf(stderr, "Error: %s (%s)\n", task, errorString); exit(1); } @end 

补充笔记

midiInputCallback函数

  • midiInputCallback是通过MIDI设备(键盘)发生MIDI事件时调用的function。
    注意:这是您可以开始处理MIDI信息的地方

handleMIDIStatus函数

  • handleMIDIStatus获取MIDI数据包(其中包含有关播放内容和MIDIController实例的信息
    注意:您需要对MIDIController的引用,以便您可以填充该类的属性…在我的情况下,我将所有弹奏的音符(通过MIDI编号)存储在一个数组中,供以后使用

  • status0x90 ,这意味着一个音符已被触发,如果它的速度为0,则认为没有播放…我需要添加这个if语句,因为它不能正常工作
    注:我只处理key onkey off事件,所以你会扩大开关语句来处理更多的MIDI事件

updateKeyboardButtonAfterKeyPressed方法

  • 这是我用来存储演奏的音符的一种方法,并且一旦琴键被释放,我就从这个数组中移除音符

我希望这有帮助。