diff options
author | Neil Puttock <n.puttock@gmail.com> | 2011-02-13 23:32:12 +0000 |
---|---|---|
committer | Neil Puttock <n.puttock@gmail.com> | 2011-02-13 23:32:12 +0000 |
commit | f40beee2bdf96ff578b5a3d004cc276ee333b799 (patch) | |
tree | 86a84f58e1afc294a9848ea2dc9aed8770cc012c | |
parent | 90fcc649dc06ad006158945acc15a69e24e942cd (diff) |
Better support for beat slashes (multi-slash & mixed duration).
* 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)
-rw-r--r-- | input/regression/repeat-slash-mixed.ly | 18 | ||||
-rw-r--r-- | input/regression/repeat-slash-multi.ly | 11 | ||||
-rw-r--r-- | lily/context.cc | 10 | ||||
-rw-r--r-- | lily/double-percent-repeat-engraver.cc | 113 | ||||
-rw-r--r-- | lily/include/context.hh | 4 | ||||
-rw-r--r-- | lily/include/percent-repeat-item.hh | 2 | ||||
-rw-r--r-- | lily/multi-measure-rest.cc | 1 | ||||
-rw-r--r-- | lily/percent-repeat-engraver.cc | 181 | ||||
-rw-r--r-- | lily/percent-repeat-item.cc | 36 | ||||
-rw-r--r-- | lily/percent-repeat-iterator.cc | 27 | ||||
-rw-r--r-- | lily/slash-repeat-engraver.cc | 40 | ||||
-rw-r--r-- | ly/engraver-init.ly | 1 | ||||
-rw-r--r-- | scm/define-event-classes.scm | 5 | ||||
-rw-r--r-- | scm/define-grobs.scm | 16 | ||||
-rw-r--r-- | scm/define-music-properties.scm | 2 | ||||
-rw-r--r-- | scm/define-music-types.scm | 12 | ||||
-rw-r--r-- | scm/music-functions.scm | 32 |
17 files changed, 326 insertions, 185 deletions
diff --git a/input/regression/repeat-slash-mixed.ly b/input/regression/repeat-slash-mixed.ly new file mode 100644 index 0000000000..a474504443 --- /dev/null +++ b/input/regression/repeat-slash-mixed.ly @@ -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 index 0000000000..dd670402d3 --- /dev/null +++ b/input/regression/repeat-slash-multi.ly @@ -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 } +} diff --git a/lily/context.cc b/lily/context.cc index 5dd6cf10ba..4dbb6e5657 100644 --- a/lily/context.cc +++ b/lily/context.cc @@ -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 index 0000000000..ad64657e97 --- /dev/null +++ b/lily/double-percent-repeat-engraver.cc @@ -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 " + ); diff --git a/lily/include/context.hh b/lily/include/context.hh index 3806c957e8..4121f84c78 100644 --- a/lily/include/context.hh +++ b/lily/include/context.hh @@ -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 */ - diff --git a/lily/include/percent-repeat-item.hh b/lily/include/percent-repeat-item.hh index 1bc02fe155..a9e59e35f5 100644 --- a/lily/include/percent-repeat-item.hh +++ b/lily/include/percent-repeat-item.hh @@ -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 */ diff --git a/lily/multi-measure-rest.cc b/lily/multi-measure-rest.cc index 60b5c03c66..9628402a5e 100644 --- a/lily/multi-measure-rest.cc +++ b/lily/multi-measure-rest.cc @@ -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. diff --git a/lily/percent-repeat-engraver.cc b/lily/percent-repeat-engraver.cc index 5757f8b8ab..1b437b2822 100644 --- a/lily/percent-repeat-engraver.cc +++ b/lily/percent-repeat-engraver.cc @@ -18,14 +18,10 @@ */ -#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" @@ -33,46 +29,32 @@ #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 " + "" ); diff --git a/lily/percent-repeat-item.cc b/lily/percent-repeat-item.cc index 337df45058..1e97753fee 100644 --- a/lily/percent-repeat-item.cc +++ b/lily/percent-repeat-item.cc @@ -18,12 +18,14 @@ */ #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 " ); - diff --git a/lily/percent-repeat-iterator.cc b/lily/percent-repeat-iterator.cc index 845bd729b6..d829553557 100644 --- a/lily/percent-repeat-iterator.cc +++ b/lily/percent-repeat-iterator.cc @@ -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); } diff --git a/lily/slash-repeat-engraver.cc b/lily/slash-repeat-engraver.cc index 26a64f9380..0db3ceffb3 100644 --- a/lily/slash-repeat-engraver.cc +++ b/lily/slash-repeat-engraver.cc @@ -18,22 +18,15 @@ 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 */ "" diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 92c8398f34..28c7c9706f 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -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" diff --git a/scm/define-event-classes.scm b/scm/define-event-classes.scm index 539288b843..022ae640e1 100644 --- a/scm/define-event-classes.scm +++ b/scm/define-event-classes.scm @@ -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)) diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 59f756e8a0..92edba5f1d 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -667,7 +667,6 @@ (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 @@ -699,6 +698,20 @@ 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)) @@ -1570,6 +1583,7 @@ (RepeatSlash . ( + (slash-negative-kern . 0.85) (slope . 1.7) (stencil . ,ly:percent-repeat-item-interface::beat-slash) (thickness . 0.48) diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm index b2db381b7e..b18a10f3ad 100644 --- a/scm/define-music-properties.scm +++ b/scm/define-music-properties.scm @@ -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}.") diff --git a/scm/define-music-types.scm b/scm/define-music-types.scm index 43b826e8b8..cdf5c0a6a1 100644 --- a/scm/define-music-types.scm +++ b/scm/define-music-types.scm @@ -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)) diff --git a/scm/music-functions.scm b/scm/music-functions.scm index b015c536a6..ed96cfd8d2 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -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)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |