CLAM-Development  1.4.0
MIDIReader.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * MIDIFileReader C++ classes
20  * This code is part of the CLAM library, but also usable stand-alone.
21  * Maarten de Boer <mdeboer@iua.upf.es>
22  *
23  */
24 #include "MIDIReader.hxx"
25 #include "MIDISong.hxx"
26 #include "MIDITrack.hxx"
27 
28 namespace MIDI
29 {
30 
31  void Reader::Read(Song& s)
32  /* ToDo: document and explain this function */
33  {
34  static int nbytesPerChnMsg[7] =
35  { 3,3,3,3,2,3,3 };
36 
37  ChunkType chnkType = GetChunkType();
38  unsigned int length;
39  unsigned short format,ntrcks;
40 
41  if (chnkType!="MThd") throw Error("Expected a header chunk\n");
42 
43  length = GetInt();
44  if (length!=6)
45  throw Error("Unexpected header chunk length\n");
46 
47  format = GetShort();
48  if (format!=0 && format!=1)
49  throw Error("Unsupported MIDI file format\n");
50 
51  ntrcks = GetShort();
52 
54 
55  for (int i=0;i<ntrcks;i++)
56  {
57  chnkType = GetChunkType();
58  if (chnkType!="MTrk") throw Error("Expected a track chunk\n");
59 
60  int chnkLength = GetInt();
61 
62  Byte runningStatus = 0;
63  Ticks t = 0;
64  Track *track = new Track;
65  s.AddTrack(track);
66 
67  mCnt = 0;
68 
69  while (mCnt!=chnkLength)
70  {
71  unsigned int dt = GetVarLength();
72  t += dt;
73  Byte b = GetByte();
74  if (b & 0x80)
75  {
76  int type = ((b&0xF0)>>4)-8;
77  if (type==7)
78  {
79  if (b == 0xFF)
80  {
81  Byte metaType = GetByte();
82  unsigned int length = GetVarLength();
83  if (metaType!=0x2F) // don't add end-of-track events
84  {
85  MetaEvent* ev = new MetaEvent(Message(b,metaType),t,length);
86 
87  track->Add(ev);
88 
89  for (unsigned int i=0;i<length;i++)
90  ev->mData[i] = GetByte();
91 
92  if (metaType == 3) // sequence/track name
93  {
94  track->Name(ev->mData,length);
95  }
96  }
97  }
98  else if (b == 0xF0 || b==0xF7)
99  {
100  /* TODO: For now, we'll just skip SysEx events */
101  int length = GetVarLength();
102  while (--length)
103  {
104  GetByte();
105  }
106  if (GetByte()!=0xF7)
107  {
108  throw Error("SysEx message did not terminate with 0xF7");
109  }
110  }
111  else
112  {
113  throw Error("Encountered a message that I don't know how to handle");
114  }
115  runningStatus = 0;
116  }else{
117  if (nbytesPerChnMsg[type]==2)
118  {
119  Byte b1 = GetByte();
120  track->Add(new Event(Message(b,b1),t));
121  }
122  else
123  {
124  Byte b1 = GetByte();
125  Byte b2 = GetByte();
126  track->Add(new Event(Message(b,b1,b2),t));
127  }
128  runningStatus = b;
129  }
130  }else{
131  int type = ((runningStatus&0xF0)>>4)-8;
132  if (nbytesPerChnMsg[type]==2)
133  {
134  track->Add(new Event(Message(runningStatus,b),t));
135  }
136  else
137  {
138  Byte b2 = GetByte();
139  track->Add(new Event(Message(runningStatus,b,b2),t));
140  }
141  }
142  }
143  }
144  }
145 
146 }
147