A class that converts byte streams into MIDI messages, and stores them in a FIFO. This is useful if you wish to read MIDI messages via polling instead of interrupts. The class supports every type of MIDI message, and System Realtime messages can be interleaved with regular ones.

Committer:
Padman
Date:
Thu Aug 04 12:15:36 2016 +0000
Revision:
2:cbd43ba7f842
Parent:
0:69cbdcd5d770
Further API documentation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Padman 0:69cbdcd5d770 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
Padman 0:69cbdcd5d770 2 *
Padman 0:69cbdcd5d770 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
Padman 0:69cbdcd5d770 4 * and associated documentation files (the "Software"), to deal in the Software without
Padman 0:69cbdcd5d770 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
Padman 0:69cbdcd5d770 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
Padman 0:69cbdcd5d770 7 * Software is furnished to do so, subject to the following conditions:
Padman 0:69cbdcd5d770 8 *
Padman 0:69cbdcd5d770 9 * The above copyright notice and this permission notice shall be included in all copies or
Padman 0:69cbdcd5d770 10 * substantial portions of the Software.
Padman 0:69cbdcd5d770 11 *
Padman 0:69cbdcd5d770 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
Padman 0:69cbdcd5d770 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Padman 0:69cbdcd5d770 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
Padman 0:69cbdcd5d770 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Padman 0:69cbdcd5d770 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Padman 0:69cbdcd5d770 17 */
Padman 0:69cbdcd5d770 18
Padman 0:69cbdcd5d770 19 #ifndef MIDIMESSAGE_H
Padman 0:69cbdcd5d770 20 #define MIDIMESSAGE_H
Padman 0:69cbdcd5d770 21
Padman 0:69cbdcd5d770 22 #include "mbed.h"
Padman 0:69cbdcd5d770 23
Padman 0:69cbdcd5d770 24 #define MAX_MIDI_MESSAGE_SIZE 256 // Max message size. SysEx can be up to 65536 but 256 should be fine for most usage
Padman 0:69cbdcd5d770 25
Padman 0:69cbdcd5d770 26 // MIDI Message Format
Padman 0:69cbdcd5d770 27 //
Padman 0:69cbdcd5d770 28 // [ msg(4) | channel(4) ] [ 0 | n(7) ] [ 0 | m(7) ]
Padman 0:69cbdcd5d770 29 //
Padman 0:69cbdcd5d770 30 // MIDI Data Messages (Channel Specific)
Padman 0:69cbdcd5d770 31 //
Padman 0:69cbdcd5d770 32 // Message msg n m
Padman 0:69cbdcd5d770 33 // ---------------------------------------------
Padman 0:69cbdcd5d770 34 // Note Off 0x8 Key Velocity
Padman 0:69cbdcd5d770 35 // Note On 0x9 Key Velocity
Padman 0:69cbdcd5d770 36 // Polyphonic Aftertouch 0xA Key Pressure
Padman 0:69cbdcd5d770 37 // Control Change 0xB Controller Value
Padman 0:69cbdcd5d770 38 // Program Change 0xC Program -
Padman 0:69cbdcd5d770 39 // Channel Aftertouch 0xD Pressure -
Padman 0:69cbdcd5d770 40 // Pitch Wheel 0xE LSB MSB
Padman 0:69cbdcd5d770 41
Padman 0:69cbdcd5d770 42 #define CABLE_NUM (0<<4)
Padman 0:69cbdcd5d770 43
Padman 0:69cbdcd5d770 44 /** A MIDI message container */
Padman 0:69cbdcd5d770 45 class MIDIMessage {
Padman 0:69cbdcd5d770 46 public:
Padman 0:69cbdcd5d770 47 MIDIMessage() : length(4) {}
Padman 0:69cbdcd5d770 48
Padman 0:69cbdcd5d770 49 MIDIMessage(uint8_t *buf) : length(4) {
Padman 0:69cbdcd5d770 50 for (int i = 0; i < 4; i++)
Padman 0:69cbdcd5d770 51 data[i] = buf[i];
Padman 0:69cbdcd5d770 52 }
Padman 0:69cbdcd5d770 53
Padman 0:69cbdcd5d770 54 // New constructor, buf is a true MIDI message (not USBMidi message) and buf_len true message length.
Padman 0:69cbdcd5d770 55 MIDIMessage(uint8_t *buf, int buf_len) {
Padman 0:69cbdcd5d770 56 length=buf_len+1;
Padman 0:69cbdcd5d770 57 // first byte keeped for retro-compatibility
Padman 0:69cbdcd5d770 58 data[0]=0;
Padman 0:69cbdcd5d770 59
Padman 0:69cbdcd5d770 60 for (int i = 0; i < buf_len; i++)
Padman 0:69cbdcd5d770 61 data[i+1] = buf[i];
Padman 0:69cbdcd5d770 62 }
Padman 0:69cbdcd5d770 63
Padman 0:69cbdcd5d770 64 // create messages
Padman 0:69cbdcd5d770 65
Padman 0:69cbdcd5d770 66 /** Create a NoteOff message
Padman 0:69cbdcd5d770 67 * @param key Key ID
Padman 0:69cbdcd5d770 68 * @param velocity Key velocity (0-127, default = 127)
Padman 0:69cbdcd5d770 69 * @param channel Key channel (0-15, default 0)
Padman 0:69cbdcd5d770 70 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 71 */
Padman 0:69cbdcd5d770 72 static MIDIMessage NoteOff(int key, int velocity = 127, int channel = 0) {
Padman 0:69cbdcd5d770 73 MIDIMessage msg;
Padman 0:69cbdcd5d770 74 msg.data[0] = CABLE_NUM | 0x08;
Padman 0:69cbdcd5d770 75 msg.data[1] = 0x80 | (channel & 0x0F);
Padman 0:69cbdcd5d770 76 msg.data[2] = key & 0x7F;
Padman 0:69cbdcd5d770 77 msg.data[3] = velocity & 0x7F;
Padman 0:69cbdcd5d770 78 return msg;
Padman 0:69cbdcd5d770 79 }
Padman 0:69cbdcd5d770 80
Padman 0:69cbdcd5d770 81 /** Create a NoteOn message
Padman 0:69cbdcd5d770 82 * @param key Key ID
Padman 0:69cbdcd5d770 83 * @param velocity Key velocity (0-127, default = 127)
Padman 0:69cbdcd5d770 84 * @param channel Key channel (0-15, default 0)
Padman 0:69cbdcd5d770 85 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 86 */
Padman 0:69cbdcd5d770 87 static MIDIMessage NoteOn(int key, int velocity = 127, int channel = 0) {
Padman 0:69cbdcd5d770 88 MIDIMessage msg;
Padman 0:69cbdcd5d770 89 msg.data[0] = CABLE_NUM | 0x09;
Padman 0:69cbdcd5d770 90 msg.data[1] = 0x90 | (channel & 0x0F);
Padman 0:69cbdcd5d770 91 msg.data[2] = key & 0x7F;
Padman 0:69cbdcd5d770 92 msg.data[3] = velocity & 0x7F;
Padman 0:69cbdcd5d770 93 return msg;
Padman 0:69cbdcd5d770 94 }
Padman 0:69cbdcd5d770 95
Padman 0:69cbdcd5d770 96 /** Create a PolyPhonic Aftertouch message
Padman 0:69cbdcd5d770 97 * @param key Key ID
Padman 0:69cbdcd5d770 98 * @param pressure Aftertouch pressure (0-127)
Padman 0:69cbdcd5d770 99 * @param channel Key channel (0-15, default 0)
Padman 0:69cbdcd5d770 100 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 101 */
Padman 0:69cbdcd5d770 102 static MIDIMessage PolyphonicAftertouch(int key, int pressure, int channel = 0) {
Padman 0:69cbdcd5d770 103 MIDIMessage msg;
Padman 0:69cbdcd5d770 104 msg.data[0] = CABLE_NUM | 0x0A;
Padman 0:69cbdcd5d770 105 msg.data[1] = 0xA0 | (channel & 0x0F);
Padman 0:69cbdcd5d770 106 msg.data[2] = key & 0x7F;
Padman 0:69cbdcd5d770 107 msg.data[3] = pressure & 0x7F;
Padman 0:69cbdcd5d770 108 return msg;
Padman 0:69cbdcd5d770 109 }
Padman 0:69cbdcd5d770 110
Padman 0:69cbdcd5d770 111 /** Create a Control Change message
Padman 0:69cbdcd5d770 112 * @param control Controller ID
Padman 0:69cbdcd5d770 113 * @param value Controller value (0-127)
Padman 0:69cbdcd5d770 114 * @param channel Controller channel (0-15, default 0)
Padman 0:69cbdcd5d770 115 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 116 */
Padman 0:69cbdcd5d770 117 static MIDIMessage ControlChange(int control, int value, int channel = 0) {
Padman 0:69cbdcd5d770 118 MIDIMessage msg;
Padman 0:69cbdcd5d770 119 msg.data[0] = CABLE_NUM | 0x0B;
Padman 0:69cbdcd5d770 120 msg.data[1] = 0xB0 | (channel & 0x0F);
Padman 0:69cbdcd5d770 121 msg.data[2] = control & 0x7F;
Padman 0:69cbdcd5d770 122 msg.data[3] = value & 0x7F;
Padman 0:69cbdcd5d770 123 return msg;
Padman 0:69cbdcd5d770 124 }
Padman 0:69cbdcd5d770 125
Padman 0:69cbdcd5d770 126 /** Create a Program Change message
Padman 0:69cbdcd5d770 127 * @param program Program ID
Padman 0:69cbdcd5d770 128 * @param channel Channel (0-15, default 0)
Padman 0:69cbdcd5d770 129 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 130 */
Padman 0:69cbdcd5d770 131 static MIDIMessage ProgramChange(int program, int channel = 0) {
Padman 0:69cbdcd5d770 132 MIDIMessage msg;
Padman 0:69cbdcd5d770 133 msg.data[0] = CABLE_NUM | 0x0C;
Padman 0:69cbdcd5d770 134 msg.data[1] = 0xC0 | (channel & 0x0F);
Padman 0:69cbdcd5d770 135 msg.data[2] = program & 0x7F;
Padman 0:69cbdcd5d770 136 msg.data[3] = 0x00;
Padman 0:69cbdcd5d770 137 return msg;
Padman 0:69cbdcd5d770 138 }
Padman 0:69cbdcd5d770 139
Padman 0:69cbdcd5d770 140 /** Create a Channel Aftertouch message
Padman 0:69cbdcd5d770 141 * @param pressure Pressure
Padman 0:69cbdcd5d770 142 * @param channel Key channel (0-15, default 0)
Padman 0:69cbdcd5d770 143 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 144 */
Padman 0:69cbdcd5d770 145 static MIDIMessage ChannelAftertouch(int pressure, int channel = 0) {
Padman 0:69cbdcd5d770 146 MIDIMessage msg;
Padman 0:69cbdcd5d770 147 msg.data[0] = CABLE_NUM | 0x0D;
Padman 0:69cbdcd5d770 148 msg.data[1] = 0xD0 | (channel & 0x0F);
Padman 0:69cbdcd5d770 149 msg.data[2] = pressure & 0x7F;
Padman 0:69cbdcd5d770 150 msg.data[3] = 0x00;
Padman 0:69cbdcd5d770 151 return msg;
Padman 0:69cbdcd5d770 152 }
Padman 0:69cbdcd5d770 153
Padman 0:69cbdcd5d770 154 /** Create a Pitch Wheel message
Padman 0:69cbdcd5d770 155 * @param pitch Pitch (-8192 - 8191, default = 0)
Padman 0:69cbdcd5d770 156 * @param channel Channel (0-15, default 0)
Padman 0:69cbdcd5d770 157 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 158 */
Padman 0:69cbdcd5d770 159 static MIDIMessage PitchWheel(int pitch = 0, int channel = 0) {
Padman 0:69cbdcd5d770 160 MIDIMessage msg;
Padman 0:69cbdcd5d770 161 int p = pitch + 8192; // 0 - 16383, 8192 is center
Padman 0:69cbdcd5d770 162 msg.data[0] = CABLE_NUM | 0x0E;
Padman 0:69cbdcd5d770 163 msg.data[1] = 0xE0 | (channel & 0x0F);
Padman 0:69cbdcd5d770 164 msg.data[2] = p & 0x7F;
Padman 0:69cbdcd5d770 165 msg.data[3] = (p >> 7) & 0x7F;
Padman 0:69cbdcd5d770 166 return msg;
Padman 0:69cbdcd5d770 167 }
Padman 0:69cbdcd5d770 168
Padman 0:69cbdcd5d770 169 /** Create an All Notes Off message
Padman 0:69cbdcd5d770 170 * @param channel Channel (0-15, default 0)
Padman 0:69cbdcd5d770 171 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 172 */
Padman 0:69cbdcd5d770 173 static MIDIMessage AllNotesOff(int channel = 0) {
Padman 0:69cbdcd5d770 174 return ControlChange(123, 0, channel);
Padman 0:69cbdcd5d770 175 }
Padman 0:69cbdcd5d770 176
Padman 0:69cbdcd5d770 177 /** Create a SysEx message
Padman 0:69cbdcd5d770 178 * @param data SysEx data (including 0xF0 .. 0xF7)
Padman 0:69cbdcd5d770 179 * @param len SysEx data length
Padman 0:69cbdcd5d770 180 * @returns A MIDIMessage
Padman 0:69cbdcd5d770 181 */
Padman 0:69cbdcd5d770 182 static MIDIMessage SysEx(uint8_t *data, int len) {
Padman 0:69cbdcd5d770 183 MIDIMessage msg=MIDIMessage(data,len);
Padman 0:69cbdcd5d770 184 return msg;
Padman 0:69cbdcd5d770 185 }
Padman 0:69cbdcd5d770 186
Padman 0:69cbdcd5d770 187 // decode messages
Padman 0:69cbdcd5d770 188
Padman 0:69cbdcd5d770 189 /** MIDI Message Types */
Padman 0:69cbdcd5d770 190 enum MIDIMessageType {
Padman 0:69cbdcd5d770 191 ErrorType,
Padman 0:69cbdcd5d770 192 NoteOffType,
Padman 0:69cbdcd5d770 193 NoteOnType,
Padman 0:69cbdcd5d770 194 PolyphonicAftertouchType,
Padman 0:69cbdcd5d770 195 ControlChangeType,
Padman 0:69cbdcd5d770 196 ProgramChangeType,
Padman 0:69cbdcd5d770 197 ChannelAftertouchType,
Padman 0:69cbdcd5d770 198 PitchWheelType,
Padman 0:69cbdcd5d770 199 AllNotesOffType,
Padman 0:69cbdcd5d770 200 SysExType
Padman 0:69cbdcd5d770 201 };
Padman 0:69cbdcd5d770 202
Padman 0:69cbdcd5d770 203 /** Read the message type
Padman 0:69cbdcd5d770 204 * @returns MIDIMessageType
Padman 0:69cbdcd5d770 205 */
Padman 0:69cbdcd5d770 206 MIDIMessageType type() {
Padman 0:69cbdcd5d770 207 switch((data[1] >> 4) & 0xF) {
Padman 0:69cbdcd5d770 208 case 0x8: return NoteOffType;
Padman 0:69cbdcd5d770 209 case 0x9: return NoteOnType;
Padman 0:69cbdcd5d770 210 case 0xA: return PolyphonicAftertouchType;
Padman 0:69cbdcd5d770 211 case 0xB:
Padman 0:69cbdcd5d770 212 if(controller() < 120) { // standard controllers
Padman 0:69cbdcd5d770 213 return ControlChangeType;
Padman 0:69cbdcd5d770 214 } else if(controller() == 123) {
Padman 0:69cbdcd5d770 215 return AllNotesOffType;
Padman 0:69cbdcd5d770 216 } else {
Padman 0:69cbdcd5d770 217 return ErrorType; // unsupported atm
Padman 0:69cbdcd5d770 218 }
Padman 0:69cbdcd5d770 219 case 0xC: return ProgramChangeType;
Padman 0:69cbdcd5d770 220 case 0xD: return ChannelAftertouchType;
Padman 0:69cbdcd5d770 221 case 0xE: return PitchWheelType;
Padman 0:69cbdcd5d770 222 case 0xF: return SysExType;
Padman 0:69cbdcd5d770 223 default: return ErrorType;
Padman 0:69cbdcd5d770 224 }
Padman 0:69cbdcd5d770 225 }
Padman 0:69cbdcd5d770 226
Padman 0:69cbdcd5d770 227 /** Read the channel number */
Padman 0:69cbdcd5d770 228 int channel() {
Padman 0:69cbdcd5d770 229 return (data[1] & 0x0F);
Padman 0:69cbdcd5d770 230 }
Padman 0:69cbdcd5d770 231
Padman 0:69cbdcd5d770 232 /** Read the key ID */
Padman 0:69cbdcd5d770 233 int key() {
Padman 0:69cbdcd5d770 234 return (data[2] & 0x7F);
Padman 0:69cbdcd5d770 235 }
Padman 0:69cbdcd5d770 236
Padman 0:69cbdcd5d770 237 /** Read the velocity */
Padman 0:69cbdcd5d770 238 int velocity() {
Padman 0:69cbdcd5d770 239 return (data[3] & 0x7F);
Padman 0:69cbdcd5d770 240 }
Padman 0:69cbdcd5d770 241
Padman 0:69cbdcd5d770 242 /** Read the controller value */
Padman 0:69cbdcd5d770 243 int value() {
Padman 0:69cbdcd5d770 244 return (data[3] & 0x7F);
Padman 0:69cbdcd5d770 245 }
Padman 0:69cbdcd5d770 246
Padman 0:69cbdcd5d770 247 /** Read the aftertouch pressure */
Padman 0:69cbdcd5d770 248 int pressure() {
Padman 0:69cbdcd5d770 249 if(type() == PolyphonicAftertouchType) {
Padman 0:69cbdcd5d770 250 return (data[3] & 0x7F);
Padman 0:69cbdcd5d770 251 } else {
Padman 0:69cbdcd5d770 252 return (data[2] & 0x7F);
Padman 0:69cbdcd5d770 253 }
Padman 0:69cbdcd5d770 254 }
Padman 0:69cbdcd5d770 255
Padman 0:69cbdcd5d770 256 /** Read the controller number */
Padman 0:69cbdcd5d770 257 int controller() {
Padman 0:69cbdcd5d770 258 return (data[2] & 0x7F);
Padman 0:69cbdcd5d770 259 }
Padman 0:69cbdcd5d770 260
Padman 0:69cbdcd5d770 261 /** Read the program number */
Padman 0:69cbdcd5d770 262 int program() {
Padman 0:69cbdcd5d770 263 return (data[2] & 0x7F);
Padman 0:69cbdcd5d770 264 }
Padman 0:69cbdcd5d770 265
Padman 0:69cbdcd5d770 266 /** Read the pitch value */
Padman 0:69cbdcd5d770 267 int pitch() {
Padman 0:69cbdcd5d770 268 int p = ((data[3] & 0x7F) << 7) | (data[2] & 0x7F);
Padman 0:69cbdcd5d770 269 return p - 8192; // 0 - 16383, 8192 is center
Padman 0:69cbdcd5d770 270 }
Padman 0:69cbdcd5d770 271
Padman 0:69cbdcd5d770 272 uint8_t data[MAX_MIDI_MESSAGE_SIZE+1];
Padman 0:69cbdcd5d770 273 uint8_t length;
Padman 0:69cbdcd5d770 274 };
Padman 0:69cbdcd5d770 275
Padman 0:69cbdcd5d770 276 #endif