jdkmidi class library documentation

Copyright © 2004 J.D. Koftinoff Software, Ltd.

Released under the GNU General Public License (GPL)




Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

src/jdkmidi_multitrack.cpp

Go to the documentation of this file.
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 }