]> git.donarmstrong.com Git - lilypond.git/commitdiff
Better support for beat slashes (multi-slash & mixed duration).
authorNeil Puttock <n.puttock@gmail.com>
Sun, 13 Feb 2011 23:32:12 +0000 (23:32 +0000)
committerNeil Puttock <n.puttock@gmail.com>
Sun, 13 Feb 2011 23:32:12 +0000 (23:32 +0000)
* input/regression/repeat-slash-mixed.ly, repeat-slash-multi.ly:

  new regtests

* lily/context.cc (check_repeat_count_visibility):

  add repeat count visibility proc for use in percent repeat engravers

* lily/double-percent-repeat-engraver.cc (new file):

  create separate engraver for double-measure percent repeats, which listens
  to DoublePercentEvent

* lily/percent-repeat-engraver.cc:

  listen to PercentEvent and create single-measure repeats only

* lily/percent-repeat-item.cc: (brew_slash, brew_slash):

  add count arg to set number of slashes
  read slash-count from event-cause

* lily/percent-repeat-iterator.cc (get_music_list):

  send separate synthetic events for percent, double-percent and beat repeats

  use measure length to choose between full-measure types

  call scheme proc to get slash count for beat repeats

* lily/slash-repeat-engraver.cc:

  listen to RepeatSlashEvent and use slash-count to switch between RepeatSlash
  and DoublePercentRepeat

* ly/engraver-init.ly:

  add Double_percent_repeat_engraver to Voice context

* scm/define-event-classes.scm (event-classes):

  add new classes (double-percent-event/repeat-slash-event)

* scm/define-grobs.scm (all-grob-descriptions):

  add DoubleRepeatSlash

  set slash-negative-kern in RepeatSlash (required for multi-slash beat repeats)

* scm/define-music-properties.scm (all-music-properties):

  doc slash-count

* scm/define-music-types.scm (music-descriptions):

  add synthetic events DoublePercentEvent and RepeatSlashEvent

* scm/music-functions.scm (calc-repeat-slash-count):

  new function used by Percent_repeat_iterator to check durations; returns
  either number of slashes (if all durations equal) or 0 (if durations vary)

17 files changed:
input/regression/repeat-slash-mixed.ly [new file with mode: 0644]
input/regression/repeat-slash-multi.ly [new file with mode: 0644]
lily/context.cc
lily/double-percent-repeat-engraver.cc [new file with mode: 0644]
lily/include/context.hh
lily/include/percent-repeat-item.hh
lily/multi-measure-rest.cc
lily/percent-repeat-engraver.cc
lily/percent-repeat-item.cc
lily/percent-repeat-iterator.cc
lily/slash-repeat-engraver.cc
ly/engraver-init.ly
scm/define-event-classes.scm
scm/define-grobs.scm
scm/define-music-properties.scm
scm/define-music-types.scm
scm/music-functions.scm

diff --git a/input/regression/repeat-slash-mixed.ly b/input/regression/repeat-slash-mixed.ly
new file mode 100644 (file)
index 0000000..a474504
--- /dev/null
@@ -0,0 +1,18 @@
+\version "2.13.51"
+
+\header {
+  texidoc = "Beat repeats for patterns containing mixed durations use
+a double percent symbol."
+}
+
+\relative c' {
+  \repeat percent 4 {
+    c8. <d f>16
+  }
+  \repeat percent 2 {
+    \times 2/3 {
+      r8 d e
+    }
+    c4
+  }
+}
diff --git a/input/regression/repeat-slash-multi.ly b/input/regression/repeat-slash-multi.ly
new file mode 100644 (file)
index 0000000..dd67040
--- /dev/null
@@ -0,0 +1,11 @@
+\version "2.13.51"
+
+\header {
+  texidoc = "Beat repeats for patterns containing identical durations
+shorter than an eighth note use multiple slashes."
+}
+
+\relative c' {
+  \repeat percent 2 { c16 d e f }
+  \repeat percent 4 { c32 e g e }
+}
index 5dd6cf10ba5aef813d736d2dd50b726bf029428d..4dbb6e5657721e436dc4f52227d24409c62a53e8 100644 (file)
@@ -772,3 +772,13 @@ melisma_busy (Context *tr)
 
   return busy;
 }
