Мне не удалось найти много информации о CoreMIDI для iOS. Можно ли даже воспроизвести звук MIDI, отправив сообщение самому устройству. Установлен ли на iPhone или iPad MIDI-устройство или у вас есть устройство, подключенное к интерфейсу?
Как использовать CoreMIDI на iOS?
Ответ 1
Вы должны посмотреть блог pete goodliffe, и он щедро предоставляет примерный проект. Это помогло мне начать программирование CoreMIDI.
Теперь о ваших вопросах, на iOS, в основном используются сетевые сессии CoreMIDI. Участники одной и той же "Сетевой сессии" отправляют сообщения друг другу.
Например, вы настраиваете сетевой сеанс на своем Mac (используя инструмент Audio MIDI Setup), и вы можете подключить к нему устройства iOS. Таким образом, вы можете отправлять сообщения с iOS на ваш хост OSX и наоборот.
Сетевые сеансы CoreMIDI полагаются на протокол RTP для передачи MIDI-сообщений и Bonjour для обнаружения хостов.
Кроме того, CoreMIDI также может обрабатывать MIDI-интерфейс, подключенный к системе, но устройства iOS по умолчанию не имеют физического MIDI-интерфейса. Вы должны купить внешнее оборудование, если хотите напрямую подключить свой iPhone к синтезатору. Однако iPad можно подключить к интерфейсу Midi, совместимому с USB-интерфейсом, через комплект камеры.
Другое дело, что на автономном устройстве iOS вы можете отправить локальный сеанс CoreMIDI для отправки или получения сообщений из другого приложения, совместимого с CoreMIDI.
Ответ 2
Это на пару лет слишком поздно, но это может помочь кому-то другому, как это помогло мне. Этот сайт помог мне прочитать 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-устройство (клавиатура)
ПРИМЕЧАНИЕ. Здесь вы можете начать обработку информации MIDI.
функция handleMIDIStatus
-
handleMIDIStatus
принимает MIDI-пакет (который содержит информацию о том, что было воспроизведено, и экземпляр MIDIController
ПРИМЕЧАНИЕ. Вам нужна ссылка на MIDIController, чтобы вы могли заполнять свойства для класса... в моем случае я сохраняю все воспроизведенные ноты по номеру MIDI в массиве для использования позже -
когда
status
равно0x90
, что означает, что нота была запущена, если она имеет скорость 0, считается, что она не воспроизводится... Мне нужно было добавить этот оператор if, потому что это wasn правильно функционирует ПРИМЕЧАНИЕ. Я обрабатываю только тегиkey on
иkey off
, поэтому вы должны увеличить оператор switch для обработки большего количества событий MIDI
updateKeyboardButtonAfterKeyPressed Method
- Это метод, который я использовал для хранения заметок, которые были воспроизведены, и я удаляю заметки из этого массива после того, как ключ был выпущен.
Надеюсь, это поможет.