]> git.donarmstrong.com Git - lilypond.git/blob - mi2mu/midi-track.cc
release: 0.1.7
[lilypond.git] / mi2mu / midi-track.cc
1 //
2 // midi-track.cc -- implement Midi_track
3 //
4 // copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
5
6 #include "mi2mu.hh"
7
8 Midi_track::Midi_track( int number_i, String copyright_str, String track_name_str, String instrument_str )
9 {
10         number_i_ = number_i;
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 );
16 #ifdef TCOL_LIST
17         tcol_p_list_.bottom().add( new Track_column( Moment( 0 ) ) );
18 #else
19         tcol_p_array_.push( new Track_column( Moment( 0 ) ) );
20 #endif
21 }
22
23 Midi_track::~Midi_track()
24 {
25         delete midi_time_p_;
26         delete midi_tempo_p_;
27 }
28
29 #ifdef MVOICE_LIST
30 void
31 Midi_track::add_begin_at( Link_list<Midi_voice*>& open_voices_r, Moment mom )
32 {
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 );
37                 }
38 }
39 #else
40 void
41 Midi_track::add_begin_at( Array<Midi_voice*>& open_voices_r, Moment mom )
42 {
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 ] );
47                 }
48 }
49 #endif
50
51 void
52 Midi_track::add_event( Moment mom, Midi_event* midi_event_p )
53 {
54         if ( ! midi_event_p )
55                 return;
56         tcol_l( mom - midi_event_p->mom() )->add_event( midi_event_p );
57 }
58
59 int
60 Midi_track::check_begin_bar_i( Moment now_mom, int open_bar_i )
61 {
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; 
66                 return bar_i;
67         }
68         return 0;
69 }
70
71 int
72 Midi_track::check_end_bar_i( Moment now_mom, int open_bar_i )
73 {
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; 
78                 return bar_i;
79         }
80         return open_bar_i;
81 }
82
83 Moment
84 Midi_track::end_mom()
85 {
86         // heu..
87         Moment mom = 0.0;
88 #ifdef MVOICE_LIST
89         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) 
90                 mom = i->end_mom() >? mom;
91 #else
92         for ( int i = 0; i < midi_voice_p_array_.size(); i++ ) 
93                 mom = midi_voice_p_array_[ i ]->end_mom() >? mom;
94 #endif
95         return mom;
96 }
97
98 Midi_voice*
99 Midi_track::get_free_midi_voice_l( Moment mom )
100 {
101 #ifdef MVOICE_LIST
102         Real f = 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 )
106                         return *i;
107         }
108
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 );
112         return midi_voice_l; 
113 #else
114         Real f = mom;
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 ];
119         }
120
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 );
124         return midi_voice_l; 
125 #endif
126 }
127
128 String
129 Midi_track::id_str()
130 {
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 ) = '_';
136         return str;
137 }
138
139 String
140 Midi_track::name_str()
141 {
142         if ( name_str_.length_i() )
143                 return name_str_;
144         return String( "track" ) + String( number_i_ );
145 }
146
147 Moment
148 Midi_track::next_begin_mom( Moment now_mom )
149 {
150 //      Moment begin_mom = Midi_track::end_mom() + 1;
151         Moment begin_mom = Midi_track::end_mom();
152 #ifdef MVOICE_LIST
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();
156 #else
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();
160 #endif
161         return begin_mom;
162 }
163
164 Moment
165 Midi_track::next_end_mom( Moment now_mom )
166 {
167         Moment end_mom = Midi_track::end_mom();
168 #ifdef MVOICE_LIST
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();
172 #else
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();
176 #endif
177         return end_mom;
178 }
179
180 void
181 Midi_track::process()
182 {
183         /* 
184            columns to voices
185         */
186 //      int bar_i = 1;
187         int bar_i = 0;
188 #ifdef TCOL_LIST
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 );
191                 if ( begin_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 );
196         }
197 #else
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 );
201                 if ( begin_bar_i )
202                         tor( NORMAL_ver ) << begin_bar_i << flush; 
203 #ifdef MEVENT_LIST
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() );
206 #else
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 );
212                 }
213 #else
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;
217                 }
218                 tcol_l->midi_event_p_array_.clear();
219 #endif 
220 #endif
221                 bar_i = check_end_bar_i( tcol_l->mom(), bar_i );
222         }
223 #endif
224
225         tor( DEBUG_ver ) << "ends: " << endl;
226         int n = 0;
227 #ifdef MVOICE_LIST
228         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) 
229                 tor( VERBOSE_ver ) << "voice " << n++ << ": " << i->end_mom() << endl;
230 #else
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;
233 #endif
234         tor( DEBUG_ver ) << ":sdne" << endl;
235 }
236
237 void
238 Midi_track::output_mudela( Lily_stream& lily_stream_r )
239 {
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";
243 //      int bar_i = 1;
244         int bar_i = 0;
245
246 #ifdef MVOICE_LIST
247         Link_list<Midi_voice*> open_voices;
248 #else
249         Array<Midi_voice*> open_voices;
250 #endif
251         Moment now_mom = 0.0;
252         Real now_f = now_mom;
253         Real begin_f = 0;
254         Real end_f = end_mom();
255         Real then_f;
256
257         /* 
258            now we step through time while writing all voices
259
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
263
264            [todo]
265            voice defragmentation/concatenation could make this
266            lost blonder
267         */
268
269         bool start_of_track_bo = true;
270
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 );
274                 if ( begin_bar_i )
275                         output_mudela_begin_bar( lily_stream_r, now_mom, begin_bar_i );
276                 add_begin_at( open_voices, now_mom );
277
278                 Moment begin_mom = next_begin_mom( now_mom ); 
279
280                 if ( begin_bar_i )
281                         tor( NORMAL_ver ) << begin_bar_i << flush; 
282
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;
287                 else 
288                         then_mom = end_mom;
289
290                 tor( DEBUG_ver ) << "begin: " << begin_mom << " end: " << end_mom << endl;
291                 tor( DEBUG_ver ) << "slice: " << now_mom << ", " << then_mom << endl;
292
293                 now_f = now_mom;
294                 begin_f = begin_mom;
295                 end_f = end_mom;
296                 then_f = then_mom;
297                 
298 // ugh, rests
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;
305                         String str;
306 #ifdef MVOICE_LIST
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 );
309 #else
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 );
312 #endif
313                         if ( str.length_i() )
314                                 lily_stream_r << str;
315                         else
316                                 output_mudela_rest( lily_stream_r, now_mom, then_mom );
317                 }
318                 else {
319 #ifdef MVOICE_LIST
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 );
322 #else
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 );
325 #endif
326                         if ( !open_voices.size() )
327                                 output_mudela_rest( lily_stream_r, now_mom, then_mom );
328                 }
329 //              *lily_stream_r.os_p_ << flush;
330                         
331                 if ( open_voices.size() > 1 )
332                         lily_stream_r << "> ";
333                 remove_end_at( open_voices, then_mom );
334
335                 bar_i = check_end_bar_i( now_mom, bar_i );
336
337                 now_mom = then_mom;
338         }
339 //      bar_i++;
340 //      tor( NORMAL_ver ) << '[' << bar_i << ']' << flush; 
341
342         lily_stream_r << "} % " << name_str() << "\n";
343 }
344
345
346 void
347 Midi_track::output_mudela_begin_bar( Lily_stream& lily_stream_r, Moment now_mom, int bar_i )
348 {
349         Moment bar_mom = midi_time_p_->bar_mom();
350         Moment into_bar_mom = now_mom - Moment( bar_i - 1 ) * bar_mom;
351         if ( bar_i > 1 ) {
352                 if ( !into_bar_mom )
353                         lily_stream_r << "|\n";
354         }
355         lily_stream_r << "% " << String_convert::i2dec_str( bar_i, 0, ' ' );
356         if ( into_bar_mom )
357                 lily_stream_r << ":" << Duration_convert::dur2_str( Duration_convert::mom2_dur( into_bar_mom ) );
358         lily_stream_r << "\n";
359 }
360
361
362 void 
363 Midi_track::output_mudela_rest( Lily_stream& lily_stream_r, Moment begin_mom, Moment end_mom )
364 {
365         Moment bar_mom = midi_time_p_->bar_mom();
366         Moment now_mom = begin_mom;
367
368         int begin_bar_i = (int)( now_mom / bar_mom ) + 1; 
369         int end_bar_i = (int)( end_mom / bar_mom ) + 1;
370
371         if ( end_bar_i == begin_bar_i ) {
372                 output_mudela_rest_remain( lily_stream_r, end_mom - begin_mom );
373                 return;
374         }
375
376         // multiple bars involved
377         int bar_i = (int)( now_mom / bar_mom ) + 1;
378
379         //fill current bar
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 );
385
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;
390                 }
391
392                 bar_i = check_end_bar_i( now_mom, bar_i );
393         }
394
395         // fill whole bars
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 );
399                 if ( begin_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;
403                 if ( begin_bar_i )
404                         tor( NORMAL_ver ) << begin_bar_i << flush; 
405                 bar_i = check_end_bar_i( now_mom, bar_i );
406                 now_mom += bar_mom;
407         }
408
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 );
411         if ( ii )
412                 output_mudela_begin_bar( lily_stream_r, now_mom, ii );
413
414 //      bar_i = check_end_bar_i( now_mom, bar_i );
415
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;
420         }
421         assert( now_mom == end_mom );
422 }
423
424 void
425 Midi_track::output_mudela_rest_remain( Lily_stream& lily_stream_r, Moment mom )
426 {
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() );
432                 return;
433         }
434                 
435         Duration dur = Duration_convert::mom2standardised_dur( mom );
436         if ( dur.type_i_ )
437                 lily_stream_r << "r" << dur.str() << " ";
438 }
439
440
441 #ifdef MVOICE_LIST
442 void
443 Midi_track::remove_end_at( Link_list<Midi_voice*>& open_voices_r, Moment mom )
444 {
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";
448                         i.remove_p();
449                         if ( !i.ok() )
450                                 break;
451                 }
452 }
453 #else
454 void
455 Midi_track::remove_end_at( Array<Midi_voice*>& open_voices_r, Moment mom )
456 {
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 );
463                 }
464 }
465 #endif
466
467 void
468 Midi_track::set_tempo( int useconds_per_4_i )
469 {
470         delete midi_tempo_p_;
471         midi_tempo_p_ = new Midi_tempo( useconds_per_4_i );
472 }
473
474 void
475 Midi_track::set_time( int num_i, int den_i, int clocks_i, int count_32_i )
476 {
477         delete midi_time_p_;
478         midi_time_p_ = new Midi_time( num_i, den_i, clocks_i, count_32_i );
479 }
480
481 Track_column*
482 Midi_track::tcol_l( Moment mom )
483 {
484 #ifdef TCOL_LIST
485         for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
486                 if ( i->mom() > mom ) { //not used, let's use array!
487 //                      assert( 0 );
488 // 97-07-21; it's used now! cannot use array
489                         Track_column* tcol_p = new Track_column( mom );
490                         i.insert( tcol_p );
491                         return tcol_p;
492                 }
493                 if ( i->mom() == mom )
494                         return *i;
495         }
496
497         Track_column* tcol_p = new Track_column( mom );
498         tcol_p_list_.bottom().add( tcol_p );
499         return tcol_p;
500 #elif 0
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 ];
504
505         Track_column* tcol_p = new Track_column( mom );
506         tcol_p_array_.push( tcol_p );
507         return tcol_p;
508 #else
509         /*
510          as "insert" is never called, the right column will
511          always be found, unless mom > tcol_p_array[ i ]->mom().
512          */
513         int upper_i = max( 0, tcol_p_array_.size() - 1 );
514         int lower_i = 0;
515         int i = upper_i;
516         while ( 1 ) {
517                 Moment i_mom = tcol_p_array_[ i ]->mom();
518                 if ( i_mom == mom )
519                         return tcol_p_array_[ i ];
520                 if ( mom < i_mom )
521                         upper_i = i;
522                 else
523                         lower_i = 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 );
528                         return tcol_p;
529                 }
530                 i = ( upper_i + lower_i + 1 ) / 2;
531         }
532         assert( 0 );
533         return 0;
534 #endif
535 }
536