You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.2 KiB
104 lines
3.2 KiB
/*
|
|
* 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;
|
|
}
|