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.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MIDIMessage.h Source File

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