void CollapseMultiTrack( const MIDIMultiTrack &src, MIDIMultiTrack &dst ) { dst.ClearAndResize( 1 ); dst.SetClksPerBeat( src.GetClksPerBeat() ); MIDISequencer seq( &src ); seq.GoToZero(); MIDITimedBigMessage ev; int ev_track; while ( seq.GetNextEvent( &ev_track, &ev ) ) { // ignore all src EndOfTrack messages!! if ( ev.IsDataEnd() ) continue; // ignore NoOp, BeatMarker and other Service messages if ( ev.IsServiceMsg() || ev.IsNoOp() ) continue; dst.GetTrack(0)->PutEvent(ev); } // set (single!) dst EndOfTrack message MIDITimedBigMessage end(ev); // copy time of last src event end.SetDataEnd(); dst.GetTrack(0)->PutEvent(end); }
void CopyWithoutChannel( const MIDIMultiTrack &src, MIDIMultiTrack &dst, int ignore_channel ) { dst.ClearAndResize( src.GetNumTracks() ); dst.SetClksPerBeat( src.GetClksPerBeat() ); MIDIClockTime ev_time = 0; MIDISequencer seq( &src ); seq.GoToTime( 0 ); if ( !seq.GetNextEventTime ( &ev_time ) ) return; // empty src multitrack MIDITimedBigMessage ev; int ev_track; while ( seq.GetNextEvent( &ev_track, &ev ) ) { if ( ev.IsServiceMsg() || ev.IsNoOp() ) continue; if ( ev.IsChannelEvent() && ev.GetChannel() == ignore_channel ) continue; dst.GetTrack(ev_track)->PutEvent(ev); } }
void ClipMultiTrack( const MIDIMultiTrack &src, MIDIMultiTrack &dst, double max_time_sec ) { dst.ClearAndResize( src.GetNumTracks() ); dst.SetClksPerBeat( src.GetClksPerBeat() ); double max_event_time = 1000.*max_time_sec; // msec double event_time = 0.; // msec MIDISequencer seq( &src ); seq.GoToTimeMs( 0.f ); if ( !seq.GetNextEventTimeMs ( &event_time ) ) return; // empty src multitrack MIDITimedBigMessage ev; int ev_track; while ( seq.GetNextEvent( &ev_track, &ev ) ) { // ignore NoOp, BeatMarker and other Service messages if ( ev.IsServiceMsg() || ev.IsNoOp() ) continue; dst.GetTrack(ev_track)->PutEvent(ev); if ( event_time >= max_event_time ) break; // end of max_time_sec if ( !seq.GetNextEventTimeMs( &event_time ) ) break; // end of src multitrack } }
GenePool::MIDIEventList *GenePool::getEvents(void) { list<MIDITimedBigMessage*> *events = new list<MIDITimedBigMessage*>; for (EventPool::iterator i = pool_.begin(); i != pool_.end(); ++i) { for (BreadNoteCluster::iterator j = (*i)->begin(); j != (*i)->end(); ++j) { BreadNote *e = (*j); u_int8_t pitch = e->pitch(); u_int32_t ontime = e->ontime(); u_int32_t duration = e->duration(); u_int8_t channel = e->channel(); u_int8_t dynamic = e->dynamic(); MIDITimedBigMessage *m = new MIDITimedBigMessage; m->SetTime(ontime); m->SetNoteOn(channel, pitch, dynamic); events->push_back(m); m = new MIDITimedBigMessage; m->SetTime(ontime+duration); m->SetNoteOff(channel, pitch, dynamic); events->push_back(m); // printf("(%d %d %d %d %d) ", ontime, pitch, duration, channel, // dynamic); } } return events; }
int AdvancedSequencer::FindFirstChannelOnTrack ( int trk ) { if ( !file_loaded ) { return -1; } int first_channel = -1; MIDITrack *t = tracks.GetTrack ( trk ); if ( t ) { // go through all events // until we find a channel message // and then return the channel number plus 1 for ( int i = 0; i < t->GetNumEvents(); ++i ) { MIDITimedBigMessage *m = t->GetEventAddress ( i ); if ( m ) { if ( m->IsChannelMsg() ) { first_channel = m->GetChannel() + 1; break; } } } } return first_channel; }
bool AddEndingPause( MIDIMultiTrack &tracks, int track_num, MIDIClockTime pause_ticks ) { MIDIClockTime t = tracks.GetTrack( track_num )->GetLastEventTime(); MIDITimedBigMessage msg; msg.SetTime( t + pause_ticks ); // add lowest "note on" in channel 0 with velocity 0 (i.e. "note off") msg.SetNoteOn( 0, 0, 0 ); return tracks.GetTrack( track_num )->PutEvent( msg ); }
std::string EventAsText(const MIDITimedBigMessage &ev) { char buf[256]; ev.MsgToText( buf ); MIDIClockTime time = ev.GetTime(); /*std::ostringstream ostr; ostr << " Midi tick " << time; ostr << " MSG " << buf << " "; return ostr.str();*/ return std::string("EventAsText Stub"); }
bool MIDIDriverDump::HardwareMsgOut ( const MIDITimedBigMessage &msg ) { char buf[256]; fprintf ( f, "OUTPUT: %s\n", msg.MsgToText ( buf ) ); return true; }
bool MIDITrack::PutEvent( const MIDITimedMessage &msg, MIDISystemExclusive *sysex ) { if( num_events >= buf_size ) { if( !Expand() ) return false; } MIDITimedBigMessage *e = GetEventAddress( num_events ); e->Copy( msg ); e->CopySysEx( sysex ); ++num_events; return true; }
bool MIDITrack::MakeEventNoOp( int event_num ) { if( event_num>=num_events ) { return false; } else { MIDITimedBigMessage *ev = GetEventAddress( event_num ); if( ev ) { ev->ClearSysEx(); ev->SetNoOp(); } return true; } }
void LastEventsProlongation( MIDIMultiTrack &tracks, int track_num, MIDIClockTime add_ticks ) { MIDITrack *track = tracks.GetTrack( track_num ); int index = track->GetNumEvents() - 1; if ( add_ticks == 0 || index < 0 ) return; MIDITimedBigMessage *msg = track->GetEvent( index ); MIDIClockTime tmax = msg->GetTime(); while ( msg->GetTime() == tmax ) { msg->SetTime( tmax + add_ticks ); if ( --index < 0 ) break; msg = track->GetEvent( index ); } }
void CompressStartPause( const MIDIMultiTrack &src, MIDIMultiTrack &dst, int ignore_channel ) { dst.ClearAndResize( src.GetNumTracks() ); dst.SetClksPerBeat( src.GetClksPerBeat() ); MIDIClockTime ev_time = 0; MIDISequencer seq( &src ); seq.GoToTime( 0 ); if ( !seq.GetNextEventTime ( &ev_time ) ) return; // empty src multitrack MIDITimedBigMessage ev; int ev_track; bool compress = true; MIDIClockTime old_ev_time = 0, delta_ev_time = 0, ev_time0 = 0; while ( seq.GetNextEvent( &ev_track, &ev ) ) { if ( ev.IsServiceMsg() || ev.IsNoOp() ) continue; if ( ev.IsChannelEvent() && ev.GetChannel() == ignore_channel ) continue; ev_time = ev.GetTime(); if ( compress ) { // compress time intervals between adjacent messages to 1 tick if (ev_time > old_ev_time) ++delta_ev_time; old_ev_time = ev_time; ev.SetTime( delta_ev_time ); if ( ev.ImplicitIsNoteOn() ) { compress = false; ev_time0 = ev_time - delta_ev_time; } } else { ev.SetTime( ev_time - ev_time0 ); } dst.GetTrack(ev_track)->PutEvent(ev); } }
bool MIDIMultiTrackIterator::GoToNextEventOnTrack ( int track_num ) { // Get the track that we are dealing with MIDITrack *track = multitrack->GetTrack ( track_num ); // Get ptr to the current event number for this track int *event_num = &state.next_event_number[ track_num ]; // skip this track if this event number is <0 - This track has hit end already. if ( *event_num <0 ) { return false; // at end of track } // increment *event_num to next event on track ( *event_num ) += 1; // are we at end of track? if ( *event_num >= track->GetNumEvents() ) { // yes, set *event_num to -1 *event_num=-1; return false; // at end of track } else { // not at end of track yet - get the time of the event MIDITimedBigMessage *msg; msg = track->GetEventAddress ( *event_num ); state.next_event_time[ track_num ] = msg->GetTime(); } return true; }
double MIDISequencer::GetMusicDurationInSeconds() { double event_time = 0.; // in milliseconds MIDITimedBigMessage ev; int ev_track; GoToZero(); while ( GetNextEvent( &ev_track, &ev ) ) { // std::cout << "MIDISequencer::GetMusicDurationInSeconds: " << EventAsText( ev ) << std::endl; // skip these events if ( ev.IsEndOfTrack() || ev.IsBeatMarker() ) continue; // end of music is the time of last not end of track midi event! event_time = GetCurrentTimeInMs(); } return ( 0.001 * event_time ); }
// delete all text events from multitrack object bool DeleteAllTracksText( MIDIMultiTrack &tracks ) { bool text_deleted = false; int num_tracks = tracks.GetNumTracksWithEvents(); for ( int nt = 0; nt < num_tracks; ++nt ) { MIDITrack &trk = *tracks.GetTrack( nt ); int num_events = trk.GetNumEvents(); for ( int ne = 0; ne < num_events; ++ne ) { MIDITimedBigMessage *msg = trk.GetEvent( ne ); // convert any text midi event to NoOp event if ( msg->IsTextEvent() ) { trk.MakeEventNoOp( ne ); text_deleted = true; } } } return text_deleted; }
void MIDIDriver::AllNotesOff ( int chan ) { MIDITimedBigMessage msg; // send a note off for every note on in the out_matrix if ( out_matrix.GetChannelCount ( chan ) > 0 ) { for ( int note = 0; note < 128; ++note ) { while ( out_matrix.GetNoteCount ( chan, note ) > 0 ) { // make a note off with note on msg, velocity 0 msg.SetNoteOn ( ( unsigned char ) chan, ( unsigned char ) note, 0 ); OutputMessage ( msg ); } } } msg.SetControlChange ( chan, C_DAMPER, 0 ); OutputMessage ( msg ); msg.SetAllNotesOff ( ( unsigned char ) chan ); OutputMessage ( msg ); }
void AdvancedSequencer::ExtractMarkers ( std::vector< std::string > *list ) { if ( !file_loaded ) { list->clear(); num_markers = 0; return; } MIDITrack *t = tracks.GetTrack ( 0 ); list->clear(); int cnt = 0; int measure = 0; int beat = 0; int timesig_numerator = 4; int timesig_denominator = 4; MIDIClockTime last_beat_time = 0; MIDIClockTime last_event_time = 0; int clks_per_beat = tracks.GetClksPerBeat(); for ( int i = 0; i < t->GetNumEvents(); ++i ) { MIDITimedBigMessage *m = t->GetEventAddress ( i ); if ( m ) { // how many beats have gone by since the last event? long beats_gone_by = ( m->GetTime() - last_beat_time ) / clks_per_beat; if ( beats_gone_by > 0 ) { // calculate what our new measure/beat is beat += beats_gone_by; // carry over beat overflow to measure measure += beat / timesig_numerator; beat = beat % timesig_numerator; last_beat_time += ( clks_per_beat * beats_gone_by ); } if ( m->IsMetaEvent() && m->IsTimeSig() ) { timesig_numerator = m->GetTimeSigNumerator(); timesig_denominator = m->GetTimeSigDenominator(); clks_per_beat = tracks.GetClksPerBeat() * 4 / timesig_denominator; } if ( m->IsTextEvent() && m->GetSysEx() ) { if ( ( m->GetMetaType() == META_GENERIC_TEXT ) || m->GetMetaType() == META_MARKER_TEXT || m->GetMetaType() == META_CUE_TEXT ) { char buf[256]; char line[256]; memcpy ( buf, m->GetSysEx()->GetBuf(), m->GetSysEx()->GetLength() ); buf[ m->GetSysEx()->GetLength() ] = '\0'; FixQuotes ( buf ); sprintf ( line, "%03d:%d %s", measure + 1, beat + 1, buf ); list->push_back ( std::string ( line ) ); marker_times[ cnt++ ] = m->GetTime(); } } last_event_time = m->GetTime(); } } num_markers = cnt; }
void MIDIMultiTrackIterator::GoToTime ( MIDIClockTime time ) { // start at time 0 state.Reset(); // transfer info from the first events in each track in the // multitrack object to our current state. for ( int i=0; i<multitrack->GetNumTracks(); ++i ) { MIDITrack *track = multitrack->GetTrack ( i ); // default: set the next_event_number for this track to -1 // to signify end of track state.next_event_number[ i ] = -1; // are there any events in this track? if ( track && track->GetNumEvents() >0 ) { // yes, extract the time of the first event MIDITimedBigMessage *msg = track->GetEventAddress ( 0 ); if ( msg ) { // found the first message of the track. Keep track // of the event number and the event time. state.next_event_number[i]=0; state.next_event_time[i]=msg->GetTime(); } } } // are there any events at all? find the track with the // earliest event if ( state.FindTrackOfFirstEvent() !=-1 ) { // yes // iterate through all the events until we find a time >= the requested time while ( state.GetCurrentTime() <time ) { // did not get to the requested time yet. // go to the next chronological event on all tracks if ( !GoToNextEvent() ) { // there is no more events to go to break; } } } }
void MIDITrack::ClearAndMerge( const MIDITrack *src1, const MIDITrack *src2 ) { Clear(); const MIDITimedBigMessage *ev1; int cur_trk1ev=0; int num_trk1ev = src1->GetNumEvents(); const MIDITimedBigMessage *ev2; int cur_trk2ev=0; int num_trk2ev = src2->GetNumEvents(); MIDIClockTime last_data_end_time=0; while( cur_trk1ev<num_trk1ev || cur_trk2ev<num_trk2ev ) { // skip any NOPs on track 1 ev1=src1->GetEventAddress( cur_trk1ev ); ev2=src2->GetEventAddress( cur_trk2ev ); bool has_ev1 = (cur_trk1ev<num_trk1ev) && ev1; bool has_ev2 = (cur_trk2ev<num_trk2ev) && ev2; if( has_ev1 && ev1->IsNoOp() ) { cur_trk1ev++; continue; } // skip any NOPs on track 2 if( has_ev2 && ev2->IsNoOp() ) { cur_trk2ev++; continue; } // skip all data end if( has_ev1 && ev1->IsDataEnd() ) { if( ev1->GetTime() > last_data_end_time ) { last_data_end_time = ev1->GetTime(); } cur_trk1ev++; continue; } if( has_ev2 && ev2->IsDataEnd() ) { if( ev2->GetTime() > last_data_end_time ) { last_data_end_time = ev2->GetTime(); } cur_trk2ev++; continue; } if( (has_ev1 && !has_ev2) ) { // nothing left on trk 2 if( !ev1->IsNoOp()) { if( ev1->GetTime() > last_data_end_time ) { last_data_end_time = ev1->GetTime(); } PutEvent( *ev1 ); ++cur_trk1ev; } } else if( (!has_ev1 && has_ev2) ) { // nothing left on trk 1 if( !ev2->IsNoOp() ) { PutEvent( *ev2 ); ++cur_trk2ev; } } else if( has_ev1 && has_ev2 ) { int trk=1; if( (ev1->GetTime() <= ev2->GetTime()) ) { trk=1; } else { trk=2; } if( trk==1 ) { if( ev1->GetTime() > last_data_end_time ) { last_data_end_time = ev1->GetTime(); } PutEvent( *ev1 ); ++cur_trk1ev; } else { if( ev2->GetTime() > last_data_end_time ) { last_data_end_time = ev2->GetTime(); } PutEvent( *ev2 ); ++cur_trk2ev; } } } // put single final data end event MIDITimedBigMessage dataend; dataend.SetTime( last_data_end_time ); dataend.SetDataEnd(); PutEvent( dataend ); }
void SoloMelodyConverter( const MIDIMultiTrack &src, MIDIMultiTrack &dst, int ignore_channel ) { // this simple code works better for src MultiTrack with 1 track, // if not, we can make before the call of CollapseMultiTrack() dst.ClearAndResize( src.GetNumTracks() ); dst.SetClksPerBeat( src.GetClksPerBeat() ); MIDIClockTime ev_time = 0; MIDISequencer seq( &src ); seq.GoToTime( 0 ); if ( !seq.GetNextEventTime ( &ev_time ) ) return; // empty src multitrack MIDITimedBigMessage ev; int ev_track; int solo_note = -1; // highest midi note number in current time, valid values 0...127 bool solo_note_on = false; MIDITimedBigMessage solo_note_on_ev; // last solo note on event solo_note_on_ev.SetNoOp(); while ( seq.GetNextEvent( &ev_track, &ev ) ) { if ( ev.IsServiceMsg() || ev.IsNoOp() ) continue; if ( ev.IsChannelEvent() ) { if ( ev.GetChannel() == ignore_channel ) continue; // if ( ev.IsAllNotesOff() ) ... ; // for future work... if ( ev.IsNote() ) { int new_note = ev.GetNote(); // skip all note events if new note lower than solo note if ( new_note < solo_note ) continue; // else ( new_note >= solo_note ) if ( ev.ImplicitIsNoteOn() ) // new note on event { if ( solo_note_on ) // new note on after previous solo note on { // make noteoff message for previous solo note solo_note_on_ev.SetTime( ev.GetTime() ); solo_note_on_ev.SetVelocity( 0 ); // note off dst.GetTrack(ev_track)->PutEvent( solo_note_on_ev ); // make new solo note solo_note_on_ev = ev; solo_note = new_note; } else // ( solo_note_on == false ) - new note on after previous silence { // make new solo note solo_note_on = true; solo_note_on_ev = ev; solo_note = new_note; } } else // new note off event ( new_note >= solo_note ) { if ( solo_note_on ) // new note off after previous solo note on { if ( new_note == solo_note ) // solo note off event { // test channels of the events if ( ev.GetChannel() == solo_note_on_ev.GetChannel() ) { solo_note_on = false; solo_note = -1; // erase solo_note } else continue; // skip other note off stuff } else // ( new_note > solo_note ) any other note off event continue; // skip other note off stuff } else // ( solo_note_on == false ) - new note off after previous silence continue; // skip other note off stuff } } } dst.GetTrack(ev_track)->PutEvent(ev); } }