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