bool MIDISequencer::GetNextEventTimeMs ( float *t ) { double t2; bool res = GetNextEventTimeMs ( &t2 ); *t = ( float ) t2; return res; }
bool MIDISequencer::GoToTimeMs ( float time_ms ) { // temporarily disable the gui notifier bool notifier_mode = false; if ( state.notifier ) { notifier_mode = state.notifier->GetEnable(); state.notifier->SetEnable ( false ); } if ( time_ms < state.cur_time_ms || time_ms == 0.0 ) { // start from zero if desired time is before where we are for ( int i = 0; i < state.num_tracks; ++i ) { state.track_state[i]->GoToZero(); } state.iterator.GoToTime ( 0 ); state.cur_time_ms = 0.0; state.cur_clock = 0; // state.next_beat_time = state.multitrack->GetClksPerBeat(); state.next_beat_time = state.multitrack->GetClksPerBeat() * 4 / ( state.track_state[0]->timesig_denominator ); state.cur_beat = 0; state.cur_measure = 0; } float t = 0; int trk; MIDITimedBigMessage ev; while ( GetNextEventTimeMs ( &t ) && t < time_ms && GetNextEvent ( &trk, &ev ) ) { ; } // examine all the events at this specific time // and update the track states to reflect this time // ScanEventsAtThisTime(); // re-enable the gui notifier if it was enabled previously if ( state.notifier ) { state.notifier->SetEnable ( notifier_mode ); // cause a full gui refresh now state.notifier->Notify ( this, MIDISequencerGUIEvent::GROUP_ALL ); } return true; }
bool MIDISequencer::GetNextEvent( int *tracknum, MIDITimedBigMessage *msg ) { MIDIClockTime t; // ask the iterator for the current event time if( state.iterator.GetCurEventTime(&t) ) { // move current time forward one event MIDIClockTime new_clock; float new_time_ms=0.0f; GetNextEventTime( &new_clock ); GetNextEventTimeMs( &new_time_ms ); // must set cur_clock AFTER GetnextEventTimeMs() is called // since GetNextEventTimeMs() uses cur_clock to calculate state.cur_clock = new_clock; state.cur_time_ms = new_time_ms; // is the next beat marker before this event? if( state.next_beat_time<=t ) { // yes, this is a beat event now. // say this event came on track 0, the conductor track *tracknum = 0; // put current info into beat marker message beat_marker_msg.SetBeatMarker(); beat_marker_msg.SetTime( state.next_beat_time ); *msg = beat_marker_msg; // update our beat count int new_beat = state.cur_beat+1; int new_measure = state.cur_measure; // do we need to update the measure number? if( new_beat>=state.track_state[0]->timesig_numerator ) { // yup new_beat=0; ++new_measure; } // update our next beat time // denom=4 (16) ---> 4/16 midi file beats per symbolic beat // denom=3 (8) ---> 4/8 midi file beats per symbolic beat // denom=2 (4) ---> 4/4 midi file beat per symbolic beat // denom=1 (2) ---> 4/2 midi file beats per symbolic beat // denom=0 (1) ---> 4/1 midi file beats per symbolic beat state.next_beat_time += state.multitrack->GetClksPerBeat() * 4 / (state.track_state[0]->timesig_denominator); state.cur_beat = new_beat; state.cur_measure = new_measure; // now notify the GUI that the beat number changed state.notifier->Notify( this, MIDISequencerGUIEvent( MIDISequencerGUIEvent::GROUP_TRANSPORT, 0, MIDISequencerGUIEvent::GROUP_TRANSPORT_BEAT ) ); // if the new beat number is 0 then the measure changed too if( state.cur_beat==0 ) { state.notifier->Notify( this, MIDISequencerGUIEvent( MIDISequencerGUIEvent::GROUP_TRANSPORT, 0, MIDISequencerGUIEvent::GROUP_TRANSPORT_MEASURE ) ); } // give the beat marker event to the conductor track to process state.track_state[*tracknum]->Process(msg); return true; } else // this event comes before the next beat { MIDITimedBigMessage *msg_ptr; if( state.iterator.GetCurEvent( tracknum, &msg_ptr ) ) { int trk=*tracknum; // copy the event so Process can modify it *msg = *msg_ptr; bool allow_msg=true; // are we in solo mode? if( solo_mode ) { // yes, only allow this message thru if // the track is either track 0 // or it is explicitly solod. if( trk==0 || track_processors[trk]->solo ) { allow_msg=true; } else { allow_msg=false; } } if( !(allow_msg && track_processors[trk]->Process(msg) && state.track_state[trk]->Process(msg)) ) { // the message is not allowed to come out! // erase it msg->SetNoOp(); } // go to the next event on the multitrack state.iterator.GoToNextEvent(); return true; } } } return false; }