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_sequencer.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 #include "jdkmidi/world.h"
00025 #include "jdkmidi/sequencer.h"
00026 
00027 namespace jdkmidi
00028 {
00029   
00030   static void FixQuotes( char *s_ )
00031   {
00032     unsigned char *s = (unsigned char *)s_;
00033     while( *s )
00034     {
00035       if( *s==0xd2 || *s==0xd3 )
00036       {
00037         *s='"';
00038       }
00039       else if( *s==0xd5 )
00040       {
00041         *s='\'';
00042       }
00043       else if( *s>=0x80 )
00044       {
00045         *s = ' ';
00046       }
00047       s++;
00048     }
00049   }
00050   
00052   
00053   MIDISequencerGUIEventNotifier::MIDISequencerGUIEventNotifier()
00054   {
00055   }
00056   
00057   MIDISequencerGUIEventNotifier::~MIDISequencerGUIEventNotifier()
00058   {
00059   }
00060   
00061   
00062   
00064   
00065   
00066   MIDISequencerGUIEventNotifierText::MIDISequencerGUIEventNotifierText(
00067     FILE *f_
00068     )
00069     :
00070     f(f_),
00071     en(true)
00072   {
00073     
00074   }
00075   
00076   MIDISequencerGUIEventNotifierText::~MIDISequencerGUIEventNotifierText()
00077   {
00078   }
00079   
00080   
00081   void MIDISequencerGUIEventNotifierText::Notify(
00082     const MIDISequencer *seq,
00083     MIDISequencerGUIEvent e
00084     )
00085   {
00086     if( en )
00087     {
00088       fprintf( f, "GUI EVENT: G=%d, SG=%d, ITEM=%d\n",
00089                e.GetEventGroup(),
00090                e.GetEventSubGroup(),
00091                e.GetEventItem()
00092         );
00093       
00094       if( e.GetEventGroup() == MIDISequencerGUIEvent::GROUP_TRANSPORT )
00095       {
00096         if(
00097           e.GetEventItem() == MIDISequencerGUIEvent::GROUP_TRANSPORT_BEAT
00098           )
00099         {
00100           fprintf( f, "MEAS %3d BEAT %3d\n",
00101                    seq->GetCurrentMeasure()+1,
00102                    seq->GetCurrentBeat()+1
00103             );
00104         }
00105       }
00106       else
00107         if( e.GetEventGroup() == MIDISequencerGUIEvent::GROUP_CONDUCTOR )
00108         {
00109           
00110           if(
00111             e.GetEventItem() == MIDISequencerGUIEvent::GROUP_CONDUCTOR_TIMESIG
00112             )
00113           {
00114             fprintf( f, "TIMESIG: %d/%d\n",
00115                      seq->GetTrackState(0)->timesig_numerator,
00116                      seq->GetTrackState(0)->timesig_denominator
00117               );
00118           }
00119           if(
00120             e.GetEventItem() == MIDISequencerGUIEvent::GROUP_CONDUCTOR_TEMPO
00121             )
00122           {
00123             fprintf( f, "TEMPO: %3.2f\n",
00124                      seq->GetTrackState(0)->tempobpm
00125               );
00126           }
00127         }
00128     }
00129   }
00130   
00131   bool MIDISequencerGUIEventNotifierText::GetEnable() const
00132   {
00133     return en;
00134   }
00135   
00136   void MIDISequencerGUIEventNotifierText::SetEnable( bool f )
00137   {
00138     en = f;
00139   }
00140   
00142   
00143   MIDISequencerTrackNotifier::MIDISequencerTrackNotifier(
00144     MIDISequencer *seq_,
00145     int trk,
00146     MIDISequencerGUIEventNotifier *n
00147     )
00148     :
00149     seq( seq ),
00150     track_num( trk ),
00151     notifier( n )
00152   {
00153     
00154   }
00155   
00156   MIDISequencerTrackNotifier::~MIDISequencerTrackNotifier()
00157   {
00158     
00159   }
00160   
00161   void MIDISequencerTrackNotifier::Notify( int item )
00162   {
00163     if( notifier )
00164     {
00165       notifier->Notify(
00166         seq,
00167         MIDISequencerGUIEvent(
00168           MIDISequencerGUIEvent::GROUP_TRACK,
00169           track_num,
00170           item
00171           )
00172         );
00173     }
00174   }
00175   
00176   void MIDISequencerTrackNotifier::NotifyConductor( int item )
00177   {
00178     // only notify conductor if we are track #0
00179     if( notifier && track_num==0 )
00180     {
00181       notifier->Notify(
00182         seq,
00183         MIDISequencerGUIEvent(
00184           MIDISequencerGUIEvent::GROUP_CONDUCTOR,
00185           0,
00186           item
00187           )
00188         );
00189     }
00190   }
00191   
00193   
00194   MIDISequencerTrackProcessor::MIDISequencerTrackProcessor() 
00195     :
00196     mute(false),
00197     solo(false),
00198     velocity_scale(100),
00199     rechannel(-1),
00200     transpose(0),
00201     extra_proc(0)
00202   {
00203   } 
00204   
00205   
00206   MIDISequencerTrackProcessor::~MIDISequencerTrackProcessor() 
00207   {
00208   } 
00209   
00210   
00211   void MIDISequencerTrackProcessor::Reset() 
00212   {
00213     mute=false;
00214     solo=false;
00215     velocity_scale=100;
00216     rechannel=-1;
00217     transpose=0;
00218   } 
00219   
00220   
00221   bool MIDISequencerTrackProcessor::Process( MIDITimedBigMessage *msg ) 
00222   {
00223     
00224     // are we muted?
00225     
00226     if( mute )
00227     {
00228       // yes, ignore event.
00229       return false;
00230     }
00231     
00232     // is the event a NoOp?
00233     
00234     if( msg->IsNoOp() )
00235     {
00236       // yes, ignore event.
00237       
00238       return false;
00239     }
00240     
00241     // pass the event to our extra_proc if we have one
00242     
00243     if( extra_proc && extra_proc->Process(msg)==false )
00244     {
00245       // extra_proc wanted to ignore this event
00246       return false;
00247     }
00248     
00249     // is it a normal MIDI channel message?
00250     if( msg->IsChannelMsg() )
00251     {
00252       // yes, are we to re-channel it?
00253       if( rechannel!=-1 )
00254       {
00255         msg->SetChannel( (unsigned char)rechannel );
00256       }
00257       
00258       // is it a note on message?
00259       if( msg->IsNoteOn() && msg->GetVelocity()>0 )
00260       {
00261         // yes, scale the velocity value as required
00262         
00263         int vel = (int)msg->GetVelocity();
00264         
00265         vel = vel*velocity_scale / 100;
00266         
00267         // make sure velocity is never less than 0
00268         
00269         if( vel<0 )
00270         {
00271           vel=0;
00272         }
00273         
00274         // rewrite the velocity
00275         
00276         msg->SetVelocity( (unsigned char)vel );
00277         
00278       }
00279       
00280       // is it a type of event that needs to be transposed?
00281       
00282       if( msg->IsNoteOn() || msg->IsNoteOff() || msg->IsPolyPressure() )
00283       {
00284         int new_note = ((int)msg->GetNote())+transpose;
00285         
00286         if( new_note>=0 && new_note<=127 )
00287         {
00288           // set new note number
00289           msg->SetNote( (unsigned char)new_note );
00290         }
00291         else
00292         {
00293           // otherwise delete this note - transposed value is out of range
00294           return false;
00295         }
00296         
00297       }
00298       
00299     }
00300     
00301     return true;
00302   } 
00303   
00304   
00306   
00307   MIDISequencerTrackState::MIDISequencerTrackState(
00308     MIDISequencer *seq_,
00309     int trk,
00310     MIDISequencerGUIEventNotifier *n
00311     ) 
00312     :
00313     MIDISequencerTrackNotifier( seq_, trk, n ),
00314     tempobpm( 120.0 ),
00315     volume(100),
00316     timesig_numerator(4),
00317     timesig_denominator(4),
00318     bender_value(0),
00319     got_good_track_name(false),
00320     notes_are_on(false),
00321     note_matrix()
00322   {
00323     *track_name = 0;
00324   } 
00325   
00326   
00327   MIDISequencerTrackState::~MIDISequencerTrackState() 
00328   {
00329   } 
00330   
00331   void MIDISequencerTrackState::GoToZero() 
00332   {
00333     tempobpm = 120.0;
00334     timesig_numerator=4;
00335     timesig_denominator=4;
00336     bender_value=0;
00337     note_matrix.Clear();
00338   } 
00339   
00340   void MIDISequencerTrackState::Reset() 
00341   {
00342     tempobpm = 120.0;
00343     volume=100;
00344     notes_are_on=false;
00345     timesig_numerator=4;
00346     timesig_denominator=4;
00347     bender_value=0;
00348     *track_name=0;
00349     note_matrix.Clear();
00350     got_good_track_name=false;
00351   } 
00352   
00353   
00354   bool MIDISequencerTrackState::Process( MIDITimedBigMessage *msg ) 
00355   {
00356     // is the event a NoOp?
00357     
00358     if( msg->IsNoOp() )
00359     {
00360       // yes, ignore event.
00361       
00362       return false;
00363     }
00364     
00365     // is it a normal MIDI channel message?
00366     if( msg->IsChannelMsg() )
00367     {
00368       
00369       if( msg->GetType()==PITCH_BEND ) // is it a bender event?
00370       {
00371         // yes
00372         // remember the bender wheel value
00373         
00374         bender_value = msg->GetBenderValue();
00375       }
00376       else if( msg->IsControlChange() ) // is it a control change event?
00377       {
00378         // yes
00379         
00380         // is it a volume change event?
00381         
00382         if( msg->GetController()==C_MAIN_VOLUME )
00383         {
00384           // yes, store the current volume level
00385           volume = msg->GetControllerValue();
00386           
00387           Notify(
00388             MIDISequencerGUIEvent::GROUP_TRACK_VOLUME
00389             );
00390         }
00391       }
00392       else if( msg->IsProgramChange() ) // is it a program change event?
00393       {
00394         // yes
00395         
00396         // update the current program change value
00397         pg = msg->GetPGValue();
00398         
00399         Notify(
00400           MIDISequencerGUIEvent::GROUP_TRACK_PG
00401           );
00402       }
00403       
00404     }
00405     else
00406     {
00407       // event is not a channel message. is it a meta-event?
00408       if( msg->IsMetaEvent() )
00409       {
00410         // yes, is it a tempo event
00411         if( msg->IsTempo() )
00412         {
00413           // yes get the current tempo
00414           
00415           tempobpm = ((float)msg->GetTempo32())*(1.0f/32.0f);
00416           if(tempobpm<1 )
00417           {
00418             tempobpm=120.0;
00419           }
00420           
00421           NotifyConductor(
00422             MIDISequencerGUIEvent::GROUP_CONDUCTOR_TEMPO
00423             );
00424         }
00425         else // is it a time signature event?
00426           if( msg->GetMetaType()==META_TIMESIG )
00427           {
00428             // yes, extract the current numerator and denominator
00429             
00430             timesig_numerator = msg->GetTimeSigNumerator();
00431             timesig_denominator = msg->GetTimeSigDenominator();
00432             
00433             NotifyConductor(
00434               MIDISequencerGUIEvent::GROUP_CONDUCTOR_TIMESIG
00435               );
00436             
00437           }
00438           else // is it a track name event?
00439             if( ( msg->GetMetaType()==META_TRACK_NAME
00440                   || msg->GetMetaType()==META_INSTRUMENT_NAME
00441                   || (!got_good_track_name && msg->GetMetaType()==META_GENERIC_TEXT && msg->GetTime()==0)
00442                   )
00443                 &&
00444                 msg->GetSysEx() )
00445             {
00446               got_good_track_name = true;
00447               
00448               // yes, copy the track name
00449               int len = msg->GetSysEx()->GetLength();
00450               
00451               if( len>(int)sizeof(track_name)-1 )
00452                 len=(int)sizeof(track_name)-1;
00453               
00454               memcpy(track_name, msg->GetSysEx()->GetBuf(), len );
00455               
00456               track_name[len]='\0';
00457               
00458               FixQuotes( track_name );
00459               
00460               Notify(
00461                 MIDISequencerGUIEvent::GROUP_TRACK_NAME
00462                 );
00463               
00464             }
00465         
00466       }
00467       
00468     }
00469     
00470     // pass the message to our note matrix to keep track of all notes on
00471     // on this track
00472     
00473     if( note_matrix.Process( *msg ) )
00474     {
00475       // did the "any notes on" status change?
00476       
00477       if(    (  notes_are_on && note_matrix.GetTotalCount()==0)
00478              || (!notes_are_on && note_matrix.GetTotalCount()>0 ) )
00479       {
00480         // yes, toggle our notes_are_on flag
00481         notes_are_on = !notes_are_on;
00482         
00483         // and notify the gui about the activity on this track
00484         Notify(
00485           MIDISequencerGUIEvent::GROUP_TRACK_NOTE
00486           );
00487       }
00488     }
00489     
00490     
00491     return true;
00492   } 
00493   
00495   
00496   MIDISequencerState::MIDISequencerState(
00497     MIDISequencer *s,
00498     MIDIMultiTrack *  m,
00499     MIDISequencerGUIEventNotifier *n
00500     )
00501     :
00502     notifier(n),
00503     multitrack(m),
00504     num_tracks( m->GetNumTracks() ),
00505     iterator( m ),
00506     cur_clock(0),
00507     cur_time_ms(0),
00508     cur_beat(0),
00509     cur_measure(0),
00510     next_beat_time(0)
00511   {
00512     
00513     for( int i=0; i<num_tracks; ++i )
00514     {
00515       track_state[i] = new MIDISequencerTrackState( s, i, notifier );
00516     }
00517   }
00518   
00519   MIDISequencerState::MIDISequencerState( const MIDISequencerState &s )
00520     :
00521     notifier(s.notifier),
00522     multitrack(s.multitrack),
00523     num_tracks( s.num_tracks ),
00524     iterator( s.iterator ),
00525     cur_clock( s.cur_clock),
00526     cur_time_ms( s.cur_time_ms),
00527     cur_beat( s.cur_beat),
00528     cur_measure( s.cur_measure),
00529     next_beat_time(s.next_beat_time)
00530   {
00531     
00532     for( int i=0; i<num_tracks; ++i )
00533     {
00534       track_state[i] = new MIDISequencerTrackState( *s.track_state[i] );
00535     }
00536     
00537   }
00538   
00539   
00540   MIDISequencerState::~MIDISequencerState()
00541   {
00542     for( int i=0; i<num_tracks; ++i )
00543     {
00544       delete track_state[i];
00545     }
00546   }
00547   
00548   const MIDISequencerState & MIDISequencerState::operator = ( const MIDISequencerState & s )
00549   {
00550     if( num_tracks!=s.num_tracks )
00551     {
00552     {
00553       for( int i=0; i<num_tracks; ++i )
00554       {
00555         delete track_state[i];
00556       }
00557     }
00558       
00559       
00560        num_tracks = s.num_tracks;
00561       
00562      {
00563       for( int i=0; i<num_tracks; ++i )
00564       {
00565         track_state[i] = new MIDISequencerTrackState( *s.track_state[i] );
00566       }
00567      }
00568    
00569     }
00570     
00571     
00572     iterator = s.iterator;
00573     cur_clock = s.cur_clock;
00574     cur_time_ms = s.cur_time_ms;
00575     cur_beat = s.cur_beat;
00576     cur_measure = s.cur_measure;
00577     next_beat_time = s.next_beat_time;
00578     
00579     return *this;
00580   }
00581   
00582   
00584   
00585   
00586   MIDISequencer::MIDISequencer(
00587     MIDIMultiTrack *m,
00588     MIDISequencerGUIEventNotifier *n
00589     ) 
00590     :
00591     solo_mode(false),
00592     tempo_scale(100),
00593     num_tracks( m->GetNumTracks() ),
00594     state( this, m,n ) // TODO: fix this hack
00595   {
00596     
00597     for( int i=0; i<num_tracks; ++i )
00598     {
00599       track_processors[i] = new MIDISequencerTrackProcessor;
00600     }
00601   } 
00602   
00603   
00604   MIDISequencer::~MIDISequencer() 
00605   {
00606     for(int i=0; i<num_tracks; ++i )
00607     {
00608       delete track_processors[i];
00609     }
00610   } 
00611   
00612   void MIDISequencer::ResetTrack( int trk )
00613   {
00614     state.track_state[trk]->Reset();
00615     track_processors[trk]->Reset();
00616   }
00617   
00618   void MIDISequencer::ResetAllTracks()
00619   {
00620     for( int i=0; i<num_tracks; ++i )
00621     {
00622       state.track_state[i]->Reset();
00623       track_processors[i]->Reset();
00624     }
00625   }
00626   
00627   MIDISequencerState *MIDISequencer::GetState()
00628   {
00629     return &state;
00630   }
00631   
00632   const MIDISequencerState *MIDISequencer::GetState() const
00633   {
00634     return &state;
00635   }
00636   
00637   void MIDISequencer::SetState( MIDISequencerState *s )
00638   {
00639     state = *s;
00640   }
00641   
00642   MIDIClockTime MIDISequencer::GetCurrentMIDIClockTime() const 
00643   {
00644     return state.cur_clock;
00645   } 
00646   
00647   double MIDISequencer::GetCurrentTimeInMs() const 
00648   {
00649     return state.cur_time_ms;
00650   } 
00651   
00652   int MIDISequencer::GetCurrentBeat() const 
00653   {
00654     return state.cur_beat;
00655   } 
00656   
00657   
00658   int MIDISequencer::GetCurrentMeasure() const 
00659   {
00660     return state.cur_measure;
00661   } 
00662   
00663   double MIDISequencer::GetCurrentTempoScale() const 
00664   {
00665     return ((double)tempo_scale)*0.01;
00666   } 
00667   
00668   double MIDISequencer::GetCurrentTempo() const 
00669   {
00670     return state.track_state[0]->tempobpm;
00671   } 
00672   
00673   MIDISequencerTrackState * MIDISequencer::GetTrackState( int trk ) 
00674   {
00675     return state.track_state[trk];
00676   } 
00677   
00678   const MIDISequencerTrackState * MIDISequencer::GetTrackState( int trk ) const 
00679   {
00680     return state.track_state[ trk ];
00681   } 
00682   
00683   MIDISequencerTrackProcessor * MIDISequencer::GetTrackProcessor( int trk ) 
00684   {
00685     return track_processors[trk];
00686   } 
00687   
00688   const MIDISequencerTrackProcessor * MIDISequencer::GetTrackProcessor( int trk ) const 
00689   {
00690     return track_processors[ trk ];
00691   } 
00692   
00693   bool MIDISequencer::GetSoloMode() const 
00694   {
00695     return solo_mode;
00696   } 
00697   
00698   void MIDISequencer::SetCurrentTempoScale( float scale ) 
00699   {
00700     tempo_scale = (int)(scale*100);
00701   } 
00702   
00703   void MIDISequencer::SetSoloMode( bool m, int trk ) 
00704   {
00705     int i;
00706     solo_mode = m;
00707     
00708     for( i=0; i<num_tracks; ++i )
00709     {
00710       if( i==trk )
00711       {
00712         track_processors[i]->solo = true;
00713       }
00714       else
00715       {
00716         track_processors[i]->solo = false;
00717       }
00718     }
00719     
00720   } 
00721   
00722   void MIDISequencer::GoToZero() 
00723   {
00724     // go to time zero
00725     
00726     for( int i=0; i<num_tracks; ++i )
00727     {
00728       state.track_state[i]->GoToZero();
00729     }
00730     
00731     state.iterator.GoToTime( 0 );
00732     
00733     state.cur_time_ms = 0.0;
00734     state.cur_clock = 0;
00735     
00736 //  state.next_beat_time = state.multitrack->GetClksPerBeat();
00737     state.next_beat_time =
00738       state.multitrack->GetClksPerBeat()
00739       * 4 / (state.track_state[0]->timesig_denominator);
00740     
00741     // examine all the events at this specific time
00742     // and update the track states to reflect this time
00743     
00744     ScanEventsAtThisTime();
00745   } 
00746   
00747   bool MIDISequencer::GoToTime( MIDIClockTime time_clk ) 
00748   {
00749     // temporarily disable the gui notifier
00750     
00751     bool notifier_mode=false;
00752     if( state.notifier )
00753     {
00754       notifier_mode = state.notifier->GetEnable();
00755       state.notifier->SetEnable(false);
00756     }
00757     
00758     if( time_clk < state.cur_clock || time_clk==0 )
00759     {
00760       // start from zero if desired time is before where we are
00761       for( int i=0; i<state.num_tracks; ++i )
00762       {
00763         state.track_state[i]->GoToZero();
00764       }
00765       
00766       state.iterator.GoToTime( 0 );
00767       
00768       state.cur_time_ms = 0.0;
00769       state.cur_clock = 0;
00770 //    state.next_beat_time = state.multitrack->GetClksPerBeat();
00771       state.next_beat_time =
00772         state.multitrack->GetClksPerBeat()
00773         * 4 / (state.track_state[0]->timesig_denominator);
00774       
00775       state.cur_beat = 0;
00776       state.cur_measure = 0;
00777       
00778     }
00779     
00780     MIDIClockTime t=0;
00781     int trk;
00782     MIDITimedBigMessage ev;
00783     
00784     while(
00785       GetNextEventTime( &t )
00786       && t<time_clk
00787       && GetNextEvent(&trk,&ev)
00788       )
00789     {
00790       ;
00791     }
00792     
00793     
00794     // examine all the events at this specific time
00795     // and update the track states to reflect this time
00796     
00797     ScanEventsAtThisTime();
00798     
00799     // re-enable the gui notifier if it was enabled previously
00800     if( state.notifier )
00801     {
00802       state.notifier->SetEnable( notifier_mode );
00803       
00804       // cause a full gui refresh now
00805       
00806       state.notifier->Notify( this, MIDISequencerGUIEvent::GROUP_ALL );
00807     }
00808     
00809     
00810     
00811     return true;
00812     
00813   } 
00814   
00815   bool MIDISequencer::GoToTimeMs( float time_ms ) 
00816   {
00817     // temporarily disable the gui notifier
00818     
00819     bool notifier_mode=false;
00820     if( state.notifier )
00821     {
00822       notifier_mode = state.notifier->GetEnable();
00823       state.notifier->SetEnable(false);
00824     }
00825     
00826     if( time_ms < state.cur_time_ms || time_ms==0.0 )
00827     {
00828       // start from zero if desired time is before where we are
00829       for( int i=0; i<state.num_tracks; ++i )
00830       {
00831         state.track_state[i]->GoToZero();
00832       }
00833       
00834       state.iterator.GoToTime( 0 );
00835       
00836       state.cur_time_ms = 0.0;
00837       state.cur_clock = 0;
00838 //    state.next_beat_time = state.multitrack->GetClksPerBeat();
00839       state.next_beat_time =
00840         state.multitrack->GetClksPerBeat()
00841         * 4 / (state.track_state[0]->timesig_denominator);
00842       
00843       state.cur_beat = 0;
00844       state.cur_measure = 0;
00845     }
00846     
00847     float t=0;
00848     int trk;
00849     MIDITimedBigMessage ev;
00850     
00851     while(
00852       GetNextEventTimeMs( &t )
00853       && t<time_ms
00854       && GetNextEvent(&trk,&ev)
00855       )
00856     {
00857       ;
00858     }
00859     
00860     // examine all the events at this specific time
00861     // and update the track states to reflect this time
00862     
00863 //  ScanEventsAtThisTime();
00864     
00865     // re-enable the gui notifier if it was enabled previously
00866     if( state.notifier )
00867     {
00868       state.notifier->SetEnable( notifier_mode );
00869       
00870       // cause a full gui refresh now
00871       
00872       state.notifier->Notify( this, MIDISequencerGUIEvent::GROUP_ALL );
00873     }
00874     
00875     
00876     return true;
00877     
00878   } 
00879   
00880   bool MIDISequencer::GoToMeasure( int measure, int beat ) 
00881   {
00882     // temporarily disable the gui notifier
00883     
00884     bool notifier_mode=false;
00885     if( state.notifier )
00886     {
00887       notifier_mode = state.notifier->GetEnable();
00888       state.notifier->SetEnable(false);
00889     }
00890     
00891     if( measure < state.cur_measure || measure==0 )
00892     {
00893       for( int i=0; i<state.num_tracks; ++i )
00894       {
00895         state.track_state[i]->GoToZero();
00896       }
00897       
00898       state.iterator.GoToTime( 0 );
00899       
00900       state.cur_time_ms = 0.0;
00901       state.cur_clock = 0;
00902       state.cur_beat = 0;
00903       state.cur_measure = 0;
00904 //    state.next_beat_time = state.multitrack->GetClksPerBeat();
00905       state.next_beat_time =
00906         state.multitrack->GetClksPerBeat()
00907         * 4 / (state.track_state[0]->timesig_denominator);
00908       
00909     }
00910     
00911     MIDIClockTime t=0;
00912     int trk;
00913     MIDITimedBigMessage ev;
00914     
00915     // iterate thru all the events until cur-measure and cur_beat are
00916     // where we want them.
00917     
00918     while(
00919       GetNextEventTime( &t )
00920       && GetNextEvent(&trk,&ev)
00921       && state.cur_measure<=measure
00922       )
00923     {
00924       if( state.cur_measure==measure && state.cur_beat>=beat )
00925       {
00926         break;
00927       }
00928     }
00929     
00930     
00931     // examine all the events at this specific time
00932     // and update the track states to reflect this time
00933     
00934     
00935     ScanEventsAtThisTime();
00936     
00937     
00938     
00939     // re-enable the gui notifier if it was enabled previously
00940     if( state.notifier )
00941     {
00942       state.notifier->SetEnable( notifier_mode );
00943       
00944       // cause a full gui refresh now
00945       
00946       state.notifier->Notify( this, MIDISequencerGUIEvent::GROUP_ALL );
00947     }
00948     
00949     // return true if we actually found the measure requested
00950     
00951     return state.cur_measure == measure && state.cur_beat == beat;
00952     
00953   } 
00954   
00955   
00956   
00957   bool MIDISequencer::GetNextEventTimeMs( float *t ) 
00958   {
00959     MIDIClockTime ct;
00960     bool f = GetNextEventTime( &ct );
00961     
00962     if( f )
00963     {
00964       // calculate delta time from last event time
00965       
00966       double delta_clocks = (double)(ct - state.cur_clock);
00967       
00968       // calculate tempo in milliseconds per clock
00969       
00970       double clocks_per_sec = ((state.track_state[0]->tempobpm *
00971                                 (((double)tempo_scale)*0.01)
00972                                 * (1.0f/60.0f)) * state.multitrack->GetClksPerBeat());
00973       
00974       if( clocks_per_sec>0 )
00975       {
00976         float ms_per_clock = 1000.0f /clocks_per_sec;
00977         
00978         // calculate delta time in milliseconds
00979         
00980         float delta_ms = float(delta_clocks * ms_per_clock);
00981         
00982         // return it added with the current time in ms.
00983         
00984         *t = delta_ms + state.cur_time_ms;
00985       }
00986       else
00987       {
00988         f=false;
00989       }
00990     }
00991     
00992     return f;
00993   } 
00994   
00995   bool MIDISequencer::GetNextEventTime( MIDIClockTime *t ) 
00996   {
00997     // ask the iterator for the current event time
00998     bool f = state.iterator.GetCurEventTime(t);
00999     
01000     if( f )
01001     {
01002       // if we have an event in the future, check to see if it is
01003       // further in time than the next beat marker
01004       
01005       if( (*t) >= state.next_beat_time )
01006       {
01007         // ok, the next event is a beat - return the next beat time
01008         
01009         *t = state.next_beat_time;
01010       }
01011     }
01012     
01013     return f;
01014   } 
01015   
01016   bool MIDISequencer::GetNextEvent( int *tracknum, MIDITimedBigMessage *msg ) 
01017   {
01018     MIDIClockTime t;
01019     
01020     
01021     // ask the iterator for the current event time
01022     if( state.iterator.GetCurEventTime(&t) )
01023     {
01024       // move current time forward one event
01025       
01026       MIDIClockTime new_clock;
01027       float new_time_ms;
01028       
01029       GetNextEventTime( &new_clock );
01030       GetNextEventTimeMs( &new_time_ms );
01031       
01032       // must set cur_clock AFTER GetnextEventTimeMs() is called
01033       // since GetNextEventTimeMs() uses cur_clock to calculate
01034       
01035       state.cur_clock = new_clock;
01036       state.cur_time_ms = new_time_ms;
01037       
01038       
01039       // is the next beat marker before this event?
01040       
01041       if( state.next_beat_time<=t )
01042       {
01043         // yes, this is a beat event now.
01044         
01045         // say this event came on track 0, the conductor track
01046         *tracknum = 0;
01047         
01048         // put current info into beat marker message
01049         beat_marker_msg.SetBeatMarker();
01050         beat_marker_msg.SetTime( state.next_beat_time );
01051         *msg = beat_marker_msg;
01052         
01053         // update our beat count
01054         
01055         int new_beat = state.cur_beat+1;
01056         int new_measure = state.cur_measure;
01057         
01058         // do we need to update the measure number?
01059         
01060         if( new_beat>=state.track_state[0]->timesig_numerator )
01061         {
01062           // yup
01063           
01064           new_beat=0;
01065           ++new_measure;
01066         }
01067         
01068         // update our next beat time
01069         
01070         
01071         // denom=4  (16) ---> 4/16 midi file beats per symbolic beat
01072         // denom=3  (8)  ---> 4/8 midi file beats per symbolic beat
01073         // denom=2  (4)  ---> 4/4 midi file beat per symbolic beat
01074         // denom=1  (2)  ---> 4/2 midi file beats per symbolic beat
01075         // denom=0  (1)  ---> 4/1 midi file beats per symbolic beat
01076         
01077         state.next_beat_time +=
01078           state.multitrack->GetClksPerBeat()
01079           * 4 / (state.track_state[0]->timesig_denominator);
01080         
01081         state.cur_beat = new_beat;
01082         state.cur_measure = new_measure;
01083         
01084         // now notify the GUI that the beat number changed
01085         state.notifier->Notify(
01086           this,
01087           MIDISequencerGUIEvent(
01088             MIDISequencerGUIEvent::GROUP_TRANSPORT,
01089             0,
01090             MIDISequencerGUIEvent::GROUP_TRANSPORT_BEAT
01091             )
01092           );
01093         
01094         // if the new beat number is 0 then the measure changed too
01095         if( state.cur_beat==0 )
01096         {
01097           state.notifier->Notify(
01098             this,
01099             MIDISequencerGUIEvent(
01100               MIDISequencerGUIEvent::GROUP_TRANSPORT,
01101               0,
01102               MIDISequencerGUIEvent::GROUP_TRANSPORT_MEASURE
01103               )
01104             );
01105         }
01106         
01107         // give the beat marker event to the conductor track to process
01108         state.track_state[*tracknum]->Process(msg);
01109         
01110         
01111         return true;
01112       }
01113       else  // this event comes before the next beat
01114       {
01115         MIDITimedBigMessage *msg_ptr;
01116         
01117         if( state.iterator.GetCurEvent( tracknum, &msg_ptr ) )
01118         {
01119           int trk=*tracknum;
01120           
01121           // copy the event so Process can modify it
01122           
01123           *msg = *msg_ptr;
01124           
01125           bool allow_msg=true;
01126           
01127           // are we in solo mode?
01128           
01129           if( solo_mode )
01130           {
01131             // yes, only allow this message thru if
01132             // the track is either track 0
01133             // or it is explicitly solod.
01134             
01135             if( trk==0 || track_processors[trk]->solo )
01136             {
01137               allow_msg=true;
01138             }
01139             else
01140             {
01141               allow_msg=false;
01142             }
01143             
01144           }
01145           
01146           
01147           if( !(allow_msg
01148                 && track_processors[trk]->Process(msg)
01149                 && state.track_state[trk]->Process(msg))
01150             )
01151           {
01152             // the message is not allowed to come out!
01153             // erase it
01154             msg->SetNoOp();
01155           }
01156           
01157           // go to the next event on the multitrack
01158           state.iterator.GoToNextEvent();
01159           
01160           return true;
01161           
01162         }
01163       }
01164     }
01165     
01166     return false;
01167   } 
01168   
01169   void MIDISequencer::ScanEventsAtThisTime() 
01170   {
01171     // save the current iterator state
01172     
01173     MIDIMultiTrackIteratorState istate( state.iterator.GetState() );
01174     int prev_measure = state.cur_measure;
01175     int prev_beat = state.cur_beat;
01176     
01177     
01178     // process all messages up to and including this time only
01179     
01180     MIDIClockTime orig_clock = state.cur_clock;
01181     double orig_time_ms = state.cur_time_ms;
01182     
01183     
01184     MIDIClockTime t=0;
01185     int trk;
01186     MIDITimedBigMessage ev;
01187     
01188     while(
01189       GetNextEventTime( &t )
01190       && t==orig_clock
01191       && GetNextEvent(&trk,&ev)
01192       )
01193     {
01194       ;
01195     }
01196     
01197     // restore the iterator state
01198     state.iterator.SetState( istate );
01199     
01200     // and current time
01201     state.cur_clock = orig_clock;
01202     state.cur_time_ms = float(orig_time_ms);
01203     
01204     state.cur_measure=prev_measure;
01205     state.cur_beat = prev_beat;
01206     
01207   } 
01208   
01209   
01210   
01211   
01212 }