/* * 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; }