From 2760d9ed270cdaf7bf8e564c07ecda67c89dd9cf Mon Sep 17 00:00:00 2001 From: Reinhold Kainhofer Date: Sat, 7 Jun 2008 00:35:19 +0200 Subject: [PATCH] Feature: Include text in \tempo indications A tempo indication in general is either a text markup, a note=count or both. So far, lilypond only supported the note=count type of tempo indications in its \tempo command. This patch extends the \tempo function to include a text string, too. It allows any of the following types of tempo settings: \tempo 4=120 \tempo "Allegro" 4=120 \tempo "Allegro" \tempo \markup{\italic \medium "Allegro"} etc. What it does: - Extend the parser to allow the above forms for \tempo - Add a tempoText property, similar to tempoUnitCount - Metronome_mark_engraver uses this property and checks whether it has changed - Extend the metronomeMarkFormatter to take four arguments (text, duration, count, context) and print either the text, the note=count or text (note=count), depending on whether the properties are set to sensible values. - Add a tempoHideNote property to hide note=count in the metronome mark - Extend the define-extra-display-method to also check for tempoText and produce any of the allowed \tempo forms when you use \displayLilyMusic - Added a convert-ly rule to warn the user about the change to the signature of the metronomeMarkFormater function --- input/regression/metronome-text.ly | 29 +++++++++++++++++++++++ lily/metronome-engraver.cc | 21 ++++++++++++----- lily/parser.yy | 16 +++++++++++- python/convertrules.py | 9 +++++++ scm/define-context-properties.scm | 4 ++- scm/define-music-display-methods.scm | 37 ++++++++++++++++++++++++++--- scm/display-lily.scm | 2 +- scm/ly-syntax-constructors.scm | 20 +++++++++++----- scm/translation-functions.scm | 42 +++++++++++++++++++++++++-------- 9 files changed, 150 insertions(+), 30 deletions(-) create mode 100644 input/regression/metronome-text.ly diff --git a/input/regression/metronome-text.ly b/input/regression/metronome-text.ly new file mode 100644 index 0000000..af4844d --- /dev/null +++ b/input/regression/metronome-text.ly @@ -0,0 +1,29 @@ +\version "2.11.48" + +\header{ + texidoc=" +The tempo command supports text markup and/or note=count. Using the +Score.hideTempoNote, one can hide the note=count in the tempo mark. +" +} + +\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 + + \set Score.tempoHideNote = ##f + \tempo "Allegro" 4=120 c1 + \set Score.tempoHideNote = ##t + \tempo "No note" 8=160 c1 + \tempo "Still not" c1 + \tempo "Allegro" 4=120 c1 + \set Score.tempoHideNote = ##f + \tempo "With note" 8=80 c1 +} diff --git a/lily/metronome-engraver.cc b/lily/metronome-engraver.cc index 5bc7153..b06333b 100644 --- a/lily/metronome-engraver.cc +++ b/lily/metronome-engraver.cc @@ -16,6 +16,7 @@ using namespace std; #include "grob-array.hh" #include "item.hh" #include "stream-event.hh" +#include "text-interface.hh" #include "translator.icc" @@ -33,6 +34,7 @@ protected: SCM last_duration_; SCM last_count_; + SCM last_text_; protected: virtual void derived_mark () const; @@ -52,6 +54,7 @@ Metronome_mark_engraver::derived_mark () const { scm_gc_mark (last_count_); scm_gc_mark (last_duration_); + scm_gc_mark (last_text_); } void @@ -72,16 +75,19 @@ Metronome_mark_engraver::process_music () { SCM count = get_property ("tempoUnitCount"); SCM duration = get_property ("tempoUnitDuration"); - - if (unsmob_duration (duration) - && scm_is_number (count) + SCM text = get_property ("tempoText"); + + if ( ( (unsmob_duration (duration) && scm_is_number (count)) + || Text_interface::is_markup (text) ) && !(ly_is_equal (count, last_count_) - && ly_is_equal (duration, last_duration_))) + && ly_is_equal (duration, last_duration_) + && ly_is_equal (text, last_text_))) { text_ = make_item ("MetronomeMark", SCM_EOL); SCM proc = get_property ("metronomeMarkFormatter"); - SCM result = scm_call_3 (proc, + SCM result = scm_call_4 (proc, + text, duration, count, context ()->self_scm ()); @@ -91,6 +97,7 @@ Metronome_mark_engraver::process_music () last_duration_ = duration; last_count_ = count; + last_text_ = text; } ADD_TRANSLATOR (Metronome_mark_engraver, @@ -108,7 +115,9 @@ ADD_TRANSLATOR (Metronome_mark_engraver, "stavesFound " "metronomeMarkFormatter " "tempoUnitDuration " - "tempoUnitCount ", + "tempoUnitCount " + "tempoText " + "tempoHideNote ", /* write */ "" diff --git a/lily/parser.yy b/lily/parser.yy index 3b690e8..feb763f 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -820,8 +820,20 @@ output_def_body: tempo_event: TEMPO steno_duration '=' bare_unsigned { - $$ = MAKE_SYNTAX ("tempo", @$, $2, scm_int2num ($4)); - } + $$ = MAKE_SYNTAX ("tempo", @$, SCM_BOOL_F, $2, scm_int2num ($4)); + } + | TEMPO string steno_duration '=' bare_unsigned { + $$ = MAKE_SYNTAX ("tempo", @$, make_simple_markup($2), $3, scm_int2num ($5)); + } + | TEMPO full_markup steno_duration '=' bare_unsigned { + $$ = MAKE_SYNTAX ("tempo", @$, $2, $3, scm_int2num ($5)); + } + | TEMPO string { + $$ = MAKE_SYNTAX ("tempoText", @$, make_simple_markup($2) ); + } + | TEMPO full_markup { + $$ = MAKE_SYNTAX ("tempoText", @$, $2 ); + } ; /* diff --git a/python/convertrules.py b/python/convertrules.py index 66c0835..7bf3286 100644 --- a/python/convertrules.py +++ b/python/convertrules.py @@ -3056,3 +3056,12 @@ def conv (str): return str conversions.append (((2, 11, 48), conv, """\\compressMusic -> \\scaleDurations""")) + +def conv (str): + if re.search ('metronomeMarkFormatter', str): + stderr_write (NOT_SMART % _ ("metronomeMarkFormatter got an additional text argument.\n")) + stderr_write (_ ("The function assigned to Score.metronomeMarkFunction now uses the signature\n%s") % + "\t(format-metronome-markup text dur count context)\n") + return str + +conversions.append (((2, 11, 49), conv, """metronomeMarkFormatter uses text markup as second argument""")) \ No newline at end of file diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 469b900..77ad346 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -301,7 +301,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 two arguments, event and context.") +markup. Called with four arguments: text, duration, count and context.") (midiInstrument ,string? "Name of the MIDI instrument to use.") (midiMaximumVolume ,number? "Analogous to @code{midiMinimumVolume}.") @@ -432,6 +432,8 @@ note head; it takes a string number, a list of string tunings and a minute.") (tempoUnitCount ,number? "Count for specifying tempo.") (tempoUnitDuration ,ly:duration? "Unit for specifying tempo.") + (tempoText ,markup? "Text for tempo marks.") + (tempoHideNote ,boolean? "Hide the note=count in tempo marks.") (tieWaitForNote ,boolean? "If true, tied notes do not have to follow each other directly. This can be used for writing out arpeggios.") diff --git a/scm/define-music-display-methods.scm b/scm/define-music-display-methods.scm index b1b9111..6240c4e 100644 --- a/scm/define-music-display-methods.scm +++ b/scm/define-music-display-methods.scm @@ -880,10 +880,11 @@ Otherwise, return #f." symbol 'melismaBusy))) "\\melismaEnd")) +;;; TODO: Add the tempoText property here, too! ;;; \tempo (define-extra-display-method ContextSpeccedMusic (expr parser) "If expr is a tempo, return \"\\tempo x = nnn\", otherwise return #f." - (with-music-match (expr (music 'ContextSpeccedMusic + (let* ((count_expr (with-music-match (expr (music 'ContextSpeccedMusic element (music 'SequentialMusic elements ((music 'PropertySet symbol 'tempoWholesPerMinute) @@ -893,9 +894,37 @@ Otherwise, return #f." (music 'PropertySet value ?unit-count symbol 'tempoUnitCount))))) - (format #f "\\tempo ~a = ~a" - (duration->lily-string ?unit-duration #:force-duration #t) - ?unit-count))) + (format #f "~a = ~a" + (duration->lily-string ?unit-duration #:force-duration #t) + ?unit-count))) + ; Extract a textual representation. We need to match count, duration etc. too! + (text_expr (or (with-music-match (expr (music 'ContextSpeccedMusic + element (music 'SequentialMusic + elements ((music 'PropertySet + symbol 'tempoWholesPerMinute) + (music 'PropertySet + value ?unit-duration + symbol 'tempoUnitDuration) + (music 'PropertySet + value ?unit-count + symbol 'tempoUnitCount) + (music 'PropertySet + value ?tempo-text + symbol 'tempoText))))) + ?tempo-text) + (with-music-match (expr (music 'ContextSpeccedMusic + element (music 'SequentialMusic + elements ((music 'PropertySet + value ?tempo-text + symbol 'tempoText))))) + ?tempo-text)))) + (if text_expr + (if count_expr (format #f "\\tempo ~a ~a" (scheme-expr->lily-string text_expr) count_expr) + (format #f "\\tempo ~a" (scheme-expr->lily-string text_expr))) + (if count_expr (format #f "\\tempo ~a" count_expr) + #f)) + ) +) ;;; \clef (define clef-name-alist #f) diff --git a/scm/display-lily.scm b/scm/display-lily.scm index eb1b876..c53da46 100644 --- a/scm/display-lily.scm +++ b/scm/display-lily.scm @@ -132,7 +132,7 @@ display method will be called." (define (gen-condition expr pattern) "Helper function for `with-music-match'. Generate an form that checks if the properties of `expr' -match thoses desscribed in `pattern'." +match thoses described in `pattern'." (let* (;; all (property . value) found at the first depth in pattern, ;; including a (name . ) pair. (pat-all-props (cons (cons 'name (second pattern)) diff --git a/scm/ly-syntax-constructors.scm b/scm/ly-syntax-constructors.scm index 9e6325a..f1857be 100644 --- a/scm/ly-syntax-constructors.scm +++ b/scm/ly-syntax-constructors.scm @@ -78,15 +78,23 @@ (make-music 'TransposedMusic 'element (ly:music-transpose music pitch))) -(define-ly-syntax-simple (tempo duration tempo) +(define-ly-syntax-simple (tempo text duration tempo) + (let ((props (list + (make-property-set 'tempoWholesPerMinute + (ly:moment-mul (ly:make-moment tempo 1) + (ly:duration-length duration))) + (make-property-set 'tempoUnitDuration duration) + (make-property-set 'tempoUnitCount tempo)))) + (if text (set! props (append props (list (make-property-set 'tempoText text))))) + (context-spec-music + (make-sequential-music props) + 'Score))) + +(define-ly-syntax-simple (tempoText text) (context-spec-music (make-sequential-music (list - (make-property-set 'tempoWholesPerMinute - (ly:moment-mul (ly:make-moment tempo 1) - (ly:duration-length duration))) - (make-property-set 'tempoUnitDuration duration) - (make-property-set 'tempoUnitCount tempo))) + (make-property-set 'tempoText text))) 'Score)) (define-ly-syntax-simple (skip-music dur) diff --git a/scm/translation-functions.scm b/scm/translation-functions.scm index 366f44f..3ef8b06 100644 --- a/scm/translation-functions.scm +++ b/scm/translation-functions.scm @@ -6,16 +6,38 @@ ;;;; Jan Nieuwenhuizen ;; metronome marks -(define-public (format-metronome-markup dur count context) - (let* ((note-mark (make-smaller-markup - (make-note-by-number-markup (ly:duration-log dur) - (ly:duration-dot-count dur) - 1)))) - (make-line-markup - (list - (make-general-align-markup Y DOWN note-mark) - (make-simple-markup "=") - (make-simple-markup (number->string count)))))) +(define-public (format-metronome-markup text dur count context) + (let* ((hide_note (eq? #t (ly:context-property context 'tempoHideNote))) + (note-mark (if (and (not hide_note) (ly:duration? dur)) + (make-smaller-markup + (make-note-by-number-markup (ly:duration-log dur) + (ly:duration-dot-count dur) + 1)) + #f)) + (note-markup (if (and note-mark (number? count) (> count 0) ) + (list + (make-general-align-markup Y DOWN note-mark) + (make-simple-markup "=") + (make-simple-markup (number->string count))) + #f)) + (text-markup (if (not (null? text)) + (make-bold-markup text) + #f))) + (if text-markup + (if note-markup + (make-line-markup (list text-markup + (make-concat-markup (append (list (make-simple-markup "(")) + note-markup + (list (make-simple-markup ")")))))) + (make-line-markup (list text-markup)) + ) + (if note-markup + (make-line-markup note-markup) + #f + ) + ) + ) +) (define-public (format-mark-alphabet mark context) (make-bold-markup (make-markalphabet-markup (1- mark)))) -- 1.5.4.3