X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fcompletion-note-heads-engraver.cc;h=cb4471528623ed66c9a7ce5ded3c4b708a533fc9;hb=f9214bac21e9926dc3248416f58190c98c4167a9;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..cb44715286 100644 --- a/lily/completion-note-heads-engraver.cc +++ b/lily/completion-note-heads-engraver.cc @@ -1,108 +1,131 @@ /* - head-grav.cc -- part of GNU LilyPond + completion-note-heads-engraver.cc -- Completion_heads_engraver - (c) 1997--2001 Han-Wen Nienhuys + (c) 1997--2007 Han-Wen Nienhuys */ -#include +#include +using namespace std; -#include "rhythmic-head.hh" -#include "paper-def.hh" -#include "musical-request.hh" -#include "dots.hh" #include "dot-column.hh" -#include "staff-symbol-referencer.hh" +#include "dots.hh" +#include "duration.hh" +#include "global-context.hh" #include "item.hh" +#include "output-def.hh" +#include "pitch.hh" +#include "rhythmic-head.hh" #include "score-engraver.hh" +#include "spanner.hh" +#include "staff-symbol-referencer.hh" +#include "stream-event.hh" +#include "tie.hh" #include "warn.hh" -/** - make balls and rests - */ +#include "translator.icc" + +/* + TODO: make matching rest engraver. +*/ + +/* + 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 events into scratch note events, to make sure that we get + all durations exactly right. +*/ + class Completion_heads_engraver : public Engraver { - Link_array note_p_arr_; - - Link_array dot_p_arr_; - Link_array note_req_l_arr_; - Link_array scratch_note_reqs_; + vector notes_; + vector prev_notes_; + vector ties_; + + vector dots_; + vector note_events_; + vector scratch_note_events_; Moment note_end_mom_; - bool first_b_; + bool is_first_; Rational left_to_do_; + Rational do_nothing_until_; Moment next_barline_moment (); Duration find_nearest_duration (Rational length); - + public: - TRANSLATOR_DECLARATIONS(Completion_heads_engraver); + TRANSLATOR_DECLARATIONS (Completion_heads_engraver); protected: virtual void initialize (); - virtual void start_translation_timestep (); - virtual bool try_music (Music *req_l) ; - virtual void process_music (); - virtual void stop_translation_timestep (); + void start_translation_timestep (); + void process_music (); + void stop_translation_timestep (); + DECLARE_TRANSLATOR_LISTENER (note); }; void Completion_heads_engraver::initialize () { - first_b_ = false; + is_first_ = false; } -bool -Completion_heads_engraver::try_music (Music *m) +IMPLEMENT_TRANSLATOR_LISTENER (Completion_heads_engraver, note); +void +Completion_heads_engraver::listen_note (Stream_event *ev) { - if (Note_req * n =dynamic_cast (m)) - { - note_req_l_arr_.push (n); - - first_b_ = true; - Moment musiclen = m->length_mom (); - Moment now = now_mom(); + note_events_.push_back (ev); + + is_first_ = true; + Moment musiclen = get_event_length (ev); + Moment now = now_mom (); - if (now_mom ().grace_part_) - { - musiclen.grace_part_ = musiclen.main_part_ ; - musiclen.main_part_ = Rational (0,1); - } - note_end_mom_ = note_end_mom_ >? (now + musiclen); - return true; - } - else if (dynamic_cast (m)) + if (now_mom ().grace_part_) { - return now_mom () < note_end_mom_; + musiclen.grace_part_ = musiclen.main_part_; + musiclen.main_part_ = Rational (0, 1); } - return false; - + + note_end_mom_ = max (note_end_mom_, (now + musiclen)); + do_nothing_until_ = Rational (0, 0); } +/* + The duration _until_ the next barline. +*/ Moment -Completion_heads_engraver::next_barline_moment ( ) +Completion_heads_engraver::next_barline_moment () { Moment *e = unsmob_moment (get_property ("measurePosition")); Moment *l = unsmob_moment (get_property ("measureLength")); if (!e || !l) { - programming_error ("No timing props set?"); - return Moment (1,1); + programming_error ("no timing props set?"); + return Moment (1, 1); } return (*l - *e); } -Duration +Duration Completion_heads_engraver::find_nearest_duration (Rational length) { - int log_limit= 6; + int log_limit = 6; - Duration d(0,0); + Duration d (0, 0); /* 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 ()) { @@ -110,9 +133,7 @@ Completion_heads_engraver::find_nearest_duration (Rational length) continue; } else - { - d = Duration (d.duration_log () + 1, 2); - } + d = Duration (d.duration_log () + 1, 2); } if (d.duration_log () >= log_limit) @@ -121,154 +142,143 @@ 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; } void Completion_heads_engraver::process_music () { - if (!first_b_ && !left_to_do_) - return ; + if (!is_first_ && !left_to_do_) + return; + + is_first_ = false; + + Moment now = now_mom (); + if (do_nothing_until_ > now.main_part_) + return; - first_b_ = false; - Duration note_dur; Duration *orig = 0; if (left_to_do_) - { - note_dur = find_nearest_duration (left_to_do_); - } + note_dur = find_nearest_duration (left_to_do_); else { - orig = unsmob_duration (note_req_l_arr_[0]->get_mus_property ("duration")); + orig = unsmob_duration (note_events_[0]->get_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 (); - top_engraver ()->add_moment_to_process (next); + Moment next = now; + next.main_part_ += note_dur.get_length (); + + get_global_context ()->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++) + if (!scratch_note_events_.size ()) + for (vsize i = 0; i < note_events_.size (); i++) { - Music * m = note_req_l_arr_[i]->clone (); - scratch_note_reqs_.push (m); + Stream_event *m = note_events_[i]->clone (); + scratch_note_events_.push_back (m); } - - for (int i =0; i < scratch_note_reqs_.size (); i++) - scratch_note_reqs_[i]->set_mus_property ("duration", note_dur.smobbed_copy ()); } - + else + { + for (vsize i = 0; i < note_events_.size (); i++) + { + Stream_event *c = note_events_[i]->clone (); + scratch_note_events_.push_back (c); + } + } - for (int i = 0; - left_to_do_ && i < note_req_l_arr_.size (); i++) + for (vsize i = 0; left_to_do_ && i < note_events_.size (); i++) { - Item *note_p = new Item (get_property ("NoteHead")); - - Staff_symbol_referencer::set_interface (note_p); - - Music * req = note_req_l_arr_[i]; - if (scratch_note_reqs_.size()) + Stream_event *event = note_events_[i]; + if (scratch_note_events_.size ()) { - req = scratch_note_reqs_[i]; - req->set_mus_property ("pitch", - note_req_l_arr_[i]->get_mus_property ("pitch")); + event = scratch_note_events_[i]; + SCM pits = note_events_[i]->get_property ("pitch"); + event->set_property ("pitch", pits); } - note_p->set_grob_property ("duration-log", - gh_int2scm (note_dur.duration_log ())); - int dots= note_dur.dot_count (); + event->set_property ("duration", note_dur.smobbed_copy ()); + + Item *note = make_item ("NoteHead", event->self_scm ()); + note->set_property ("duration-log", + scm_from_int (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); - - /* - measly attempt to save an eeny-weenie bit of memory. - */ - 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); + Item *d = make_item ("Dots", SCM_EOL); + Rhythmic_head::set_dots (note, d); + + d->set_property ("dot-count", scm_from_int (dots)); + + d->set_parent (note, Y_AXIS); + dots_.push_back (d); } - Pitch *pit =unsmob_pitch (req->get_mus_property ("pitch")); + Pitch *pit = unsmob_pitch (event->get_property ("pitch")); int pos = pit->steps (); - SCM c0 = get_property ("centralCPosition"); - if (gh_number_p (c0)) - pos += gh_scm2int (c0); + SCM c0 = get_property ("middleCPosition"); + if (scm_is_number (c0)) + pos += scm_to_int (c0); - note_p->set_grob_property ("staff-position", gh_int2scm (pos)); - if (to_boolean (get_property ("easyPlay"))) + note->set_property ("staff-position", scm_from_int (pos)); + notes_.push_back (note); + } + + if (prev_notes_.size () == notes_.size ()) + { + for (vsize i = 0; i < notes_.size (); i++) { - char s[2] = "a"; - s[0] = (pit->notename_i_ + 2)%7 + 'a'; + Grob *p = make_spanner ("Tie", SCM_EOL); + Tie::set_head (p, LEFT, prev_notes_[i]); + Tie::set_head (p, RIGHT, notes_[i]); - s[0] = toupper (s[0]); - note_p->set_grob_property ("note-character", ly_str02scm (s)); + ties_.push_back (p); } - - 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. - */ + */ if (orig - && now_mom().grace_part_ ) - { - left_to_do_ = Rational (0,0); - } - + && now_mom ().grace_part_) + left_to_do_ = Rational (0, 0); } - + void Completion_heads_engraver::stop_translation_timestep () { - for (int i=0; i < note_p_arr_.size (); i++) - { - typeset_grob (note_p_arr_[i]); - } - note_p_arr_.clear (); - - for (int i=0; i < dot_p_arr_.size (); i++) - { - typeset_grob (dot_p_arr_[i]); - } - dot_p_arr_.clear (); + ties_.clear (); - for (int i = scratch_note_reqs_.size(); i--;) - { - scm_gc_unprotect_object (scratch_note_reqs_[i]->self_scm () ); - - } - scratch_note_reqs_.clear(); -} + if (notes_.size ()) + prev_notes_ = notes_; + notes_.clear (); + + dots_.clear (); -Tie_req * tie_req = 0; + for (vsize i = scratch_note_events_.size (); i--;) + scratch_note_events_[i]->unprotect (); + + scratch_note_events_.clear (); +} void Completion_heads_engraver::start_translation_timestep () @@ -276,31 +286,26 @@ 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_events_.clear (); + prev_notes_.clear (); } } -Completion_heads_engraver::Completion_heads_engraver() +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 */ "", -/* write */ ""); +ADD_TRANSLATOR (Completion_heads_engraver, + /* doc */ "This engraver replaces " + "@code{Note_heads_engraver}. It plays some trickery to " + "break long notes and automatically tie them into the next measure.", + /* create */ + "NoteHead " + "Dots " + "Tie", + /* read */ + "middleCPosition " + "measurePosition " + "measureLength", + + /* write */ "");