X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ftie-engraver.cc;h=e5f9efddf9cb953c35d2d0af184c61a77600db66;hb=9c419fba51d06d4ac4f615486f292d3c89bc879c;hp=57f9baad363f960829c85771d73305f11cc3dcac;hpb=1161a2b71bc32575ea9878a8631221edb8c03279;p=lilypond.git diff --git a/lily/tie-engraver.cc b/lily/tie-engraver.cc index 57f9baad36..e5f9efddf9 100644 --- a/lily/tie-engraver.cc +++ b/lily/tie-engraver.cc @@ -3,58 +3,42 @@ source file of the GNU LilyPond music typesetter - (c) 1998--2000 Han-Wen Nienhuys + (c) 1998--2002 Han-Wen Nienhuys */ -#include "tie-engraver.hh" #include "command-request.hh" -#include "rhythmic-head.hh" #include "musical-request.hh" #include "tie.hh" #include "translator-group.hh" #include "spanner.hh" #include "tie-column.hh" -#include "pqueue.hh" #include "engraver.hh" #include "item.hh" - -struct CHead_melodic_tuple { - Melodic_req *req_l_ ; - Grob *head_l_; - Moment end_; - CHead_melodic_tuple (); - CHead_melodic_tuple (Grob*, Melodic_req*, Moment); - static int pitch_compare (CHead_melodic_tuple const &, CHead_melodic_tuple const &); - static int time_compare (CHead_melodic_tuple const &, CHead_melodic_tuple const &); -}; - -inline int compare (CHead_melodic_tuple const &a, CHead_melodic_tuple const &b) -{ - return CHead_melodic_tuple::time_compare (a,b); -} - +#include "grob-pitch-tuple.hh" +#include "warn.hh" +#include "note-head.hh" /** Manufacture ties. Acknowledge noteheads, and put them into a priority queue. If we have a Tie_req, connect the notes that finish just at this time, and note that start at this time. - TODO: junk the pq; the PQ is overkill if we assume that no - different durations occur in parallel. + TODO: Remove the dependency on musical info. We should tie on the + basis of position and duration-log of the heads (not of the reqs). + */ class Tie_engraver : public Engraver { - PQueue past_notes_pq_; Moment end_mom_; Moment next_end_mom_; - Tie_req *req_l_; - Array now_heads_; - Array stopped_heads_; - Link_array tie_p_arr_; + Tie_req *req_; + Link_array now_heads_; + Link_array stopped_heads_; + Link_array ties_; - Spanner * tie_column_p_; + Spanner * tie_column_; void set_melisma (bool); @@ -63,19 +47,18 @@ protected: virtual void stop_translation_timestep (); virtual void acknowledge_grob (Grob_info); virtual bool try_music (Music*); - virtual void create_grobs (); + virtual void process_acknowledged_grobs (); void typeset_tie (Grob*); public: - VIRTUAL_COPY_CONS(Translator); - Tie_engraver(); + TRANSLATOR_DECLARATIONS(Tie_engraver); }; -Tie_engraver::Tie_engraver() +Tie_engraver::Tie_engraver () { - req_l_ = 0; - tie_column_p_ = 0; + req_ = 0; + tie_column_ = 0; } @@ -87,7 +70,7 @@ Tie_engraver::try_music (Music *m) /* if (end_mom_ > now_mom ()) return false; */ - req_l_ = c; + req_ = c; SCM m = get_property ("automaticMelismata"); bool am = gh_boolean_p (m) &&gh_scm2bool (m); if (am) @@ -102,60 +85,63 @@ Tie_engraver::try_music (Music *m) void Tie_engraver::set_melisma (bool m) { - daddy_trans_l_->set_property ("tieMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F); + daddy_trans_->set_property ("tieMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F); } void Tie_engraver::acknowledge_grob (Grob_info i) { - if (Rhythmic_head::has_interface (i.elem_l_)) + if (Note_head::has_interface (i.grob_)) { - Note_req * m = dynamic_cast (i.req_l_); - if (!m) - return; - now_heads_.push (CHead_melodic_tuple (i.elem_l_, m, now_mom()+ m->length_mom ())); + now_heads_.push (i.grob_); } } +int +head_pitch_compare (Grob *const&a,Grob *const&b) +{ + Music *m1 =unsmob_music (a->get_grob_property ("cause")); + Music *m2 =unsmob_music (b->get_grob_property ("cause")); + + return Pitch::compare (* unsmob_pitch (m1->get_mus_property ("pitch")), + * unsmob_pitch (m2->get_mus_property ("pitch"))); +} void -Tie_engraver::create_grobs () +Tie_engraver::process_acknowledged_grobs () { - if (req_l_) + if (req_) { - now_heads_.sort (CHead_melodic_tuple::pitch_compare); - stopped_heads_.sort(CHead_melodic_tuple::pitch_compare); + now_heads_.sort (&head_pitch_compare); + /* + We could sort stopped_heads_ as well (and use a linear alg. in + stead of nested loop), but we'd have to use a stable sorting + algorithm, since the ordering of the stopped heads (of the + same pitch) is relevant. + */ SCM head_list = SCM_EOL; - int j = stopped_heads_.size ()-1; - int i = now_heads_.size ()-1; - - while (i >= 0 && j >=0) + for (int i = now_heads_.size(); i--;) { - int comp - = Pitch::compare (*unsmob_pitch (now_heads_[i].req_l_->get_mus_property ("pitch") ), - *unsmob_pitch (stopped_heads_[j].req_l_->get_mus_property ("pitch"))); - - if (comp) + for (int j = stopped_heads_.size(); j--;) { - (comp < 0) ? j -- : i--; - continue; - } - else - { - head_list = gh_cons (gh_cons (stopped_heads_[j].head_l_->self_scm (), - now_heads_[i].head_l_->self_scm ()), - head_list); - - past_notes_pq_. insert (now_heads_[i]); - now_heads_.del (i); - stopped_heads_.del (j); - i--; - j--; + int comp + = head_pitch_compare (now_heads_[i], stopped_heads_[j]); + + if (!comp) + { + head_list = gh_cons (gh_cons (stopped_heads_[j]->self_scm (), + now_heads_[i]->self_scm ()), + head_list); + + now_heads_.del (i); + stopped_heads_.del (j); + break ; + } } } - + SCM basic = get_property ("Tie"); SCM sparse = get_property ("sparseTies"); if (to_boolean (sparse)) @@ -165,34 +151,36 @@ Tie_engraver::create_grobs () if (!i) return; - SCM pair = gh_list_ref (head_list, gh_int2scm (i/2)); + SCM pair = scm_list_ref (head_list, gh_int2scm (i/2)); Spanner * p = new Spanner (basic); - Tie::set_head (p,LEFT, dynamic_cast (unsmob_grob (gh_car (pair)))); - Tie::set_head (p,RIGHT, dynamic_cast (unsmob_grob (gh_cdr (pair)))); + + Tie::set_interface (p); // cannot remove. + Tie::set_head (p,LEFT, dynamic_cast (unsmob_grob (ly_car (pair)))); + Tie::set_head (p,RIGHT, dynamic_cast (unsmob_grob (ly_cdr (pair)))); - tie_p_arr_.push (p); - announce_grob (p, req_l_); + ties_.push (p); + announce_grob(p, req_->self_scm()); } - else for (SCM s = head_list; gh_pair_p (s); s = gh_cdr (s)) + else for (SCM s = head_list; gh_pair_p (s); s = ly_cdr (s)) { Grob * p = new Spanner (basic); - Tie::set_interface (p); + Tie::set_interface (p); // cannot remove yet! - Tie::set_head (p, LEFT, dynamic_cast (unsmob_grob (gh_caar (s)))); - Tie::set_head (p, RIGHT, dynamic_cast (unsmob_grob (gh_cdar (s)))); + Tie::set_head (p, LEFT, dynamic_cast (unsmob_grob (ly_caar (s)))); + Tie::set_head (p, RIGHT, dynamic_cast (unsmob_grob (ly_cdar (s)))); - tie_p_arr_.push (p); - announce_grob (p, req_l_); + ties_.push (p); + announce_grob(p, req_->self_scm()); } - if (tie_p_arr_.size () > 1 && !tie_column_p_) + if (ties_.size () > 1 && !tie_column_) { - tie_column_p_ = new Spanner (get_property ("TieColumn")); - Tie_column::set_interface (tie_column_p_); - for (int i = tie_p_arr_.size (); i--; ) - Tie_column::add_tie (tie_column_p_,tie_p_arr_ [i]); - announce_grob (tie_column_p_, 0); + tie_column_ = new Spanner (get_property ("TieColumn")); + + for (int i = ties_.size (); i--;) + Tie_column::add_tie (tie_column_,ties_ [i]); + announce_grob(tie_column_, SCM_EOL); } } } @@ -201,46 +189,43 @@ Tie_engraver::create_grobs () void Tie_engraver::stop_translation_timestep () { - for (int i=0; i < now_heads_.size (); i++) - { - past_notes_pq_.insert (now_heads_[i]); - } + req_ = 0; + now_heads_.clear (); - if (req_l_ && !tie_p_arr_.size ()) - { - req_l_->origin ()->warning (_ ("No ties were created!")); - } + /* + we don't warn for no ties, since this happens naturally when you + use skipTypesetting. */ - for (int i=0; i< tie_p_arr_.size (); i++) + for (int i=0; i< ties_.size (); i++) { - typeset_tie (tie_p_arr_[i]); + typeset_tie (ties_[i]); } - tie_p_arr_.clear (); - if (tie_column_p_) + ties_.clear (); + if (tie_column_) { - typeset_grob (tie_column_p_); - tie_column_p_ =0; + typeset_grob (tie_column_); + tie_column_ =0; } } void Tie_engraver::typeset_tie (Grob *her) { - if (!(Tie::head (her,LEFT) && Tie::head (her,RIGHT))) + if (! (Tie::head (her,LEFT) && Tie::head (her,RIGHT))) warning (_ ("lonely tie")); Direction d = LEFT; Drul_array new_head_drul; - new_head_drul[LEFT] = Tie::head(her,LEFT); + new_head_drul[LEFT] = Tie::head (her,LEFT); new_head_drul[RIGHT] = Tie::head (her,RIGHT); do { if (!Tie::head (her,d)) - new_head_drul[d] = Tie::head(her,(Direction)-d); - } while (flip(&d) != LEFT); + new_head_drul[d] = Tie::head (her, (Direction)-d); + } while (flip (&d) != LEFT); - index_set_cell (her->get_grob_property ("heads"), LEFT, new_head_drul[LEFT]->self_scm () ); - index_set_cell (her->get_grob_property ("heads"), RIGHT, new_head_drul[RIGHT]->self_scm () ); + index_set_cell (her->get_grob_property ("heads"), LEFT, new_head_drul[LEFT]->self_scm ()); + index_set_cell (her->get_grob_property ("heads"), RIGHT, new_head_drul[RIGHT]->self_scm ()); typeset_grob (her); } @@ -253,53 +238,49 @@ Tie_engraver::start_translation_timestep () { set_melisma (false); } - req_l_ = 0; - Moment now = now_mom (); - while (past_notes_pq_.size () && past_notes_pq_.front ().end_ < now) - past_notes_pq_.delmin (); - + SCM grobs = get_property ("busyGrobs"); + Moment now = now_mom(); stopped_heads_.clear (); - while (past_notes_pq_.size () - && past_notes_pq_.front ().end_ == now) - stopped_heads_.push (past_notes_pq_.get ()); + + for (; gh_pair_p (grobs); grobs = gh_cdr (grobs)) + { + Grob * grob = unsmob_grob (gh_cdar (grobs)); + Moment end =*unsmob_moment (gh_caar (grobs)); + + /* + This is slightly ugh: we are now confunding the frontend + (iterators) and the backend (note heads) */ + if (end > now) + break; + else if (end == now + && Note_head::has_interface (grob)) + stopped_heads_.push (grob); + } -} -ADD_THIS_TRANSLATOR(Tie_engraver); + /* + + The list starts with entries that start earlier. By going through + it, we reverse the order, where as we'd like to use the `last' + heads first. + This makes a difference for grace notes. If we have -CHead_melodic_tuple::CHead_melodic_tuple () -{ - head_l_ =0; - req_l_ =0; - end_ = 0; -} + c4 \grace c8 ~ c4 -CHead_melodic_tuple::CHead_melodic_tuple (Grob *h, Melodic_req*m, Moment mom) -{ - head_l_ = h; - req_l_ = m; - end_ = mom; -} + Then busyGrobs will have ((1/4 . gc8) (1/4 . c4)). -/* - signed compare, should use pitchget_mus_property ("pitch"); - SCM p2 = h2.req_l_->get_mus_property ("pitch"); - - return Pitch::compare (*unsmob_pitch (p1), - *unsmob_pitch (p2)); + We want stopped_heads_ to contain (c4 gc8), because we start with + it at the top. + */ + stopped_heads_.reverse(); } -int -CHead_melodic_tuple::time_compare (CHead_melodic_tuple const&h1, - CHead_melodic_tuple const &h2) -{ - return (h1.end_ - h2.end_ ).sign (); -} + +ENTER_DESCRIPTION(Tie_engraver, +/* descr */ "Generate ties between noteheads of equal pitch.", +/* creats*/ "Tie TieColumn", +/* acks */ "rhythmic-head-interface", +/* reads */ "sparseTies tieMelismaBusy", +/* write */ "");