]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/completion-note-heads-engraver.cc
Imported Upstream version 2.14.2
[lilypond.git] / lily / completion-note-heads-engraver.cc
index b4c4afb0877a7a945e2c385d2eb6cb0fbee262be..a2c606f472897c58c6c17d221aa806902114a9dc 100644 (file)
@@ -1,7 +1,20 @@
 /*
-  completion-note-heads-engraver.cc -- Completion_heads_engraver
+  This file is part of LilyPond, the GNU music typesetter.
 
-  (c) 1997--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
+  Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include <cctype>
@@ -14,33 +27,17 @@ using namespace std;
 #include "item.hh"
 #include "output-def.hh"
 #include "pitch.hh"
-#include "pqueue.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 "tie-column.hh"
 #include "warn.hh"
 
 #include "translator.icc"
 
-/*
-  TODO: make matching rest engraver.
-*/
-struct Pending_tie
-{
-  Moment when_;
-  Stream_event* tie_event_;
-  Pending_tie() { tie_event_ = 0; }
-};
-
-int compare(Pending_tie const &a, Pending_tie const &b)
-{
-  return compare(a.when_, b.when_);
-}
-
-
 /*
   How does this work?
 
@@ -58,24 +55,22 @@ int compare(Pending_tie const &a, Pending_tie const &b)
 
 class Completion_heads_engraver : public Engraver
 {
-  vector<Item*> notes_;
-  vector<Item*> prev_notes_;
-
+  vector<Item *> notes_;
+  vector<Item *> prev_notes_;
   // Must remember notes for explicit ties.
-  vector<Item*> tie_note_candidates_;
-  vector<Stream_event*> tie_note_candidate_events_;
-  vector<Grob*> ties_;
-  PQueue<Pending_tie> pending_ties_;
-  vector<Stream_event*> note_events_;
-
-  Stream_event *current_tie_event_;
+  vector<Item *> tie_note_candidates_;
+  vector<Stream_event *> tie_note_candidate_events_;
+  vector<Grob *> ties_;
+  vector<Stream_event *> note_events_;
+  Spanner *tie_column_;
   Moment note_end_mom_;
   bool is_first_;
   Rational left_to_do_;
   Rational do_nothing_until_;
+  Rational factor_;
 
   Moment next_barline_moment ();
-  Item *make_note_head (Stream_event*);
+  Item *make_note_head (Stream_event *);
 
 public:
   TRANSLATOR_DECLARATIONS (Completion_heads_engraver);
@@ -87,14 +82,12 @@ protected:
   void process_music ();
   void stop_translation_timestep ();
   DECLARE_TRANSLATOR_LISTENER (note);
-  DECLARE_TRANSLATOR_LISTENER (tie);
 };
 
 void
 Completion_heads_engraver::initialize ()
 {
   is_first_ = false;
-  current_tie_event_ = 0;
 }
 
 IMPLEMENT_TRANSLATOR_LISTENER (Completion_heads_engraver, note);
@@ -102,7 +95,7 @@ void
 Completion_heads_engraver::listen_note (Stream_event *ev)
 {
   note_events_.push_back (ev);
-  
+
   is_first_ = true;
   Moment now = now_mom ();
   Moment musiclen = get_event_length (ev, now);
@@ -111,16 +104,8 @@ Completion_heads_engraver::listen_note (Stream_event *ev)
   do_nothing_until_ = Rational (0, 0);
 }
 
-IMPLEMENT_TRANSLATOR_LISTENER (Completion_heads_engraver, tie);
-void
-Completion_heads_engraver::listen_tie (Stream_event *ev)
-{
-  is_first_ = true;
-  current_tie_event_ = ev;
-}
-
 /*
-  The duration _until_ the next barline.
+  The duration _until_ the next bar line.
 */
 Moment
 Completion_heads_engraver::next_barline_moment ()
@@ -135,7 +120,7 @@ Completion_heads_engraver::next_barline_moment ()
   return (*l - *e);
 }
 
-Item*
+Item *
 Completion_heads_engraver::make_note_head (Stream_event *ev)
 {
   Item *note = make_item ("NoteHead", ev->self_scm ());
@@ -157,14 +142,6 @@ Completion_heads_engraver::process_music ()
   if (!is_first_ && !left_to_do_)
     return;
 
-  if (current_tie_event_)
-    {
-      Pending_tie pending;
-      pending.when_ = note_end_mom_;
-      pending.tie_event_ = current_tie_event_;
-      pending_ties_.insert (pending);
-    }
-  
   is_first_ = false;
 
   Moment now = now_mom ();
@@ -174,22 +151,33 @@ Completion_heads_engraver::process_music ()
   Duration note_dur;
   Duration *orig = 0;
   if (left_to_do_)
-    note_dur = Duration (left_to_do_, false);
+    {
+      /*
+       note that note_dur may be strictly less than left_to_do_
+       (say, if left_to_do_ == 5/8)
+      */
+      if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
+       note_dur = Duration (left_to_do_, false);
+      else
+       note_dur = Duration (left_to_do_ / factor_, false).compressed (factor_);
+    }
   else
     {
       orig = unsmob_duration (note_events_[0]->get_property ("duration"));
       note_dur = *orig;
+      factor_ = note_dur.factor ();
+      left_to_do_ = orig->get_length ();
     }
   Moment nb = next_barline_moment ();
   if (nb.main_part_ && nb < note_dur.get_length ())
     {
-      note_dur = Duration (nb.main_part_, false);
-
-      do_nothing_until_ = now.main_part_ + note_dur.get_length ();
+      if (factor_.denominator () == 1 && factor_ > Rational (1, 1))
+       note_dur = Duration (nb.main_part_, false);
+      else
+       note_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_);
     }
 
