]> git.donarmstrong.com Git - lilypond.git/commitdiff
Fix #305: Allow alignment spanner to be broken for dynamics.
authorNeil Puttock <n.puttock@gmail.com>
Sun, 30 May 2010 22:17:24 +0000 (23:17 +0100)
committerNeil Puttock <n.puttock@gmail.com>
Sun, 30 May 2010 22:17:24 +0000 (23:17 +0100)
Introduce a new event class which will trigger the end of a DynamicLineSpanner
prematurely, thus allowing dynamics to be positioned independently.

input/regression/dynamics-alignment-breaker.ly [new file with mode: 0644]
lily/dynamic-align-engraver.cc
ly/spanners-init.ly
scm/define-event-classes.scm
scm/define-music-types.scm

diff --git a/input/regression/dynamics-alignment-breaker.ly b/input/regression/dynamics-alignment-breaker.ly
new file mode 100644 (file)
index 0000000..872dff7
--- /dev/null
@@ -0,0 +1,21 @@
+\version "2.13.23"
+
+\header {
+  texidoc = "Hairpins, DynamicTextSpanners and dynamics can be
+positioned independently using @code{\\breakDynamicSpan}, which
+causes the alignment spanner to end prematurely.
+"
+}
+
+\relative c' {
+  c1^\<
+  \dimTextDim
+  c1_\>
+  f,1\p
+
+  c'1^\<
+  \breakDynamicSpan
+  c1_\>
+  \breakDynamicSpan
+  f,1\p
+}
index 074569d63a14f2b20f11ed89d2959dd9365c140a..96d19b7ded506402fa17323bbf69fdd79004f474 100644 (file)
@@ -2,7 +2,7 @@
   This file is part of LilyPond, the GNU music typesetter.
 
   Copyright (C) 2008--2010 Han-Wen Nienhuys <hanwen@lilypond.org>
-  
+
 
   LilyPond is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -34,6 +34,7 @@
 class Dynamic_align_engraver : public Engraver
 {
   TRANSLATOR_DECLARATIONS (Dynamic_align_engraver);
+  DECLARE_TRANSLATOR_LISTENER (break_span);
   DECLARE_ACKNOWLEDGER (note_column);
   DECLARE_ACKNOWLEDGER (dynamic);
   DECLARE_END_ACKNOWLEDGER (dynamic);
@@ -43,19 +44,21 @@ protected:
 
 private:
   void create_line_spanner (Stream_event *cause);
-  Spanner* line_;
-
-  vector<Spanner*> ended_;
-  vector<Spanner*> started_;
-  vector<Grob*> scripts_;
-  vector<Grob*> support_;
-  
-  set<Spanner*> running_;
+  Spanner *line_;
+  vector<Spanner *> ended_;
+  vector<Spanner *> started_;
+  vector<Grob *> scripts_;
+  vector<Grob *> support_;
+
+  set<Spanner *> running_;
+
+  bool early_end_;
 };
 
 Dynamic_align_engraver::Dynamic_align_engraver ()
 {
   line_ = 0;
+  early_end_ = false;
 }
 
 ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
@@ -63,17 +66,17 @@ ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column);
 ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
 
 void
-Dynamic_align_engraver::create_line_spanner (Stream_eventevent)
+Dynamic_align_engraver::create_line_spanner (Stream_event *event)
 {
   if (!line_)
     line_ = make_spanner ("DynamicLineSpanner",
-                         event ? event->self_scm() : SCM_EOL);
+                         event ? event->self_scm () : SCM_EOL);
 }
 
 void
 Dynamic_align_engraver::acknowledge_end_dynamic (Grob_info info)
 {
-  if (Spanner::has_interface(info.grob()))
+  if (Spanner::has_interface (info.grob ()))
     ended_.push_back (info.spanner ());
 }
 
@@ -83,17 +86,25 @@ Dynamic_align_engraver::acknowledge_note_column (Grob_info info)
   support_.push_back (info.grob ());
 }
 