+
+bool
+check_repeat_count_visibility (Context const *context, SCM count)
+{
+  SCM proc = context->get_property ("repeatCountVisibility");
+  return (ly_is_procedure (proc)
+         && to_boolean (scm_call_2 (proc,
+                                    count,
+                                    context->self_scm ())));
+}
diff --git a/lily/double-percent-repeat-engraver.cc b/lily/double-percent-repeat-engraver.cc
new file mode 100644 (file)
index 0000000..ad64657
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2011 Neil Puttock <n.puttock@gmail.com>
+
+  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 "engraver.hh"
+#include "global-context.hh"
+#include "international.hh"
+#include "item.hh"
+#include "side-position-interface.hh"
+#include "stream-event.hh"
+#include "warn.hh"
+
+#include "translator.icc"
+
+class Double_percent_repeat_engraver : public Engraver
+{
+public:
+  TRANSLATOR_DECLARATIONS (Double_percent_repeat_engraver);
+
+protected:
+  Stream_event *percent_event_;
+
+  // moment (global time) where percent started
+  Moment start_mom_;
+
+  DECLARE_TRANSLATOR_LISTENER (double_percent);
+
+  void process_music ();
+};
+
+Double_percent_repeat_engraver::Double_percent_repeat_engraver ()
+{
+  percent_event_ = 0;
+}
+
+IMPLEMENT_TRANSLATOR_LISTENER (Double_percent_repeat_engraver, double_percent);
+void
+Double_percent_repeat_engraver::listen_double_percent (Stream_event *ev)
+{
+  if (!percent_event_)
+    {
+      Moment meas_len (robust_scm2moment (get_property ("measureLength"),
+                                         Moment (1)));
+      start_mom_ = now_mom () + meas_len;
+      get_global_context ()->add_moment_to_process (start_mom_);
+      percent_event_ = ev;
+    }
+  else
+    ASSIGN_EVENT_ONCE (percent_event_, ev);
+}
+
+void
+Double_percent_repeat_engraver::process_music ()
+{
+  if (percent_event_ && now_mom ().main_part_ == start_mom_.main_part_)
+    {
+      Item *double_percent = make_item ("DoublePercentRepeat",
+                                       percent_event_->self_scm ());
+
+      SCM count = percent_event_->get_property ("repeat-count");
+      if (count != SCM_EOL && to_boolean (get_property ("countPercentRepeats"))
+         && check_repeat_count_visibility (context (), count))
+       {
+         Item *double_percent_counter
+           = make_item ("DoublePercentRepeatCounter",
+                        percent_event_->self_scm ());
+
+         SCM text = scm_number_to_string (count, scm_from_int (10));
+         double_percent_counter->set_property ("text", text);
+
+         Side_position_interface::add_support (double_percent_counter,
+                                               double_percent);
+         double_percent_counter->set_parent (double_percent, Y_AXIS);
+         double_percent_counter->set_parent (double_percent, X_AXIS);
+       }
+      // forbid breaks on a % line
+      context ()->get_score_context ()->set_property ("forbidBreak",
+                                                     SCM_BOOL_T);
+      percent_event_ = 0;
+    }
+}
+
+ADD_TRANSLATOR (Double_percent_repeat_engraver,
+               /* doc */
+               "Make double measure repeats.",
+
+               /* create */
+               "DoublePercentRepeat "
+               "DoublePercentRepeatCounter ",
+
+               /* read */
+               "countPercentRepeats "
+               "measureLength "
+               "repeatCountVisibility ",
+
+               /* write */
+               "forbidBreak "
+               );
index 3806c957e8cee47cbf4e14a8354593ff8073d23f..4121f84c7836de7ac9aab17cb91286c9f62bafc7 100644 (file)
@@ -154,6 +154,9 @@ Moment measure_position (Context const *context);
 Moment measure_position (Context const *context, Duration const *dur);
 Rational measure_length (Context const *context);
 int measure_number (Context const *context);
+
+bool check_repeat_count_visibility (Context const *context, SCM count);
+
 void set_context_property_on_children (Context *trans, SCM sym, SCM val);
 
 /* Shorthand for creating and broadcasting stream events. */
