midi.cpp

Go to the documentation of this file.
00001 /*
00002  * midi.cpp
00003  *
00004  * Copyright 2002 Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  * Implements some basic midi-handling functions
00008  */
00009 
00010 // includes --------------------------------------------------------------------
00011 #include "midi.h"               // always include our own header first!
00012 
00013 
00014 // namespace
00015 namespace media
00016 {
00017 
00018 
00019 /*
00020  * data size table
00021  */
00022 const static int s_DataSize[8] = {
00023         2,      // eNoteOff
00024         2,      // eNoteOn
00025         2,      // eNoteAfter
00026         2,      // eControl
00027         1,      // eProgram
00028         1,      // eChannelAfter
00029         3,      // ePitch (3 --> SPECIAL, represent as word value)
00030         0,      // eSystem
00031 };
00032 
00033 
00034 static const char * s_EventName[8] = {
00035         "Note Off",
00036         "Note On",
00037         "Note Aftertouch",
00038         "Control Change",
00039         "Program Change",
00040         "Channel Aftertouch",
00041         "Pitch",
00042         "System Exclusive"
00043 };
00044 
00045 
00046 static const char * s_DataName[8][2] = {
00047         { "Note Number",                "Velocity"      },
00048         { "Note Number",                "Velocity"      },
00049         { "Note Number",                "Pressure"      },
00050         { "Control Number",             "Control Value" },
00051         { "Patch",                      NULL            },
00052         { "Pressure Value",             NULL            },
00053         { "Pitch Bend",                 NULL            },
00054         { NULL,                         NULL            }
00055 };
00056 
00057 /*
00058  * class MidiEventImpl
00059  *
00060  * Gives access to protected data
00061  */
00062 class MidiEventImpl : public MidiEvent {
00063 public:
00064         void SetStatus(IN byte_t status) throw()
00065                 { m_status = status; }
00066         void SetData(IN int index, IN byte_t value) throw()
00067                 { m_data[index] = value; }
00068 };
00069 
00070 
00071 
00072 ////////////////////////////////////////////////////////////////////////////////
00073 //
00074 //      MidiEvent - static public methods (utility methods)
00075 //
00076 ////////////////////////////////////////////////////////////////////////////////
00077 
00078 bool
00079 MidiEvent::IsValidStatus
00080 (
00081 IN eStatus status
00082 )
00083 throw()
00084 {
00085         switch (status) {
00086                 case eNoteOn:
00087                 case eNoteOff:
00088                 case eNoteAfter:
00089                 case eControl:
00090                 case eProgram:
00091                 case eChannelAfter:
00092                 case ePitch:
00093                 case eSystem:
00094                         return true;
00095                 
00096                 default:
00097                         return false;
00098         }
00099 }
00100 
00101 
00102 int
00103 MidiEvent::GetDataByteCount
00104 (
00105 IN eStatus status
00106 )
00107 throw()
00108 {
00109         int retval;
00110         
00111         ASSERT(IsValidStatus(status), "Invalid status");
00112 
00113         retval = s_DataSize[status - 8];
00114         if (3 == retval)
00115                 retval = 2;     // handle special word case
00116 
00117         return retval;
00118 }
00119 
00120 
00121 
00122 /*
00123  * Function:    ParseMidi
00124  *
00125  * Description:
00126  *      Given a raw byte input, parses through and finds midi events.
00127  */
00128 void
00129 ParseMidi
00130 (
00131 IN MidiReceiver * receiver,
00132 IN const byte_t * buffer,
00133 IN long bytes,
00134 OUT long * offset
00135 )
00136 {
00137         MidiEventImpl event;
00138         int count = 0;
00139 
00140         ASSERT(receiver, "NULL receiver");
00141         ASSERT(buffer, "NULL buffer");
00142         ASSERT(bytes > 0, "invalid byte count");
00143         ASSERT(offset, "NULL offset pointer");
00144         *offset = 0;
00145 
00146         for (;;) {
00147                 // look for status byte
00148                 while (*buffer < 0x80 && bytes > 0) {
00149                         DPRINTF("Skipping non-status byte: 0x%02x",
00150                             (int) *buffer);
00151                         buffer++;
00152                         bytes--;
00153                 }
00154 
00155                 // end of parsing?
00156                 if (bytes <= 0) {
00157                         ASSERT(0 == bytes, "Invalid remainder");
00158                         break;
00159                 }
00160 
00161                 // found a status byte!
00162                 count = *(buffer);      // status byte
00163                 count = (count >> 4) & 0xf;     // get high bits
00164                 ASSERT(count >= 8, "Invalid count?");
00165                 // DPRINTF("  MIDI event: %d", count);
00166                 count -= 8;
00167                 ASSERT(count >= 0 && count < 8, "Invalid status?");
00168                 count = s_DataSize[count];      // look up data size (bytes)
00169                 // DPRINTF("  data bytes: %d", count);
00170 
00171                 // can we read this?
00172                 if (count >= bytes) {
00173                         // not enough data in buffer--tell clients how many
00174                         // bytes we left in buffer
00175                         *offset = bytes;
00176                         break;
00177                 }
00178 
00179                 // set status byte
00180                 event.SetStatus(*buffer);
00181                 buffer++;
00182                 bytes--;
00183 
00184                 if (0 == count) {
00185                         DPRINTF("SYSTEM EXCLUSIVE!!  Ignoring status = 0x%02x",
00186                             event.GetStatus());
00187                         continue;
00188                 }
00189 
00190                 // read first data byte?
00191                 if (count > 0) {
00192                         event.SetData(0, *buffer);
00193                         buffer++;
00194                         bytes--;
00195                 }
00196 
00197                 // read second data byte?
00198                 if (count > 1) {
00199                         event.SetData(1, *buffer);
00200                         buffer++;
00201                         bytes--;
00202                 }
00203 
00204                 // fire event
00205                 receiver->NotifyEvent(event);
00206         }
00207 }
00208 
00209 
00210 
00211 void
00212 PrintEvent
00213 (
00214 IN FILE * output,
00215 IN const MidiEvent& event
00216 )
00217 throw()
00218 {
00219         int index;
00220         int count;
00221 
00222         ASSERT(output, "NULL output stream");
00223 
00224         index = event.GetStatus() - 0x8;
00225         if (index < 0 || index > 7) {
00226                 DPRINTF("Invalid status?");
00227                 return;
00228         }
00229 
00230         fprintf(output, "Event: %s\n", s_EventName[index]);
00231         fprintf(output, "  Channel: %d\n", (int) event.GetChannel());
00232 
00233         count = s_DataSize[index];
00234         if (1 == count || 2 == count) {
00235                 fprintf(output, "  %s: %d\n", s_DataName[index][0],
00236                     (int) event.GetNote());
00237         }
00238 
00239         if (2 == count) {
00240                 fprintf(output, "  %s: %d\n", s_DataName[index][1],
00241                     (int) event.GetVelocity());
00242         }
00243 
00244         if (3 == count) {
00245                 fprintf(output, "  %s: %d\n", s_DataName[index][0],
00246                     (int) event.GetPitch());
00247         }
00248 }
00249 
00250 
00251 
00252 };      // media namespace