Skip to content

Instantly share code, notes, and snippets.

@coffindragger
Last active December 25, 2015 09:48
Show Gist options
  • Save coffindragger/6956330 to your computer and use it in GitHub Desktop.
Save coffindragger/6956330 to your computer and use it in GitHub Desktop.
objc midi parser
static void handle_midi_input (const MIDIPacketList *list, void *inputUserdata, void *srcUserdata)
{
AppDelegate *self = (__bridge AppDelegate *)inputUserdata;
const MIDIPacket *packet = list->packet;
for (int i = 0; i < list->numPackets; i++) {
[self->midiParser feedPacketData:packet->data :packet->length];
packet = MIDIPacketNext(packet);
}
}
- (void)listenToAllMidiEndpoints
{
midiParser = [[MidiParser alloc] init];
[midiParser setDelegate:self];
status = MIDIClientCreate(CFSTR("MyMidiControlledDevice"), NULL, NULL, &midiClient);
status = MIDIInputPortCreate(midiClient, CFSTR("Input"), handle_midi_input, (__bridge void*)self, &midiInput);
int num_midi = MIDIGetNumberOfDevices();
for (int i=0; i < num_midi; i++) {
MIDIEndpointRef src = MIDIGetSource(i);
CFStringRef srcName;
MIDIObjectGetStringProperty(src, kMIDIPropertyName, &srcName);
status = MIDIPortConnectSource(midiInput, src, NULL);
}
}
#import <Foundation/Foundation.h>
#define kReferenceNoteNumber 69
#define kReferenceNoteFrequency 440
#define kNotesPerOctave 12
@interface MidiParser : NSObject
{
id delegate;
}
@property id delegate;
- (id) init;
- (int) feedPacketData:(UInt8 *)bytes :(int)num_bytes;
- (void)systemMessage:(unsigned char)message;
- (void)controllerMessage:(UInt8)controller withValue:(UInt8)value onChannel:(UInt8)channel;
- (void)noteOn:(UInt8)noteNumber withVelocity:(UInt8)velocity onChannel:(UInt8)channel;
- (void)noteOff:(UInt8)noteNumber withVelocity:(UInt8)velocity onChannel:(UInt8)channel;
+ (double)frequencyFromNoteNumber:(UInt8)noteNumber;
@end
#import "MidiParser.h"
@implementation MidiParser
@synthesize delegate;
- (id) init
{
if (self) {
}
return self;
}
- (int) feedPacketData:(UInt8 *)bytes :(int)num_bytes
{
int read;
for (read=1; read < num_bytes; read++) {
unsigned char b = bytes[0];
if (b & 0x30) {
// status message
unsigned char high = (b & 0xF0);
unsigned char low = (b & 0x0F);
switch (high) {
case 0x80: {
UInt8 noteNumber = bytes[read++];
UInt8 velocity = bytes[read++];
[self noteOff:noteNumber withVelocity:velocity onChannel:low];
break;
}
case 0x90: {
UInt8 noteNumber = bytes[read++];
UInt8 velocity = bytes[read++];
if (velocity == 0) {
[self noteOff:noteNumber withVelocity:velocity onChannel:low];
} else {
[self noteOn:noteNumber withVelocity:velocity onChannel:low];
}
break;
}
case 0xB0: {
UInt8 controller = bytes[read++];
UInt8 value = bytes[read++];
[self controllerMessage:controller withValue:value onChannel:low];
break;
}
case 0xF0: {
if (low == 0) {
// skip system exclusive "sysex" messages
}
else {
// 0xF0 .. 0xF7 - system common messages
// 0xF8 .. 0xFF - system realtime messages
[self systemMessage:b];
}
break;
}
default: {
//fall through and skip this message
}
}
} else {
//skip data we dont care about
}
}
return read;
}
- (void)systemMessage:(unsigned char)message
{
if ([delegate respondsToSelector:@selector(systemMessage:)]) {
[delegate systemMessage:message];
}
}
- (void)controllerMessage:(UInt8)controller withValue:(UInt8)value onChannel:(UInt8)channel
{
if ([delegate respondsToSelector:@selector(controllerMessage:withValue:onChannel:)]) {
[delegate controllerMessage:controller withValue:value onChannel:channel];
}
}
- (void)noteOn:(UInt8)noteNumber withVelocity:(UInt8)velocity onChannel:(UInt8)channel
{
if ([delegate respondsToSelector:@selector(noteOn:withVelocity:onChannel:)]) {
[delegate noteOn:noteNumber withVelocity:velocity onChannel:channel];
}
}
- (void)noteOff:(UInt8)noteNumber withVelocity:(UInt8)velocity onChannel:(UInt8)channel
{
if ([delegate respondsToSelector:@selector(noteOff:withVelocity:onChannel:)]) {
[delegate noteOff:noteNumber withVelocity:velocity onChannel:channel];
}
}
+ (double)frequencyFromNoteNumber:(UInt8)noteNumber
{
double offset = (noteNumber - kReferenceNoteNumber) / (double) kNotesPerOctave;
return kReferenceNoteFrequency * pow(2.0, offset);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment