Home | History | Annotate | Download | only in WALT
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #import "MIDIMessage.h"
     18 
     19 const uint8_t kMIDINoChannel = -1;
     20 
     21 MIDIMessageType MIDIMessageTypeFromStatus(MIDIByte status) {
     22   if (status < MIDIMessageSysEx) {
     23     return (status & 0xF0) >> 4;
     24   } else {
     25     return status;
     26   }
     27 }
     28 
     29 MIDIChannel MIDIChannelFromStatus(MIDIByte status) {
     30   if (status < MIDIMessageSysEx) {
     31     return (status & 0x0F) + 1;
     32   } else {
     33     return -1;
     34   }
     35 }
     36 
     37 NSData *MIDIMessageBody(NSData *message) {
     38   if (message.length == 0) {
     39     return nil;
     40   }
     41 
     42   const MIDIByte *bytes = (const MIDIByte *)message.bytes;
     43 
     44   // Slice off any header/trailer bytes.
     45   if (MIDIMessageTypeFromStatus(bytes[0]) == MIDIMessageSysEx) {
     46     NSCAssert(bytes[message.length - 1] == MIDIMessageSysExEnd, @"SysEx message without trailer.");
     47     return [message subdataWithRange:NSMakeRange(1, message.length - 2)];
     48   } else {
     49     return [message subdataWithRange:NSMakeRange(1, message.length - 1)];
     50   }
     51 }
     52 
     53 MIDIByte MIDIStatusByte(MIDIMessageType type, MIDIChannel channel) {
     54   if (type >= MIDIMessageSysEx) {
     55     return type;
     56   } else {
     57     return (type << 4) | (channel - 1);
     58   }
     59 }
     60 
     61 NSData *MIDIChannelMessageCreate(MIDIMessageType type, MIDIChannel channel, NSData *body) {
     62   NSMutableData *message =
     63       [[NSMutableData alloc] initWithCapacity:body.length + 2];  // +2 for status and SysEx trailer
     64 
     65   const MIDIByte status = MIDIStatusByte(type, channel);
     66   [message appendBytes:&status length:1];
     67   [message appendData:body];
     68 
     69   if (type == MIDIMessageSysEx) {
     70     const MIDIByte trailer = MIDIMessageSysEx;
     71     [message appendBytes:&trailer length:1];
     72   }
     73 
     74   return message;
     75 }
     76 
     77 NSData *MIDIMessageCreateSimple1(MIDIMessageType type, MIDIChannel channel, MIDIByte first) {
     78   NSCAssert(type != MIDIMessageSysEx, @"MIDIMessageCreateSimple1 cannot create SysEx messages.");
     79 
     80   NSMutableData *message = [[NSMutableData alloc] initWithCapacity:2];  // Status + Data
     81 
     82   const MIDIByte status = MIDIStatusByte(type, channel);
     83   [message appendBytes:&status length:1];
     84   [message appendBytes:&first length:1];
     85 
     86   return message;
     87 }
     88 
     89 NSData *MIDIMessageCreateSimple2(MIDIMessageType type,
     90                                  MIDIChannel channel,
     91                                  MIDIByte first,
     92                                  MIDIByte second) {
     93   NSCAssert(type != MIDIMessageSysEx, @"MIDIMessageCreateSimple2 cannot create SysEx messages.");
     94 
     95   NSMutableData *message = [[NSMutableData alloc] initWithCapacity:3];  // Status + Data + Data
     96 
     97   const MIDIByte status = MIDIStatusByte(type, channel);
     98   [message appendBytes:&status length:1];
     99   [message appendBytes:&first length:1];
    100   [message appendBytes:&second length:1];
    101 
    102   return message;
    103 }
    104