-  if (orig)
-    left_to_do_ = orig->get_length ();
+  do_nothing_until_ = now.main_part_ + note_dur.get_length ();
 
   for (vsize i = 0; left_to_do_ && i < note_events_.size (); i++)
     {
@@ -200,41 +188,42 @@ Completion_heads_engraver::process_music ()
        event = event->clone ();
 
       SCM pits = note_events_[i]->get_property ("pitch");
-
       event->set_property ("pitch", pits);
       event->set_property ("duration", note_dur.smobbed_copy ());
       event->set_property ("length", Moment (note_dur.get_length ()).smobbed_copy ());
       event->set_property ("duration-log", scm_from_int (note_dur.duration_log ()));
 
+      /*
+       The Completion_heads_engraver splits an event into a group of consecutive events.
+       For each event in the group, the property "autosplit-end" denotes whether the current event
+       was truncated during splitting. Based on "autosplit-end", the Tie_engraver decides whether a
+       tie event should be processed.
+      */
+      event->set_property ("autosplit-end",
+                          ly_bool2scm (left_to_do_ - note_dur.get_length () > Rational (0)));
+
       Item *note = make_note_head (event);
       if (need_clone)
        event->unprotect ();
       notes_.push_back (note);
     }
-  
-  if (pending_ties_.size ()
-      && pending_ties_.front().when_ == now_mom())
-    {
-      for (vsize i = 0; i < tie_note_candidate_events_.size(); i++)
-       for (vsize j = 0; j < note_events_.size(); j++)
-         {
-           Pitch *p =  unsmob_pitch (note_events_[j]->get_property ("pitch"));
-           Pitch *p_last
-             = unsmob_pitch (tie_note_candidate_events_[j]->get_property ("pitch"));
-           if (p && p_last && *p == *p_last)
-             make_tie (tie_note_candidates_[i], notes_[j]);
-         }
-    }
-      
+
   if (prev_notes_.size () == notes_.size ())
     {
       for (vsize i = 0; i < notes_.size (); i++)
        make_tie (prev_notes_[i], notes_[i]);
     }
 
+  if (ties_.size () && !tie_column_)
+    tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ());
+
+  if (tie_column_)
+    for (vsize i = ties_.size (); i--;)
+      Tie_column::add_tie (tie_column_, ties_[i]);
+
   left_to_do_ -= note_dur.get_length ();
   if (left_to_do_)
-    get_global_context ()->add_moment_to_process (now.main_part_ + note_dur.get_length());
+    get_global_context ()->add_moment_to_process (now.main_part_ + note_dur.get_length ());
   /*
     don't do complicated arithmetic with grace notes.
   */
@@ -250,11 +239,12 @@ Completion_heads_engraver::make_tie (Grob *left, Grob *right)
   Tie::set_head (p, RIGHT, right);
   ties_.push_back (p);
 }
-                                    
+
 void
 Completion_heads_engraver::stop_translation_timestep ()
 {
   ties_.clear ();
+  tie_column_ = 0;
 
   if (notes_.size ())
     prev_notes_ = notes_;
@@ -265,11 +255,6 @@ void
 Completion_heads_engraver::start_translation_timestep ()
 {
   Moment now = now_mom ();
-  while (pending_ties_.size() && pending_ties_.front().when_ < now)
-    {
-      pending_ties_.delmin();
-    }
-  current_tie_event_ = 0;
   if (note_end_mom_.main_part_ <= now.main_part_)
     {
       tie_note_candidate_events_ = note_events_;
@@ -284,6 +269,7 @@ Completion_heads_engraver::start_translation_timestep ()
 
 Completion_heads_engraver::Completion_heads_engraver ()
 {
+  tie_column_ = 0;
 }
 
 ADD_TRANSLATOR (Completion_heads_engraver,
@@ -294,13 +280,14 @@ ADD_TRANSLATOR (Completion_heads_engraver,
 
                /* create */
                "NoteHead "
-               "Dots "
-               "Tie ",
+               "Tie "
+               "TieColumn ",
 
                /* read */
-               "middleCPosition "
+               "measureLength "
                "measurePosition "
-               "measureLength ",
+               "middleCPosition "
+               "timing ",
 
                /* write */
                "completionBusy "