From 266e143bd34a6cf92298b9af4ced3e4dd87872e4 Mon Sep 17 00:00:00 2001 From: Neil Puttock Date: Wed, 9 Feb 2011 22:27:06 +0000 Subject: [PATCH] Fix #1205. Reinstate an event for \tempo, instead of relying on context property changes. * input/regression/metronome-range.ly, metronome-text.ly: replace explicit tempo changes using context props with exported events * lily/metronome-engraver.cc: listen to TempoChangeEvent; set as cause for MetronomeMark; pass to metronomeMarkFormatter proc instead of explicit text, duration and count * lily/parser.yy (tempo_event): simplify rule; use single constructor for all types * scm/define-context-properties.scm (all-user-translation-properties): emend metronomeMarkFormatter description remove tempoUnitCount, tempoUnitDuration and tempoText definitions * scm/define-event-classes.scm (event-classes): add tempo-change-event * scm/define-music-display-methods.scm: rework display method for \tempo * scm/define-music-properties.scm (all-music-properties): change type predicate for 'metronome-count * scm/define-music-types.scm (music-descriptions): add TempoChangeEvent definition * scm/ly-syntax-constructors.scm: rework `tempo' constructor; use for all \tempo styles remove `tempoText' * scm/song.scm (tempo->beats): extract tempo from TempoChangeEvent * scm/translation-functions.scm (format-metronome-markup): read tempo properties from event instead of passing as separate args --- input/regression/metronome-range.ly | 11 ++-- input/regression/metronome-text.ly | 36 +++++------ lily/metronome-engraver.cc | 64 +++++++------------- lily/parser.yy | 14 ++--- scm/define-context-properties.scm | 7 +-- scm/define-event-classes.scm | 2 +- scm/define-music-display-methods.scm | 89 ++++++++++------------------ scm/define-music-properties.scm | 2 +- scm/define-music-types.scm | 5 ++ scm/ly-syntax-constructors.scm | 55 ++++++++--------- scm/song.scm | 45 +++++++------- scm/translation-functions.scm | 8 ++- 12 files changed, 145 insertions(+), 193 deletions(-) diff --git a/input/regression/metronome-range.ly b/input/regression/metronome-range.ly index e5456ab529..3fc046bab1 100644 --- a/input/regression/metronome-range.ly +++ b/input/regression/metronome-range.ly @@ -1,4 +1,4 @@ -\version "2.13.41" +\version "2.13.50" \header { texidoc = " @@ -9,7 +9,10 @@ printed with an en-dash character, separated by thin-spaces. \relative c'' { \tempo 4 = 66 ~ 72 - c1 c - \set Score.tempoUnitCount = #(cons 124 132) - c1 c + c1 | c + #(ly:export + (make-event-chord (list (make-music 'TempoChangeEvent + 'tempo-unit (ly:make-duration 2 0 1 1) + 'metronome-count (cons 124 132))))) + c1 | c } diff --git a/input/regression/metronome-text.ly b/input/regression/metronome-text.ly index f1b94fbcb7..471b757e81 100644 --- a/input/regression/metronome-text.ly +++ b/input/regression/metronome-text.ly @@ -1,4 +1,4 @@ -\version "2.12.0" +\version "2.13.50" \header{ texidoc=" @@ -10,31 +10,33 @@ The tempo command supports text markup and/or duration=count. Using \relative c'' { \tempo "Allegro" c1 \tempo "Allegro" c1 - \set Score.tempoText = #"blah" d1 - \tempo \markup{\italic \medium "Allegro"} c1\break - \tempo 4=120 c1 - \tempo "Allegro" 4=120 c1 - \tempo "Allegro" 4=120 c1 - \tempo "Allegro" 4=110 c1 - \tempo "Allegretto" 4=110 c1\break + #(ly:export + (make-event-chord (list (make-music 'TempoChangeEvent + 'text "blah")))) + d1 + \tempo \markup { \italic \medium "Allegro" } c1 \break + \tempo 4 = 120 c1 + \tempo "Allegro" 4 = 120 c1 + \tempo "Allegro" 4 = 120 c1 + \tempo "Allegro" 4 = 110 c1 + \tempo "Allegretto" 4 = 110 c1 \break \set Score.tempoHideNote = ##f - \tempo "Allegro" 4=120 c1 + \tempo "Allegro" 4 = 120 c1 \set Score.tempoHideNote = ##t - \tempo "No note" 8=160 c1 + \tempo "No note" 8 = 160 c1 \tempo "Still not" c1 % No text and also no note => \null markup - \tempo 4=100 c1 - \tempo "Allegro" 4=120 c1 + \tempo 4 = 100 c1 + \tempo "Allegro" 4 = 120 c1 \set Score.tempoHideNote = ##f - \tempo "With note" 8=80 c1\break + \tempo "With note" 8 = 80 c1 \break % Unsetting the tempoText using only note=count: - \tempo 8=80 c1 - \tempo "Allegro" 8=80 c1 - \tempo 8=80 c1 + \tempo 8 = 80 c1 + \tempo "Allegro" 8 = 80 c1 + \tempo 8 = 80 c1 % Unsetting the count using only text \tempo "no note (text-only)" c1 } - diff --git a/lily/metronome-engraver.cc b/lily/metronome-engraver.cc index 7b472d3e22..09673b7e14 100644 --- a/lily/metronome-engraver.cc +++ b/lily/metronome-engraver.cc @@ -34,26 +34,23 @@ using namespace std; class Metronome_mark_engraver : public Engraver { -public: - TRANSLATOR_DECLARATIONS (Metronome_mark_engraver); - -protected: Item *text_; Grob *support_; Grob *bar_; + Stream_event *tempo_ev_; - SCM last_duration_; - SCM last_count_; - SCM last_text_; +public: + TRANSLATOR_DECLARATIONS (Metronome_mark_engraver); + +protected: + void stop_translation_timestep (); + void process_music (); DECLARE_ACKNOWLEDGER (break_aligned); DECLARE_ACKNOWLEDGER (break_alignment); DECLARE_ACKNOWLEDGER (grob); -protected: - virtual void derived_mark () const; - void stop_translation_timestep (); - void process_music (); + DECLARE_TRANSLATOR_LISTENER (tempo_change); }; Metronome_mark_engraver::Metronome_mark_engraver () @@ -61,17 +58,14 @@ Metronome_mark_engraver::Metronome_mark_engraver () text_ = 0; support_ = 0; bar_ = 0; - last_duration_ = SCM_EOL; - last_count_ = SCM_EOL; - last_text_ = SCM_EOL; + tempo_ev_ = 0; } +IMPLEMENT_TRANSLATOR_LISTENER (Metronome_mark_engraver, tempo_change); void -Metronome_mark_engraver::derived_mark () const +Metronome_mark_engraver::listen_tempo_change (Stream_event *ev) { - scm_gc_mark (last_count_); - scm_gc_mark (last_duration_); - scm_gc_mark (last_text_); + ASSIGN_EVENT_ONCE (tempo_ev_, ev); } static bool @@ -89,7 +83,7 @@ Metronome_mark_engraver::acknowledge_break_aligned (Grob_info info) if (text_ && g->get_property ("break-align-symbol") == ly_symbol2scm ("staff-bar")) - bar_ = g; + bar_ = g; else if (text_ && !support_ && safe_is_member (g->get_property ("break-align-symbol"), @@ -153,41 +147,26 @@ Metronome_mark_engraver::stop_translation_timestep () text_ = 0; support_ = 0; bar_ = 0; + tempo_ev_ = 0; } } void Metronome_mark_engraver::process_music () { - SCM count = get_property ("tempoUnitCount"); - SCM duration = get_property ("tempoUnitDuration"); - SCM text = get_property ("tempoText"); - - if ( ( (unsmob_duration (duration) && scm_is_true (count)) - || Text_interface::is_markup (text) ) - && !(ly_is_equal (count, last_count_) - && ly_is_equal (duration, last_duration_) - && ly_is_equal (text, last_text_))) + if (tempo_ev_) { - text_ = make_item ("MetronomeMark", SCM_EOL); + text_ = make_item ("MetronomeMark", tempo_ev_->self_scm ()); SCM proc = get_property ("metronomeMarkFormatter"); - SCM result = scm_call_4 (proc, - text, - duration, - count, + SCM result = scm_call_2 (proc, + tempo_ev_->self_scm (), context ()->self_scm ()); text_->set_property ("text", result); } - - last_duration_ = duration; - last_count_ = count; - last_text_ = text; } - - ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_aligned); ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_alignment); ADD_ACKNOWLEDGER (Metronome_mark_engraver, grob); @@ -204,11 +183,10 @@ ADD_TRANSLATOR (Metronome_mark_engraver, "MetronomeMark ", /* read */ - "stavesFound " + "currentCommandColumn " + "currentMusicalColumn " "metronomeMarkFormatter " - "tempoUnitDuration " - "tempoUnitCount " - "tempoText " + "stavesFound " "tempoHideNote ", /* write */ diff --git a/lily/parser.yy b/lily/parser.yy index 240a4c1e3b..0bb4c152f2 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -912,19 +912,13 @@ output_def_body: tempo_event: TEMPO steno_duration '=' tempo_range { - $$ = MAKE_SYNTAX ("tempo", @$, SCM_BOOL_F, $2, $4); + $$ = MAKE_SYNTAX ("tempo", @$, SCM_EOL, $2, $4); } - | TEMPO string steno_duration '=' tempo_range { - $$ = MAKE_SYNTAX ("tempo", @$, make_simple_markup($2), $3, $5); - } - | TEMPO full_markup steno_duration '=' tempo_range { + | TEMPO scalar steno_duration '=' tempo_range { $$ = MAKE_SYNTAX ("tempo", @$, $2, $3, $5); } - | TEMPO string { - $$ = MAKE_SYNTAX ("tempoText", @$, make_simple_markup($2) ); - } - | TEMPO full_markup { - $$ = MAKE_SYNTAX ("tempoText", @$, $2 ); + | TEMPO scalar { + $$ = MAKE_SYNTAX ("tempo", @$, $2); } ; diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 5853474179..de702c3f6f 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -339,7 +339,7 @@ manual beams are considered. Possible values include @code{melismaBusy}, @code{slurMelismaBusy}, @code{tieMelismaBusy}, and @code{beamMelismaBusy}.") (metronomeMarkFormatter ,procedure? "How to produce a metronome -markup. Called with four arguments: text, duration, count and context.") +markup. Called with two arguments: a @code{TempoChangeEvent} and context.") (middleCClefPosition ,number? "The position of the middle C, as determined only by the clef. This can be calculated by looking at @code{clefPosition} and @code{clefGlyph}.") @@ -478,10 +478,7 @@ fret number. It returns the text as a markup.") (tabStaffLineLayoutFunction ,procedure? "A function determining the staff position of a tablature note head. Called with two arguments: the context and the string.") - (tempoHideNote ,boolean? "Hide the note=count in tempo marks.") - (tempoText ,markup? "Text for tempo marks.") - (tempoUnitCount ,number-or-pair? "Count for specifying tempo.") - (tempoUnitDuration ,ly:duration? "Unit for specifying tempo.") + (tempoHideNote ,boolean? "Hide the note = count in tempo marks.") (tempoWholesPerMinute ,ly:moment? "The tempo in whole notes per minute.") (tieWaitForNote ,boolean? "If true, tied notes do not have to diff --git a/scm/define-event-classes.scm b/scm/define-event-classes.scm index ff7229e236..539288b843 100644 --- a/scm/define-event-classes.scm +++ b/scm/define-event-classes.scm @@ -30,7 +30,7 @@ rhythmic-event dynamic-event break-event label-event percent-event key-change-event string-number-event stroke-finger-event tie-event part-combine-event part-combine-force-event - beam-forbid-event script-event + beam-forbid-event script-event tempo-change-event tremolo-event bend-after-event fingering-event glissando-event harmonic-event hyphen-event laissez-vibrer-event mark-event multi-measure-text-event note-grouping-event diff --git a/scm/define-music-display-methods.scm b/scm/define-music-display-methods.scm index 4676747896..574ba04678 100644 --- a/scm/define-music-display-methods.scm +++ b/scm/define-music-display-methods.scm @@ -283,7 +283,7 @@ expression." (music 'SlurEvent span-direction START)))))) - #t) + #t) (with-music-match (?stop (music 'SequentialMusic elements ((music @@ -325,7 +325,7 @@ expression." grob-property-path '(stroke-style) grob-value "grace" symbol 'Stem))))) - #t) + #t) (with-music-match (?stop (music 'SequentialMusic elements ((music @@ -915,56 +915,30 @@ Otherwise, return #f." "\\melismaEnd")) ;;; \tempo -;;; Check for all three different syntaxes of tempo: -;;; \tempo string duration=note, \tempo duration=note and \tempo string -(define-extra-display-method ContextSpeccedMusic (expr parser) - "If expr is a tempo, return \"\\tempo x = nnn\", otherwise return #f." - (or (with-music-match (expr (music 'ContextSpeccedMusic - element (music 'SequentialMusic - elements ((music 'PropertySet - value ?unit-text - symbol 'tempoText) - (music 'PropertySet - symbol 'tempoWholesPerMinute) - (music 'PropertySet - value ?unit-duration - symbol 'tempoUnitDuration) - (music 'PropertySet - value ?unit-count - symbol 'tempoUnitCount))))) - (format #f "\\tempo ~a ~a = ~a" - (scheme-expr->lily-string ?unit-text) - (duration->lily-string ?unit-duration #:force-duration #t) - (if (number-pair? ?unit-count) - (format #f "~a ~~ ~a" - (car ?unit-count) - (cdr ?unit-count)) - ?unit-count))) - (with-music-match (expr (music 'ContextSpeccedMusic - element (music 'SequentialMusic - elements ((music 'PropertyUnset - symbol 'tempoText) - (music 'PropertySet - symbol 'tempoWholesPerMinute) - (music 'PropertySet - value ?unit-duration - symbol 'tempoUnitDuration) - (music 'PropertySet - value ?unit-count - symbol 'tempoUnitCount))))) - (format #f "\\tempo ~a = ~a" - (duration->lily-string ?unit-duration #:force-duration #t) - (if (number-pair? ?unit-count) - (format #f "~a ~~ ~a" - (car ?unit-count) - (cdr ?unit-count)) - ?unit-count))) - (with-music-match (expr (music 'ContextSpeccedMusic - element (music 'SequentialMusic - elements ((music 'PropertySet - value ?tempo-text - symbol 'tempoText))))) - (format #f "\\tempo ~a" (scheme-expr->lily-string ?tempo-text))))) +(define-extra-display-method SequentialMusic (expr parser) + (with-music-match (expr (music 'SequentialMusic + elements ((music 'TempoChangeEvent + text ?text + tempo-unit ?unit + metronome-count ?count) + (music 'ContextSpeccedMusic + element (music 'PropertySet + symbol 'tempoWholesPerMinute))))) + (format #f "\\tempo ~{~a~a~}~a = ~a~a" + (if (markup? ?text) + (list (markup->lily-string ?text) " ") + '()) + (duration->lily-string ?unit #:force-duration #t) + (if (pair? ?count) + (format #f "~a ~~ ~a" (car ?count) (cdr ?count)) + ?count) + (new-line->lily-string)))) + +(define-display-method TempoChangeEvent (expr parser) + (let ((text (ly:music-property expr 'text))) + (format #f "\\tempo ~a~a" + (markup->lily-string text) + (new-line->lily-string)))) ;;; \clef (define clef-name-alist #f) @@ -997,7 +971,7 @@ Otherwise, return @code{#f}." (music 'ApplyContext procedure ly:set-middle-C!))))) (let ((clef-name (assoc-get (list ?clef-glyph ?clef-position 0) - clef-name-alist))) + clef-name-alist))) (if clef-name (format #f "\\clef \"~a~{~a~a~}\"~a" clef-name @@ -1019,10 +993,9 @@ Otherwise, return #f." element (music 'PropertySet value ?bar-type symbol 'whichBar))) - (format #f "\\bar \"~a\"~a" ?bar-type (new-line->lily-string)))) + (format #f "\\bar \"~a\"~a" ?bar-type (new-line->lily-string)))) ;;; \partial - (define-extra-display-method ContextSpeccedMusic (expr parser) "If `expr' is a partial measure, return \"\\partial ...\". Otherwise, return #f." @@ -1035,9 +1008,9 @@ Otherwise, return #f." 'PartialSet partial-duration ?duration)))) - (and ?duration - (format #f "\\partial ~a" - (duration->lily-string ?duration #:force-duration #t))))) + (and ?duration + (format #f "\\partial ~a" + (duration->lily-string ?duration #:force-duration #t))))) ;;; ;;; diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm index eb8cb54513..b2db381b7e 100644 --- a/scm/define-music-properties.scm +++ b/scm/define-music-properties.scm @@ -105,7 +105,7 @@ This property can only be defined as initializer in (line-break-permission ,symbol? "When the music is at top-level, whether to allow, forbid or force a line break.") - (metronome-count ,number? "How many beats in a minute?") + (metronome-count ,number-or-pair? "How many beats in a minute?") (name ,symbol? "Name of this music object.") (no-continuation ,boolean? "If set, disallow continuation lines.") diff --git a/scm/define-music-types.scm b/scm/define-music-types.scm index a349934c23..43b826e8b8 100644 --- a/scm/define-music-types.scm +++ b/scm/define-music-types.scm @@ -573,6 +573,11 @@ Syntax: @code{\\rightHandFinger @var{text}}") (types . (general-music event pedal-event sustain-event)) )) + (TempoChangeEvent + . ((description . "A metronome mark or tempo indication.") + (types . (general-music event tempo-change-event)) + )) + (TextScriptEvent . ((description . "Print text.") (types . (general-music script-event text-script-event event)) diff --git a/scm/ly-syntax-constructors.scm b/scm/ly-syntax-constructors.scm index 60af06436e..171cee1240 100644 --- a/scm/ly-syntax-constructors.scm +++ b/scm/ly-syntax-constructors.scm @@ -89,33 +89,34 @@ (make-music 'TransposedMusic 'element (ly:music-transpose music pitch))) -(define-ly-syntax-simple (tempo text duration tempo) - (let* ((range-tempo? (pair? tempo)) - (tempo-count (if range-tempo? - (round (/ (+ (car tempo) (cdr tempo)) 2)) - tempo)) - (props (list - (make-property-set 'tempoWholesPerMinute - (ly:moment-mul (ly:make-moment tempo-count 1) - (ly:duration-length duration))) - (make-property-set 'tempoUnitDuration duration) - (make-property-set 'tempoUnitCount tempo)))) - (set! props (cons - (if text (make-property-set 'tempoText text) - (make-property-unset 'tempoText)) - props)) - (context-spec-music - (make-sequential-music props) - 'Score))) - -(define-ly-syntax-simple (tempoText text) - (context-spec-music - (make-sequential-music - (list - (make-property-unset 'tempoUnitDuration) - (make-property-unset 'tempoUnitCount) - (make-property-set 'tempoText text))) - 'Score)) +(define-ly-syntax (tempo parser location text . rest) + (let* ((unit (and (pair? rest) + (car rest))) + (count (and unit + (cadr rest))) + (range-tempo? (pair? count)) + (tempo-change (make-music 'TempoChangeEvent + 'origin location + 'text text + 'tempo-unit unit + 'metronome-count count)) + (tempo-set + (and unit + (context-spec-music + (make-property-set 'tempoWholesPerMinute + (ly:moment-mul + (ly:make-moment + (if range-tempo? + (round (/ (+ (car count) (cdr count)) + 2)) + count) + 1) + (ly:duration-length unit))) + 'Score)))) + + (if tempo-set + (make-sequential-music (list tempo-change tempo-set)) + tempo-change))) (define-ly-syntax-simple (skip-music dur) (make-music 'SkipMusic diff --git a/scm/song.scm b/scm/song.scm index 88b4423702..9dbca9fd62 100644 --- a/scm/song.scm +++ b/scm/song.scm @@ -141,33 +141,28 @@ (exact->inexact (* (expt 2 (- log)) (+ 1 (/ dots 2)) (/ (car factor) (cdr factor)))))) (define (tempo->beats music) - (let* ((tempo-spec (or (find-child-named music 'MetronomeChangeEvent) - (find-child-named music 'SequentialMusic))) + (let* ((tempo-spec (find-child-named music 'SequentialMusic)) (tempo (cond - ((not tempo-spec) - #f) - ((music-name? tempo-spec 'MetronomeChangeEvent) - (* (ly:music-property tempo-spec 'metronome-count) - (duration->number (ly:music-property tempo-spec 'tempo-unit)))) - ((music-name? tempo-spec 'SequentialMusic) - (* (property-value - (find-child tempo-spec (lambda (elt) - (let ((tempo (music-property? elt 'tempoUnitCount))) - (if (pair? tempo) - (round (/ (+ (car tempo) (cdr tempo)) 2)) - tempo))))) - (duration->number - (property-value - (find-child tempo-spec (lambda (elt) (music-property? elt 'tempoUnitDuration))))))) - (else - (format #t "Programming error (tempo->beats): ~a~%" tempo-spec))))) + (tempo-spec + (let ((tempo-event (find-child-named tempo-spec + 'TempoChangeEvent))) + (and tempo-event + (let ((count (ly:music-property tempo-event + 'metronome-count))) + (* (if (pair? count) + (round (/ (+ (car count) (cdr count)) 2)) + count) + (duration->number + (ly:music-property tempo-event 'tempo-unit))))))) + (else + (format #t "Programming error (tempo->beats): ~a~%" + tempo-spec))))) (debug-enable 'backtrace) - (if (and tempo (music-name? tempo-spec 'SequentialMusic)) - (set! *default-tempo* (property-value - (find-child tempo-spec (lambda (elt) (music-property? elt 'tempoWholesPerMinute)))))) - (if tempo - (round (* tempo (expt 2 (+ 2 *base-octave-shift*)))) - #f))) + (and tempo + (set! *default-tempo* (property-value + (find-child tempo-spec (lambda (elt) + (music-property? elt 'tempoWholesPerMinute))))) + (round (* tempo (expt 2 (+ 2 *base-octave-shift*))))))) (defstruct music-context music diff --git a/scm/translation-functions.scm b/scm/translation-functions.scm index 5a22e72a89..facabd8ab5 100644 --- a/scm/translation-functions.scm +++ b/scm/translation-functions.scm @@ -20,8 +20,12 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; metronome marks -(define-public (format-metronome-markup text dur count context) - (let* ((hide-note (eq? #t (ly:context-property context 'tempoHideNote)))) +(define-public (format-metronome-markup event context) + (let ((hide-note (ly:context-property context 'tempoHideNote #f)) + (text (ly:event-property event 'text)) + (dur (ly:event-property event 'tempo-unit)) + (count (ly:event-property event 'metronome-count))) + (metronome-markup text dur count hide-note))) (define-public (metronome-markup text dur count hide-note) -- 2.39.2