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
-\version "2.13.41"
+\version "2.13.50"
\header {
texidoc = "
\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
}
-\version "2.12.0"
+\version "2.13.50"
\header{
texidoc="
\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
}
-
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 ()
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
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"),
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);
"MetronomeMark ",
/* read */
- "stavesFound "
+ "currentCommandColumn "
+ "currentMusicalColumn "
"metronomeMarkFormatter "
- "tempoUnitDuration "
- "tempoUnitCount "
- "tempoText "
+ "stavesFound "
"tempoHideNote ",
/* write */
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);
}
;
@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}.")
(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
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
(music
'SlurEvent
span-direction START))))))
- #t)
+ #t)
(with-music-match (?stop (music
'SequentialMusic
elements ((music
grob-property-path '(stroke-style)
grob-value "grace"
symbol 'Stem)))))
- #t)
+ #t)
(with-music-match (?stop (music
'SequentialMusic
elements ((music
"\\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)
(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
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."
'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)))))
;;;
;;;
(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.")
(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))
(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
(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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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)