summaryrefslogtreecommitdiff
path: root/doxygen/html/MidiFileIn_8cpp-source.html
blob: a7109dd681d92297f39ffb2960273d3a99d19569 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
<HTML>
<HEAD>
<TITLE>The Synthesis ToolKit in C++ (STK)</TITLE>
<LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<CENTER>
<img src="princeton.gif"> &nbsp; <img src="ccrma.gif"><P>
<a class="qindex" href="index.html">Home</a> &nbsp; <a class="qindex" href="information.html">Information</a> &nbsp; <a class="qindex" href="classes.html">Classes</a> &nbsp; <a class="qindex" href="download.html">Download</a> &nbsp; <a class="qindex" href="usage.html">Usage</a> &nbsp; <a class="qindex" href="maillist.html">Mail List</a> &nbsp; <a class="qindex" href="system.html">Requirements</a> &nbsp; <a class="qindex" href="links.html">Links</a> &nbsp; <a class="qindex" href="tutorial.html">Tutorial</a></CENTER>
<HR>
<!-- Generated by Doxygen 1.3-rc3 -->
<h1>MidiFileIn.cpp</h1><div class="fragment"><pre>00001 <span class="comment">/**********************************************************************/</span>
00016 <span class="comment">/**********************************************************************/</span>
00017 
00018 <span class="preprocessor">#include "MidiFileIn.h"</span>
00019 <span class="preprocessor">#include &lt;iostream&gt;</span>
00020 
<a name="l00021"></a><a class="code" href="classMidiFileIn.html#a0">00021</a> <a class="code" href="classMidiFileIn.html#a0">MidiFileIn :: MidiFileIn</a>( std::string fileName )
00022 {
00023   <span class="comment">// Attempt to open the file.</span>
00024   file_.open( fileName.c_str(), std::ios::in );
00025   <span class="keywordflow">if</span> ( !file_ ) {
00026     errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn: error opening or finding file ("</span> &lt;&lt;  fileName &lt;&lt; <span class="stringliteral">")."</span>;
00027     <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FILE_NOT_FOUND );
00028   }
00029 
00030   <span class="comment">// Parse header info.</span>
00031   <span class="keywordtype">char</span> chunkType[4];
00032   <span class="keywordtype">char</span> buffer[4];
00033   SINT32 *length;
00034   <span class="keywordflow">if</span> ( !file_.read( chunkType, 4 ) ) <span class="keywordflow">goto</span> error;
00035   <span class="keywordflow">if</span> ( !file_.read( buffer, 4 ) ) <span class="keywordflow">goto</span> error;
00036   length = (SINT32 *) &amp;buffer;
00037   <span class="keywordflow">if</span> ( strncmp( chunkType, <span class="stringliteral">"MThd"</span>, 4 ) || ( *length != 6 ) ) {
00038     errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn: file ("</span> &lt;&lt;  fileName &lt;&lt; <span class="stringliteral">") does not appear to be a MIDI file!"</span>;
00039     <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FILE_UNKNOWN_FORMAT );
00040   }
00041 
00042   <span class="comment">// Read the MIDI file format.</span>
00043   SINT16 *data;
00044   <span class="keywordflow">if</span> ( !file_.read( buffer, 2 ) ) <span class="keywordflow">goto</span> error;
00045   data = (SINT16 *) &amp;buffer;
00046   <span class="keywordflow">if</span> ( *data &lt; 0 || *data &gt; 2 ) {
00047     errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn: the file ("</span> &lt;&lt;  fileName &lt;&lt; <span class="stringliteral">") format is invalid!"</span>;
00048     <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FILE_ERROR );
00049   }
00050   format_ = *data;
00051 
00052   <span class="comment">// Read the number of tracks.</span>
00053   <span class="keywordflow">if</span> ( !file_.read( buffer, 2 ) ) <span class="keywordflow">goto</span> error;
00054   <span class="keywordflow">if</span> ( format_ == 0 &amp;&amp; *data != 1 ) {
00055     errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn: invalid number of tracks (&gt;1) for a file format = 0!"</span>;
00056     <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FILE_ERROR );
00057   }
00058   nTracks_ = *data;
00059 
00060   <span class="comment">// Read the beat division.</span>
00061   <span class="keywordflow">if</span> ( !file_.read( buffer, 2 ) ) <span class="keywordflow">goto</span> error;
00062   division_ = (int) *data;
00063   <span class="keywordtype">double</span> tickrate;
00064   usingTimeCode_ = <span class="keyword">false</span>;
00065   <span class="keywordflow">if</span> ( *data &amp; 0x8000 ) {
00066     <span class="comment">// Determine ticks per second from time-code formats.</span>
00067     tickrate = (double) -(*data &amp; 0x7F00);
00068     <span class="comment">// If frames per second value is 29, it really should be 29.97.</span>
00069     <span class="keywordflow">if</span> ( tickrate == 29.0 ) tickrate = 29.97;
00070     tickrate *= (*data &amp; 0x00FF);
00071     usingTimeCode_ = <span class="keyword">true</span>;
00072   }
00073   <span class="keywordflow">else</span> {
00074     tickrate = (double) (*data &amp; 0x7FFF); <span class="comment">// ticks per quarter note</span>
00075   }
00076 
00077   <span class="comment">// Now locate the track offsets and lengths.  If not using time</span>
00078   <span class="comment">// code, we can initialize the "tick time" using a default tempo of</span>
00079   <span class="comment">// 120 beats per minute.  We will then check for tempo meta-events</span>
00080   <span class="comment">// afterward.</span>
00081   <span class="keywordflow">for</span> ( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> i=0; i&lt;nTracks_; i++ ) {
00082     <span class="keywordflow">if</span> ( !file_.read( chunkType, 4 ) ) <span class="keywordflow">goto</span> error;
00083     <span class="keywordflow">if</span> ( strncmp( chunkType, <span class="stringliteral">"MTrk"</span>, 4 ) ) <span class="keywordflow">goto</span> error;
00084     <span class="keywordflow">if</span> ( !file_.read( buffer, 4 ) ) <span class="keywordflow">goto</span> error;
00085     length = (SINT32 *) &amp;buffer;
00086     trackLengths_.push_back( *length );
00087     trackOffsets_.push_back( file_.tellg() );
00088     trackPointers_.push_back( file_.tellg() );
00089     trackStatus_.push_back( 0 );
00090     file_.seekg( *length, std::ios_base::cur );
00091     <span class="keywordflow">if</span> ( usingTimeCode_ ) tickSeconds_.push_back( (<span class="keywordtype">double</span>) (1.0 / tickrate) );
00092     <span class="keywordflow">else</span> tickSeconds_.push_back( (<span class="keywordtype">double</span>) (0.5 / tickrate) );
00093   }
00094 
00095   <span class="comment">// Save the initial tickSeconds parameter.</span>
00096   TempoChange tempoEvent;
00097   tempoEvent.count = 0;
00098   tempoEvent.tickSeconds = tickSeconds_[0];
00099   tempoEvents_.push_back( tempoEvent );
00100 
00101   <span class="comment">// If format 1 and not using time code, parse and save the tempo map</span>
00102   <span class="comment">// on track 0.</span>
00103   <span class="keywordflow">if</span> ( format_ == 1 &amp;&amp; !usingTimeCode_ ) {
00104     std::vector&lt;unsigned char&gt; event;
00105     <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> value, count;
00106 
00107     <span class="comment">// We need to temporarily change the usingTimeCode_ value here so</span>
00108     <span class="comment">// that the getNextEvent() function doesn't try to check the tempo</span>
00109     <span class="comment">// map (which we're creating here).</span>
00110     usingTimeCode_ = <span class="keyword">true</span>;
00111     count = <a class="code" href="classMidiFileIn.html#a7">getNextEvent</a>( &amp;event, 0 );
00112     <span class="keywordflow">while</span> ( event.size() ) {
00113       <span class="keywordflow">if</span> ( ( event.size() == 6 ) &amp;&amp; ( event[0] == 0xff ) &amp;&amp;
00114            ( event[1] == 0x51 ) &amp;&amp; ( event[2] == 0x03 ) ) {
00115         tempoEvent.count = count;
00116         value = ( event[3] &lt;&lt; 16 ) + ( event[4] &lt;&lt; 8 ) + event[5];
00117         tempoEvent.tickSeconds = (double) (0.000001 * value / tickrate);
00118         <span class="keywordflow">if</span> ( count &gt; tempoEvents_.back().count )
00119           tempoEvents_.push_back( tempoEvent );
00120         <span class="keywordflow">else</span>
00121           tempoEvents_.back() = tempoEvent;
00122       }
00123       count += <a class="code" href="classMidiFileIn.html#a7">getNextEvent</a>( &amp;event, 0 );
00124     }
00125     <a class="code" href="classMidiFileIn.html#a5">rewindTrack</a>( 0 );
00126     <span class="keywordflow">for</span> ( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> i=0; i&lt;nTracks_; i++ ) {
00127       trackCounters_.push_back( 0 );
00128       trackTempoIndex_.push_back( 0 );
00129     }
00130     <span class="comment">// Change the time code flag back!</span>
00131     usingTimeCode_ = <span class="keyword">false</span>;
00132   }
00133 
00134   <span class="keywordflow">return</span>;
00135 
00136  error:
00137   errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn: error reading from file ("</span> &lt;&lt;  fileName &lt;&lt; <span class="stringliteral">")."</span>;
00138   <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FILE_ERROR );
00139 }
00140 
<a name="l00141"></a><a class="code" href="classMidiFileIn.html#a1">00141</a> <a class="code" href="classMidiFileIn.html#a1">MidiFileIn :: ~MidiFileIn</a>()
00142 {
00143   <span class="comment">// An ifstream object implicitly closes itself during destruction</span>
00144   <span class="comment">// but we'll make an explicit call to "close" anyway.</span>
00145   file_.close(); 
00146 }
00147 
<a name="l00148"></a><a class="code" href="classMidiFileIn.html#a2">00148</a> <span class="keywordtype">int</span> <a class="code" href="classMidiFileIn.html#a2">MidiFileIn :: getFileFormat</a>()<span class="keyword"> const</span>
00149 <span class="keyword"></span>{
00150   <span class="keywordflow">return</span> format_;
00151 }
00152 
<a name="l00153"></a><a class="code" href="classMidiFileIn.html#a3">00153</a> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> <a class="code" href="classMidiFileIn.html#a3">MidiFileIn :: getNumberOfTracks</a>()<span class="keyword"> const</span>
00154 <span class="keyword"></span>{
00155   <span class="keywordflow">return</span> nTracks_;
00156 }
00157 
<a name="l00158"></a><a class="code" href="classMidiFileIn.html#a4">00158</a> <span class="keywordtype">int</span> <a class="code" href="classMidiFileIn.html#a4">MidiFileIn :: getDivision</a>()<span class="keyword"> const</span>
00159 <span class="keyword"></span>{
00160   <span class="keywordflow">return</span> division_;
00161 }
00162 
<a name="l00163"></a><a class="code" href="classMidiFileIn.html#a5">00163</a> <span class="keywordtype">void</span> <a class="code" href="classMidiFileIn.html#a5">MidiFileIn :: rewindTrack</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> track )
00164 {
00165   <span class="keywordflow">if</span> ( track &gt;= nTracks_ ) {
00166     errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn::getNextEvent: invalid track argument ("</span> &lt;&lt;  track &lt;&lt; <span class="stringliteral">")."</span>;
00167     <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FUNCTION_ARGUMENT );
00168   }
00169 
00170   trackPointers_[track] = trackOffsets_[track];
00171   trackStatus_[track] = 0;
00172   tickSeconds_[track] = tempoEvents_[0].tickSeconds;
00173 }
00174 
<a name="l00175"></a><a class="code" href="classMidiFileIn.html#a6">00175</a> <span class="keywordtype">double</span> <a class="code" href="classMidiFileIn.html#a6">MidiFileIn :: getTickSeconds</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> track )
00176 {
00177   <span class="comment">// Return the current tick value in seconds for the given track.</span>
00178   <span class="keywordflow">if</span> ( track &gt;= nTracks_ ) {
00179     errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn::getTickSeconds: invalid track argument ("</span> &lt;&lt;  track &lt;&lt; <span class="stringliteral">")."</span>;
00180     <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FUNCTION_ARGUMENT );
00181   }
00182 
00183   <span class="keywordflow">return</span> tickSeconds_[track];
00184 }
00185 
<a name="l00186"></a><a class="code" href="classMidiFileIn.html#a7">00186</a> <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> <a class="code" href="classMidiFileIn.html#a7">MidiFileIn :: getNextEvent</a>( std::vector&lt;unsigned char&gt; *event, <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> track )
00187 {
00188   <span class="comment">// Fill the user-provided vector with the next event in the</span>
00189   <span class="comment">// specified track (default = 0) and return the event delta time in</span>
00190   <span class="comment">// ticks.  This function assumes that the stored track pointer is</span>
00191   <span class="comment">// positioned at the start of a track event.  If the track has</span>
00192   <span class="comment">// reached its end, the event vector size will be zero.</span>
00193   <span class="comment">//</span>
00194   <span class="comment">// If we have a format 0 or 2 file and we're not using timecode, we</span>
00195   <span class="comment">// should check every meta-event for tempo changes and make</span>
00196   <span class="comment">// appropriate updates to the tickSeconds_ parameter if so.</span>
00197   <span class="comment">//</span>
00198   <span class="comment">// If we have a format 1 file and we're not using timecode, keep a</span>
00199   <span class="comment">// running sum of ticks for each track and update the tickSeconds_</span>
00200   <span class="comment">// parameter as needed based on the stored tempo map.</span>
00201 
00202   <span class="keywordflow">if</span> ( track &gt;= nTracks_ ) {
00203     errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn::getNextEvent: invalid track argument ("</span> &lt;&lt;  track &lt;&lt; <span class="stringliteral">")."</span>;
00204     <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FUNCTION_ARGUMENT );
00205   }
00206 
00207   event-&gt;clear();
00208   <span class="comment">// Check for the end of the track.</span>
00209   <span class="keywordflow">if</span> ( (trackPointers_[track] - trackOffsets_[track]) &gt;= trackLengths_[track] )
00210     <span class="keywordflow">return</span> 0;
00211 
00212   <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> ticks = 0, bytes = 0;
00213   <span class="keywordtype">bool</span> isTempoEvent = <span class="keyword">false</span>;
00214 
00215   <span class="comment">// Read the event delta time.</span>
00216   file_.seekg( trackPointers_[track], std::ios_base::beg );
00217   <span class="keywordflow">if</span> ( !readVariableLength( &amp;ticks ) ) <span class="keywordflow">goto</span> error;
00218 
00219   <span class="comment">// Parse the event stream to determine the event length.</span>
00220   <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> c;
00221   <span class="keywordflow">if</span> ( !file_.read( (<span class="keywordtype">char</span> *)&amp;c, 1 ) ) <span class="keywordflow">goto</span> error;
00222   <span class="keywordflow">switch</span> ( c ) {
00223 
00224   <span class="keywordflow">case</span> 0xFF: <span class="comment">// A Meta-Event</span>
00225     <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> position;
00226     trackStatus_[track] = 0;
00227     event-&gt;push_back( c );
00228     <span class="keywordflow">if</span> ( !file_.read( (<span class="keywordtype">char</span> *)&amp;c, 1 ) ) <span class="keywordflow">goto</span> error;
00229     event-&gt;push_back( c );
00230     <span class="keywordflow">if</span> ( format_ != 1 &amp;&amp; ( c == 0x51 ) ) isTempoEvent = <span class="keyword">true</span>;
00231     position = file_.tellg();
00232     <span class="keywordflow">if</span> ( !readVariableLength( &amp;bytes ) ) <span class="keywordflow">goto</span> error;
00233     bytes += ( (<span class="keywordtype">unsigned</span> <span class="keywordtype">long</span>)file_.tellg() - position );
00234     file_.seekg( position, std::ios_base::beg );
00235     <span class="keywordflow">break</span>;
00236 
00237   <span class="keywordflow">case</span> 0xF0 || 0xF7: <span class="comment">// The start or continuation of a Sysex event</span>
00238     trackStatus_[track] = 0;
00239     event-&gt;push_back( c );
00240     position = file_.tellg();
00241     <span class="keywordflow">if</span> ( !readVariableLength( &amp;bytes ) ) <span class="keywordflow">goto</span> error;
00242     bytes += ( (<span class="keywordtype">unsigned</span> <span class="keywordtype">long</span>)file_.tellg() - position );
00243     file_.seekg( position, std::ios_base::beg );
00244     <span class="keywordflow">break</span>;
00245 
00246   <span class="keywordflow">default</span>: <span class="comment">// Should be a MIDI channel event</span>
00247     <span class="keywordflow">if</span> ( c &amp; 0x80 ) { <span class="comment">// MIDI status byte</span>
00248       <span class="keywordflow">if</span> ( c &gt; 0xF0 ) <span class="keywordflow">goto</span> error;
00249       trackStatus_[track] = c;
00250       event-&gt;push_back( c );
00251       c &amp;= 0xF0;
00252       <span class="keywordflow">if</span> ( (c == 0xC0) || (c == 0xD0) ) bytes = 1;
00253       <span class="keywordflow">else</span> bytes = 2;
00254     }
00255     <span class="keywordflow">else</span> <span class="keywordflow">if</span> ( trackStatus_[track] &amp; 0x80 ) { <span class="comment">// Running status</span>
00256       event-&gt;push_back( trackStatus_[track] );
00257       event-&gt;push_back( c );
00258       c = trackStatus_[track] &amp; 0xF0;
00259       <span class="keywordflow">if</span> ( (c != 0xC0) &amp;&amp; (c != 0xD0) ) bytes = 1;
00260     }
00261     <span class="keywordflow">else</span> <span class="keywordflow">goto</span> error;
00262 
00263   }
00264 
00265   <span class="comment">// Read the rest of the event into the event vector.</span>
00266   <span class="keywordflow">for</span> ( <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> i=0; i&lt;bytes; i++ ) {
00267     <span class="keywordflow">if</span> ( !file_.read( (<span class="keywordtype">char</span> *)&amp;c, 1 ) ) <span class="keywordflow">goto</span> error;
00268     event-&gt;push_back( c );
00269   }
00270 
00271   <span class="keywordflow">if</span> ( !usingTimeCode_ ) {
00272     <span class="keywordflow">if</span> ( isTempoEvent ) {
00273       <span class="comment">// Parse the tempo event and update tickSeconds_[track].</span>
00274       <span class="keywordtype">double</span> tickrate = (double) (division_ &amp; 0x7FFF);
00275       <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> value = ( event-&gt;at(3) &lt;&lt; 16 ) + ( event-&gt;at(4) &lt;&lt; 8 ) + event-&gt;at(5);
00276       tickSeconds_[track] = (double) (0.000001 * value / tickrate);
00277     }
00278 
00279     <span class="keywordflow">if</span> ( format_ == 1 ) {
00280       <span class="comment">// Update track counter and check the tempo map.</span>
00281       trackCounters_[track] += ticks;
00282       TempoChange tempoEvent = tempoEvents_[ trackTempoIndex_[track] ];
00283       <span class="keywordflow">if</span> ( trackCounters_[track] &gt;= tempoEvent.count ) {
00284         trackTempoIndex_[track]++;
00285         tickSeconds_[track] = tempoEvent.tickSeconds;
00286       }
00287     }
00288   }
00289 
00290   <span class="comment">// Save the current track pointer value.</span>
00291   trackPointers_[track] = file_.tellg();
00292 
00293   <span class="keywordflow">return</span> ticks;
00294 
00295  error:
00296   errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn::getNextEvent: file read error!"</span>;
00297   <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FILE_ERROR );
00298   <span class="keywordflow">return</span> 0;
00299 }
00300 
<a name="l00301"></a><a class="code" href="classMidiFileIn.html#a8">00301</a> <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> <a class="code" href="classMidiFileIn.html#a8">MidiFileIn :: getNextMidiEvent</a>( std::vector&lt;unsigned char&gt; *midiEvent, <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> track )
00302 {
00303   <span class="comment">// Fill the user-provided vector with the next MIDI event in the</span>
00304   <span class="comment">// specified track (default = 0) and return the event delta time in</span>
00305   <span class="comment">// ticks.  Meta-Events preceeding this event are skipped and ignored.</span>
00306   <span class="keywordflow">if</span> ( track &gt;= nTracks_ ) {
00307     errorString_ &lt;&lt; <span class="stringliteral">"MidiFileIn::getNextMidiEvent: invalid track argument ("</span> &lt;&lt;  track &lt;&lt; <span class="stringliteral">")."</span>;
00308     <a class="code" href="classStk.html#e0">handleError</a>( errorString_.str(), StkError::FUNCTION_ARGUMENT );
00309   }
00310 
00311   <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> ticks = <a class="code" href="classMidiFileIn.html#a7">getNextEvent</a>( midiEvent, track );
00312   <span class="keywordflow">while</span> ( midiEvent-&gt;size() &amp;&amp; ( midiEvent-&gt;at(0) &gt;= 0xF0 ) ) {
00313     <span class="keywordflow">for</span> ( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> i=0; i&lt;midiEvent-&gt;size(); i++ )
00314       std::cout &lt;&lt; <span class="stringliteral">"event byte = "</span> &lt;&lt; i &lt;&lt; <span class="stringliteral">", value = "</span> &lt;&lt; (int)midiEvent-&gt;at(i) &lt;&lt; std::endl;
00315     ticks = <a class="code" href="classMidiFileIn.html#a7">getNextEvent</a>( midiEvent, track );
00316   }
00317 
00318   <span class="keywordflow">for</span> ( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> i=0; i&lt;midiEvent-&gt;size(); i++ )
00319   std::cout &lt;&lt; <span class="stringliteral">"event byte = "</span> &lt;&lt; i &lt;&lt; <span class="stringliteral">", value = "</span> &lt;&lt; (int)midiEvent-&gt;at(i) &lt;&lt; std::endl;
00320 
00321   <span class="keywordflow">return</span> ticks;
00322 }
00323 
00324 <span class="keywordtype">bool</span> MidiFileIn :: readVariableLength( <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> *value )
00325 {
00326   <span class="comment">// It is assumed that this function is called with the file read</span>
00327   <span class="comment">// pointer positioned at the start of a variable-length value.  The</span>
00328   <span class="comment">// function returns "true" if the value is successfully parsed and</span>
00329   <span class="comment">// "false" otherwise.</span>
00330   *value = 0;
00331   <span class="keywordtype">char</span> c;
00332 
00333   <span class="keywordflow">if</span> ( !file_.read( &amp;c, 1 ) ) <span class="keywordflow">return</span> <span class="keyword">false</span>;
00334   *value = (<span class="keywordtype">unsigned</span> <span class="keywordtype">long</span>) c;
00335   <span class="keywordflow">if</span> ( *value &amp; 0x80 ) {
00336     *value &amp;= 0x7f;
00337     <span class="keywordflow">do</span> {
00338       <span class="keywordflow">if</span> ( !file_.read( &amp;c, 1 ) ) <span class="keywordflow">return</span> <span class="keyword">false</span>;
00339       *value = ( *value &lt;&lt; 7 ) + ( c &amp; 0x7f );
00340     } <span class="keywordflow">while</span> ( c &amp; 0x80 );
00341   }
00342 
00343   <span class="keywordflow">return</span> <span class="keyword">true</span>;
00344 } 
</pre></div><HR>

<table>
  <tr><td><A HREF="http://www-ccrma.stanford.edu/software/stk/"><I>The Synthesis ToolKit in C++ (STK)</I></A></td></tr>
  <tr><td>&copy;1995-2002 Perry R. Cook and Gary P. Scavone. All Rights Reserved.</td></tr>
</table>

</BODY>
</HTML>