]> git.donarmstrong.com Git - lilypond.git/blob - mi2mu/midi-track.cc
release: 0.0.62
[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         tcol_p_list_.bottom().add( new Track_column( Moment( 0 ) ) );
17 }
18
19 Midi_track::~Midi_track()
20 {
21         delete midi_time_p_;
22         delete midi_tempo_p_;
23 }
24
25 void
26 Midi_track::add_begin_at( Pointer_list<Midi_voice*>& open_voices_r, Moment mom )
27 {
28         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
29                 if ( i->begin_mom() == mom ) {
30                         tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): +1\n";
31                         open_voices_r.bottom().add( *i );
32                 }
33 }
34
35 void
36 Midi_track::add_event( Moment mom, Midi_event* midi_event_p )
37 {
38         if ( ! midi_event_p )
39                 return;
40         tcol_l( mom - midi_event_p->mom() )->add_event( midi_event_p );
41 }
42
43 int
44 Midi_track::check_begin_bar_i( Moment now_mom, int open_bar_i )
45 {
46         Moment bar_mom = midi_time_p_->bar_mom();
47         int bar_i = (int)( now_mom / bar_mom ) + 1;
48         if ( bar_i > open_bar_i ) { 
49                 tor( NORMAL_ver ) << '[' << flush; 
50                 return bar_i;
51         }
52         return 0;
53 }
54
55 int
56 Midi_track::check_end_bar_i( Moment now_mom, int open_bar_i )
57 {
58         Moment bar_mom = midi_time_p_->bar_mom();
59         int bar_i = (int)( now_mom / bar_mom ) + 1;
60         if ( bar_i > open_bar_i ) {
61                 tor( NORMAL_ver ) << ']' << flush; 
62                 return bar_i;
63         }
64         return open_bar_i;
65 }
66
67 Moment
68 Midi_track::end_mom()
69 {
70         // heu..
71         Moment mom = 0.0;
72         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) 
73                 mom = i->end_mom() >? mom;
74         return mom;
75 }
76
77 Midi_voice*
78 Midi_track::get_free_midi_voice_l( Moment mom )
79 {
80         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
81                 if ( i->end_mom() == mom )
82                         return *i;
83
84         Midi_voice* midi_voice_p = new Midi_voice( mom );
85         Midi_voice* midi_voice_l = midi_voice_p;
86         midi_voice_p_list_.bottom().add( midi_voice_p );
87         return midi_voice_l; 
88 }
89
90 String
91 Midi_track::name_str()
92 {
93         if ( name_str_.length_i() )
94                 return name_str_;
95         return String( "track" ) + String( number_i_ );
96 }
97
98 Moment
99 Midi_track::next_begin_mom( Moment now_mom )
100 {
101 //      Moment begin_mom = Midi_track::end_mom() + 1;
102         Moment begin_mom = Midi_track::end_mom();
103         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
104 //              if ( i->begin_mom() >= now_mom )
105                 if ( i->begin_mom() > now_mom )
106                         begin_mom = begin_mom <? i->begin_mom();
107         return begin_mom;
108 }
109
110 Moment
111 Midi_track::next_end_mom( Moment now_mom )
112 {
113         Moment end_mom = Midi_track::end_mom();
114         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) 
115                 if ( i->end_mom() > now_mom )
116                         end_mom = end_mom <? i->end_mom();
117         return end_mom;
118 }
119
120 void
121 Midi_track::process()
122 {
123         /* 
124            columns to voices
125         */
126         int bar_i = 1;
127         for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
128                 int begin_bar_i = check_begin_bar_i( i->mom(), bar_i );
129                 if ( begin_bar_i )
130                         tor( NORMAL_ver ) << begin_bar_i << flush; 
131                 while ( i->midi_event_p_list_.size() ) 
132                         get_free_midi_voice_l( i->mom() )->add_event( i->midi_event_p_list_.top().remove_p() );
133                 bar_i = check_end_bar_i( i->mom(), bar_i );
134         }
135
136         tor( DEBUG_ver ) << "ends: " << endl;
137         int n = 0;
138         for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ ) 
139                 tor( VERBOSE_ver ) << "voice " << n++ << ": " << i->end_mom() << endl;
140         tor( DEBUG_ver ) << ":sdne" << endl;
141 }
142
143
144 void
145 Midi_track::output_mudela( Lily_stream& lily_stream_r )
146 {
147         lily_stream_r << name_str() << " = \\melodic{";
148         lily_stream_r.indent();
149         lily_stream_r << "% midi copyright:" << copyright_str_;
150         lily_stream_r.newline();
151         lily_stream_r << "% instrument:" << instrument_str_;
152         lily_stream_r.newline();
153
154         int bar_i = 0;
155
156         Pointer_list<Midi_voice*> open_voices;
157         Moment now_mom = 0.0;
158         Real now_f = now_mom;
159         Real begin_f = 0;
160         Real end_f = end_mom();
161         Real then_f;
162
163         /* 
164            now we step through time while writing all voices
165
166            we can only output time slices that have a constant
167            number of open voices; each begin or end of a voice
168            starts or ends a chord or multivoice
169
170            [todo]
171            voice defragmentation/concatenation could make this
172            lost blonder
173         */
174
175         bool start_of_track_bo = true;
176
177         /// ugh, avoid status track 0 full of rests...
178         while ( number_i_ && ( now_mom < end_mom() ) ) {
179                 int begin_bar_i = check_begin_bar_i( now_mom, bar_i );
180                 if ( begin_bar_i )
181                         output_mudela_begin_bar( lily_stream_r, now_mom, begin_bar_i );
182                 add_begin_at( open_voices, now_mom );
183
184                 Moment begin_mom = next_begin_mom( now_mom ); 
185
186                 if ( begin_bar_i )
187                         tor( NORMAL_ver ) << begin_bar_i << flush; 
188
189                 Moment end_mom = next_end_mom( now_mom ); 
190                 Moment then_mom = 0.0;
191                 if ( ( begin_mom > now_mom ) && ( begin_mom < end_mom ) )
192                         then_mom = begin_mom;
193                 else 
194                         then_mom = end_mom;
195
196                 tor( DEBUG_ver ) << "begin: " << begin_mom << " end: " << end_mom << endl;
197                 tor( DEBUG_ver ) << "slice: " << now_mom << ", " << then_mom << endl;
198
199                 now_f = now_mom;
200                 begin_f = begin_mom;
201                 end_f = end_mom;
202                 then_f = then_mom;
203                 
204 // ugh, rests
205 // checking for no open voice does not work for initial rests.
206 // for some reason the voice is open, but does not procuce notes?
207                 if ( open_voices.size() > 1 )
208                         lily_stream_r << "< ";
209                 if ( start_of_track_bo ) {
210                         start_of_track_bo = false;
211                         String str;
212                         for ( PCursor<Midi_voice*> i( open_voices.top() ); i.ok(); i++ )
213                                 lily_stream_r << i->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
214                         if ( str.length_i() )
215                                 lily_stream_r << str;
216                         else
217                                 output_mudela_rest( lily_stream_r, now_mom, then_mom );
218                 }
219                 else {
220                         for ( PCursor<Midi_voice*> i( open_voices.top() ); i.ok(); i++ )
221                                 lily_stream_r << i->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
222                         if ( !open_voices.size() )
223                                 output_mudela_rest( lily_stream_r, now_mom, then_mom );
224                 }
225 //              *lily_stream_r.os_p_ << flush;
226                         
227                 if ( open_voices.size() > 1 )
228                         lily_stream_r << "> ";
229                 remove_end_at( open_voices, then_mom );
230
231                 bar_i = check_end_bar_i( now_mom, bar_i );
232
233                 now_mom = then_mom;
234         }
235         bar_i++;
236         tor( NORMAL_ver ) << '[' << bar_i << ']' << flush; 
237
238         lily_stream_r.tnedni();
239         lily_stream_r << "} % " << name_str();
240         lily_stream_r.newline();
241 }
242
243
244 void
245 Midi_track::output_mudela_begin_bar( Lily_stream& lily_stream_r, Moment now_mom, int bar_i )
246 {
247         Moment bar_mom = midi_time_p_->bar_mom();
248         Moment into_bar_mom = now_mom - Moment( bar_i - 1 ) * bar_mom;
249         if ( bar_i > 1 ) {
250                 if ( !into_bar_mom )
251                         lily_stream_r << "|";
252                 lily_stream_r.newline();
253         }
254         lily_stream_r << "% " << String_convert::i2dec_str( bar_i, 0, ' ' );
255         if ( into_bar_mom )
256                 lily_stream_r << ":" << Duration_convert::dur2_str( Duration_convert::mom2_dur( into_bar_mom ) );
257         lily_stream_r.newline();
258 }
259
260
261 void 
262 Midi_track::output_mudela_rest( Lily_stream& lily_stream_r, Moment begin_mom, Moment end_mom )
263 {
264         Moment bar_mom = midi_time_p_->bar_mom();
265         Moment now_mom = begin_mom;
266
267         int begin_bar_i = (int)( now_mom / bar_mom ) + 1; 
268         int end_bar_i = (int)( end_mom / bar_mom ) + 1;
269
270         if ( end_bar_i == begin_bar_i ) {
271                 output_mudela_rest_remain( lily_stream_r, end_mom - begin_mom );
272                 return;
273         }
274
275         // multiple bars involved
276         int bar_i = (int)( now_mom / bar_mom ) + 1;
277
278         //fill current bar
279         Moment begin_bar_mom = Moment( begin_bar_i - 1 ) * bar_mom;
280         if ( now_mom > begin_bar_mom ) {
281                 int next_bar_i = (int)( now_mom / bar_mom ) + 2; 
282                 Moment next_bar_mom = Moment( next_bar_i - 1 ) * bar_mom;
283                 assert( next_bar_mom <= end_mom );
284
285                 Moment remain_mom = next_bar_mom - now_mom;
286                 if ( remain_mom > Moment( 0 ) ) {
287                         output_mudela_rest_remain( lily_stream_r, remain_mom );
288                         now_mom += remain_mom;
289                 }
290
291                 bar_i = check_end_bar_i( now_mom, bar_i );
292         }
293
294         // fill whole bars
295         int count_i = end_bar_i - bar_i;
296         for ( int i = 0; i < count_i; i++ ) {
297                 int begin_bar_i = check_begin_bar_i( now_mom, bar_i );
298                 if ( begin_bar_i )
299                         output_mudela_begin_bar( lily_stream_r, now_mom, begin_bar_i );
300                 lily_stream_r << "r1 ";
301 //              *lily_stream_r.os_p_ << flush;
302                 tor( NORMAL_ver ) << begin_bar_i << flush; 
303                 bar_i = check_end_bar_i( now_mom, bar_i );
304                 now_mom += bar_mom;
305         }
306
307         // use "int i" here, and gcc 2.7.2 hits internal compiler error
308         int ii = check_begin_bar_i( now_mom, bar_i );
309         if ( ii )
310                 output_mudela_begin_bar( lily_stream_r, now_mom, ii );
311
312 //      bar_i = check_end_bar_i( now_mom, bar_i );
313
314         Moment remain_mom = end_mom - Moment( end_bar_i - 1 ) * bar_mom;
315         if ( remain_mom > Moment( 0 ) ) {
316                 output_mudela_rest_remain( lily_stream_r, remain_mom );
317                 now_mom += remain_mom;
318         }
319         assert( now_mom == end_mom );
320 }
321
322 void
323 Midi_track::output_mudela_rest_remain( Lily_stream& lily_stream_r, Moment mom )
324 {
325         if ( Duration_convert::no_quantify_b_s ) {
326                 Duration dur = Duration_convert::mom2_dur( mom );
327                 lily_stream_r << "r" << dur.str() << " ";
328 //              assert( mom == dur.mom() );
329                 assert( mom == dur.length() );
330                 return;
331         }
332                 
333         Duration dur = Duration_convert::mom2standardised_dur( mom );
334         if ( dur.type_i_ )
335                 lily_stream_r << "r" << dur.str() << " ";
336 }
337
338 void
339 Midi_track::remove_end_at( Pointer_list<Midi_voice*>& open_voices_r, Moment mom )
340 {
341         for ( PCursor<Midi_voice*> i( open_voices_r.top() ); i.ok(); i++ )
342 //              if ( i->end_mom() == mom ) { }
343                 if ( i->end_mom() <= mom ) {
344                         tor( DEBUG_ver ) << "open_voices (" << open_voices_r.size() << "): -1\n";
345                         i.remove_p();
346                         if ( !i.ok() )
347                                 break;
348                 }
349 }
350
351 void
352 Midi_track::set_tempo( int useconds_per_4_i )
353 {
354         delete midi_tempo_p_;
355         midi_tempo_p_ = new Midi_tempo( useconds_per_4_i );
356 }
357
358 void
359 Midi_track::set_time( int num_i, int den_i, int clocks_i, int count_32_i )
360 {
361         delete midi_time_p_;
362         midi_time_p_ = new Midi_time( num_i, den_i, clocks_i, count_32_i );
363 }
364
365 Track_column*
366 Midi_track::tcol_l( Moment mom )
367 {
368         for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
369                 if ( i->mom() == mom )
370                         return *i;
371                 if ( i->mom() > mom ) {
372                         Track_column* tcol_p = new Track_column( mom );
373                         i.insert( tcol_p );
374                         return tcol_p;
375                 }
376         }
377
378         Track_column* tcol_p = new Track_column( mom );
379         tcol_p_list_.bottom().add( tcol_p );
380         return tcol_p;
381 }
382