@@ -168,4 +171,3 @@ SCM nested_property_revert_alist (SCM alist, SCM prop_path);
 SCM evict_from_alist (SCM, SCM, SCM);
 
 #endif /* CONTEXT_HH */
-
index 1bc02fe15549595a3c01ccb3a1c371200d2ac956..a9e59e35f512f1fc711d27993f71dc5c33cffab5 100644 (file)
@@ -30,7 +30,7 @@ public:
   DECLARE_SCHEME_CALLBACK (beat_slash, (SCM));
   DECLARE_SCHEME_CALLBACK (double_percent, (SCM));
   static Stencil x_percent (Grob *, int);
-  static Stencil brew_slash (Grob *);
+  static Stencil brew_slash (Grob *, int);
 };
 
 #endif /* PERCENT_REPEAT_ITEM_HH */
index 60b5c03c6602957605585054ab442edb37c13c13..9628402a5ecec1ce899d4ef1d4ea57002b7529af 100644 (file)
@@ -63,6 +63,7 @@ Multi_measure_rest::percent (SCM smob)
   Spanner *sp = dynamic_cast<Spanner *> (me);
 
   Stencil r = Percent_repeat_item_interface::x_percent (me, 1);
+  r.translate_axis (-r.extent (X_AXIS).center (), X_AXIS);
 
   // ugh copy & paste.
 
index 5757f8b8ab9779df8ff439327570bba82d3328b1..1b437b28224b302d60ade8126f28b6e395101354 100644 (file)
 */
 
 
-#include "score-engraver.hh"
-
-#include "bar-line.hh"
+#include "engraver.hh"
 #include "global-context.hh"
 #include "international.hh"
 #include "item.hh"
-#include "misc.hh"
-#include "repeated-music.hh"
 #include "side-position-interface.hh"
 #include "spanner.hh"
 #include "stream-event.hh"
 
 #include "translator.icc"
 
-/*
-* TODO: Create separate Double_percent_repeat_engraver? 
-* Or, at least move double percent handling to Slash_repeat_engraver
-*/
-
 class Percent_repeat_engraver : public Engraver
 {
   void typeset_perc ();
-  bool check_count_visibility (SCM count);
+
 public:
   TRANSLATOR_DECLARATIONS (Percent_repeat_engraver);
   
 protected:
   Stream_event *percent_event_;
 
-  /// moment (global time) where percent started.
-  Moment stop_mom_;
+  // moment (global time) where percent started
   Moment start_mom_;
-
-  enum Repeat_sign_type
-    {
-      UNKNOWN,
-      MEASURE,
-      DOUBLE_MEASURE,
-    };
-  Repeat_sign_type repeat_sign_type_;
+  // moment (global time) where percent should end
+  Moment stop_mom_;
 
   Spanner *percent_;
   Spanner *percent_counter_;
 
-  
   Grob *first_command_column_;
   Moment command_moment_;
-  
-protected:
+
   virtual void finalize ();
   DECLARE_TRANSLATOR_LISTENER (percent);
 
-  void stop_translation_timestep ();
   void start_translation_timestep ();
+  void stop_translation_timestep ();
   void process_music ();
 };
 
@@ -91,7 +73,8 @@ Percent_repeat_engraver::start_translation_timestep ()
 {
   if (now_mom ().main_part_ != command_moment_.main_part_)
     {
-      first_command_column_ = unsmob_grob (get_property ("currentCommandColumn"));
+      first_command_column_
+       = unsmob_grob (get_property ("currentCommandColumn"));
       command_moment_ = now_mom ();
     }
 
@@ -100,7 +83,6 @@ Percent_repeat_engraver::start_translation_timestep ()
       if (percent_)
        typeset_perc ();
       percent_event_ = 0;
-      repeat_sign_type_ = UNKNOWN;
     }
 }
 
