]> git.donarmstrong.com Git - lilypond.git/blob - mi2mu/midi-track.cc
release: 0.0.65
[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 #error doing list!
18         tcol_p_list_.bottom().add( new Track_column( Moment( 0 ) ) );
19 #else
20         tcol_p_array_.push( new Track_column( Moment( 0 ) ) );
21 #endif
22 }
23
24 Midi_track::~Midi_track()
25 {
26         delete midi_time_p_;
27         delete midi_tempo_p_;
28 }
29
30 #ifdef MVOICE_LIST
31 void
32 Midi_track::add_begin_at( Link_list<Midi_voice*>& open_voices_r, Moment mom )
33 {
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 );
38                 }
39 }
40 #else
41 void
42 Midi_track::add_begin_at( Array<Midi_voice*>& open_voices_r, Moment mom )
43 {
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 ] );
48                 }
49 }
50 #endif
51
52 void
53 Midi_track::add_event( Moment mom, Midi_event* midi_event_p )
54 {
55         if ( ! midi_event_p )
56                 return;
57         tcol_l( mom - midi_event_p->mom() )->add_event( midi_event_p );
58 }
59
60 int
61 Midi_track::check_begin_bar_i( Moment now_mom, int open_bar_i )
62 {
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; 
67                 return bar_i;
68         }
69         return 0;
70 }
71
72 int
73 Midi_track::check_end_bar_i( Moment now_mom, int open_bar_i )
74 {
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; 
79                 return bar_i;
80         }
81         return open_bar_i;
82 }
83
84 Moment
85 Midi_track::end_mom()
86 {
87         // heu..
88         Moment mom = 0.0;
89 #ifdef MVOICE_LIST
90         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) 
91                 mom = i->end_mom() >? mom;
92 #else
93         for ( int i = 0; i < midi_voice_p_array_.size(); i++ ) 
94                 mom = midi_voice_p_array_[ i ]->end_mom() >? mom;
95 #endif
96         return mom;
97 }
98
99 Midi_voice*
100 Midi_track::get_free_midi_voice_l( Moment mom )
101 {
102 #ifdef MVOICE_LIST
103         Real f = 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 )
107                         return *i;
108         }
109
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 );
113         return midi_voice_l; 
114 #else
115         Real f = mom;
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 ];
120         }
121
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 );
125         return midi_voice_l; 
126 #endif
127 }
128
129 String
130 Midi_track::name_str()
131 {
132         if ( name_str_.length_i() )
133                 return name_str_;
134         return String( "track" ) + String( number_i_ );
135 }
136
137 Moment
138 Midi_track::next_begin_mom( Moment now_mom )
139 {
140 //      Moment begin_mom = Midi_track::end_mom() + 1;
141         Moment begin_mom = Midi_track::end_mom();
142 #ifdef MVOICE_LIST
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();
147 #else
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();
152 #endif
153         return begin_mom;
154 }
155
156 Moment
157 Midi_track::next_end_mom( Moment now_mom )
158 {
159         Moment end_mom = Midi_track::end_mom();
160 #ifdef MVOICE_LIST
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();
164 #else
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();
169 #endif
170         return end_mom;
171 }
172
173 void
174 Midi_track::process()
175 {
176         /* 
177            columns to voices
178         */
179 //      int bar_i = 1;
180         int bar_i = 0;
181 #ifdef TCOL_LIST
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 );
184                 if ( begin_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 );
189         }
190 #else
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 );
194                 if ( begin_bar_i )
195                         tor( NORMAL_ver ) << begin_bar_i << flush; 
196 #ifdef MEVENT_LIST
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() );
199 #else
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 );
205                 }
206 #else
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;
210                 }
211                 tcol_l->midi_event_p_array_.clear();
212 #endif 
213 #endif
214                 bar_i = check_end_bar_i( tcol_l->mom(), bar_i );
215         }
216 #endif
217
218         tor( DEBUG_ver ) << "ends: " << endl;
219         int n = 0;
220 #ifdef MVOICE_LIST
221         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) 
222                 tor( VERBOSE_ver ) << "voice " << n++ << ": " << i->end_mom() << endl;
223 #else
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;
226 #endif
227         tor( DEBUG_ver ) << ":sdne" << endl;
228 }
229
230
231 void
232 Midi_track::output_mudela( Lily_stream& lily_stream_r )
233 {
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();
240
241 //      int bar_i = 1;
242         int bar_i = 0;
243
244 #ifdef MVOICE_LIST
245         Link_list<Midi_voice*> open_voices;
246 #else
247         Array<Midi_voice*> open_voices;
248 #endif
249         Moment now_mom = 0.0;
250         Real now_f = now_mom;
251         Real begin_f = 0;
252         Real end_f = end_mom();
253         Real then_f;
254
255         /* 
256            now we step through time while writing all voices
257
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
261
262            [todo]
263            voice defragmentation/concatenation could make this
264            lost blonder
265         */
266
267         bool start_of_track_bo = true;
268
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 );
272                 if ( begin_bar_i )
273                         output_mudela_begin_bar( lily_stream_r, now_mom, begin_bar_i );
274                 add_begin_at( open_voices, now_mom );
275
276                 Moment begin_mom = next_begin_mom( now_mom ); 
277
278                 if ( begin_bar_i )
279                         tor( NORMAL_ver ) << begin_bar_i << flush; 
280
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;
285                 else 
286                         then_mom = end_mom;
287
288                 tor( DEBUG_ver ) << "begin: " << begin_mom << " end: " << end_mom << endl;
289                 tor( DEBUG_ver ) << "slice: " << now_mom << ", " << then_mom << endl;
290
291                 now_f = now_mom;
292                 begin_f = begin_mom;
293                 end_f = end_mom;
294                 then_f = then_mom;
295                 
296 // ugh, rests
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;
303                         String str;
304 #ifdef MVOICE_LIST
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 );
307 #else
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 );
310 #endif
311                         if ( str.length_i() )
312                                 lily_stream_r << str;
313                         else
314                                 output_mudela_rest( lily_stream_r, now_mom, then_mom );
315                 }
316                 else {
317 #ifdef MVOICE_LIST
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 );
320 #else
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 );
323 #endif
324                         if ( !open_voices.size() )
325                                 output_mudela_rest( lily_stream_r, now_mom, then_mom );
326                 }
327 //              *lily_stream_r.os_p_ << flush;
328                         
329                 if ( open_voices.size() > 1 )
330                         lily_stream_r << "> ";
331                 remove_end_at( open_voices, then_mom );
332
333                 bar_i = check_end_bar_i( now_mom, bar_i );
334
335                 now_mom = then_mom;
336         }
337 //      bar_i++;
338 //      tor( NORMAL_ver ) << '[' << bar_i << ']' << flush; 
339
340         lily_stream_r.tnedni();
341         lily_stream_r << "} % " << name_str();
342         lily_stream_r.newline();
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 << "|";
354                 lily_stream_r.newline();
355         }
356         lily_stream_r << "% " << String_convert::i2dec_str( bar_i, 0, ' ' );
357         if ( into_bar_mom )
358                 lily_stream_r << ":" << Duration_convert::dur2_str( Duration_convert::mom2_dur( into_bar_mom ) );
359         lily_stream_r.newline();
360 }
361
362
363 void 
364 Midi_track::output_mudela_rest( Lily_stream& lily_stream_r, Moment begin_mom, Moment end_mom )
365 {
366         Moment bar_mom = midi_time_p_->bar_mom();
367         Moment now_mom = begin_mom;
368
369         int begin_bar_i = (int)( now_mom / bar_mom ) + 1; 
370         int end_bar_i = (int)( end_mom / bar_mom ) + 1;
371
372         if ( end_bar_i == begin_bar_i ) {
373                 output_mudela_rest_remain( lily_stream_r, end_mom - begin_mom );
374                 return;
375         }
376
377         // multiple bars involved
378         int bar_i = (int)( now_mom / bar_mom ) + 1;
379
380         //fill current bar
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 );
386
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;
391                 }
392
393                 bar_i = check_end_bar_i( now_mom, bar_i );
394         }
395
396         // fill whole bars
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 );
400                 if ( begin_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;
404                 if ( begin_bar_i )
405                         tor( NORMAL_ver ) << begin_bar_i << flush; 
406                 bar_i = check_end_bar_i( now_mom, bar_i );
407                 now_mom += bar_mom;
408         }
409
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 );
412         if ( ii )
413                 output_mudela_begin_bar( lily_stream_r, now_mom, ii );
414
415 //      bar_i = check_end_bar_i( now_mom, bar_i );
416
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;
421         }
422         assert( now_mom == end_mom );
423 }
424
425 void
426 Midi_track::output_mudela_rest_remain( Lily_stream& lily_stream_r, Moment mom )
427 {
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() );
433                 return;
434         }
435                 
436         Duration dur = Duration_convert::mom2standardised_dur( mom );
437         if ( dur.type_i_ )
438                 lily_stream_r << "r" << dur.str() << " ";
439 }
440
441
442 #ifdef MVOICE_LIST
443 void
444 Midi_track::remove_end_at( Link_list<Midi_voice*>& open_voices_r, Moment mom )
445 {
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";
450                         i.remove_p();
451                         if ( !i.ok() )
452                                 break;
453                 }
454 }
455 #else
456 void
457 Midi_track::remove_end_at( Array<Midi_voice*>& open_voices_r, Moment mom )
458 {
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 );
465                 }
466 }
467 #endif
468
469 void
470 Midi_track::set_tempo( int useconds_per_4_i )
471 {
472         delete midi_tempo_p_;
473         midi_tempo_p_ = new Midi_tempo( useconds_per_4_i );
474 }
475
476 void
477 Midi_track::set_time( int num_i, int den_i, int clocks_i, int count_32_i )
478 {
479         delete midi_time_p_;
480         midi_time_p_ = new Midi_time( num_i, den_i, clocks_i, count_32_i );
481 }
482
483 Track_column*
484 Midi_track::tcol_l( Moment mom )
485 {
486 #ifdef TCOL_LIST
487         for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
488                 if ( i->mom() > mom ) { //not used, let's use array!
489                         assert( 0 );
490                         Track_column* tcol_p = new Track_column( mom );
491                         i.insert( tcol_p );
492                         return tcol_p;
493                 }
494                 if ( i->mom() == mom )
495                         return *i;
496         }
497
498         Track_column* tcol_p = new Track_column( mom );
499         tcol_p_list_.bottom().add( tcol_p );
500         return tcol_p;
501 #elif 0
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 ];
505
506         Track_column* tcol_p = new Track_column( mom );
507         tcol_p_array_.push( tcol_p );
508         return tcol_p;
509 #else
510         /*
511          as "insert" is never called, the right column will
512          always be found, unless mom > tcol_p_array[ i ]->mom().
513          */
514         int upper_i = max( 0, tcol_p_array_.size() - 1 );
515         int lower_i = 0;
516         int i = upper_i;
517         while ( 1 ) {
518                 Moment i_mom = tcol_p_array_[ i ]->mom();
519                 if ( i_mom == mom )
520                         return tcol_p_array_[ i ];
521                 if ( mom < i_mom )
522                         upper_i = i;
523                 else
524                         lower_i = 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 );
529                         return tcol_p;
530                 }
531                 i = ( upper_i + lower_i + 1 ) / 2;
532         }
533         assert( 0 );
534         return 0;
535 #endif
536 }
537