+IMPLEMENT_TRANSLATOR_LISTENER (Dynamic_align_engraver, break_span);
+void
+Dynamic_align_engraver::listen_break_span (Stream_event *event)
+{
+  if (event->in_event_class ("break-dynamic-span-event"))
+    early_end_ = true;
+}
+
 void
 Dynamic_align_engraver::acknowledge_dynamic (Grob_info info)
 {
   Stream_event *cause = info.event_cause ();
   create_line_spanner (cause);
-  if (Spanner::has_interface(info.grob()))
+  if (Spanner::has_interface (info.grob ()))
     started_.push_back (info.spanner ());
-  else if (info.item())
-    scripts_.push_back (info.item());
+  else if (info.item ())
+    scripts_.push_back (info.item ());
   else
-    info.grob ()->programming_error ("Unknown dynamic grob.");
+    info.grob ()->programming_error ("unknown dynamic grob");
 
   Axis_group_interface::add_element (line_, info.grob ());
 
@@ -107,20 +118,21 @@ Dynamic_align_engraver::acknowledge_dynamic (Grob_info info)
 void
 Dynamic_align_engraver::stop_translation_timestep ()
 {
-  for (vsize i = 0; i < started_.size(); i++)
+  for (vsize i = 0; i < started_.size (); i++)
     running_.insert (started_[i]);
-  for (vsize i = 0; i < ended_.size(); i++)
+  for (vsize i = 0; i < ended_.size (); i++)
     {
       Spanner *sp = ended_[i];
 
-      set<Spanner*>::iterator it  = running_.find (sp);
-      if (it != running_.end())
+      set<Spanner *>::iterator it = running_.find (sp);
+      if (it != running_.end ())
        running_.erase (it);
       else
-       started_[i]->programming_error ("Lost track of this dynamic spanner.");
+       started_[i]->programming_error ("lost track of this dynamic spanner");
     }
 
-  bool end = line_ && running_.empty ();
+  bool end = line_ && (running_.empty ()
+                      || early_end_);
   Direction d = LEFT;
   do
     {
@@ -128,18 +140,19 @@ Dynamic_align_engraver::stop_translation_timestep ()
          && ((d == LEFT && !line_->get_bound (LEFT))
              || (end && d == RIGHT && !line_->get_bound (RIGHT))))
        {
-         vector<Spanner*> const &spanners =
-           (d == LEFT) ? started_ : ended_;
-         
+         vector<Spanner *> const &spanners
+           (d == LEFT) ? started_ : ended_;
+
          Grob *bound = 0;
-         if (scripts_.size())
+         if (scripts_.size ())
            bound = scripts_[0];
-         else if (spanners.size())
+         else if (spanners.size ())
            bound = spanners[0]->get_bound (d);
          else
            {
-             programming_error ("Started DynamicLineSpanner but have no left bound.");
              bound = unsmob_grob (get_property ("currentMusicalColumn"));
+             if (!early_end_)
+               programming_error ("started DynamicLineSpanner but have no left bound");
            }
 
          line_->set_bound (d, bound);
@@ -150,8 +163,11 @@ Dynamic_align_engraver::stop_translation_timestep ()
   for (vsize i = 0; line_ && i < support_.size (); i++)
     Side_position_interface::add_support (line_, support_[i]);
 
-  if (end) 
-    line_ = 0;
+  if (end)
+    {
+      line_ = 0;
+      early_end_ = false;
+    }
 
   ended_.clear ();
   started_.clear ();
@@ -159,10 +175,9 @@ Dynamic_align_engraver::stop_translation_timestep ()
   support_.clear ();
 }
 
-
 ADD_TRANSLATOR (Dynamic_align_engraver,
                /* doc */
-               "Align hairpins and dynamic texts on a horizontal line",
+               "Align hairpins and dynamic texts on a horizontal line.",
 
                /* create */
                "DynamicLineSpanner ",
index 065827ab591bd5ad2ba4478266ae2c9d09174828..6ebb6fbdbecf7d29c14a63d75fe4b3df46be1a78 100644 (file)
@@ -104,3 +104,5 @@ sostenutoOff = #(make-span-event 'SostenutoEvent STOP)
 %dim = \set crescendoText = "dim."
 
 newSpacingSection = #(make-event-chord (list (make-music 'SpacingSectionEvent)))
+
+breakDynamicSpan = #(make-music 'BreakDynamicSpanEvent)
index d9bbceb3c27f168b1222febb020469d9bd6ddc24..4de8c5d97b37d820a586c3c9683c6a86dbfed43f 100644 (file)
@@ -34,9 +34,9 @@
       harmonic-event hyphen-event laissez-vibrer-event mark-event
       multi-measure-text-event note-grouping-event 
       pes-or-flexa-event repeat-tie-event spacing-section-event
-      layout-instruction-event completize-extender-event))
+      layout-instruction-event completize-extender-event break-span-event))
     
-    (layout-instruction-event . (apply-output-event ))
+    (layout-instruction-event . (apply-output-event))
     (script-event . (articulation-event text-script-event))
     (part-combine-event . (solo-one-event solo-two-event unisono-event))
     (break-event . (line-break-event page-break-event page-turn-event))
@@ -46,6 +46,7 @@
                         text-span-event trill-span-event tremolo-span-event 
                         tuplet-span-event))
     (span-dynamic-event . (decrescendo-event crescendo-event))
+    (break-span-event . (break-dynamic-span-event))
     (pedal-event . (sostenuto-event sustain-event una-corda-event))
     (rhythmic-event . (lyric-event melodic-event multi-measure-rest-event
                                   percent-event
        root)))
 
 ;; All leaf event classes that no translator listens to
-;; directly. Avoids printing a warning.
+;; directly.  Avoids printing a warning.
 (define unlistened-music-event-classes
   '(harmonic-event line-break-event page-break-event page-turn-event label-event
-                  solo-one-event solo-two-event skip-event unisono-event))
+                  solo-one-event solo-two-event skip-event unisono-event
+                  break-dynamic-span-event))
 
 ;; produce neater representation of music event tree.
 ;; TODO: switch to this representation for the event-classes list?
 
 (define-public (ly:simplify-scheme e)
   (list 'quasiquote (simplify e)))
-
index e9dcee38cf2bc0a02893e109c437af936888a1c1..a0762025de6455f6345082dd0af0d035045c352d 100644 (file)
@@ -80,7 +80,7 @@ Syntax: @var{note}@code{-\\arpeggio}")
 
 Syntax: @var{note}@code{x}@code{y}, where @code{x} is a direction
 (@code{^} for up or @code{_} for down), or LilyPond's choice
-(no direction specified)), and where @code{y} is an articulation
+(no direction specified), and where @code{y} is an articulation
 (such as @code{-.}, @code{->}, @code{\\tenuto}, @code{\\downbow}).
 See the Notation Reference for details.")
        (types . (general-music event articulation-event script-event))
@@ -119,6 +119,11 @@ Syntax for manual control: @code{c8-[ c c-] c8}")
        (types . (general-music event beam-forbid-event))
        ))
 
+    (BreakDynamicSpanEvent
+     . ((description . "End an alignment spanner for dynamics here.")
+       (types . (general-music break-span-event break-dynamic-span-event event))
+       ))
+
     (BendAfterEvent
      . ((description . "A drop/fall/doit jazz articulation.")
        (types . (general-music bend-after-event event))))