From 8d8982cc88ba1d0b20df5aff22b9555f76976a26 Mon Sep 17 00:00:00 2001 From: Mike Solomon Date: Mon, 5 Dec 2011 07:56:37 +0100 Subject: [PATCH] Allows for automatic renumbering of measure numbers at volta repeats. Does this via the use of an AlternativeEvent, which tells the current number to either memorize its current position or to go back to the memorized position. --- lily/bar-number-engraver.cc | 105 ++++++++++++++++++++++++++- lily/volta-repeat-iterator.cc | 2 +- ly/engraver-init.ly | 1 + scm/define-context-properties.scm | 4 + scm/define-event-classes.scm | 3 +- scm/define-music-callbacks.scm | 28 +++++++ scm/define-music-display-methods.scm | 2 + scm/define-music-properties.scm | 6 ++ scm/define-music-types.scm | 6 ++ 9 files changed, 152 insertions(+), 5 deletions(-) diff --git a/lily/bar-number-engraver.cc b/lily/bar-number-engraver.cc index 269ed12620..83ff7fed51 100644 --- a/lily/bar-number-engraver.cc +++ b/lily/bar-number-engraver.cc @@ -17,12 +17,15 @@ along with LilyPond. If not, see . */ +#include // for reverse + #include "paper-column.hh" #include "output-def.hh" #include "side-position-interface.hh" #include "engraver.hh" #include "context.hh" #include "grob-array.hh" +#include "stream-event.hh" #include "translator.icc" @@ -35,14 +38,62 @@ class Bar_number_engraver : public Engraver { protected: Item *text_; + int alternative_starting_bar_number_; + int alternative_number_; + int alternative_number_increment_; + Stream_event *alternative_event_; + protected: void stop_translation_timestep (); + DECLARE_TRANSLATOR_LISTENER (alternative); DECLARE_ACKNOWLEDGER (break_alignment); void process_music (); void create_items (); TRANSLATOR_DECLARATIONS (Bar_number_engraver); }; +IMPLEMENT_TRANSLATOR_LISTENER (Bar_number_engraver, alternative); +void +Bar_number_engraver::listen_alternative (Stream_event *ev) +{ + if (alternative_event_) + return; + + alternative_event_ = ev; + int current_barnumber = robust_scm2int (get_property ("currentBarNumber"), 0); + Direction alternative_dir = robust_scm2dir (ev->get_property ("alternative-dir"), CENTER); + bool make_alternative = get_property ("alternativeNumberingStyle") == ly_symbol2scm ("numbers") + || get_property ("alternativeNumberingStyle") == ly_symbol2scm ("numbers-with-letters"); + if (make_alternative) + { + /* + if we're starting the first alternative, we set the starting + bar number to the current bar number + */ + if (alternative_dir == LEFT) + alternative_starting_bar_number_ = current_barnumber; + + /* + if the alternative is not the last one, we send the + current bar number back to the alternative bar number. + */ + if (alternative_dir < RIGHT) + current_barnumber = alternative_starting_bar_number_; + + context ()->set_property ("currentBarNumber", scm_from_int (current_barnumber)); + } +} + +int +int_pow (int n, int i) +{ + if (i == 1) + return n; + if (i <= 0) + return 1; + return int_pow (n * n, i - 1); +} + void Bar_number_engraver::process_music () { @@ -59,9 +110,51 @@ Bar_number_engraver::process_music () && to_boolean (scm_call_1 (proc, bn))) { create_items (); + SCM alternative_style = get_property ("alternativeNumberingStyle"); + string text_tag = ""; + if (alternative_style == ly_symbol2scm ("numbers-with-letters")) + { + if (alternative_event_) + { + Direction alternative_dir = robust_scm2dir (alternative_event_->get_property ("alternative-dir"), RIGHT); + switch (alternative_dir) + { + case LEFT: + alternative_number_ = 0; + break; + case CENTER: + break; + case RIGHT: + alternative_number_ = INT_MIN; + break; + default: + assert (false); + } + alternative_number_ += alternative_number_increment_; + + alternative_number_increment_ = robust_scm2int (alternative_event_->get_property ("alternative-increment"), 1); + } + if (alternative_number_ >= 0) + { + string alphabet = "abcdefghijklmnopqrstuvwxyz"; + int power = 0; + int running_sum = 0; + int scratch = alternative_number_; + while (running_sum <= alternative_number_) + { + power++; + running_sum += int_pow (26, power); + } + scratch += int_pow (26, power) - running_sum; + for (int i = power; i--;) + text_tag += alphabet.at ((scratch / int_pow (26, i)) % 26); + } + } // guh. text_->set_property - ("text", scm_number_to_string (bn, scm_from_int (10))); + ("text", + scm_string_concatenate (scm_list_2 (scm_number_to_string (bn, scm_from_int (10)), + ly_string2scm (text_tag)))); } } } @@ -70,6 +163,10 @@ Bar_number_engraver::process_music () Bar_number_engraver::Bar_number_engraver () { text_ = 0; + alternative_starting_bar_number_ = 0; + alternative_number_increment_ = 0; + alternative_number_ = INT_MIN; + alternative_event_ = 0; } void @@ -86,6 +183,7 @@ Bar_number_engraver::acknowledge_break_alignment (Grob_info inf) void Bar_number_engraver::stop_translation_timestep () { + alternative_event_ = 0; if (text_) { text_->set_object ("side-support-elements", @@ -121,8 +219,9 @@ ADD_TRANSLATOR (Bar_number_engraver, "currentBarNumber " "whichBar " "stavesFound " - "barNumberVisibility ", + "barNumberVisibility " + "alternativeNumberingStyle ", /* write */ - "" + "currentBarNumber " ); diff --git a/lily/volta-repeat-iterator.cc b/lily/volta-repeat-iterator.cc index 91bf94e42a..dddbbc2095 100644 --- a/lily/volta-repeat-iterator.cc +++ b/lily/volta-repeat-iterator.cc @@ -50,7 +50,7 @@ SCM Volta_repeat_iterator::get_music_list ()const { return scm_cons (get_music ()->get_property ("element"), - get_music ()->get_property ("elements")); + Sequential_iterator::get_music_list ()); } void diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 46b0f72b05..2e0a90d0e6 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -523,6 +523,7 @@ automatically when an output definition (a @code{\score} or %% move the alias along with the engraver. + % timing translator must come BEFORE bar number engraver \consists "Timing_translator" \consists "Default_bar_line_engraver" \consists "Output_property_engraver" diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 6c79bbdb95..a0cf0ae832 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -53,6 +53,10 @@ vertical alignment.") are aligned in bass figure context.") (alignBelowContext ,string? "Where to insert newly created context in vertical alignment.") + (alternativeNumberingStyle ,symbol? "The style of an alternative's bar +numbers. Can be @code{numbers} for going back to the same number or +@code{numbers-with-letters} for going back to the same number with letter +suffixes. No setting will not go back in measure-number time.") (associatedVoice ,string? "Name of the @code{Voice} that has the melody for this @code{Lyrics} line.") (autoAccidentals ,list? "List of different ways to typeset an diff --git a/scm/define-event-classes.scm b/scm/define-event-classes.scm index 65dbd38e4f..19444111af 100644 --- a/scm/define-event-classes.scm +++ b/scm/define-event-classes.scm @@ -35,7 +35,8 @@ 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 break-span-event)) + layout-instruction-event completize-extender-event break-span-event + alternative-event)) (layout-instruction-event . (apply-output-event)) (script-event . (articulation-event text-script-event)) diff --git a/scm/define-music-callbacks.scm b/scm/define-music-callbacks.scm index 0cbd96b862..06d616f8b0 100644 --- a/scm/define-music-callbacks.scm +++ b/scm/define-music-callbacks.scm @@ -34,6 +34,34 @@ to be used by the sequential-iterator" (make-music 'BarCheck 'origin location)))) +(define (make-volta-set music) + (let* ((alts (ly:music-property music 'elements)) + (lalts (length alts)) + (times (ly:music-property music 'repeat-count))) + (map (lambda (x y) + (make-music + 'SequentialMusic + 'elements + ;; set properties for proper bar numbering + (append + (list (make-music 'AlternativeEvent + 'alternative-dir (if (= y 0) + -1 + 0) + 'alternative-increment + (if (= 0 y) + (1+ (- times + lalts)) + 1))) + (list x) + (if (= y (1- lalts)) + (list (make-music 'AlternativeEvent + 'alternative-dir 1 + 'alternative-increment 0)) + '())))) + alts + (iota lalts)))) + (define (make-ottava-set music) "Set context properties for an ottava bracket." (let ((octavation (ly:music-property music 'ottava-number))) diff --git a/scm/define-music-display-methods.scm b/scm/define-music-display-methods.scm index d0926d5f85..85ae00d906 100644 --- a/scm/define-music-display-methods.scm +++ b/scm/define-music-display-methods.scm @@ -697,6 +697,8 @@ Otherwise, return #f." ;;; Repeats ;;; +(define-display-method AlternativeEvent (alternative parser) "") + (define (repeat->lily-string expr repeat-type parser) (format #f "\\repeat ~a ~a ~a ~a" repeat-type diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm index 8911239473..673c66a8e5 100644 --- a/scm/define-music-properties.scm +++ b/scm/define-music-properties.scm @@ -30,6 +30,10 @@ (absolute-octave ,integer? "The absolute octave for a octave check note.") (alteration ,number? "Alteration for figured bass.") + (alternative-dir ,ly:dir? "Indicates if an AlternativeMusic is the +First (-1), Middle (0), or Last (1) of group of alternate endings.") + (alternative-increment ,integer? "The number of times an alternative's +lettering should be incremented.") (articulation-type ,string? "Key for script definitions alist. TODO: Consider making type into symbol.") @@ -210,6 +214,8 @@ engraver this music expression is processed.") (value ,scheme? "Assignment value for a translation property.") (void ,boolean? "If this property is @code{#t}, then the music expression is to be discarded by the toplevel music handler.") + (volta-repeats ,list? "A list that is transformed into a volta +repeat element list.") (what ,symbol? "What to change for auto-change. diff --git a/scm/define-music-types.scm b/scm/define-music-types.scm index 015a628c53..8dbc6decc0 100644 --- a/scm/define-music-types.scm +++ b/scm/define-music-types.scm @@ -32,6 +32,11 @@ Syntax: @var{note}@code{\\x}, where @code{\\x} is a dynamic mark like (types . (general-music event dynamic-event absolute-dynamic-event)) )) + (AlternativeEvent + . ((description . "Create a alternative event.") + (types . (general-music event alternative-event)) + )) + (AnnotateOutputEvent . ((description . "Print an annotation of an output element.") (types . (general-music event annotate-output-event)) @@ -712,6 +717,7 @@ Syntax: @code{\\\\}") (VoltaRepeatedMusic . ((description . "Repeats with alternatives placed sequentially.") (iterator-ctor . ,ly:volta-repeat-iterator::constructor) + (elements-callback . ,make-volta-set) (start-callback . ,ly:repeated-music::first-start) (length-callback . ,ly:repeated-music::volta-music-length) (types . (general-music repeated-music volta-repeated-music)) -- 2.39.2