@@ -111,97 +93,50 @@ Percent_repeat_engraver::listen_percent (Stream_event *ev)
   if (!percent_event_)
     {
       Moment body_length = get_event_length (ev);
-      Moment meas_len (robust_scm2moment (get_property ("measureLength"),
-                                         Moment (1)));
-      if (meas_len == body_length)
-       {
-         repeat_sign_type_ = MEASURE;
-         start_mom_ = now_mom ();
-         stop_mom_ = now_mom () + body_length;
-         get_global_context ()->add_moment_to_process (stop_mom_);
-       }
-      else if (Moment (2) * meas_len == body_length)
-       {
-         repeat_sign_type_ = DOUBLE_MEASURE;
-         start_mom_ = now_mom () + meas_len;
-         stop_mom_ = now_mom () + body_length; /* never used */
-         get_global_context ()->add_moment_to_process (start_mom_);
-       }
-      else
-       {
-         /*
-           don't warn about percent repeats: slash repeats are not
-           exactly 1 or 2 measures long.
-         */
-         return;
-       }
+      start_mom_ = now_mom ();
+      stop_mom_ = now_mom () + body_length;
+      get_global_context ()->add_moment_to_process (stop_mom_);
       percent_event_ = ev;
     }
   else
-    /* print a warning: no assignment happens because
-       percent_event_ != 0 */
-    ASSIGN_EVENT_ONCE (percent_event_, ev);
+    {
+      /*
+       print a warning: no assignment happens because
+       percent_event_ != 0
+      */
+      ASSIGN_EVENT_ONCE (percent_event_, ev);
+    }
 }
 
 void
 Percent_repeat_engraver::process_music ()
 {
-  if (percent_event_ && now_mom ().main_part_ == start_mom_.main_part_)
+  if (percent_event_
+      && now_mom ().main_part_ == start_mom_.main_part_)
     {
-      if (repeat_sign_type_ == MEASURE)
-       {
-         if (percent_)
-           typeset_perc ();
-         
-         percent_ = make_spanner ("PercentRepeat", percent_event_->self_scm ());
-
-         Grob *col = first_command_column_;
-         percent_->set_bound (LEFT, col);
-
-         SCM count = percent_event_->get_property ("repeat-count");
-         if (count != SCM_EOL && to_boolean (get_property ("countPercentRepeats"))
-             && check_count_visibility (count))
-           {
-             percent_counter_
-               = make_spanner ("PercentRepeatCounter", percent_event_->self_scm ());
-
-             SCM text = scm_number_to_string (count, scm_from_int (10));
-             percent_counter_->set_property ("text", text);
-             percent_counter_->set_bound (LEFT, col);
-             Side_position_interface::add_support (percent_counter_,
-                                                   percent_);
-             percent_counter_->set_parent (percent_, Y_AXIS);
-           }
-         else
-           percent_counter_ = 0;
-       }
-      else if (repeat_sign_type_ == DOUBLE_MEASURE)
+      if (percent_)
+       typeset_perc ();
+
+      percent_ = make_spanner ("PercentRepeat", percent_event_->self_scm ());
+
+      Grob *col = first_command_column_;
+      percent_->set_bound (LEFT, col);
+
+      SCM count = percent_event_->get_property ("repeat-count");
+      if (count != SCM_EOL && to_boolean (get_property ("countPercentRepeats"))
+         && check_repeat_count_visibility (context (), count))
        {
-         Item *double_percent = make_item ("DoublePercentRepeat", percent_event_->self_scm ());
-
-         SCM count = percent_event_->get_property ("repeat-count");
-         if (count != SCM_EOL && to_boolean (get_property ("countPercentRepeats"))
-             && check_count_visibility (count))
-           {
-             Item *double_percent_counter = make_item ("DoublePercentRepeatCounter",
-                                                       percent_event_->self_scm ());
-
-             SCM text = scm_number_to_string (count,
-                                              scm_from_int (10));
-             double_percent_counter->set_property ("text", text);
-
-             Side_position_interface::add_support (double_percent_counter,
-                                                   double_percent);
-             double_percent_counter->set_parent (double_percent, Y_AXIS);
-             double_percent_counter->set_parent (double_percent, X_AXIS);
-           }
-         
-         /* forbid breaks on a % line. Should forbid all breaks, really. */
-         context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T);
-
-         /* No more processing needed. */
-         repeat_sign_type_ = UNKNOWN;
+         percent_counter_ = make_spanner ("PercentRepeatCounter",
+                                          percent_event_->self_scm ());
+
+         SCM text = scm_number_to_string (count, scm_from_int (10));
+         percent_counter_->set_property ("text", text);
+         percent_counter_->set_bound (LEFT, col);
+         Side_position_interface::add_support (percent_counter_, percent_);
+         percent_counter_->set_parent (percent_, Y_AXIS);
        }
+      else
+       percent_counter_ = 0;
     }
 }
 
