2 // lilypond-staff.cc -- implement Lilypond_staff
4 // copyright 1997 Jan Nieuwenhuizen <janneke@gnu.org>
9 #include "duration-convert.hh"
10 #include "string-convert.hh"
11 #include "midi2ly-proto.hh"
12 #include "midi2ly-global.hh"
13 #include "lilypond-column.hh"
14 #include "lilypond-item.hh"
15 #include "lilypond-staff.hh"
16 #include "lilypond-stream.hh"
17 #include "lilypond-voice.hh"
18 #include "lilypond-score.hh"
20 #include "killing-cons.tcc"
22 extern Lilypond_score* lilypond_score_l_g;
24 Lilypond_staff::Lilypond_staff (int number_i, String copyright_str, String track_name_str, String instrument_str)
27 copyright_str_ = copyright_str;
28 instrument_str_ = instrument_str;
29 name_str_ = track_name_str;
31 lilypond_time_signature_l_ = 0;
32 lilypond_tempo_l_ = 0;
36 Lilypond_staff::add_item (Lilypond_item* lilypond_item_p)
38 lilypond_item_p_list_.append (new Killing_cons <Lilypond_item> (lilypond_item_p, 0));
39 if (lilypond_item_p->lilypond_column_l_)
40 lilypond_item_p->lilypond_column_l_->add_item (lilypond_item_p);
43 Walk ITEMS and find voices. Remove categorised items.
47 * collect all channels into separate voices. Use chords for sim
48 notes on same channel.
49 * assume voices/assume chords modes.
53 Lilypond_staff::eat_voice (Cons_list<Lilypond_item>& items)
55 Lilypond_voice* voice_p = new Lilypond_voice (this);
56 lilypond_voice_p_list_.append (new Killing_cons<Lilypond_voice> (voice_p, 0));
58 // Rational mom = items.top ()->at_mom ();
61 for (Cons<Lilypond_item>** pp = &items.head_; *pp;)
63 Cons<Lilypond_item>* i = *pp;
64 if (i->car_->at_mom () > mom)
66 if (no_rests_b_g && voice_p->last_note_l_)
68 voice_p->last_note_l_->end_column_l_ = i->car_->lilypond_column_l_;
72 /* uh, what about quantisation? This should probably
73 use mom2standardised_dur ()
74 arg, urg: skip should get duration from start/end columns!
77 Rational r = i->car_->at_mom () - mom;
79 Lilypond_column* start = lilypond_score_l_g->find_column_l (mom);
80 voice_p->add_item (new Lilypond_skip (start, r));
83 mom = i->car_->at_mom ();
84 continue; // unnecessary
87 Link_array<Lilypond_item> now_items;
88 for (Cons<Lilypond_item> *cp = i; cp && cp->car_->at_mom () == mom; cp = cp->next_)
89 now_items.push (i->car_);
93 Why don't we use <note>, if voice has:
97 we'd get last_item == key_change -> last_note == 0;
99 Lilypond_note * last_note = dynamic_cast<Lilypond_note*> (voice_p->last_item_l_);
102 Not sure, is this better?
104 Lilypond_note * last_note = voice_p->last_note_l_;
107 Link_array<Lilypond_item> candidates;
109 for (int i=0; last_note && i < now_items.size (); i++)
111 Lilypond_note * now_note = dynamic_cast<Lilypond_note*> (now_items[i]);
112 if (now_note && last_note->channel_i_ != now_note->channel_i_)
113 candidates.push (now_note);
116 if (candidates.size())
118 now_items = candidates;
121 Lilypond_item * which = 0;
122 if (now_items.size () > 1)
124 int mindiff = 100000; // ugh
125 for (int i=0; last_note && i < now_items.size (); i++)
127 Lilypond_note *nt = dynamic_cast<Lilypond_note*> (now_items[i]);
130 int diff = abs (last_note->pitch_i_ - nt->pitch_i_ );
134 which = now_items [i];
138 if (which && mindiff > 18) // more than 1.5 octaves apart. Don't put in same voice.
143 else if (now_items.size () == 1)
144 which = now_items[0];
148 while ((*pp)->car_ != which)
151 mom += (*pp)->car_->duration_mom ();
152 Cons<Lilypond_item>* c = items.remove_cons (pp);
153 voice_p->add_item (c->car_);
165 Lilypond_staff::id_str ()
167 String id (name_str ());
168 char *cp = id.ch_l ();
169 char *end = cp + id.length_i ();
170 for (;cp < end; cp++)
181 Lilypond_staff::name_str ()
183 if (name_str_.length_i ())
185 return String ("track") + to_str (char ('A' - 1 + number_i_));
191 Lilypond_staff::output (Lilypond_stream& lilypond_stream_r)
195 String trackbody = "";
196 for (Cons<Lilypond_voice>* i = lilypond_voice_p_list_.head_; i; i = i->next_)
198 String voicename = id_str () + "voice" + to_str (char (c + 'A'));
200 lilypond_stream_r << voicename << " = \\notes ";
202 trackbody += "\\" + voicename + "\n";
204 lilypond_stream_r << '\n';
205 i->car_->output (lilypond_stream_r);
209 lilypond_stream_r << _ ("% MIDI copyright:") << copyright_str_ << '\n';
210 lilypond_stream_r << _ ("% MIDI instrument:") << instrument_str_ << '\n';
211 lilypond_stream_r << id_str () << " = ";
212 lilypond_stream_r << "<\n " << trackbody << " >\n";
214 lilypond_stream_r << " % " << name_str () << '\n';
218 Lilypond_staff::output_lilypond_begin_bar (Lilypond_stream& lilypond_stream_r, Rational now_mom, int bar_i)
220 Rational bar_mom = lilypond_time_signature_l_->bar_mom ();
221 Rational into_bar_mom = now_mom - Rational (bar_i - 1) * bar_mom;
225 lilypond_stream_r << "|\n";
227 lilypond_stream_r << "% " << String_convert::i2dec_str (bar_i, 0, ' ');
229 lilypond_stream_r << ":" << Duration_convert::dur2_str (Duration_convert::mom2_dur (into_bar_mom));
230 lilypond_stream_r << '\n';
234 #if 0 // not used for now
236 Lilypond_staff::output_lilypond_rest (Lilypond_stream& lilypond_stream_r, Rational begin_mom, Rational end_mom)
238 Rational bar_mom = lilypond_time_signature_l_->bar_mom ();
239 Rational now_mom = begin_mom;
241 int begin_bar_i = (int) (now_mom / bar_mom) + 1;
242 int end_bar_i = (int) (end_mom / bar_mom) + 1;
244 if (end_bar_i == begin_bar_i)
246 output_lilypond_rest_remain (lilypond_stream_r, end_mom - begin_mom);
250 // multiple bars involved
251 int bar_i = (int) (now_mom / bar_mom) + 1;
254 Rational begin_bar_mom = Rational (begin_bar_i - 1) * bar_mom;
255 if (now_mom > begin_bar_mom)
257 int next_bar_i = (int) (now_mom / bar_mom) + 2;
258 Rational next_bar_mom = Rational (next_bar_i - 1) * bar_mom;
259 assert (next_bar_mom <= end_mom);
261 Rational remain_mom = next_bar_mom - now_mom;
262 if (remain_mom > Rational (0))
264 output_lilypond_rest_remain (lilypond_stream_r, remain_mom);
265 now_mom += remain_mom;
268 bar_i = check_end_bar_i (now_mom, bar_i);
272 int count_i = end_bar_i - bar_i;
273 for (int i = 0; i < count_i; i++)
275 int begin_bar_i = check_begin_bar_i (now_mom, bar_i);
277 output_lilypond_begin_bar (lilypond_stream_r, now_mom, begin_bar_i);
278 lilypond_stream_r << "r1 ";
279 // *lilypond_stream_r.os_p_ << flush;
281 LOGOUT (NORMAL_ver) << begin_bar_i << flush;
282 bar_i = check_end_bar_i (now_mom, bar_i);
286 // use "int i" here, and gcc 2.7.2 hits internal compiler error
287 int ii = check_begin_bar_i (now_mom, bar_i);
289 output_lilypond_begin_bar (lilypond_stream_r, now_mom, ii);
291 // bar_i = check_end_bar_i (now_mom, bar_i);
293 Rational remain_mom = end_mom - Rational (end_bar_i - 1) * bar_mom;
294 if (remain_mom > Rational (0))
296 output_lilypond_rest_remain (lilypond_stream_r, remain_mom);
297 now_mom += remain_mom;
299 assert (now_mom == end_mom);
303 Lilypond_staff::output_lilypond_rest_remain (Lilypond_stream& lilypond_stream_r, Rational mom)
305 if (Duration_convert::no_quantify_b_s)
307 Duration dur = Duration_convert::mom2_dur (mom);
308 lilypond_stream_r << "r" << dur.str () << " ";
309 // assert (mom == dur.mom ());
310 assert (mom == dur.length ());
314 Duration dur = Duration_convert::mom2standardised_dur (mom);
316 lilypond_stream_r << "r" << dur.str () << " ";
322 Lilypond_staff::process ()
325 group items into voices
328 assert (lilypond_score_l_g);
329 lilypond_key_l_ = lilypond_score_l_g->lilypond_key_l_;
330 lilypond_time_signature_l_ = lilypond_score_l_g->lilypond_time_signature_l_;
331 lilypond_tempo_l_ = lilypond_score_l_g->lilypond_tempo_l_;
333 Cons_list<Lilypond_item> items;
334 for (Cons<Lilypond_item>* i = lilypond_item_p_list_.head_; i; i = i->next_)
335 items.append (new Cons<Lilypond_item> (i->car_, 0));
337 while (items.size_i ())