XMidiEventList.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003  The Pentagram Team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 #include "XMidiEvent.h"
00021 #include "XMidiEventList.h"
00022 
00023 #ifdef PENTAGRAM_IN_EXULT
00024 #include "databuf.h"
00025 #else
00026 #include "ODataSource.h"
00027 #endif
00028 
00029 #ifndef UNDER_CE
00030 using std::atof;
00031 using std::atoi;
00032 using std::memcmp;
00033 using std::memcpy;
00034 using std::memset;
00035 using std::size_t;
00036 #endif
00037 using std::string;
00038 using std::endl;
00039 
00040 //#include "gamma.h"
00041 
00042 
00043 //
00044 // XMidiEventList stuff
00045 //
00046 int XMidiEventList::write (ODataSource *dest)
00047 {
00048         int len = 0;
00049         
00050         if (!events)
00051         {
00052                 perr << "No midi data loaded." << endl;
00053                 return 0;
00054         }
00055 
00056         // This is so if using buffer ODataSource, the caller can know how big to make the buffer
00057         if (!dest)
00058         {
00059                 // Header is 14 bytes long and add the rest as well
00060                 len = convertListToMTrk (NULL);
00061                 return 14 + len;
00062         }
00063                 
00064         dest->write1 ('M');
00065         dest->write1 ('T');
00066         dest->write1 ('h');
00067         dest->write1 ('d');
00068         
00069         dest->write4high (6);
00070 
00071         dest->write2high (0);
00072         dest->write2high (1);
00073         dest->write2high (60);  // The PPQN
00074                 
00075         len = convertListToMTrk (dest);
00076 
00077         return len + 14;
00078 }
00079 
00080 //
00081 // PutVLQ
00082 //
00083 // Write a Conventional Variable Length Quantity
00084 //
00085 int XMidiEventList::putVLQ(ODataSource *dest, uint32 value)
00086 {
00087         int buffer;
00088         int i = 1;
00089         buffer = value & 0x7F;
00090         while (value >>= 7)
00091         {
00092                 buffer <<= 8;
00093                 buffer |= ((value & 0x7F) | 0x80);
00094                 i++;
00095         }
00096         if (!dest) return i;
00097         for (int j = 0; j < i; j++)
00098         {
00099                 dest->write1(buffer & 0xFF);
00100                 buffer >>= 8;
00101         }
00102         
00103         return i;
00104 }
00105 
00106 // Converts and event list to a MTrk
00107 // Returns bytes of the array
00108 // buf can be NULL
00109 uint32 XMidiEventList::convertListToMTrk (ODataSource *dest)
00110 {
00111         int time = 0;
00112         int lasttime = 0;
00113         XMidiEvent      *event;
00114         uint32  delta;
00115         unsigned char   last_status = 0;
00116         uint32  i = 8;
00117         uint32  j;
00118         uint32  size_pos=0;
00119 
00120         if (dest)
00121         {
00122                 dest->write1('M');
00123                 dest->write1('T');
00124                 dest->write1('r');
00125                 dest->write1('k');
00126 
00127                 size_pos = dest->getPos();
00128                 dest->skip(4);
00129         }
00130 
00131         for (event = events; event; event=event->next)
00132         {
00133                 // We don't write the end of stream marker here, we'll do it later
00134                 if (event->status == 0xFF && event->data[0] == 0x2f) {
00135                         lasttime = event->time;
00136                         continue;
00137                 }
00138 
00139                 delta = (event->time - time);
00140                 time = event->time;
00141 
00142                 i += putVLQ (dest, delta);
00143 
00144                 if ((event->status != last_status) || (event->status >= 0xF0))
00145                 {
00146                         if (dest) dest->write1(event->status);
00147                         i++;
00148                 }
00149                 
00150                 last_status = event->status;
00151                 
00152                 switch (event->status >> 4)
00153                 {
00154                         // 2 bytes data
00155                         // Note off, Note on, Aftertouch, Controller and Pitch Wheel
00156                         case 0x8: case 0x9: case 0xA: case 0xB: case 0xE:
00157                         if (dest)
00158                         {
00159                                 dest->write1(event->data[0]);
00160                                 dest->write1(event->data[1]);
00161                         }
00162                         i += 2;
00163                         break;
00164                         
00165 
00166                         // 1 bytes data
00167                         // Program Change and Channel Pressure
00168                         case 0xC: case 0xD:
00169                         if (dest) dest->write1(event->data[0]);
00170                         i++;
00171                         break;
00172                         
00173 
00174                         // Variable length
00175                         // SysEx
00176                         case 0xF:
00177                         if (event->status == 0xFF)
00178                         {
00179                                 if (dest) dest->write1(event->data[0]);
00180                                 i++;
00181                         }
00182         
00183                         i += putVLQ (dest, event->ex.sysex_data.len);
00184                         
00185                         if (event->ex.sysex_data.len)
00186                         {
00187                                 for (j = 0; j < event->ex.sysex_data.len; j++)
00188                                 {
00189                                         if (dest) dest->write1(event->ex.sysex_data.buffer[j]); 
00190                                         i++;
00191                                 }
00192                         }
00193 
00194                         break;
00195                         
00196 
00197                         // Never occur
00198                         default:
00199                         perr << "Not supposed to see this" << endl;
00200                         break;
00201                 }
00202         }
00203 
00204         // Write out end of stream marker
00205         if (lasttime > time) i += putVLQ (dest, lasttime-time);
00206         else i += putVLQ (dest, 0);
00207         if (dest) {
00208                 dest->write1(0xFF);
00209                 dest->write1(0x2F);
00210         }
00211         i += 2+putVLQ (dest, 0);
00212 
00213         if (dest)
00214         {
00215                 int cur_pos = dest->getPos();
00216                 dest->seek (size_pos);
00217                 dest->write4high (i-8);
00218                 dest->seek (cur_pos);
00219         }
00220         return i;
00221 }
00222 
00223 void XMidiEventList::decerementCounter()
00224 {
00225         if (--counter < 0) {
00226                 deleteEventList(events);
00227                 XMidiEvent::Free(this);
00228         }
00229 }
00230 
00231 void XMidiEventList::deleteEventList (XMidiEvent *mlist)
00232 {
00233         XMidiEvent *event;
00234         XMidiEvent *next;
00235         
00236         next = mlist;
00237         event = mlist;
00238 
00239         while ((event = next))
00240         {
00241                 next = event->next;
00242                 // We only do this with sysex
00243                 if ((event->status>>4) == 0xF && event->ex.sysex_data.buffer) XMidiEvent::Free (event->ex.sysex_data.buffer);
00244                 XMidiEvent::Free (event);
00245         }
00246 }

Generated on Fri Jul 27 22:27:54 2007 for pentagram by  doxygen 1.4.7