@@ -219,29 +154,16 @@ Percent_repeat_engraver::finalize ()
 void
 Percent_repeat_engraver::typeset_perc ()
 {
-  if (percent_)
-    {
-      Grob *col = first_command_column_;
+  Grob *col = first_command_column_;
 
-      percent_->set_bound (RIGHT, col);
-      percent_ = 0;
-
-      if (percent_counter_)
-       percent_counter_->set_bound (RIGHT, col);
-      percent_counter_ = 0;
-    }
-}
+  percent_->set_bound (RIGHT, col);
+  percent_ = 0;
 
-bool
-Percent_repeat_engraver::check_count_visibility (SCM count)
-{
-  SCM proc = get_property ("repeatCountVisibility");
-  return (ly_is_procedure (proc) && to_boolean (scm_call_2 (proc,
-                                                           count,
-                                                           context ()->self_scm ())));
+  if (percent_counter_)
+    percent_counter_->set_bound (RIGHT, col);
+  percent_counter_ = 0;
 }
 
-
 void
 Percent_repeat_engraver::stop_translation_timestep ()
 {
@@ -249,20 +171,17 @@ Percent_repeat_engraver::stop_translation_timestep ()
 
 ADD_TRANSLATOR (Percent_repeat_engraver,
                /* doc */
-               "Make whole bar and double bar repeats.",
+               "Make whole measure repeats.",
                
                /* create */
-               "DoublePercentRepeat "
-               "DoublePercentRepeatCounter "
                "PercentRepeat "
                "PercentRepeatCounter ",
 
                /* read */
                "countPercentRepeats "
                "currentCommandColumn "
-               "measureLength "
                "repeatCountVisibility ",
 
                /* write */
-               "forbidBreak "
+               ""
                );
index 337df4505866894e67436d4a107e3ebd6136da20..1e97753feecd95414538f4847f9613aac0d41b92 100644 (file)
 */
 
 #include "percent-repeat-item.hh"
+
 #include "item.hh"
-#include "lookup.hh"
 #include "font-interface.hh"
+#include "lookup.hh"
+#include "stream-event.hh"
 
 Stencil
-Percent_repeat_item_interface::brew_slash (Grob *me)
+Percent_repeat_item_interface::brew_slash (Grob *me, int count)
 {
   Real slope = robust_scm2double (me->get_property ("slope"), 1);
   Real wid = 2.0 / slope;
@@ -32,7 +34,14 @@ Percent_repeat_item_interface::brew_slash (Grob *me)
     todo: check out if in staff-rule thickness normally.
   */
   Real thick = robust_scm2double (me->get_property ("thickness"), 1);
-  Stencil m = Lookup::repeat_slash (wid, slope, thick);
+  Stencil slash = Lookup::repeat_slash (wid, slope, thick);
+  Stencil m = slash;
+
+  Real slash_neg_kern =
+    robust_scm2double (me->get_property ("slash-negative-kern"), 1.6);
+  for (int i = count - 1; i--;)
+    m.add_at_edge (X_AXIS, RIGHT, slash, -slash_neg_kern);
+
   m.translate_axis (-m.extent (Y_AXIS).center (), Y_AXIS);
   return m;
 }
@@ -40,16 +49,11 @@ Percent_repeat_item_interface::brew_slash (Grob *me)
 Stencil
 Percent_repeat_item_interface::x_percent (Grob *me, int count)
 {
-  Stencil m;
-  Stencil s = brew_slash (me);
+  Stencil m = brew_slash (me, count);
 
   Real dot_neg_kern =
     robust_scm2double (me->get_property ("dot-negative-kern"), 0.75);
-  Real slash_neg_kern =
-    robust_scm2double (me->get_property ("slash-negative-kern"), 1.6);
 
-  for (int i = count; i--;)
-    m.add_at_edge (X_AXIS, RIGHT, s, -slash_neg_kern);
   Stencil d1 = Font_interface::get_default_font (me)->find_by_name ("dots.dot");
   Stencil d2 = d1;
   d1.translate_axis (0.5, Y_AXIS);
@@ -58,7 +62,6 @@ Percent_repeat_item_interface::x_percent (Grob *me, int count)
   m.add_at_edge (X_AXIS, LEFT, d1, -dot_neg_kern);
   m.add_at_edge (X_AXIS, RIGHT, d2, -dot_neg_kern);
 
-  m.translate_axis (- m.extent (X_AXIS).center (), X_AXIS);
   return m;
 }
 
@@ -68,6 +71,7 @@ Percent_repeat_item_interface::double_percent (SCM grob)
 {
   Grob *me = unsmob_grob (grob);
   Stencil m = x_percent (me, 2);
+  m.translate_axis (-m.extent (X_AXIS).center (), X_AXIS);
   return m.smobbed_copy ();
 }
 
@@ -76,18 +80,24 @@ SCM
 Percent_repeat_item_interface::beat_slash (SCM grob)
 {
   Grob *me = unsmob_grob (grob);
-  Stencil m = brew_slash (me);
+  Stream_event *cause = unsmob_stream_event (me->get_property ("cause"));
+  int count = robust_scm2int (cause->get_property ("slash-count"), 1);
+
+  Stencil m;
+  if (count == 0)
+    m = x_percent (me, 2);
+  else
+    m = brew_slash (me, count);
 
   return m.smobbed_copy ();
 }
 
 ADD_INTERFACE (Percent_repeat_item_interface,
               "Repeats that look like percent signs.",
-              
+
               /* properties */
               "dot-negative-kern "
               "slash-negative-kern "
               "slope "
               "thickness "
               );
-
index 845bd729b6150b18df889daea65e3753ce9eb074..d8295535575535d0e05cd9b4ff47cc39f45d2e4e 100644 (file)
@@ -18,6 +18,7 @@
   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include "context.hh"
 #include "input.hh"
 #include "repeated-music.hh"
 #include "sequential-iterator.hh"
@@ -41,20 +42,40 @@ Percent_repeat_iterator::Percent_repeat_iterator ()
 SCM
 Percent_repeat_iterator::get_music_list () const
 {
-  /* TODO: Distinction between percent, double-percent and slash */
   Music *mus = get_music ();
   Music *child = Repeated_music::body (mus);
   SCM length = child->get_length ().smobbed_copy ();
   SCM child_list = SCM_EOL;
+  Moment measure_len = measure_length (get_outlet ());
+  Moment music_len = robust_scm2moment (length, Moment (0));
+
+  string event_type;
+  SCM slash_count = SCM_EOL;
+
+  if (measure_len == music_len)
+    event_type = "PercentEvent";
+  else if (measure_len * Moment (2) == music_len)
+    event_type = "DoublePercentEvent";
+  else
+    {
+      slash_count
+       = scm_call_1 (ly_lily_module_constant ("calc-repeat-slash-count"),
+                     child->self_scm ());
+      event_type = "RepeatSlashEvent";
+    }
 
   int repeats = scm_to_int (mus->get_property ("repeat-count"));
   for (int i = repeats; i > 1; i--)
   {
-    Music *percent = make_music_by_name (ly_symbol2scm ("PercentEvent"));
+    Music *percent = make_music_by_name (ly_symbol2scm (event_type.c_str ()));
     percent->set_spot (*mus->origin ());
     percent->set_property ("length", length);
     if (repeats > 1)
-      percent->set_property ("repeat-count", scm_from_int (i));
+      {
+       percent->set_property ("repeat-count", scm_from_int (i));
+       if (event_type == "RepeatSlashEvent")
+         percent->set_property ("slash-count", slash_count);
+      }
 
     child_list = scm_cons (percent->unprotect (), child_list);
   }
index 26a64f9380d8d461d254c79c401c1a914937cece..0db3ceffb3c334a7ba1ba5fd57f162e0151ae46f 100644 (file)
   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "bar-line.hh"
-#include "global-context.hh"
-#include "international.hh"
 #include "item.hh"
-#include "misc.hh"
-#include "repeated-music.hh"
-#include "score-engraver.hh"
-#include "spanner.hh"
+#include "engraver.hh"
 #include "stream-event.hh"
-#include "warn.hh"
 
 #include "translator.icc"
 
-/**
-   This acknowledges repeated music with "percent" style.  It typesets
-   a slash sign.
+/*
+  This acknowledges repeated music with "percent" style.  It typesets
+  a slash sign or double percent sign.
 */
 class Slash_repeat_engraver : public Engraver
 {
@@ -42,7 +35,7 @@ public:
 protected:
   Stream_event *slash_;
 protected:
-  DECLARE_TRANSLATOR_LISTENER (percent);
+  DECLARE_TRANSLATOR_LISTENER (repeat_slash);
   void process_music ();
 };
 
@@ -51,21 +44,11 @@ Slash_repeat_engraver::Slash_repeat_engraver ()
   slash_ = 0;
 }
 
-IMPLEMENT_TRANSLATOR_LISTENER (Slash_repeat_engraver, percent);
+IMPLEMENT_TRANSLATOR_LISTENER (Slash_repeat_engraver, repeat_slash);
 void
-Slash_repeat_engraver::listen_percent (Stream_event *ev)
+Slash_repeat_engraver::listen_repeat_slash (Stream_event *ev)
 {
-  /*todo: separate events for percent and slash */
-  Moment meas_length
-    = robust_scm2moment (get_property ("measureLength"), Moment (0));
-  
-  if (get_event_length (ev) < meas_length)
     ASSIGN_EVENT_ONCE (slash_, ev);
-  
-  /*
-    don't warn if nothing happens: this can happen if there are whole
-    measure repeats.
-   */
 }
 
 void
@@ -73,7 +56,11 @@ Slash_repeat_engraver::process_music ()
 {
   if (slash_)
     {
-      make_item ("RepeatSlash", slash_->self_scm ());
+      SCM count = slash_->get_property ("slash-count");
+      if (scm_to_int (count) == 0)
+       make_item ("DoubleRepeatSlash", slash_->self_scm ());
+      else
+       make_item ("RepeatSlash", slash_->self_scm ());
       slash_ = 0;
     }
 }
@@ -83,10 +70,11 @@ ADD_TRANSLATOR (Slash_repeat_engraver,
                "Make beat repeats.",
 
                /* create */
+               "DoubleRepeatSlash "
                "RepeatSlash ",
 
                /* read */
-               "measureLength ",
+               "",
 
                /* write */
                ""
index 92c8398f34c56ebeb95b30999664e2b51041f26b..28c7c9706f09b042de8b02f442eb9ff946bbe52c 100644 (file)
@@ -243,6 +243,7 @@ multiple voices on the same staff."
   \consists "New_fingering_engraver"
 
   \consists "Chord_tremolo_engraver"
+  \consists "Double_percent_repeat_engraver"
   \consists "Percent_repeat_engraver"
   \consists "Slash_repeat_engraver"
   \consists "Part_combine_engraver"
index 539288b8439f34bcc0dc2be517e9b6f882b92e3a..022ae640e1f208b82292ae682b88c72e274f502b 100644 (file)
@@ -50,8 +50,9 @@
     (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
-                                  rest-event skip-event bass-figure-event))
+                                  double-percent-event percent-event
+                                  repeat-slash-event rest-event
+                                  skip-event bass-figure-event))
     (melodic-event . (cluster-note-event note-event))
     (() . (Announcement))
     (Announcement . (AnnounceNewContext))
