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 );
17 tcol_p_list_.bottom().add( new Track_column( Moment( 0 ) ) );
19 tcol_p_array_.push( new Track_column( Moment( 0 ) ) );
23 Midi_track::~Midi_track()
31 Midi_track::add_begin_at( Link_list<Midi_voice*>& open_voices_r, Moment mom )
33 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
34 if ( i->begin_mom() == mom ) {
35 tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): +1\n";
36 open_voices_r.bottom().add( *i );
41 Midi_track::add_begin_at( Array<Midi_voice*>& open_voices_r, Moment mom )
43 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
44 if ( midi_voice_p_array_[ i ]->begin_mom() == mom ) {
45 tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): +1\n";
46 open_voices_r.push( midi_voice_p_array_[ i ] );
52 Midi_track::add_event( Moment mom, Midi_event* midi_event_p )
56 tcol_l( mom - midi_event_p->mom() )->add_event( midi_event_p );
60 Midi_track::check_begin_bar_i( Moment now_mom, int open_bar_i )
62 Moment bar_mom = midi_time_p_->bar_mom();
63 int bar_i = (int)( now_mom / bar_mom ) + 1;
64 if ( bar_i > open_bar_i ) {
65 tor( NORMAL_ver ) << '[' << flush;
72 Midi_track::check_end_bar_i( Moment now_mom, int open_bar_i )
74 Moment bar_mom = midi_time_p_->bar_mom();
75 int bar_i = (int)( now_mom / bar_mom ) + 1;
76 if ( bar_i > open_bar_i ) {
77 tor( NORMAL_ver ) << ']' << flush;
89 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
90 mom = i->end_mom() >? mom;
92 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
93 mom = midi_voice_p_array_[ i ]->end_mom() >? mom;
99 Midi_track::get_free_midi_voice_l( Moment mom )
103 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) {
104 Real e = i->end_mom();
105 if ( i->end_mom() == mom )
109 Midi_voice* midi_voice_p = new Midi_voice( mom );
110 Midi_voice* midi_voice_l = midi_voice_p;
111 midi_voice_p_list_.bottom().add( midi_voice_p );
115 for ( int i = 0; i < midi_voice_p_array_.size(); i++ ) {
116 Real e = i->end_mom();
117 if ( midi_voice_p_array_[ i ]->end_mom() == mom )
118 return midi_voice_p_array_[ i ];
121 Midi_voice* midi_voice_p = new Midi_voice( mom );
122 Midi_voice* midi_voice_l = midi_voice_p;
123 midi_voice_p_array_.push( midi_voice_p );
129 Midi_track::name_str()
131 if ( name_str_.length_i() )
133 return String( "track" ) + String( number_i_ );
137 Midi_track::next_begin_mom( Moment now_mom )
139 // Moment begin_mom = Midi_track::end_mom() + 1;
140 Moment begin_mom = Midi_track::end_mom();
142 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
143 if ( i->begin_mom() > now_mom )
144 begin_mom = begin_mom <? i->begin_mom();
146 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
147 if ( midi_voice_p_array_[ i ]->begin_mom() > now_mom )
148 begin_mom = begin_mom <? midi_voice_p_array_[ i ]->begin_mom();
154 Midi_track::next_end_mom( Moment now_mom )
156 Moment end_mom = Midi_track::end_mom();
158 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
159 if ( i->end_mom() > now_mom )
160 end_mom = end_mom <? i->end_mom();
162 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
163 if ( midi_voice_p_array_[ i ]->end_mom() > now_mom )
164 end_mom = end_mom <? midi_voice_p_array_[ i ]->end_mom();
170 Midi_track::process()
178 for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
179 int begin_bar_i = check_begin_bar_i( i->mom(), bar_i );
181 tor( NORMAL_ver ) << begin_bar_i << flush;
182 while ( i->midi_event_p_list_.size() )
183 get_free_midi_voice_l( i->mom() )->add_event( i->midi_event_p_list_.top().remove_p() );
184 bar_i = check_end_bar_i( i->mom(), bar_i );
187 for ( int i = 0; i < tcol_p_array_.size(); i++ ) {
188 Track_column* tcol_l = tcol_p_array_[ i ];
189 int begin_bar_i = check_begin_bar_i( tcol_l->mom(), bar_i );
191 tor( NORMAL_ver ) << begin_bar_i << flush;
193 while ( tcol_l->midi_event_p_list_.size() )
194 get_free_midi_voice_l( tcol_l->mom() )->add_event( tcol_l->midi_event_p_list_.top().remove_p() );
196 // what's efficient here?
197 #if 0 // heu, what's different here?
198 while ( tcol_l->midi_event_p_array_.size() ) {
199 get_free_midi_voice_l( tcol_l->mom() )->add_event( tcol_l->midi_event_p_array_[ 0 ] );
200 tcol_l->midi_event_p_array_.del( 0 );
203 for ( int j = 0; j < tcol_l->midi_event_p_array_.size(); j++ ) {
204 get_free_midi_voice_l( tcol_l->mom() )->add_event( tcol_l->midi_event_p_array_[ j ] );
205 tcol_l->midi_event_p_array_[ j ] = 0;
207 tcol_l->midi_event_p_array_.clear();
210 bar_i = check_end_bar_i( tcol_l->mom(), bar_i );
214 tor( DEBUG_ver ) << "ends: " << endl;
217 for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
218 tor( VERBOSE_ver ) << "voice " << n++ << ": " << i->end_mom() << endl;
220 for ( int i = 0; i < midi_voice_p_array_.size(); i++ )
221 tor( VERBOSE_ver ) << "voice " << n++ << ": " << midi_voice_p_array_[ i ]->end_mom() << endl;
223 tor( DEBUG_ver ) << ":sdne" << endl;
228 Midi_track::output_mudela( Lily_stream& lily_stream_r )
230 lily_stream_r << name_str() << " = \\melodic{";
231 lily_stream_r.indent();
232 lily_stream_r << "% midi copyright:" << copyright_str_;
233 lily_stream_r.newline();
234 lily_stream_r << "% instrument:" << instrument_str_;
235 lily_stream_r.newline();
241 Link_list<Midi_voice*> open_voices;
243 Array<Midi_voice*> open_voices;
245 Moment now_mom = 0.0;
246 Real now_f = now_mom;
248 Real end_f = end_mom();
252 now we step through time while writing all voices
254 we can only output time slices that have a constant
255 number of open voices; each begin or end of a voice
256 starts or ends a chord or multivoice
259 voice defragmentation/concatenation could make this
263 bool start_of_track_bo = true;
265 /// ugh, avoid status track 0 full of rests...
266 while ( number_i_ && ( now_mom < end_mom() ) ) {
267 int begin_bar_i = check_begin_bar_i( now_mom, bar_i );
269 output_mudela_begin_bar( lily_stream_r, now_mom, begin_bar_i );
270 add_begin_at( open_voices, now_mom );
272 Moment begin_mom = next_begin_mom( now_mom );
275 tor( NORMAL_ver ) << begin_bar_i << flush;
277 Moment end_mom = next_end_mom( now_mom );
278 Moment then_mom = 0.0;
279 if ( ( begin_mom > now_mom ) && ( begin_mom < end_mom ) )
280 then_mom = begin_mom;
284 tor( DEBUG_ver ) << "begin: " << begin_mom << " end: " << end_mom << endl;
285 tor( DEBUG_ver ) << "slice: " << now_mom << ", " << then_mom << endl;
293 // checking for no open voice does not work for initial rests.
294 // for some reason the voice is open, but does not procuce notes?
295 if ( open_voices.size() > 1 )
296 lily_stream_r << "< ";
297 if ( start_of_track_bo ) {
298 start_of_track_bo = false;
301 for ( PCursor<Midi_voice*> i( open_voices.top() ); i.ok(); i++ )
302 lily_stream_r << i->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
304 for ( int i = 0; i < open_voices.size(); i++ )
305 lily_stream_r << open_voices[ i ]->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
307 if ( str.length_i() )
308 lily_stream_r << str;
310 output_mudela_rest( lily_stream_r, now_mom, then_mom );
314 for ( PCursor<Midi_voice*> i( open_voices.top() ); i.ok(); i++ )
315 lily_stream_r << i->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
317 for ( int i = 0; i < open_voices.size(); i++ )
318 lily_stream_r << open_voices[ i ]->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
320 if ( !open_voices.size() )
321 output_mudela_rest( lily_stream_r, now_mom, then_mom );
323 // *lily_stream_r.os_p_ << flush;
325 if ( open_voices.size() > 1 )
326 lily_stream_r << "> ";
327 remove_end_at( open_voices, then_mom );
329 bar_i = check_end_bar_i( now_mom, bar_i );
334 // tor( NORMAL_ver ) << '[' << bar_i << ']' << flush;
336 lily_stream_r.tnedni();
337 lily_stream_r << "} % " << name_str();
338 lily_stream_r.newline();
343 Midi_track::output_mudela_begin_bar( Lily_stream& lily_stream_r, Moment now_mom, int bar_i )
345 Moment bar_mom = midi_time_p_->bar_mom();
346 Moment into_bar_mom = now_mom - Moment( bar_i - 1 ) * bar_mom;
349 lily_stream_r << "|";
350 lily_stream_r.newline();
352 lily_stream_r << "% " << String_convert::i2dec_str( bar_i, 0, ' ' );
354 lily_stream_r << ":" << Duration_convert::dur2_str( Duration_convert::mom2_dur( into_bar_mom ) );
355 lily_stream_r.newline();
360 Midi_track::output_mudela_rest( Lily_stream& lily_stream_r, Moment begin_mom, Moment end_mom )
362 Moment bar_mom = midi_time_p_->bar_mom();
363 Moment now_mom = begin_mom;
365 int begin_bar_i = (int)( now_mom / bar_mom ) + 1;
366 int end_bar_i = (int)( end_mom / bar_mom ) + 1;
368 if ( end_bar_i == begin_bar_i ) {
369 output_mudela_rest_remain( lily_stream_r, end_mom - begin_mom );
373 // multiple bars involved
374 int bar_i = (int)( now_mom / bar_mom ) + 1;
377 Moment begin_bar_mom = Moment( begin_bar_i - 1 ) * bar_mom;
378 if ( now_mom > begin_bar_mom ) {
379 int next_bar_i = (int)( now_mom / bar_mom ) + 2;
380 Moment next_bar_mom = Moment( next_bar_i - 1 ) * bar_mom;
381 assert( next_bar_mom <= end_mom );
383 Moment remain_mom = next_bar_mom - now_mom;
384 if ( remain_mom > Moment( 0 ) ) {
385 output_mudela_rest_remain( lily_stream_r, remain_mom );
386 now_mom += remain_mom;
389 bar_i = check_end_bar_i( now_mom, bar_i );
393 int count_i = end_bar_i - bar_i;
394 for ( int i = 0; i < count_i; i++ ) {
395 int begin_bar_i = check_begin_bar_i( now_mom, bar_i );
397 output_mudela_begin_bar( lily_stream_r, now_mom, begin_bar_i );
398 lily_stream_r << "r1 ";
399 // *lily_stream_r.os_p_ << flush;
401 tor( NORMAL_ver ) << begin_bar_i << flush;
402 bar_i = check_end_bar_i( now_mom, bar_i );
406 // use "int i" here, and gcc 2.7.2 hits internal compiler error
407 int ii = check_begin_bar_i( now_mom, bar_i );
409 output_mudela_begin_bar( lily_stream_r, now_mom, ii );
411 // bar_i = check_end_bar_i( now_mom, bar_i );
413 Moment remain_mom = end_mom - Moment( end_bar_i - 1 ) * bar_mom;
414 if ( remain_mom > Moment( 0 ) ) {
415 output_mudela_rest_remain( lily_stream_r, remain_mom );
416 now_mom += remain_mom;
418 assert( now_mom == end_mom );
422 Midi_track::output_mudela_rest_remain( Lily_stream& lily_stream_r, Moment mom )
424 if ( Duration_convert::no_quantify_b_s ) {
425 Duration dur = Duration_convert::mom2_dur( mom );
426 lily_stream_r << "r" << dur.str() << " ";
427 // assert( mom == dur.mom() );
428 assert( mom == dur.length() );
432 Duration dur = Duration_convert::mom2standardised_dur( mom );
434 lily_stream_r << "r" << dur.str() << " ";
440 Midi_track::remove_end_at( Link_list<Midi_voice*>& open_voices_r, Moment mom )
442 for ( PCursor<Midi_voice*> i( open_voices_r.top() ); i.ok(); i++ )
443 if ( i->end_mom() <= mom ) {
444 tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): -1\n";
452 Midi_track::remove_end_at( Array<Midi_voice*>& open_voices_r, Moment mom )
454 for ( int i = 0; i < open_voices_r.size(); i++ )
455 if ( midi_voice_p_array_[ i ]->end_mom() <= mom ) {
456 tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): -1\n";
457 open_voices_r[ i ] = 0;
458 // open_voices_r.del( i-- );
459 open_voices_r.del( i );
465 Midi_track::set_tempo( int useconds_per_4_i )
467 delete midi_tempo_p_;
468 midi_tempo_p_ = new Midi_tempo( useconds_per_4_i );
472 Midi_track::set_time( int num_i, int den_i, int clocks_i, int count_32_i )
475 midi_time_p_ = new Midi_time( num_i, den_i, clocks_i, count_32_i );
479 Midi_track::tcol_l( Moment mom )
482 for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
483 if ( i->mom() > mom ) { //not used, let's use array!
485 // 97-07-21; it's used now! cannot use array
486 Track_column* tcol_p = new Track_column( mom );
490 if ( i->mom() == mom )
494 Track_column* tcol_p = new Track_column( mom );
495 tcol_p_list_.bottom().add( tcol_p );
498 for ( int i = 0; i < tcol_p_array_.size(); i++ )
499 if ( tcol_p_array_[ i ]->mom() == mom )
500 return tcol_p_array_[ i ];
502 Track_column* tcol_p = new Track_column( mom );
503 tcol_p_array_.push( tcol_p );
507 as "insert" is never called, the right column will
508 always be found, unless mom > tcol_p_array[ i ]->mom().
510 int upper_i = max( 0, tcol_p_array_.size() - 1 );
514 Moment i_mom = tcol_p_array_[ i ]->mom();
516 return tcol_p_array_[ i ];
521 if ( ( upper_i == lower_i ) || ( i == tcol_p_array_.size() - 1 ) ) {
522 // huh? assert ( upper_i == tcol_p_array_.size() );
523 Track_column* tcol_p = new Track_column( mom );
524 tcol_p_array_.push( tcol_p );
527 i = ( upper_i + lower_i + 1 ) / 2;