blob: 75c6a3b10af81ea711639aaea9964d6a47fdfff8 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "MIDIMessage.h"
const uint8_t kMIDINoChannel = -1;
MIDIMessageType MIDIMessageTypeFromStatus(MIDIByte status) {
if (status < MIDIMessageSysEx) {
return (status & 0xF0) >> 4;
} else {
return status;
}
}
MIDIChannel MIDIChannelFromStatus(MIDIByte status) {
if (status < MIDIMessageSysEx) {
return (status & 0x0F) + 1;
} else {
return -1;
}
}
NSData *MIDIMessageBody(NSData *message) {
if (message.length == 0) {
return nil;
}
const MIDIByte *bytes = (const MIDIByte *)message.bytes;
// Slice off any header/trailer bytes.
if (MIDIMessageTypeFromStatus(bytes[0]) == MIDIMessageSysEx) {
NSCAssert(bytes[message.length - 1] == MIDIMessageSysExEnd, @"SysEx message without trailer.");
return [message subdataWithRange:NSMakeRange(1, message.length - 2)];
} else {
return [message subdataWithRange:NSMakeRange(1, message.length - 1)];
}
}
MIDIByte MIDIStatusByte(MIDIMessageType type, MIDIChannel channel) {
if (type >= MIDIMessageSysEx) {
return type;
} else {
return (type << 4) | (channel - 1);
}
}
NSData *MIDIChannelMessageCreate(MIDIMessageType type, MIDIChannel channel, NSData *body) {
NSMutableData *message =
[[NSMutableData alloc] initWithCapacity:body.length + 2]; // +2 for status and SysEx trailer
const MIDIByte status = MIDIStatusByte(type, channel);
[message appendBytes:&status length:1];
[message appendData:body];
if (type == MIDIMessageSysEx) {
const MIDIByte trailer = MIDIMessageSysEx;
[message appendBytes:&trailer length:1];
}
return message;
}
NSData *MIDIMessageCreateSimple1(MIDIMessageType type, MIDIChannel channel, MIDIByte first) {
NSCAssert(type != MIDIMessageSysEx, @"MIDIMessageCreateSimple1 cannot create SysEx messages.");
NSMutableData *message = [[NSMutableData alloc] initWithCapacity:2]; // Status + Data
const MIDIByte status = MIDIStatusByte(type, channel);
[message appendBytes:&status length:1];
[message appendBytes:&first length:1];
return message;
}
NSData *MIDIMessageCreateSimple2(MIDIMessageType type,
MIDIChannel channel,
MIDIByte first,
MIDIByte second) {
NSCAssert(type != MIDIMessageSysEx, @"MIDIMessageCreateSimple2 cannot create SysEx messages.");
NSMutableData *message = [[NSMutableData alloc] initWithCapacity:3]; // Status + Data + Data
const MIDIByte status = MIDIStatusByte(type, channel);
[message appendBytes:&status length:1];
[message appendBytes:&first length:1];
[message appendBytes:&second length:1];
return message;
}