]> git.donarmstrong.com Git - lilypond.git/blob - midi2ly/mudela-staff.cc
release: 1.2.10
[lilypond.git] / midi2ly / mudela-staff.cc
1 //
2 // mudela-staff.cc -- implement Mudela_staff
3 //
4 // copyright 1997 Jan Nieuwenhuizen <janneke@gnu.org>
5
6 #include <assert.h>
7 #include <ctype.h>
8 #include "moment.hh"
9 #include "duration-convert.hh"
10 #include "string-convert.hh"
11 #include "midi2ly-proto.hh"
12 #include "midi2ly-global.hh"
13 #include "mudela-column.hh"
14 #include "mudela-item.hh"
15 #include "mudela-staff.hh"
16 #include "mudela-stream.hh"
17 #include "mudela-voice.hh"
18 #include "mudela-score.hh"
19
20 #include "killing-cons.tcc"
21
22 extern Mudela_score* mudela_score_l_g;
23
24 Mudela_staff::Mudela_staff (int number_i, String copyright_str, String track_name_str, String instrument_str)
25 {
26   number_i_ = number_i;
27   copyright_str_ = copyright_str;
28   instrument_str_ = instrument_str;
29   name_str_ = track_name_str;
30   mudela_key_l_ = 0;
31   mudela_time_signature_l_ = 0;
32   mudela_tempo_l_ = 0;
33 }
34
35 void
36 Mudela_staff::add_item (Mudela_item* mudela_item_p)
37 {
38   mudela_item_p_list_.append (new Killing_cons <Mudela_item> (mudela_item_p, 0));
39   if (mudela_item_p->mudela_column_l_)
40     mudela_item_p->mudela_column_l_->add_item (mudela_item_p);
41 }
42 /**
43    Walk ITEMS and find voices.  Remove categorised items.
44
45    TODO: collect all channels into separate voices. Use chords for sim
46    notes on same channel.
47    
48  */
49 void
50 Mudela_staff::eat_voice (Cons_list<Mudela_item>& items)
51 {
52   Mudela_voice* voice_p = new Mudela_voice (this);
53   mudela_voice_p_list_.append (new Killing_cons<Mudela_voice> (voice_p, 0));
54
55   //    Moment mom = items.top ()->at_mom ();
56   Moment mom = 0;
57
58   for (Cons<Mudela_item>** pp = &items.head_; *pp;)
59     {
60       Cons<Mudela_item>* i = *pp;
61       if (i->car_->at_mom () > mom)
62         {
63           Moment dur = i->car_->at_mom () - mom;
64           // ugh, need score
65           Mudela_column* start = mudela_score_l_g->find_column_l (mom);
66           voice_p->add_item (new Mudela_skip (start, dur));
67           mom = i->car_->at_mom ();
68           continue;             // unnecessary
69         }
70       
71       Link_array<Mudela_item> now_items;
72       for (Cons<Mudela_item> *cp = i; cp && cp->car_->at_mom () == mom; cp = cp->next_)
73         now_items.push (i->car_);
74
75       Mudela_note * last_note = dynamic_cast<Mudela_note*> (voice_p->last_item_l_);
76       Link_array<Mudela_item> candidates; 
77
78       for (int i=0; last_note && i < now_items.size (); i++)
79         {
80           Mudela_note * now_note = dynamic_cast<Mudela_note*> (now_items[i]);
81           if (now_note && last_note->channel_i_ != now_note->channel_i_)
82             candidates.push (now_note);
83         }
84
85       if (candidates.size())
86         {
87           now_items = candidates;
88         }
89
90       Mudela_item * which = 0;
91       if (now_items.size () > 1)
92         {
93           int mindiff = 100000; // ugh
94           for (int i=0; last_note && i < now_items.size (); i++)
95             {
96               Mudela_note *nt = dynamic_cast<Mudela_note*> (now_items[i]);
97               if (!nt)
98                 continue;
99               int diff = abs (last_note->pitch_i_ - nt->pitch_i_ );
100               if(diff < mindiff)
101                 {
102                   mindiff =  diff;
103                   which = now_items [i];
104                 }
105             }
106
107           if (which && mindiff > 18)            // more than 1.5 octaves apart.  Don't put in same voice.
108             {
109               which =0;
110             }
111         }
112       else if (now_items.size () == 1)
113         which = now_items[0];
114       
115       if (which)
116         {
117           while ((*pp)->car_ != which)
118             pp = &(*pp)->next_;
119       
120           mom += (*pp)->car_->duration_mom ();
121           Cons<Mudela_item>* c = items.remove_cons (pp);
122           voice_p->add_item (c->car_);
123           delete c;
124         }
125       else 
126         {
127           pp = &(*pp)->next_;
128           continue;
129         }
130     }
131 }
132
133 String
134 Mudela_staff::id_str ()
135 {
136   String id (name_str ());
137   char *cp = id.ch_l ();
138   char *end = cp + id.length_i ();
139   for (;cp < end; cp++)
140     {
141       if (!isalpha (*cp))
142         {
143           *cp = 'X';
144         }
145     }
146   return id;
147 }
148
149 String
150 Mudela_staff::name_str ()
151 {
152   if (name_str_.length_i ())
153     return name_str_;
154   return String ("track") + to_str (char ('A' - 1 + number_i_));
155 }
156
157
158
159 void
160 Mudela_staff::output (Mudela_stream& mudela_stream_r)
161 {
162   int c =0;
163   
164   String trackbody = "";
165   for (Cons<Mudela_voice>* i = mudela_voice_p_list_.head_; i; i = i->next_)
166     {
167       String voicename = id_str () + "voice" + to_str (char (c + 'A'));
168       
169       mudela_stream_r << voicename << " = \\notes ";
170
171       trackbody += "\\"  + voicename + "\n";
172
173       mudela_stream_r << "\n";
174       i->car_->output (mudela_stream_r);
175       c++;      
176     }
177
178   mudela_stream_r << _ ("% MIDI copyright:") << copyright_str_ << '\n';
179   mudela_stream_r << _ ("% MIDI instrument:") << instrument_str_ << '\n';
180   mudela_stream_r << id_str () << " = ";
181   mudela_stream_r << "<\n " << trackbody << " >\n";
182
183   mudela_stream_r << " % " << name_str () << '\n';
184 }
185
186 void
187 Mudela_staff::output_mudela_begin_bar (Mudela_stream& mudela_stream_r, Moment now_mom, int bar_i)
188 {
189   Moment bar_mom = mudela_time_signature_l_->bar_mom ();
190   Moment into_bar_mom = now_mom - Moment (bar_i - 1) * bar_mom;
191   if (bar_i > 1)
192     {
193       if (!into_bar_mom)
194         mudela_stream_r << "|\n";
195     }
196   mudela_stream_r << "% " << String_convert::i2dec_str (bar_i, 0, ' ');
197   if (into_bar_mom)
198     mudela_stream_r << ":" << Duration_convert::dur2_str (Duration_convert::mom2_dur (into_bar_mom));
199   mudela_stream_r << '\n';
200 }
201
202
203 #if 0 // not used for now
204 void
205 Mudela_staff::output_mudela_rest (Mudela_stream& mudela_stream_r, Moment begin_mom, Moment end_mom)
206 {
207   Moment bar_mom = mudela_time_signature_l_->bar_mom ();
208   Moment now_mom = begin_mom;
209
210   int begin_bar_i = (int) (now_mom / bar_mom) + 1;
211   int end_bar_i = (int) (end_mom / bar_mom) + 1;
212
213   if (end_bar_i == begin_bar_i)
214     {
215       output_mudela_rest_remain (mudela_stream_r, end_mom - begin_mom);
216       return;
217     }
218
219   // multiple bars involved
220   int bar_i = (int) (now_mom / bar_mom) + 1;
221
222   //fill current bar
223   Moment begin_bar_mom = Moment (begin_bar_i - 1) * bar_mom;
224   if (now_mom > begin_bar_mom)
225     {
226       int next_bar_i = (int) (now_mom / bar_mom) + 2;
227       Moment next_bar_mom = Moment (next_bar_i - 1) * bar_mom;
228       assert (next_bar_mom <= end_mom);
229
230       Moment remain_mom = next_bar_mom - now_mom;
231       if (remain_mom > Moment (0))
232         {
233           output_mudela_rest_remain (mudela_stream_r, remain_mom);
234           now_mom += remain_mom;
235         }
236
237       bar_i = check_end_bar_i (now_mom, bar_i);
238     }
239
240   // fill whole bars
241   int count_i = end_bar_i - bar_i;
242   for (int i = 0; i < count_i; i++)
243     {
244       int begin_bar_i = check_begin_bar_i (now_mom, bar_i);
245       if (begin_bar_i)
246         output_mudela_begin_bar (mudela_stream_r, now_mom, begin_bar_i);
247       mudela_stream_r << "r1 ";
248       //        *mudela_stream_r.os_p_ << flush;
249       if (begin_bar_i)
250         LOGOUT (NORMAL_ver) << begin_bar_i << flush;
251       bar_i = check_end_bar_i (now_mom, bar_i);
252       now_mom += bar_mom;
253     }
254
255   // use "int i" here, and gcc 2.7.2 hits internal compiler error
256   int ii = check_begin_bar_i (now_mom, bar_i);
257   if (ii)
258     output_mudela_begin_bar (mudela_stream_r, now_mom, ii);
259
260   //    bar_i = check_end_bar_i (now_mom, bar_i);
261
262   Moment remain_mom = end_mom - Moment (end_bar_i - 1) * bar_mom;
263   if (remain_mom > Moment (0))
264     {
265       output_mudela_rest_remain (mudela_stream_r, remain_mom);
266       now_mom += remain_mom;
267     }
268   assert (now_mom == end_mom);
269 }
270
271 void
272 Mudela_staff::output_mudela_rest_remain (Mudela_stream& mudela_stream_r, Moment mom)
273 {
274   if (Duration_convert::no_quantify_b_s)
275     {
276       Duration dur = Duration_convert::mom2_dur (mom);
277       mudela_stream_r << "r" << dur.str () << " ";
278       //        assert (mom == dur.mom ());
279       assert (mom == dur.length ());
280       return;
281     }
282
283   Duration dur = Duration_convert::mom2standardised_dur (mom);
284   if (dur.type_i_>-10)
285     mudela_stream_r << "r" << dur.str () << " ";
286 }
287 #endif
288
289
290 void
291 Mudela_staff::process ()
292 {
293   /*
294      group items into voices
295      */
296
297   assert (mudela_score_l_g);
298   mudela_key_l_ = mudela_score_l_g->mudela_key_l_;
299   mudela_time_signature_l_ = mudela_score_l_g->mudela_time_signature_l_;
300   mudela_tempo_l_ = mudela_score_l_g->mudela_tempo_l_;
301
302   Cons_list<Mudela_item> items;
303   for (Cons<Mudela_item>* i = mudela_item_p_list_.head_; i; i = i->next_)
304     items.append (new Cons<Mudela_item> (i->car_, 0));
305
306   while (items.size_i ())
307     eat_voice (items);
308 }