X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fcompletion-note-heads-engraver.cc;h=641bb2358448f3f6459062b4282fd44bd7f262ae;hb=21085be16bbb0fc1914210b69476c4f0a3ec92ea;hp=965f6cda80a8b829bf0fa56c5fd153acbe6fd4e3;hpb=d4bd65ce87936a9b2abdbf941ad572bda4e76768;p=lilypond.git diff --git a/lily/completion-note-heads-engraver.cc b/lily/completion-note-heads-engraver.cc index 965f6cda80..641bb23584 100644 --- a/lily/completion-note-heads-engraver.cc +++ b/lily/completion-note-heads-engraver.cc @@ -1,36 +1,54 @@ /* head-grav.cc -- part of GNU LilyPond - (c) 1997--2001 Han-Wen Nienhuys + (c) 1997--2003 Han-Wen Nienhuys */ #include #include "rhythmic-head.hh" #include "paper-def.hh" -#include "musical-request.hh" +#include "event.hh" #include "dots.hh" #include "dot-column.hh" #include "staff-symbol-referencer.hh" #include "item.hh" #include "score-engraver.hh" #include "warn.hh" +#include "spanner.hh" +#include "tie.hh" -/** - make balls and rests +/* + + How does this work? + + When we catch the note, we predict the end of the note. We keep the + events living until we reach the predicted end-time. + + Every time process_music() is called and there are note events, we + figure out how long the note to typeset should be. It should be no + longer than what's specified, than what is left to do and it should + not cross barlines. + + We copy the reqs into scratch note reqs, to make sure that we get + all durations exactly right. */ + class Completion_heads_engraver : public Engraver { - Link_array note_p_arr_; + Link_array notes_; + Link_array prev_notes_; + Link_array ties_; - Link_array dot_p_arr_; - Link_array note_req_l_arr_; + Link_array dots_; + Link_array note_reqs_; Link_array scratch_note_reqs_; Moment note_end_mom_; bool first_b_; Rational left_to_do_; - + Rational do_nothing_until_; + Moment next_barline_moment (); Duration find_nearest_duration (Rational length); @@ -40,7 +58,7 @@ public: protected: virtual void initialize (); virtual void start_translation_timestep (); - virtual bool try_music (Music *req_l) ; + virtual bool try_music (Music *req) ; virtual void process_music (); virtual void stop_translation_timestep (); }; @@ -54,12 +72,12 @@ Completion_heads_engraver::initialize () bool Completion_heads_engraver::try_music (Music *m) { - if (Note_req * n =dynamic_cast (m)) + if (m->is_mus_type ("note-event")) { - note_req_l_arr_.push (n); + note_reqs_.push (m); first_b_ = true; - Moment musiclen = m->length_mom (); + Moment musiclen = m->get_length (); Moment now = now_mom(); if (now_mom ().grace_part_) @@ -68,16 +86,22 @@ Completion_heads_engraver::try_music (Music *m) musiclen.main_part_ = Rational (0,1); } note_end_mom_ = note_end_mom_ >? (now + musiclen); + do_nothing_until_ = Rational (0,0); + return true; } - else if (dynamic_cast (m)) + else if (m->is_mus_type ("busy-playing-event")) { - return now_mom () < note_end_mom_; + return note_reqs_.size (); } + return false; } +/* + The duration _until_ the next barline. + */ Moment Completion_heads_engraver::next_barline_moment ( ) { @@ -102,7 +126,7 @@ Completion_heads_engraver::find_nearest_duration (Rational length) /* this could surely be done more efficient. Left to the reader as an excercise. */ - while (d.length_mom () > length && d.duration_log () < log_limit) + while (d.get_length () > length && d.duration_log () < log_limit) { if (d.dot_count ()) { @@ -121,7 +145,7 @@ Completion_heads_engraver::find_nearest_duration (Rational length) d = Duration (d.duration_log (), 0); // scale up. - d = d.compressed (length / d.length_mom ()); + d = d.compressed (length / d.get_length ()); } return d; @@ -132,8 +156,12 @@ Completion_heads_engraver::process_music () { if (!first_b_ && !left_to_do_) return ; - + first_b_ = false; + + Moment now = now_mom (); + if (do_nothing_until_ > now.main_part_) + return ; Duration note_dur; Duration *orig = 0; @@ -143,61 +171,58 @@ Completion_heads_engraver::process_music () } else { - orig = unsmob_duration (note_req_l_arr_[0]->get_mus_property ("duration")); + orig = unsmob_duration (note_reqs_[0]->get_mus_property ("duration")); note_dur = *orig; } - Moment nb = next_barline_moment (); - if (nb < note_dur.length_mom ()) + if (nb < note_dur.get_length ()) { note_dur = find_nearest_duration (nb.main_part_); - Moment next = now_mom(); - next.main_part_ += note_dur.length_mom (); + Moment next = now; + next.main_part_ += note_dur.get_length (); top_engraver ()->add_moment_to_process (next); + do_nothing_until_ = next.main_part_; } if (orig) { - left_to_do_ = orig->length_mom (); + left_to_do_ = orig->get_length (); } - if (orig && note_dur.length_mom() != orig->length_mom()) + if (orig && note_dur.get_length () != orig->get_length ()) { if (!scratch_note_reqs_.size ()) - for (int i = 0; i < note_req_l_arr_.size (); i++) + for (int i = 0; i < note_reqs_.size (); i++) { - Music * m = note_req_l_arr_[i]->clone (); + Music * m = note_reqs_[i]->clone (); scratch_note_reqs_.push (m); } - - for (int i =0; i < scratch_note_reqs_.size (); i++) - scratch_note_reqs_[i]->set_mus_property ("duration", note_dur.smobbed_copy ()); } for (int i = 0; - left_to_do_ && i < note_req_l_arr_.size (); i++) + left_to_do_ && i < note_reqs_.size (); i++) { - Item *note_p = new Item (get_property ("NoteHead")); + Item *note = new Item (get_property ("NoteHead")); - Staff_symbol_referencer::set_interface (note_p); - - Music * req = note_req_l_arr_[i]; + Music * req = note_reqs_[i]; if (scratch_note_reqs_.size()) { req = scratch_note_reqs_[i]; - req->set_mus_property ("pitch", - note_req_l_arr_[i]->get_mus_property ("pitch")); + SCM pits = note_reqs_[i]->get_mus_property ("pitch"); + req->set_mus_property ("pitch",pits); } - note_p->set_grob_property ("duration-log", + + req->set_mus_property ("duration", note_dur.smobbed_copy ()); + note->set_grob_property ("duration-log", gh_int2scm (note_dur.duration_log ())); - + int dots= note_dur.dot_count (); if (dots) { Item * d = new Item (get_property ("Dots")); - Rhythmic_head::set_dots (note_p, d); + Rhythmic_head::set_dots (note, d); /* measly attempt to save an eeny-weenie bit of memory. @@ -205,9 +230,9 @@ Completion_heads_engraver::process_music () if (dots != gh_scm2int (d->get_grob_property ("dot-count"))) d->set_grob_property ("dot-count", gh_int2scm (dots)); - d->set_parent (note_p, Y_AXIS); - announce_grob (d,0); - dot_p_arr_.push (d); + d->set_parent (note, Y_AXIS); + announce_grob (d, SCM_EOL); + dots_.push (d); } Pitch *pit =unsmob_pitch (req->get_mus_property ("pitch")); @@ -217,22 +242,27 @@ Completion_heads_engraver::process_music () if (gh_number_p (c0)) pos += gh_scm2int (c0); - note_p->set_grob_property ("staff-position", gh_int2scm (pos)); - if (to_boolean (get_property ("easyPlay"))) + note->set_grob_property ("staff-position", gh_int2scm (pos)); + announce_grob (note,req->self_scm ()); + notes_.push (note); + } + + if (prev_notes_.size() == notes_.size ()) + { + for (int i= 0; i < notes_.size(); i++) { - char s[2] = "a"; - s[0] = (pit->notename_i_ + 2)%7 + 'a'; - - s[0] = toupper (s[0]); - note_p->set_grob_property ("note-character", ly_str02scm (s)); + Grob * p = new Spanner (get_property ("Tie")); + Tie::set_interface (p); // cannot remove yet! + + Tie::set_head (p, LEFT, prev_notes_[i]); + Tie::set_head (p, RIGHT, notes_[i]); + + ties_.push (p); + announce_grob(p, SCM_EOL); } - - announce_grob (note_p,req); - note_p_arr_.push (note_p); } - left_to_do_ -= note_dur.length_mom (); - + left_to_do_ -= note_dur.get_length (); /* don't do complicated arithmetic with grace notes. @@ -242,53 +272,46 @@ Completion_heads_engraver::process_music () { left_to_do_ = Rational (0,0); } - } void Completion_heads_engraver::stop_translation_timestep () { - for (int i=0; i < note_p_arr_.size (); i++) + for (int i = ties_.size (); i--;) + typeset_grob (ties_[i]); + ties_.clear(); + + for (int i=0; i < notes_.size (); i++) { - typeset_grob (note_p_arr_[i]); + typeset_grob (notes_[i]); } - note_p_arr_.clear (); + if (notes_.size()) + prev_notes_ = notes_; + notes_.clear (); - for (int i=0; i < dot_p_arr_.size (); i++) + for (int i=0; i < dots_.size (); i++) { - typeset_grob (dot_p_arr_[i]); + typeset_grob (dots_[i]); } - dot_p_arr_.clear (); + dots_.clear (); for (int i = scratch_note_reqs_.size(); i--;) { scm_gc_unprotect_object (scratch_note_reqs_[i]->self_scm () ); } + scratch_note_reqs_.clear(); } -Tie_req * tie_req = 0; - void Completion_heads_engraver::start_translation_timestep () { Moment now = now_mom (); if (note_end_mom_.main_part_ <= now.main_part_) { - note_req_l_arr_.clear (); - } - - if (left_to_do_) - { - if (!tie_req) - tie_req = new Tie_req; - - bool succ = daddy_trans_l_->try_music (tie_req); - if (!succ) - { - programming_error ("Completion_heads_engraver: no-one to make tie."); - } + note_reqs_.clear (); + prev_notes_.clear (); } } @@ -297,10 +320,11 @@ Completion_heads_engraver::Completion_heads_engraver() } ENTER_DESCRIPTION(Completion_heads_engraver, -/* descr */ "This engraver replaces -@code{Note_heads_engraver}. It plays some trickery to -break long notes and automatically tie them into the next measure.", -/* creats*/ "NoteHead Dots", -/* acks */ "", -/* reads */ "", +/* descr */ "This engraver replaces " +"@code{Note_heads_engraver}. It plays some trickery to " +"break long notes and automatically tie them into the next measure.", +/* creats*/ "NoteHead Dots Tie", +/* accepts */ "busy-playing-event note-event", +/* acks */ "", +/* reads */ "centralCPosition measurePosition measureLength", /* write */ "");