index 59f756e8a0ccb709b0db7f39230f5a9d4c1550a0..92edba5f1df693faef00317964d77e2105a69d4c 100644 (file)
        (slope . 1.0)
        (stencil . ,ly:percent-repeat-item-interface::double-percent)
        (thickness . 0.48)
-       (width . 2.0)
        (meta . ((class . Item)
                 (interfaces . (break-aligned-interface
                                font-interface
                                side-position-interface
                                text-interface))))))
 
+    (DoubleRepeatSlash
+     . (
+       (dot-negative-kern . 0.75)
+       (font-encoding . fetaMusic)
+       (slash-negative-kern . 1.6)
+       (slope . 1.0)
+       (stencil . ,ly:percent-repeat-item-interface::beat-slash)
+       (thickness . 0.48)
+       (meta . ((class . Item)
+                (interfaces . (font-interface
+                               percent-repeat-interface
+                               percent-repeat-item-interface
+                               rhythmic-grob-interface))))))
+
     (DynamicLineSpanner
      . (
        (axes . (,Y))
 
     (RepeatSlash
      . (
+       (slash-negative-kern . 0.85)
        (slope . 1.7)
        (stencil . ,ly:percent-repeat-item-interface::beat-slash)
        (thickness . 0.48)
index b2db381b7e4f372da16c35a08650f90d83589430..b18a10f3adf551cdd0d6fd4adb8ec020fa31b2c0 100644 (file)
@@ -157,6 +157,8 @@ or down-stem?")
 
      (repeat-count ,integer? "Do a @code{\\repeat} how often?")
 
+     (slash-count ,integer? "The number of slashes in a single-beat repeat.
+If zero, signals a beat containing varying durations.")
      (span-direction ,ly:dir? "Does this start or stop a spanner?")
      (span-type ,symbol? "What kind of dynamic spanner should be created?
 Options are @code{'text} and @code{'hairpin}.")
index 43b826e8b8ab4d7a9ecf7a30c9412c718c0cdc94..cdf5c0a6a1e1e92b5a8ef2f301894e0a53a5f031 100644 (file)
@@ -175,6 +175,11 @@ An alternative syntax is @var{note}@code{\\decr} @dots{}
                  event))
        ))
 
+    (DoublePercentEvent
+     . ((description . "Used internally to signal double percent repeats.")
+       (types . (general-music event double-percent-event rhythmic-event))
+       ))
+
     (EpisemaEvent
      . ((description . "Begin or end an episema.")
        (types . (general-music span-event event episema-event))
@@ -375,7 +380,7 @@ as separate voices.")
        ))
 
     (PercentRepeatedMusic
-     . ((description . "Repeats encoded by percents.")
+     . ((description . "Repeats encoded by percents and slashes.")
        (iterator-ctor . ,ly:percent-repeat-iterator::constructor)
        (start-callback .  ,ly:repeated-music::first-start)
        (length-callback . ,ly:repeated-music::unfolded-music-length)
@@ -450,6 +455,11 @@ Syntax: @code{\\unset @var{context}.@var{prop}}")
        (types . (general-music repeated-music))
        ))
 
+    (RepeatSlashEvent
+     . ((description . "Used internally to signal beat repeats.")
+       (types . (general-music event repeat-slash-event rhythmic-event))
+       ))
+
     (RepeatTieEvent
      . ((description . "Ties for starting a second volta bracket.")
        (types . (general-music event repeat-tie-event))
index b015c536a6f07fd05e70b55a727f7830d3580621..ed96cfd8d21dcda0cf61430c1596ad2422b72b6b 100644 (file)
@@ -301,6 +301,20 @@ through MUSIC."
          (shift-duration-log r shift dots))
        r)))
 
+(define (calc-repeat-slash-count music)
+  "Given the child-list @var{music} in @code{PercentRepeatMusic},
+calculate the number of slashes based on the durations.  Returns @code{0}
+if durations in in @var{music} vary, allowing slash beats and double-percent
+beats to be distinguished."
+  (let* ((durs (map (lambda (elt)
+                     (duration-of-note elt))
+                   (extract-named-music music 'EventChord)))
+        (first-dur (car durs)))
+
+    (if (every (lambda (d) (equal? d first-dur)) durs)
+       (max (- (ly:duration-log first-dur) 2) 1)
+       0)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; clusters.
 
@@ -1385,14 +1399,20 @@ as a context."
     skip))
 
 (define-public (pitch-of-note event-chord)
+  (let ((evs (filter (lambda (x)
+                      (music-has-type x 'note-event))
+                    (ly:music-property event-chord 'elements))))
 
-  (let*
-      ((evs (filter (lambda (x) (memq 'note-event (ly:music-property x 'types)))
-                   (ly:music-property event-chord 'elements))))
+    (and (pair? evs)
+        (ly:music-property (car evs) 'pitch))))
+
+(define-public (duration-of-note event-chord)
+  (let ((evs (filter (lambda (x)
+                      (music-has-type x 'rhythmic-event))
+                    (ly:music-property event-chord 'elements))))
 
-    (if (pair? evs)
-       (ly:music-property (car evs) 'pitch)
-       #f)))
+    (and (pair? evs)
+        (ly:music-property (car evs) 'duration))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;