MIDIReader.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
00003  * UNIVERSITAT POMPEU FABRA
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  *
00019  * MIDIFileReader C++ classes
00020  * This code is part of the CLAM library, but also usable stand-alone.
00021  * Maarten de Boer <mdeboer@iua.upf.es>
00022  *
00023  */
00024 #include "MIDIReader.hxx"
00025 #include "MIDISong.hxx"
00026 #include "MIDITrack.hxx"
00027 
00028 namespace MIDI
00029 {
00030 
00031         void Reader::Read(Song& s)
00032   /* ToDo: document and explain this function */
00033         {
00034                 static int nbytesPerChnMsg[7] =
00035                 { 3,3,3,3,2,3,3 };
00036 
00037                 ChunkType chnkType = GetChunkType();
00038                 unsigned int length;
00039                 unsigned short format,ntrcks;
00040                 
00041                 if (chnkType!="MThd") throw Error("Expected a header chunk\n");
00042 
00043                 length = GetInt();
00044                 if (length!=6)
00045                         throw Error("Unexpected header chunk length\n");
00046 
00047                 format = GetShort();
00048                 if (format!=0 && format!=1)
00049                         throw Error("Unsupported MIDI file format\n");
00050 
00051                 ntrcks = GetShort();
00052 
00053                 s.SetTicksPerQ(GetShort());
00054 
00055                 for (int i=0;i<ntrcks;i++)
00056                 {
00057                         chnkType = GetChunkType();
00058                         if (chnkType!="MTrk") throw Error("Expected a track chunk\n");
00059 
00060                         int chnkLength = GetInt();
00061 
00062                         Byte runningStatus = 0;
00063                         Ticks t = 0;
00064                         Track *track = new Track;
00065                         s.AddTrack(track);
00066 
00067                         mCnt = 0;
00068 
00069                         while (mCnt!=chnkLength)
00070                         {
00071                                 unsigned int dt = GetVarLength();
00072                                 t += dt;
00073                                 Byte b = GetByte();
00074                                 if (b & 0x80)
00075                                 {
00076                                         int type = ((b&0xF0)>>4)-8;
00077                                         if (type==7)
00078                                         {
00079                                                 if (b == 0xFF)
00080                                                 {
00081                                                         Byte metaType = GetByte();
00082                                                         unsigned int length = GetVarLength();
00083                                                         if (metaType!=0x2F) // don't add end-of-track events
00084                                                         {
00085                                                                 MetaEvent* ev = new MetaEvent(Message(b,metaType),t,length);
00086 
00087                                                                 track->Add(ev);
00088 
00089                                                                 for (unsigned int i=0;i<length;i++)
00090                                                                         ev->mData[i] = GetByte();
00091 
00092                                                                 if (metaType == 3) // sequence/track name
00093                                                                 {
00094                                                                         track->Name(ev->mData,length);
00095                                                                 }
00096                                                         }
00097                                                 }
00098                                                 else if (b == 0xF0 || b==0xF7)
00099                                                 {
00100                                                         /* TODO: For now, we'll just skip SysEx events */
00101                                                         int length = GetVarLength();
00102                                                         while (--length)
00103                                                         {
00104                                                                 GetByte();
00105                                                         }
00106                                                         if (GetByte()!=0xF7)
00107                                                         {
00108                                                                 throw Error("SysEx message did not terminate with 0xF7");
00109                                                         }
00110                                                 }
00111                                                 else
00112                                                 {
00113                                                         throw Error("Encountered a message that I don't know how to handle");
00114                                                 }
00115                                                 runningStatus = 0;
00116                                         }else{
00117                                                 if (nbytesPerChnMsg[type]==2)
00118                                                 {
00119                                                         Byte b1 = GetByte();
00120                                                         track->Add(new Event(Message(b,b1),t));
00121                                                 }
00122                                                 else
00123                                                 {
00124                                                         Byte b1 = GetByte();
00125                                                         Byte b2 = GetByte();
00126                                                         track->Add(new Event(Message(b,b1,b2),t));
00127                                                 }
00128                                                 runningStatus = b;
00129                                         }
00130                                 }else{
00131                                         int type = ((runningStatus&0xF0)>>4)-8;
00132                                         if (nbytesPerChnMsg[type]==2)
00133                                         {
00134                                                 track->Add(new Event(Message(runningStatus,b),t));
00135                                         }
00136                                         else
00137                                         {
00138                                                 Byte b2 = GetByte();
00139                                                 track->Add(new Event(Message(runningStatus,b,b2),t));
00140                                         }
00141                                 }
00142                         }
00143                 }       
00144         }
00145 
00146 }
00147 
Generated by  doxygen 1.6.3