我无法在CoreMIDI for iOS上找到太多信息。甚至可以通过向设备本身发送消息来播放MIDI声音。 iPhone或iPad是否安装了MIDI设备,或者您是否必须将设备连接到界面?
答案 0 :(得分:8)
这已经太晚了几年,但它可能会帮助那些帮助我的人。这website帮助我从外部MIDI键盘读取MIDI数据。连接是最棘手的部分,但本教程将引导您完成它。
这是我创建的课程。
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事件时调用的功能 handleMIDIStatus功能
handleMIDIStatus
获取MIDI数据包(其中包含有关播放内容和MIDIController实例的信息)
注意:您需要对MIDIController的引用,以便您可以填充类的属性...在我的情况下,我将所有已播放的音符按MIDI编号存储在一个数组中,以便稍后使用
当status
为0x90
时,表示已触发音符,如果速度为0,则认为未播放...我需要添加此项声明,因为它没有正常运作
注意:我只处理key on
和key off
事件,因此您可以扩充switch语句以处理更多MIDI事件
updateKeyboardButtonAfterKeyPressed方法
我希望这会有所帮助。
答案 1 :(得分:6)
你应该看看pete goodliffe's blog,他慷慨地提供了一个示例项目。 开始编程CoreMIDI对我帮助很大。
现在关于您的问题,在iOS上,主要使用CoreMIDI网络会话。 同一“网络会话”的参与者向彼此发送消息。
例如,您在Mac上配置网络会话(使用音频MIDI设置工具),您可以将iOS设备连接到它。 这样,您就可以将消息从iOS发送到OSX主机,反之亦然。
CoreMIDI网络会话依赖于RTP协议传输MIDI消息,而Bonjour依赖于发现主机。
除此之外,CoreMIDI还可以处理连接到系统的MIDI接口,但iOS设备默认没有物理MIDI接口。 如果要将iPhone直接连接到合成器,则必须购买外部硬件。 但是,iPad可以通过相机套件连接到兼容USB类的Midi接口。
另一方面,在独立的iOS设备上,您可以发送使用本地CoreMIDI会话从/向另一个兼容CoreMIDI的应用程序发送或接收消息。