00001 /* 00002 * libjdkmidi-2004 C++ Class Library for MIDI 00003 * 00004 * Copyright (C) 2004 J.D. Koftinoff Software, Ltd. 00005 * www.jdkoftinoff.com 00006 * jeffk@jdkoftinoff.com 00007 * 00008 * *** RELEASED UNDER THE GNU GENERAL PUBLIC LICENSE (GPL) April 27, 2004 *** 00009 * 00010 * This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with this program; if not, write to the Free Software 00022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 */ 00024 /* 00025 ** Copyright 1986 to 1998 By J.D. Koftinoff Software, Ltd. 00026 ** 00027 ** All rights reserved. 00028 ** 00029 ** No one may duplicate this source code in any form for any reason 00030 ** without the written permission given by J.D. Koftinoff Software, Ltd. 00031 ** 00032 */ 00033 00034 00035 00036 #include "jdkmidi/world.h" 00037 00038 #include "jdkmidi/multitrack.h" 00039 00040 00041 #ifndef DEBUG_MDMLTTRK 00042 # define DEBUG_MDMLTTRK 0 00043 #endif 00044 00045 #if DEBUG_MDMLTTRK 00046 # undef DBG 00047 # define DBG(a) a 00048 #endif 00049 00050 namespace jdkmidi 00051 { 00052 00053 00054 MIDIMultiTrack::MIDIMultiTrack( int num_tracks_, bool deletable_ ) 00055 : 00056 num_tracks( num_tracks_ ), 00057 deletable( deletable_ ) 00058 { 00059 ENTER( "MIDIMultiTrack::MIDIMultiTrack()" ); 00060 00061 tracks = new MIDITrack * [num_tracks]; 00062 if( tracks ) 00063 { 00064 if( deletable ) 00065 { 00066 for( int i=0; i<num_tracks; ++i ) 00067 tracks[i]=new MIDITrack; 00068 } 00069 else 00070 { 00071 for( int i=0; i<num_tracks; ++i ) 00072 tracks[i]=0; 00073 } 00074 } 00075 } 00076 00077 MIDIMultiTrack::~MIDIMultiTrack() 00078 { 00079 ENTER( "MIDIMultiTrack::~MIDIMultiTrack()" ); 00080 00081 if( deletable ) 00082 { 00083 for( int i=0; i<num_tracks; ++i ) 00084 delete tracks[i]; 00085 } 00086 00087 delete [] tracks; 00088 } 00089 00090 void MIDIMultiTrack::Clear() 00091 { 00092 for( int i=0; i<num_tracks; ++i ) 00093 { 00094 tracks[i]->Clear(); 00095 } 00096 } 00097 00098 void MIDIMultiTrack::SetTrack( int trk, MIDITrack *t ) 00099 { 00100 tracks[trk]=t; 00101 } 00102 00103 00104 MIDITrack *MIDIMultiTrack::GetTrack( int trk ) 00105 { 00106 return tracks[trk]; 00107 } 00108 00109 const MIDITrack *MIDIMultiTrack::GetTrack( int trk ) const 00110 { 00111 return tracks[trk]; 00112 } 00113 00114 00115 00116 00117 00118 00119 MIDIMultiTrackIteratorState::MIDIMultiTrackIteratorState( int num_tracks_) 00120 { 00121 num_tracks = num_tracks_; 00122 00123 cur_event_track=0; 00124 00125 next_event_number = new int [num_tracks]; 00126 next_event_time = new MIDIClockTime [num_tracks]; 00127 00128 Reset(); 00129 00130 } 00131 00132 MIDIMultiTrackIteratorState::MIDIMultiTrackIteratorState( const MIDIMultiTrackIteratorState &m ) 00133 { 00134 num_tracks = m.num_tracks; 00135 cur_event_track = m.cur_event_track; 00136 next_event_number = new int [num_tracks]; 00137 next_event_time = new MIDIClockTime [num_tracks]; 00138 cur_time = m.cur_time; 00139 00140 for( int i=0; i<num_tracks; ++i ) 00141 { 00142 next_event_number[i] = m.next_event_number[i]; 00143 next_event_time[i] = m.next_event_time[i]; 00144 } 00145 00146 } 00147 00148 MIDIMultiTrackIteratorState::~MIDIMultiTrackIteratorState() 00149 { 00150 delete [] next_event_number; 00151 delete [] next_event_time; 00152 } 00153 00154 const MIDIMultiTrackIteratorState & MIDIMultiTrackIteratorState::operator = ( const MIDIMultiTrackIteratorState &m ) 00155 { 00156 if( num_tracks != m.num_tracks ) 00157 { 00158 delete [] next_event_number; 00159 delete [] next_event_time; 00160 00161 num_tracks = m.num_tracks; 00162 next_event_number = new int [num_tracks]; 00163 next_event_time = new MIDIClockTime [num_tracks]; 00164 } 00165 00166 cur_time = m.cur_time; 00167 cur_event_track = m.cur_event_track; 00168 00169 for( int i=0; i<num_tracks; ++i ) 00170 { 00171 next_event_number[i] = m.next_event_number[i]; 00172 next_event_time[i] = m.next_event_time[i]; 00173 } 00174 00175 return *this; 00176 } 00177 00178 void MIDIMultiTrackIteratorState::Reset() 00179 { 00180 cur_time = 0; 00181 cur_event_track = 0; 00182 for( int i=0; i<num_tracks; ++i ) 00183 { 00184 next_event_number[i] = 0; 00185 next_event_time[i] = 0xffffffff; 00186 } 00187 } 00188 00189 int MIDIMultiTrackIteratorState::FindTrackOfFirstEvent() 00190 { 00191 MIDIClockTime minimum_time=0xffffffff; 00192 int minimum_time_track=-1; 00193 00194 00195 // go through all tracks and find the track with the smallest 00196 // event time. 00197 00198 for( int j=0; j<num_tracks; ++j ) 00199 { 00200 int i=(j+cur_event_track+1) % num_tracks; 00201 00202 // skip any tracks that have a current event number less than 0 - these are 00203 // finished already 00204 00205 00206 if( next_event_number[i]>=0 && next_event_time[i]<minimum_time ) 00207 { 00208 minimum_time = next_event_time[i]; 00209 minimum_time_track = i; 00210 } 00211 } 00212 00213 // set cur_event_track to -1 if there are no more events left 00214 cur_event_track = minimum_time_track; 00215 cur_time = minimum_time; 00216 00217 return cur_event_track; 00218 } 00219 00220 00221 00222 00223 00224 00225 MIDIMultiTrackIterator::MIDIMultiTrackIterator( MIDIMultiTrack *mlt ) 00226 : 00227 multitrack(mlt), 00228 state( mlt->GetNumTracks() ) 00229 00230 { 00231 } 00232 00233 MIDIMultiTrackIterator::~MIDIMultiTrackIterator() 00234 { 00235 } 00236 00237 void MIDIMultiTrackIterator::GoToTime( MIDIClockTime time ) 00238 { 00239 // start at time 0 00240 00241 state.Reset(); 00242 00243 // transfer info from the first events in each track in the 00244 // multitrack object to our current state. 00245 00246 for( int i=0; i<multitrack->GetNumTracks(); ++i ) 00247 { 00248 MIDITrack *track = multitrack->GetTrack(i); 00249 00250 // default: set the next_event_number for this track to -1 00251 // to signify end of track 00252 00253 state.next_event_number[ i ] = -1; 00254 00255 // are there any events in this track? 00256 if( track && track->GetNumEvents()>0 ) 00257 { 00258 // yes, extract the time of the first event 00259 00260 MIDITimedBigMessage *msg = track->GetEventAddress( 0 ); 00261 00262 if( msg ) 00263 { 00264 // found the first message of the track. Keep track 00265 // of the event number and the event time. 00266 00267 state.next_event_number[i]=0; 00268 state.next_event_time[i]=msg->GetTime(); 00269 } 00270 } 00271 } 00272 00273 00274 // are there any events at all? find the track with the 00275 // earliest event 00276 00277 if( state.FindTrackOfFirstEvent()!=-1 ) 00278 { 00279 // yes 00280 // iterate through all the events until we find a time >= the requested time 00281 00282 while( state.GetCurrentTime()<time ) 00283 { 00284 // did not get to the requested time yet. 00285 // go to the next chronological event on all tracks 00286 00287 if( !GoToNextEvent() ) 00288 { 00289 // there is no more events to go to 00290 00291 break; 00292 } 00293 00294 } 00295 } 00296 00297 } 00298 00299 bool MIDIMultiTrackIterator::GetCurEventTime( MIDIClockTime *t) 00300 { 00301 // if there is a next event, then set *t to the time of the event and return true 00302 00303 if( state.GetCurEventTrack() != -1 ) 00304 { 00305 *t = state.GetCurrentTime(); 00306 return true; 00307 } 00308 else 00309 { 00310 return false; 00311 } 00312 00313 } 00314 00315 bool MIDIMultiTrackIterator::GetCurEvent( int *track, MIDITimedBigMessage **msg ) 00316 { 00317 int t = state.GetCurEventTrack(); 00318 00319 if( t != -1 ) 00320 { 00321 if( track ) 00322 { 00323 *track=t; 00324 } 00325 00326 if( msg ) 00327 { 00328 int num = state.next_event_number[t]; 00329 00330 if( num>=0 ) 00331 { 00332 *msg = multitrack->GetTrack(t)->GetEventAddress( state.next_event_number[t] ); 00333 } 00334 else 00335 { 00336 *msg = 0; 00337 } 00338 00339 // do we really have a message? 00340 if( ! *msg ) 00341 { 00342 // no, return false then 00343 return false; 00344 } 00345 } 00346 00347 return true; 00348 } 00349 else 00350 { 00351 return false; 00352 } 00353 } 00354 00355 bool MIDIMultiTrackIterator::GoToNextEvent() 00356 { 00357 // find the next event in the multitrack list 00358 // and return it 00359 // if there is no event left, return false 00360 00361 if( state.cur_event_track==-1 ) 00362 { 00363 // no tracks left - all tracks are at end 00364 return false; 00365 } 00366 00367 // update the current event for the current track to the 00368 // next event on the same track. 00369 00370 GoToNextEventOnTrack( state.cur_event_track ); 00371 00372 // now find out which track now has the earliest event 00373 00374 if( state.FindTrackOfFirstEvent()==-1 ) 00375 { 00376 // No tracks do. all tracks are at the end. return false. 00377 return false; 00378 } 00379 00380 // ok, now state.cur_event_track has a valid track # of the next event 00381 00382 return true; 00383 } 00384 00385 bool MIDIMultiTrackIterator::GoToNextEventOnTrack( int track_num ) 00386 { 00387 // Get the track that we are dealing with 00388 MIDITrack *track = multitrack->GetTrack( track_num ); 00389 00390 // Get ptr to the current event number for this track 00391 int *event_num = &state.next_event_number[ track_num ]; 00392 00393 // skip this track if this event number is <0 - This track has hit end already. 00394 00395 if( *event_num <0 ) 00396 { 00397 return false; // at end of track 00398 } 00399 00400 // increment *event_num to next event on track 00401 00402 (*event_num) += 1; 00403 00404 // are we at end of track? 00405 if( *event_num >= track->GetNumEvents() ) 00406 { 00407 // yes, set *event_num to -1 00408 *event_num=-1; 00409 return false; // at end of track 00410 } 00411 else 00412 { 00413 // not at end of track yet - get the time of the event 00414 MIDITimedBigMessage *msg; 00415 00416 msg = track->GetEventAddress( *event_num ); 00417 00418 state.next_event_time[ track_num ] = msg->GetTime(); 00419 } 00420 00421 00422 00423 return true; 00424 } 00425 00426 00427 00428 00429 }