CLAM-Development
1.1
|
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