2 head-grav.cc -- part of GNU LilyPond
4 (c) 1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "rhythmic-head.hh"
10 #include "paper-def.hh"
11 #include "musical-request.hh"
13 #include "dot-column.hh"
14 #include "staff-symbol-referencer.hh"
16 #include "score-engraver.hh"
22 class Completion_heads_engraver : public Engraver
24 Link_array<Item> note_p_arr_;
26 Link_array<Item> dot_p_arr_;
27 Link_array<Music> note_req_l_arr_;
28 Link_array<Music> scratch_note_reqs_;
34 Moment next_barline_moment ();
35 Duration find_nearest_duration (Rational length);
38 TRANSLATOR_DECLARATIONS(Completion_heads_engraver);
41 virtual void initialize ();
42 virtual void start_translation_timestep ();
43 virtual bool try_music (Music *req_l) ;
44 virtual void process_music ();
45 virtual void stop_translation_timestep ();
49 Completion_heads_engraver::initialize ()
55 Completion_heads_engraver::try_music (Music *m)
57 if (Note_req * n =dynamic_cast <Note_req *> (m))
59 note_req_l_arr_.push (n);
62 Moment musiclen = m->length_mom ();
63 Moment now = now_mom();
65 if (now_mom ().grace_part_)
67 musiclen.grace_part_ = musiclen.main_part_ ;
68 musiclen.main_part_ = Rational (0,1);
70 note_end_mom_ = note_end_mom_ >? (now + musiclen);
73 else if (dynamic_cast<Busy_playing_req*> (m))
75 return now_mom () < note_end_mom_;
82 Completion_heads_engraver::next_barline_moment ( )
84 Moment *e = unsmob_moment (get_property ("measurePosition"));
85 Moment *l = unsmob_moment (get_property ("measureLength"));
88 programming_error ("No timing props set?");
96 Completion_heads_engraver::find_nearest_duration (Rational length)
103 this could surely be done more efficient. Left to the reader as an
105 while (d.length_mom () > length && d.duration_log () < log_limit)
109 d = Duration (d.duration_log (), d.dot_count ()- 1);
114 d = Duration (d.duration_log () + 1, 2);
118 if (d.duration_log () >= log_limit)
121 d = Duration (d.duration_log (), 0);
124 d = d.compressed (length / d.length_mom ());
131 Completion_heads_engraver::process_music ()
133 if (!first_b_ && !left_to_do_)
142 note_dur = find_nearest_duration (left_to_do_);
146 orig = unsmob_duration (note_req_l_arr_[0]->get_mus_property ("duration"));
150 Moment nb = next_barline_moment ();
151 if (nb < note_dur.length_mom ())
153 note_dur = find_nearest_duration (nb.main_part_);
155 Moment next = now_mom();
156 next.main_part_ += note_dur.length_mom ();
157 top_engraver ()->add_moment_to_process (next);
162 left_to_do_ = orig->length_mom ();
165 if (orig && note_dur.length_mom() != orig->length_mom())
167 if (!scratch_note_reqs_.size ())
168 for (int i = 0; i < note_req_l_arr_.size (); i++)
170 Music * m = note_req_l_arr_[i]->clone ();
171 scratch_note_reqs_.push (m);
174 for (int i =0; i < scratch_note_reqs_.size (); i++)
175 scratch_note_reqs_[i]->set_mus_property ("duration", note_dur.smobbed_copy ());
180 left_to_do_ && i < note_req_l_arr_.size (); i++)
182 Item *note_p = new Item (get_property ("NoteHead"));
184 Staff_symbol_referencer::set_interface (note_p);
186 Music * req = note_req_l_arr_[i];
187 if (scratch_note_reqs_.size())
189 req = scratch_note_reqs_[i];
190 req->set_mus_property ("pitch",
191 note_req_l_arr_[i]->get_mus_property ("pitch"));
193 note_p->set_grob_property ("duration-log",
194 gh_int2scm (note_dur.duration_log ()));
196 int dots= note_dur.dot_count ();
199 Item * d = new Item (get_property ("Dots"));
200 Rhythmic_head::set_dots (note_p, d);
203 measly attempt to save an eeny-weenie bit of memory.
205 if (dots != gh_scm2int (d->get_grob_property ("dot-count")))
206 d->set_grob_property ("dot-count", gh_int2scm (dots));
208 d->set_parent (note_p, Y_AXIS);
213 Pitch *pit =unsmob_pitch (req->get_mus_property ("pitch"));
215 int pos = pit->steps ();
216 SCM c0 = get_property ("centralCPosition");
217 if (gh_number_p (c0))
218 pos += gh_scm2int (c0);
220 note_p->set_grob_property ("staff-position", gh_int2scm (pos));
221 if (to_boolean (get_property ("easyPlay")))
224 s[0] = (pit->notename_i_ + 2)%7 + 'a';
226 s[0] = toupper (s[0]);
227 note_p->set_grob_property ("note-character", ly_str02scm (s));
230 announce_grob (note_p,req);
231 note_p_arr_.push (note_p);
234 left_to_do_ -= note_dur.length_mom ();
238 don't do complicated arithmetic with grace notes.
241 && now_mom().grace_part_ )
243 left_to_do_ = Rational (0,0);
249 Completion_heads_engraver::stop_translation_timestep ()
251 for (int i=0; i < note_p_arr_.size (); i++)
253 typeset_grob (note_p_arr_[i]);
255 note_p_arr_.clear ();
257 for (int i=0; i < dot_p_arr_.size (); i++)
259 typeset_grob (dot_p_arr_[i]);
263 for (int i = scratch_note_reqs_.size(); i--;)
265 scm_gc_unprotect_object (scratch_note_reqs_[i]->self_scm () );
268 scratch_note_reqs_.clear();
271 Tie_req * tie_req = 0;
274 Completion_heads_engraver::start_translation_timestep ()
276 Moment now = now_mom ();
277 if (note_end_mom_.main_part_ <= now.main_part_)
279 note_req_l_arr_.clear ();
285 tie_req = new Tie_req;
287 bool succ = daddy_trans_l_->try_music (tie_req);
290 programming_error ("Completion_heads_engraver: no-one to make tie.");
295 Completion_heads_engraver::Completion_heads_engraver()
299 ENTER_DESCRIPTION(Completion_heads_engraver,
300 /* descr */ "This engraver replaces
301 @code{Note_heads_engraver}. It plays some trickery to
302 break long notes and automatically tie them into the next measure.",
303 /* creats*/ "NoteHead Dots",
305 /* reads */ "easyPlay centralCPosition measurePosition measureLength",