2 // midi-track.cc -- implement Midi_track
4 // copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
8 Midi_track::Midi_track( int number_i, String copyright_str, String track_name_str, String instrument_str )
11 copyright_str_ = copyright_str;
12 instrument_str_ = instrument_str;
13 name_str_ = track_name_str;
14 midi_time_p_ = new Midi_time( 4, 2, 24, 8 );
15 midi_tempo_p_ = new Midi_tempo( 1000000 );
18 tcol_p_list_.bottom().add( new Track_column( Moment( 0 ) ) );
20 tcol_p_array_.push( new Track_column( Moment( 0 ) ) );
24 Midi_track::~Midi_track()
32 Midi_track::add_begin_at( Link_list<Midi_voice*>& open_voices_r, Moment mom )
34 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
35 if ( i->begin_mom() == mom ) {
36 tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): +1\n";
37 open_voices_r.bottom().add( *i );
42 Midi_track::add_begin_at( Array<Midi_voice*>& open_voices_r, Moment mom )
44 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
45 if ( midi_voice_p_array_[ i ]->begin_mom() == mom ) {
46 tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): +1\n";
47 open_voices_r.push( midi_voice_p_array_[ i ] );
53 Midi_track::add_event( Moment mom, Midi_event* midi_event_p )
57 tcol_l( mom - midi_event_p->mom() )->add_event( midi_event_p );
61 Midi_track::check_begin_bar_i( Moment now_mom, int open_bar_i )
63 Moment bar_mom = midi_time_p_->bar_mom();
64 int bar_i = (int)( now_mom / bar_mom ) + 1;
65 if ( bar_i > open_bar_i ) {
66 tor( NORMAL_ver ) << '[' << flush;
73 Midi_track::check_end_bar_i( Moment now_mom, int open_bar_i )
75 Moment bar_mom = midi_time_p_->bar_mom();
76 int bar_i = (int)( now_mom / bar_mom ) + 1;
77 if ( bar_i > open_bar_i ) {
78 tor( NORMAL_ver ) << ']' << flush;
90 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
91 mom = i->end_mom() >? mom;
93 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
94 mom = midi_voice_p_array_[ i ]->end_mom() >? mom;
100 Midi_track::get_free_midi_voice_l( Moment mom )
104 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) {
105 Real e = i->end_mom();
106 if ( i->end_mom() == mom )
110 Midi_voice* midi_voice_p = new Midi_voice( mom );
111 Midi_voice* midi_voice_l = midi_voice_p;
112 midi_voice_p_list_.bottom().add( midi_voice_p );
116 for ( int i = 0; i < midi_voice_p_array_.size(); i++ ) {
117 Real e = i->end_mom();
118 if ( midi_voice_p_array_[ i ]->end_mom() == mom )
119 return midi_voice_p_array_[ i ];
122 Midi_voice* midi_voice_p = new Midi_voice( mom );
123 Midi_voice* midi_voice_l = midi_voice_p;
124 midi_voice_p_array_.push( midi_voice_p );
130 Midi_track::name_str()
132 if ( name_str_.length_i() )
134 return String( "track" ) + String( number_i_ );
138 Midi_track::next_begin_mom( Moment now_mom )
140 // Moment begin_mom = Midi_track::end_mom() + 1;
141 Moment begin_mom = Midi_track::end_mom();
143 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
144 // if ( i->begin_mom() >= now_mom )// well, which one ?
145 if ( i->begin_mom() > now_mom )
146 begin_mom = begin_mom <? i->begin_mom();
148 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
149 if ( midi_voice_p_array_[ i ]->begin_mom() >= now_mom ) // well, which one ?
150 if ( midi_voice_p_array_[ i ]->begin_mom() > now_mom )
151 // begin_mom = begin_mom <? midi_voice_p_array_[ i ]->begin_mom();
157 Midi_track::next_end_mom( Moment now_mom )
159 Moment end_mom = Midi_track::end_mom();
161 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
162 if ( i->end_mom() > now_mom )
163 end_mom = end_mom <? i->end_mom();
165 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
166 // if ( midi_voice_p_array_[ i ]->end_mom() >= now_mom )
167 if ( midi_voice_p_array_[ i ]->end_mom() > now_mom )
168 end_mom = end_mom <? midi_voice_p_array_[ i ]->end_mom();
174 Midi_track::process()
182 for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
183 int begin_bar_i = check_begin_bar_i( i->mom(), bar_i );
185 tor( NORMAL_ver ) << begin_bar_i << flush;
186 while ( i->midi_event_p_list_.size() )
187 get_free_midi_voice_l( i->mom() )->add_event( i->midi_event_p_list_.top().remove_p() );
188 bar_i = check_end_bar_i( i->mom(), bar_i );
191 for ( int i = 0; i < tcol_p_array_.size(); i++ ) {
192 Track_column* tcol_l = tcol_p_array_[ i ];
193 int begin_bar_i = check_begin_bar_i( tcol_l->mom(), bar_i );
195 tor( NORMAL_ver ) << begin_bar_i << flush;
197 while ( tcol_l->midi_event_p_list_.size() )
198 get_free_midi_voice_l( tcol_l->mom() )->add_event( tcol_l->midi_event_p_list_.top().remove_p() );
200 // what's efficient here?
201 #if 0 // heu, what's different here?
202 while ( tcol_l->midi_event_p_array_.size() ) {
203 get_free_midi_voice_l( tcol_l->mom() )->add_event( tcol_l->midi_event_p_array_[ 0 ] );
204 tcol_l->midi_event_p_array_.del( 0 );
207 for ( int j = 0; j < tcol_l->midi_event_p_array_.size(); j++ ) {
208 get_free_midi_voice_l( tcol_l->mom() )->add_event( tcol_l->midi_event_p_array_[ j ] );
209 tcol_l->midi_event_p_array_[ j ] = 0;
211 tcol_l->midi_event_p_array_.clear();
214 bar_i = check_end_bar_i( tcol_l->mom(), bar_i );
218 tor( DEBUG_ver ) << "ends: " << endl;
221 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
222 tor( VERBOSE_ver ) << "voice " << n++ << ": " << i->end_mom() << endl;
224 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
225 tor( VERBOSE_ver ) << "voice " << n++ << ": " << midi_voice_p_array_[ i ]->end_mom() << endl;
227 tor( DEBUG_ver ) << ":sdne" << endl;
232 Midi_track::output_mudela( Lily_stream& lily_stream_r )
234 lily_stream_r << name_str() << " = \\melodic{";
235 lily_stream_r.indent();
236 lily_stream_r << "% midi copyright:" << copyright_str_;
237 lily_stream_r.newline();
238 lily_stream_r << "% instrument:" << instrument_str_;
239 lily_stream_r.newline();
245 Link_list<Midi_voice*> open_voices;
247 Array<Midi_voice*> open_voices;
249 Moment now_mom = 0.0;
250 Real now_f = now_mom;
252 Real end_f = end_mom();
256 now we step through time while writing all voices
258 we can only output time slices that have a constant
259 number of open voices; each begin or end of a voice
260 starts or ends a chord or multivoice
263 voice defragmentation/concatenation could make this
267 bool start_of_track_bo = true;
269 /// ugh, avoid status track 0 full of rests...
270 while ( number_i_ && ( now_mom < end_mom() ) ) {
271 int begin_bar_i = check_begin_bar_i( now_mom, bar_i );
273 output_mudela_begin_bar( lily_stream_r, now_mom, begin_bar_i );
274 add_begin_at( open_voices, now_mom );
276 Moment begin_mom = next_begin_mom( now_mom );
279 tor( NORMAL_ver ) << begin_bar_i << flush;
281 Moment end_mom = next_end_mom( now_mom );
282 Moment then_mom = 0.0;
283 if ( ( begin_mom > now_mom ) && ( begin_mom < end_mom ) )
284 then_mom = begin_mom;
288 tor( DEBUG_ver ) << "begin: " << begin_mom << " end: " << end_mom << endl;
289 tor( DEBUG_ver ) << "slice: " << now_mom << ", " << then_mom << endl;
297 // checking for no open voice does not work for initial rests.
298 // for some reason the voice is open, but does not procuce notes?
299 if ( open_voices.size() > 1 )
300 lily_stream_r << "< ";
301 if ( start_of_track_bo ) {
302 start_of_track_bo = false;
305 for ( PCursor<Midi_voice*> i( open_voices.top() ); i.ok(); i++ )
306 lily_stream_r << i->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
308 for ( int i = 0; i < open_voices.size(); i++ )
309 lily_stream_r << open_voices[ i ]->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
311 if ( str.length_i() )
312 lily_stream_r << str;
314 output_mudela_rest( lily_stream_r, now_mom, then_mom );
318 for ( PCursor<Midi_voice*> i( open_voices.top() ); i.ok(); i++ )
319 lily_stream_r << i->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
321 for ( int i = 0; i < open_voices.size(); i++ )
322 lily_stream_r << open_voices[ i ]->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
324 if ( !open_voices.size() )
325 output_mudela_rest( lily_stream_r, now_mom, then_mom );
327 // *lily_stream_r.os_p_ << flush;
329 if ( open_voices.size() > 1 )
330 lily_stream_r << "> ";
331 remove_end_at( open_voices, then_mom );
333 bar_i = check_end_bar_i( now_mom, bar_i );
338 // tor( NORMAL_ver ) << '[' << bar_i << ']' << flush;
340 lily_stream_r.tnedni();
341 lily_stream_r << "} % " << name_str();
342 lily_stream_r.newline();
347 Midi_track::output_mudela_begin_bar( Lily_stream& lily_stream_r, Moment now_mom, int bar_i )
349 Moment bar_mom = midi_time_p_->bar_mom();
350 Moment into_bar_mom = now_mom - Moment( bar_i - 1 ) * bar_mom;
353 lily_stream_r << "|";
354 lily_stream_r.newline();
356 lily_stream_r << "% " << String_convert::i2dec_str( bar_i, 0, ' ' );
358 lily_stream_r << ":" << Duration_convert::dur2_str( Duration_convert::mom2_dur( into_bar_mom ) );
359 lily_stream_r.newline();
364 Midi_track::output_mudela_rest( Lily_stream& lily_stream_r, Moment begin_mom, Moment end_mom )
366 Moment bar_mom = midi_time_p_->bar_mom();
367 Moment now_mom = begin_mom;
369 int begin_bar_i = (int)( now_mom / bar_mom ) + 1;
370 int end_bar_i = (int)( end_mom / bar_mom ) + 1;
372 if ( end_bar_i == begin_bar_i ) {
373 output_mudela_rest_remain( lily_stream_r, end_mom - begin_mom );
377 // multiple bars involved
378 int bar_i = (int)( now_mom / bar_mom ) + 1;
381 Moment begin_bar_mom = Moment( begin_bar_i - 1 ) * bar_mom;
382 if ( now_mom > begin_bar_mom ) {
383 int next_bar_i = (int)( now_mom / bar_mom ) + 2;
384 Moment next_bar_mom = Moment( next_bar_i - 1 ) * bar_mom;
385 assert( next_bar_mom <= end_mom );
387 Moment remain_mom = next_bar_mom - now_mom;
388 if ( remain_mom > Moment( 0 ) ) {
389 output_mudela_rest_remain( lily_stream_r, remain_mom );
390 now_mom += remain_mom;
393 bar_i = check_end_bar_i( now_mom, bar_i );
397 int count_i = end_bar_i - bar_i;
398 for ( int i = 0; i < count_i; i++ ) {
399 int begin_bar_i = check_begin_bar_i( now_mom, bar_i );
401 output_mudela_begin_bar( lily_stream_r, now_mom, begin_bar_i );
402 lily_stream_r << "r1 ";
403 // *lily_stream_r.os_p_ << flush;
405 tor( NORMAL_ver ) << begin_bar_i << flush;
406 bar_i = check_end_bar_i( now_mom, bar_i );
410 // use "int i" here, and gcc 2.7.2 hits internal compiler error
411 int ii = check_begin_bar_i( now_mom, bar_i );
413 output_mudela_begin_bar( lily_stream_r, now_mom, ii );
415 // bar_i = check_end_bar_i( now_mom, bar_i );
417 Moment remain_mom = end_mom - Moment( end_bar_i - 1 ) * bar_mom;
418 if ( remain_mom > Moment( 0 ) ) {
419 output_mudela_rest_remain( lily_stream_r, remain_mom );
420 now_mom += remain_mom;
422 assert( now_mom == end_mom );
426 Midi_track::output_mudela_rest_remain( Lily_stream& lily_stream_r, Moment mom )
428 if ( Duration_convert::no_quantify_b_s ) {
429 Duration dur = Duration_convert::mom2_dur( mom );
430 lily_stream_r << "r" << dur.str() << " ";
431 // assert( mom == dur.mom() );
432 assert( mom == dur.length() );
436 Duration dur = Duration_convert::mom2standardised_dur( mom );
438 lily_stream_r << "r" << dur.str() << " ";
444 Midi_track::remove_end_at( Link_list<Midi_voice*>& open_voices_r, Moment mom )
446 for ( PCursor<Midi_voice*> i( open_voices_r.top() ); i.ok(); i++ )
447 // if ( i->end_mom() == mom ) { }
448 if ( i->end_mom() <= mom ) {
449 tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): -1\n";
457 Midi_track::remove_end_at( Array<Midi_voice*>& open_voices_r, Moment mom )
459 for ( int i = 0; i < open_voices_r.size(); i++ )
460 if ( midi_voice_p_array_[ i ]->end_mom() <= mom ) {
461 tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): -1\n";
462 open_voices_r[ i ] = 0;
463 // open_voices_r.del( i-- );
464 open_voices_r.del( i );
470 Midi_track::set_tempo( int useconds_per_4_i )
472 delete midi_tempo_p_;
473 midi_tempo_p_ = new Midi_tempo( useconds_per_4_i );
477 Midi_track::set_time( int num_i, int den_i, int clocks_i, int count_32_i )
480 midi_time_p_ = new Midi_time( num_i, den_i, clocks_i, count_32_i );
484 Midi_track::tcol_l( Moment mom )
487 for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
488 if ( i->mom() > mom ) { //not used, let's use array!
490 Track_column* tcol_p = new Track_column( mom );
494 if ( i->mom() == mom )
498 Track_column* tcol_p = new Track_column( mom );
499 tcol_p_list_.bottom().add( tcol_p );
502 for ( int i = 0; i < tcol_p_array_.size(); i++ )
503 if ( tcol_p_array_[ i ]->mom() == mom )
504 return tcol_p_array_[ i ];
506 Track_column* tcol_p = new Track_column( mom );
507 tcol_p_array_.push( tcol_p );
511 as "insert" is never called, the right column will
512 always be found, unless mom > tcol_p_array[ i ]->mom().
514 int upper_i = max( 0, tcol_p_array_.size() - 1 );
518 Moment i_mom = tcol_p_array_[ i ]->mom();
520 return tcol_p_array_[ i ];
525 if ( ( upper_i == lower_i ) || ( i == tcol_p_array_.size() - 1 ) ) {
526 // huh? assert ( upper_i == tcol_p_array_.size() );
527 Track_column* tcol_p = new Track_column( mom );
528 tcol_p_array_.push( tcol_p );
531 i = ( upper_i + lower_i + 1 ) / 2;