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.
MIDIMessage.h
00001 /* Copyright (c) 2010-2011 mbed.org, MIT License 00002 * 00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00004 * and associated documentation files (the "Software"), to deal in the Software without 00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish, 00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 00007 * Software is furnished to do so, subject to the following conditions: 00008 * 00009 * The above copyright notice and this permission notice shall be included in all copies or 00010 * substantial portions of the Software. 00011 * 00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00017 */ 00018 00019 #ifndef MIDIMESSAGE_H 00020 #define MIDIMESSAGE_H 00021 00022 #include "mbed.h" 00023 00024 #define MAX_MIDI_MESSAGE_SIZE 256 // Max message size. SysEx can be up to 65536 but 256 should be fine for most usage 00025 00026 // MIDI Message Format 00027 // 00028 // [ msg(4) | channel(4) ] [ 0 | n(7) ] [ 0 | m(7) ] 00029 // 00030 // MIDI Data Messages (Channel Specific) 00031 // 00032 // Message msg n m 00033 // --------------------------------------------- 00034 // Note Off 0x8 Key Velocity 00035 // Note On 0x9 Key Velocity 00036 // Polyphonic Aftertouch 0xA Key Pressure 00037 // Control Change 0xB Controller Value 00038 // Program Change 0xC Program - 00039 // Channel Aftertouch 0xD Pressure - 00040 // Pitch Wheel 0xE LSB MSB 00041 00042 #define CABLE_NUM (0<<4) 00043 00044 /** A MIDI message container */ 00045 class MIDIMessage { 00046 public: 00047 MIDIMessage() : length(4) {} 00048 00049 MIDIMessage(uint8_t *buf) : length(4) { 00050 for (int i = 0; i < 4; i++) 00051 data[i] = buf[i]; 00052 } 00053 00054 // New constructor, buf is a true MIDI message (not USBMidi message) and buf_len true message length. 00055 MIDIMessage(uint8_t *buf, int buf_len) { 00056 length=buf_len+1; 00057 // first byte keeped for retro-compatibility 00058 data[0]=0; 00059 00060 for (int i = 0; i < buf_len; i++) 00061 data[i+1] = buf[i]; 00062 } 00063 00064 // create messages 00065 00066 /** Create a NoteOff message 00067 * @param key Key ID 00068 * @param velocity Key velocity (0-127, default = 127) 00069 * @param channel Key channel (0-15, default 0) 00070 * @returns A MIDIMessage 00071 */ 00072 static MIDIMessage NoteOff(int key, int velocity = 127, int channel = 0) { 00073 MIDIMessage msg; 00074 msg.data[0] = CABLE_NUM | 0x08; 00075 msg.data[1] = 0x80 | (channel & 0x0F); 00076 msg.data[2] = key & 0x7F; 00077 msg.data[3] = velocity & 0x7F; 00078 return msg; 00079 } 00080 00081 /** Create a NoteOn message 00082 * @param key Key ID 00083 * @param velocity Key velocity (0-127, default = 127) 00084 * @param channel Key channel (0-15, default 0) 00085 * @returns A MIDIMessage 00086 */ 00087 static MIDIMessage NoteOn(int key, int velocity = 127, int channel = 0) { 00088 MIDIMessage msg; 00089 msg.data[0] = CABLE_NUM | 0x09; 00090 msg.data[1] = 0x90 | (channel & 0x0F); 00091 msg.data[2] = key & 0x7F; 00092 msg.data[3] = velocity & 0x7F; 00093 return msg; 00094 } 00095 00096 /** Create a PolyPhonic Aftertouch message 00097 * @param key Key ID 00098 * @param pressure Aftertouch pressure (0-127) 00099 * @param channel Key channel (0-15, default 0) 00100 * @returns A MIDIMessage 00101 */ 00102 static MIDIMessage PolyphonicAftertouch(int key, int pressure, int channel = 0) { 00103 MIDIMessage msg; 00104 msg.data[0] = CABLE_NUM | 0x0A; 00105 msg.data[1] = 0xA0 | (channel & 0x0F); 00106 msg.data[2] = key & 0x7F; 00107 msg.data[3] = pressure & 0x7F; 00108 return msg; 00109 } 00110 00111 /** Create a Control Change message 00112 * @param control Controller ID 00113 * @param value Controller value (0-127) 00114 * @param channel Controller channel (0-15, default 0) 00115 * @returns A MIDIMessage 00116 */ 00117 static MIDIMessage ControlChange(int control, int value, int channel = 0) { 00118 MIDIMessage msg; 00119 msg.data[0] = CABLE_NUM | 0x0B; 00120 msg.data[1] = 0xB0 | (channel & 0x0F); 00121 msg.data[2] = control & 0x7F; 00122 msg.data[3] = value & 0x7F; 00123 return msg; 00124 } 00125 00126 /** Create a Program Change message 00127 * @param program Program ID 00128 * @param channel Channel (0-15, default 0) 00129 * @returns A MIDIMessage 00130 */ 00131 static MIDIMessage ProgramChange(int program, int channel = 0) { 00132 MIDIMessage msg; 00133 msg.data[0] = CABLE_NUM | 0x0C; 00134 msg.data[1] = 0xC0 | (channel & 0x0F); 00135 msg.data[2] = program & 0x7F; 00136 msg.data[3] = 0x00; 00137 return msg; 00138 } 00139 00140 /** Create a Channel Aftertouch message 00141 * @param pressure Pressure 00142 * @param channel Key channel (0-15, default 0) 00143 * @returns A MIDIMessage 00144 */ 00145 static MIDIMessage ChannelAftertouch(int pressure, int channel = 0) { 00146 MIDIMessage msg; 00147 msg.data[0] = CABLE_NUM | 0x0D; 00148 msg.data[1] = 0xD0 | (channel & 0x0F); 00149 msg.data[2] = pressure & 0x7F; 00150 msg.data[3] = 0x00; 00151 return msg; 00152 } 00153 00154 /** Create a Pitch Wheel message 00155 * @param pitch Pitch (-8192 - 8191, default = 0) 00156 * @param channel Channel (0-15, default 0) 00157 * @returns A MIDIMessage 00158 */ 00159 static MIDIMessage PitchWheel(int pitch = 0, int channel = 0) { 00160 MIDIMessage msg; 00161 int p = pitch + 8192; // 0 - 16383, 8192 is center 00162 msg.data[0] = CABLE_NUM | 0x0E; 00163 msg.data[1] = 0xE0 | (channel & 0x0F); 00164 msg.data[2] = p & 0x7F; 00165 msg.data[3] = (p >> 7) & 0x7F; 00166 return msg; 00167 } 00168 00169 /** Create an All Notes Off message 00170 * @param channel Channel (0-15, default 0) 00171 * @returns A MIDIMessage 00172 */ 00173 static MIDIMessage AllNotesOff(int channel = 0) { 00174 return ControlChange(123, 0, channel); 00175 } 00176 00177 /** Create a SysEx message 00178 * @param data SysEx data (including 0xF0 .. 0xF7) 00179 * @param len SysEx data length 00180 * @returns A MIDIMessage 00181 */ 00182 static MIDIMessage SysEx(uint8_t *data, int len) { 00183 MIDIMessage msg=MIDIMessage(data,len); 00184 return msg; 00185 } 00186 00187 // decode messages 00188 00189 /** MIDI Message Types */ 00190 enum MIDIMessageType { 00191 ErrorType, 00192 NoteOffType, 00193 NoteOnType, 00194 PolyphonicAftertouchType, 00195 ControlChangeType, 00196 ProgramChangeType, 00197 ChannelAftertouchType, 00198 PitchWheelType, 00199 AllNotesOffType, 00200 SysExType 00201 }; 00202 00203 /** Read the message type 00204 * @returns MIDIMessageType 00205 */ 00206 MIDIMessageType type() { 00207 switch((data[1] >> 4) & 0xF) { 00208 case 0x8: return NoteOffType; 00209 case 0x9: return NoteOnType; 00210 case 0xA: return PolyphonicAftertouchType; 00211 case 0xB: 00212 if(controller() < 120) { // standard controllers 00213 return ControlChangeType; 00214 } else if(controller() == 123) { 00215 return AllNotesOffType; 00216 } else { 00217 return ErrorType; // unsupported atm 00218 } 00219 case 0xC: return ProgramChangeType; 00220 case 0xD: return ChannelAftertouchType; 00221 case 0xE: return PitchWheelType; 00222 case 0xF: return SysExType; 00223 default: return ErrorType; 00224 } 00225 } 00226 00227 /** Read the channel number */ 00228 int channel() { 00229 return (data[1] & 0x0F); 00230 } 00231 00232 /** Read the key ID */ 00233 int key() { 00234 return (data[2] & 0x7F); 00235 } 00236 00237 /** Read the velocity */ 00238 int velocity() { 00239 return (data[3] & 0x7F); 00240 } 00241 00242 /** Read the controller value */ 00243 int value() { 00244 return (data[3] & 0x7F); 00245 } 00246 00247 /** Read the aftertouch pressure */ 00248 int pressure() { 00249 if(type() == PolyphonicAftertouchType) { 00250 return (data[3] & 0x7F); 00251 } else { 00252 return (data[2] & 0x7F); 00253 } 00254 } 00255 00256 /** Read the controller number */ 00257 int controller() { 00258 return (data[2] & 0x7F); 00259 } 00260 00261 /** Read the program number */ 00262 int program() { 00263 return (data[2] & 0x7F); 00264 } 00265 00266 /** Read the pitch value */ 00267 int pitch() { 00268 int p = ((data[3] & 0x7F) << 7) | (data[2] & 0x7F); 00269 return p - 8192; // 0 - 16383, 8192 is center 00270 } 00271 00272 uint8_t data[MAX_MIDI_MESSAGE_SIZE+1]; 00273 uint8_t length; 00274 }; 00275 00276 #endif
Generated on Tue Jul 12 2022 21:41:49 by 1.7.2