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
);
131 String str
= name_str();
132 for ( int i
= 0; i
< str
.length_i(); i
++ )
133 if ( ( !i
&& !isalpha( str
[ i
] ) )
134 || !isalnum( str
[ i
] ) )
135 *( str
.ch_l() + i
) = '_';
140 Midi_track::name_str()
142 if ( name_str_
.length_i() )
144 return String( "track" ) + String( number_i_
);
148 Midi_track::next_begin_mom( Moment now_mom
)
150 // Moment begin_mom = Midi_track::end_mom() + 1;
151 Moment begin_mom
= Midi_track::end_mom();
153 for ( PCursor
<Midi_voice
*> i( midi_voice_p_list_
.top() ); i
.ok(); i
++ )
154 if ( i
->begin_mom() > now_mom
)
155 begin_mom
= begin_mom
<? i
->begin_mom();
157 for ( int i
= 0; i
< midi_voice_p_array_
.size(); i
++ )
158 if ( midi_voice_p_array_
[ i
]->begin_mom() > now_mom
)
159 begin_mom
= begin_mom
<? midi_voice_p_array_
[ i
]->begin_mom();
165 Midi_track::next_end_mom( Moment now_mom
)
167 Moment end_mom
= Midi_track::end_mom();
169 for ( PCursor
<Midi_voice
*> i( midi_voice_p_list_
.top() ); i
.ok(); i
++ )
170 if ( i
->end_mom() > now_mom
)
171 end_mom
= end_mom
<? i
->end_mom();
173 for ( int i
= 0; i
< midi_voice_p_array_
.size(); i
++ )
174 if ( midi_voice_p_array_
[ i
]->end_mom() > now_mom
)
175 end_mom
= end_mom
<? midi_voice_p_array_
[ i
]->end_mom();
181 Midi_track::process()
189 for ( PCursor
<Track_column
*> i( tcol_p_list_
.top() ); i
.ok(); i
++ ) {
190 int begin_bar_i
= check_begin_bar_i( i
->mom(), bar_i
);
192 tor( NORMAL_ver
) << begin_bar_i
<< flush
;
193 while ( i
->midi_event_p_list_
.size() )
194 get_free_midi_voice_l( i
->mom() )->add_event( i
->midi_event_p_list_
.top().remove_p() );
195 bar_i
= check_end_bar_i( i
->mom(), bar_i
);
198 for ( int i
= 0; i
< tcol_p_array_
.size(); i
++ ) {
199 Track_column
* tcol_l
= tcol_p_array_
[ i
];
200 int begin_bar_i
= check_begin_bar_i( tcol_l
->mom(), bar_i
);
202 tor( NORMAL_ver
) << begin_bar_i
<< flush
;
204 while ( tcol_l
->midi_event_p_list_
.size() )
205 get_free_midi_voice_l( tcol_l
->mom() )->add_event( tcol_l
->midi_event_p_list_
.top().remove_p() );
207 // what's efficient here?
208 #if 0 // heu, what's different here?
209 while ( tcol_l
->midi_event_p_array_
.size() ) {
210 get_free_midi_voice_l( tcol_l
->mom() )->add_event( tcol_l
->midi_event_p_array_
[ 0 ] );
211 tcol_l
->midi_event_p_array_
.del( 0 );
214 for ( int j
= 0; j
< tcol_l
->midi_event_p_array_
.size(); j
++ ) {
215 get_free_midi_voice_l( tcol_l
->mom() )->add_event( tcol_l
->midi_event_p_array_
[ j
] );
216 tcol_l
->midi_event_p_array_
[ j
] = 0;
218 tcol_l
->midi_event_p_array_
.clear();
221 bar_i
= check_end_bar_i( tcol_l
->mom(), bar_i
);
225 tor( DEBUG_ver
) << "ends: " << endl
;
228 for ( PCursor
<Midi_voice
*> i( midi_voice_p_list_
.top() ); i
.ok(); i
++ )
229 tor( VERBOSE_ver
) << "voice " << n
++ << ": " << i
->end_mom() << endl
;
231 for ( int i
= 0; i
< midi_voice_p_array_
.size(); i
++ )
232 tor( VERBOSE_ver
) << "voice " << n
++ << ": " << midi_voice_p_array_
[ i
]->end_mom() << endl
;
234 tor( DEBUG_ver
) << ":sdne" << endl
;
238 Midi_track::output_mudela( Lily_stream
& lily_stream_r
)
240 lily_stream_r
<< "$" << id_str() << " = \\melodic{\n";
241 lily_stream_r
<< "% midi copyright:" << copyright_str_
<< "\n";
242 lily_stream_r
<< "% instrument:" << instrument_str_
<< "\n";
247 Link_list
<Midi_voice
*> open_voices
;
249 Array
<Midi_voice
*> open_voices
;
251 Moment now_mom
= 0.0;
252 Real now_f
= now_mom
;
254 Real end_f
= end_mom();
258 now we step through time while writing all voices
260 we can only output time slices that have a constant
261 number of open voices; each begin or end of a voice
262 starts or ends a chord or multivoice
265 voice defragmentation/concatenation could make this
269 bool start_of_track_bo
= true;
271 /// ugh, avoid status track 0 full of rests...
272 while ( number_i_
&& ( now_mom
< end_mom() ) ) {
273 int begin_bar_i
= check_begin_bar_i( now_mom
, bar_i
);
275 output_mudela_begin_bar( lily_stream_r
, now_mom
, begin_bar_i
);
276 add_begin_at( open_voices
, now_mom
);
278 Moment begin_mom
= next_begin_mom( now_mom
);
281 tor( NORMAL_ver
) << begin_bar_i
<< flush
;
283 Moment end_mom
= next_end_mom( now_mom
);
284 Moment then_mom
= 0.0;
285 if ( ( begin_mom
> now_mom
) && ( begin_mom
< end_mom
) )
286 then_mom
= begin_mom
;
290 tor( DEBUG_ver
) << "begin: " << begin_mom
<< " end: " << end_mom
<< endl
;
291 tor( DEBUG_ver
) << "slice: " << now_mom
<< ", " << then_mom
<< endl
;
299 // checking for no open voice does not work for initial rests.
300 // for some reason the voice is open, but does not procuce notes?
301 if ( open_voices
.size() > 1 )
302 lily_stream_r
<< "< ";
303 if ( start_of_track_bo
) {
304 start_of_track_bo
= false;
307 for ( PCursor
<Midi_voice
*> i( open_voices
.top() ); i
.ok(); i
++ )
308 lily_stream_r
<< i
->mudela_str( now_mom
, then_mom
, open_voices
.size() - 1 );
310 for ( int i
= 0; i
< open_voices
.size(); i
++ )
311 lily_stream_r
<< open_voices
[ i
]->mudela_str( now_mom
, then_mom
, open_voices
.size() - 1 );
313 if ( str
.length_i() )
314 lily_stream_r
<< str
;
316 output_mudela_rest( lily_stream_r
, now_mom
, then_mom
);
320 for ( PCursor
<Midi_voice
*> i( open_voices
.top() ); i
.ok(); i
++ )
321 lily_stream_r
<< i
->mudela_str( now_mom
, then_mom
, open_voices
.size() - 1 );
323 for ( int i
= 0; i
< open_voices
.size(); i
++ )
324 lily_stream_r
<< open_voices
[ i
]->mudela_str( now_mom
, then_mom
, open_voices
.size() - 1 );
326 if ( !open_voices
.size() )
327 output_mudela_rest( lily_stream_r
, now_mom
, then_mom
);
329 // *lily_stream_r.os_p_ << flush;
331 if ( open_voices
.size() > 1 )
332 lily_stream_r
<< "> ";
333 remove_end_at( open_voices
, then_mom
);
335 bar_i
= check_end_bar_i( now_mom
, bar_i
);
340 // tor( NORMAL_ver ) << '[' << bar_i << ']' << flush;
342 lily_stream_r
<< "} % " << name_str() << "\n";
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
<< "|\n";
355 lily_stream_r
<< "% " << String_convert::i2dec_str( bar_i
, 0, ' ' );
357 lily_stream_r
<< ":" << Duration_convert::dur2_str( Duration_convert::mom2_dur( into_bar_mom
) );
358 lily_stream_r
<< "\n";
363 Midi_track::output_mudela_rest( Lily_stream
& lily_stream_r
, Moment begin_mom
, Moment end_mom
)
365 Moment bar_mom
= midi_time_p_
->bar_mom();
366 Moment now_mom
= begin_mom
;
368 int begin_bar_i
= (int)( now_mom
/ bar_mom
) + 1;
369 int end_bar_i
= (int)( end_mom
/ bar_mom
) + 1;
371 if ( end_bar_i
== begin_bar_i
) {
372 output_mudela_rest_remain( lily_stream_r
, end_mom
- begin_mom
);
376 // multiple bars involved
377 int bar_i
= (int)( now_mom
/ bar_mom
) + 1;
380 Moment begin_bar_mom
= Moment( begin_bar_i
- 1 ) * bar_mom
;
381 if ( now_mom
> begin_bar_mom
) {
382 int next_bar_i
= (int)( now_mom
/ bar_mom
) + 2;
383 Moment next_bar_mom
= Moment( next_bar_i
- 1 ) * bar_mom
;
384 assert( next_bar_mom
<= end_mom
);
386 Moment remain_mom
= next_bar_mom
- now_mom
;
387 if ( remain_mom
> Moment( 0 ) ) {
388 output_mudela_rest_remain( lily_stream_r
, remain_mom
);
389 now_mom
+= remain_mom
;
392 bar_i
= check_end_bar_i( now_mom
, bar_i
);
396 int count_i
= end_bar_i
- bar_i
;
397 for ( int i
= 0; i
< count_i
; i
++ ) {
398 int begin_bar_i
= check_begin_bar_i( now_mom
, bar_i
);
400 output_mudela_begin_bar( lily_stream_r
, now_mom
, begin_bar_i
);
401 lily_stream_r
<< "r1 ";
402 // *lily_stream_r.os_p_ << flush;
404 tor( NORMAL_ver
) << begin_bar_i
<< flush
;
405 bar_i
= check_end_bar_i( now_mom
, bar_i
);
409 // use "int i" here, and gcc 2.7.2 hits internal compiler error
410 int ii
= check_begin_bar_i( now_mom
, bar_i
);
412 output_mudela_begin_bar( lily_stream_r
, now_mom
, ii
);
414 // bar_i = check_end_bar_i( now_mom, bar_i );
416 Moment remain_mom
= end_mom
- Moment( end_bar_i
- 1 ) * bar_mom
;
417 if ( remain_mom
> Moment( 0 ) ) {
418 output_mudela_rest_remain( lily_stream_r
, remain_mom
);
419 now_mom
+= remain_mom
;
421 assert( now_mom
== end_mom
);
425 Midi_track::output_mudela_rest_remain( Lily_stream
& lily_stream_r
, Moment mom
)
427 if ( Duration_convert::no_quantify_b_s
) {
428 Duration dur
= Duration_convert::mom2_dur( mom
);
429 lily_stream_r
<< "r" << dur
.str() << " ";
430 // assert( mom == dur.mom() );
431 assert( mom
== dur
.length() );
435 Duration dur
= Duration_convert::mom2standardised_dur( mom
);
437 lily_stream_r
<< "r" << dur
.str() << " ";
443 Midi_track::remove_end_at( Link_list
<Midi_voice
*>& open_voices_r
, Moment mom
)
445 for ( PCursor
<Midi_voice
*> i( open_voices_r
.top() ); i
.ok(); i
++ )
446 if ( i
->end_mom() <= mom
) {
447 tor( DEBUG_ver
) << "open_voices (" << open_voices_r
.size() << "): -1\n";
455 Midi_track::remove_end_at( Array
<Midi_voice
*>& open_voices_r
, Moment mom
)
457 for ( int i
= 0; i
< open_voices_r
.size(); i
++ )
458 if ( midi_voice_p_array_
[ i
]->end_mom() <= mom
) {
459 tor( DEBUG_ver
) << "open_voices (" << open_voices_r
.size() << "): -1\n";
460 open_voices_r
[ i
] = 0;
461 // open_voices_r.del( i-- );
462 open_voices_r
.del( i
);
468 Midi_track::set_tempo( int useconds_per_4_i
)
470 delete midi_tempo_p_
;
471 midi_tempo_p_
= new Midi_tempo( useconds_per_4_i
);
475 Midi_track::set_time( int num_i
, int den_i
, int clocks_i
, int count_32_i
)
478 midi_time_p_
= new Midi_time( num_i
, den_i
, clocks_i
, count_32_i
);
482 Midi_track::tcol_l( Moment mom
)
485 for ( PCursor
<Track_column
*> i( tcol_p_list_
.top() ); i
.ok(); i
++ ) {
486 if ( i
->mom() > mom
) { //not used, let's use array!
488 // 97-07-21; it's used now! cannot use array
489 Track_column
* tcol_p
= new Track_column( mom
);
493 if ( i
->mom() == mom
)
497 Track_column
* tcol_p
= new Track_column( mom
);
498 tcol_p_list_
.bottom().add( tcol_p
);
501 for ( int i
= 0; i
< tcol_p_array_
.size(); i
++ )
502 if ( tcol_p_array_
[ i
]->mom() == mom
)
503 return tcol_p_array_
[ i
];
505 Track_column
* tcol_p
= new Track_column( mom
);
506 tcol_p_array_
.push( tcol_p
);
510 as "insert" is never called, the right column will
511 always be found, unless mom > tcol_p_array[ i ]->mom().
513 int upper_i
= max( 0, tcol_p_array_
.size() - 1 );
517 Moment i_mom
= tcol_p_array_
[ i
]->mom();
519 return tcol_p_array_
[ i
];
524 if ( ( upper_i
== lower_i
) || ( i
== tcol_p_array_
.size() - 1 ) ) {
525 // huh? assert ( upper_i == tcol_p_array_.size() );
526 Track_column
* tcol_p
= new Track_column( mom
);
527 tcol_p_array_
.push( tcol_p
);
530 i
= ( upper_i
+ lower_i
+ 1 ) / 2;