%%%% You should have received a copy of the GNU General Public License
%%%% along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
-\version "2.16.0"
+\version "2.17.6"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
'break-permission 'allow))))
alterBroken =
-#(define-music-function (parser location name property arg)
- (string? scheme? list?)
- (_i "Override @var{property} for pieces of broken spanner @var{name} with
-values @var{arg}.")
- (let* ((name (string-delete name char-set:blank)) ; remove any spaces
- (name-components (string-split name #\.))
- (context-name "Bottom")
- (grob-name #f))
-
- (if (> 2 (length name-components))
- (set! grob-name (car name-components))
- (begin
- (set! grob-name (cadr name-components))
- (set! context-name (car name-components))))
-
- ;; only apply override if grob is a spanner
- (let ((description
- (assoc-get (string->symbol grob-name) all-grob-descriptions)))
- (if (and description
- (member 'spanner-interface
- (assoc-get 'interfaces
- (assoc-get 'meta description))))
- #{
- \override $context-name . $grob-name $property =
- #(value-for-spanner-piece arg)
- #}
+#(define-music-function (parser location property arg item)
+ (symbol-list-or-symbol? list? symbol-list-or-music?)
+ (_i "Override @var{property} for pieces of broken spanner @var{item}
+with values @var{arg}. @var{item} may either be music in the form of
+a starting spanner event, or a symbol list in the form
+@samp{Context.Grob} or just @samp{Grob}. Iff @var{item} is in the
+form of a spanner event, @var{property} may also have the form
+@samp{Grob.property} for specifying a directed tweak.")
+ (if (ly:music? item)
+ (if (eq? (ly:music-property item 'span-direction) START)
+ #{ \tweak #property #(value-for-spanner-piece arg) #item #}
(begin
- (ly:input-warning location (_ "not a spanner name, `~a'") grob-name)
- (make-music 'SequentialMusic 'void #t))))))
+ (ly:music-warning item (_ "not a spanner"))
+ item))
+ (let* ((p (check-grob-path item parser location
+ #:default 'Bottom
+ #:min 2
+ #:max 2))
+ (name (and p (second p)))
+ (description
+ (and name (assoc-get name all-grob-descriptions))))
+ (if (and description
+ (member 'spanner-interface
+ (assoc-get 'interfaces
+ (assoc-get 'meta description))))
+ #{
+ \override #item . #property =
+ #(value-for-spanner-piece arg)
+ #}
+ (begin
+ (ly:input-warning location (_ "not a spanner name, `~a'") name)
+ (make-music 'Music))))))
appendToTag =
#(define-music-function (parser location tag more music)
(timesig (cons (ly:moment-main-numerator mlen)
(ly:moment-main-denominator mlen))))
#{
- \once \override Staff.TimeSignature #'stencil = #(lambda (grob)
+ \once \override Staff.TimeSignature.stencil = #(lambda (grob)
(grob-interpret-markup grob (format-compound-time args)))
- \set Timing.timeSignatureFraction = $timesig
- \set Timing.baseMoment = $beat
- \set Timing.beatStructure = $beatGrouping
+ \set Timing.timeSignatureFraction = #timesig
+ \set Timing.baseMoment = #beat
+ \set Timing.beatStructure = #beatGrouping
\set Timing.beamExceptions = #'()
- \set Timing.measureLength = $mlen
+ \set Timing.measureLength = #mlen
#} ))
crossStaff =
#(define-music-function (parser location notes) (ly:music?)
(_i "Create cross-staff stems")
#{
- \override Stem #'cross-staff = #cross-staff-connect
- \override Flag #'style = #'no-flag
- $notes
- \revert Stem #'cross-staff
- \revert Flag #'style
+ \temporary \override Stem.cross-staff = #cross-staff-connect
+ \temporary \override Flag.style = #'no-flag
+ #notes
+ \revert Stem.cross-staff
+ \revert Flag.style
#})
cueClef =
argument))
footnote =
-#(define-music-function (parser location mark offset grob-name footnote music)
- ((markup?) number-pair? (symbol?) markup? (ly:music?))
- (_i "Make the markup @var{footnote} a footnote on @var{music}. The
+#(define-music-function (parser location mark offset footnote item)
+ ((markup?) number-pair? markup? symbol-list-or-music?)
+ (_i "Make the markup @var{footnote} a footnote on @var{item}. The
footnote is marked with a markup @var{mark} moved by @var{offset} with
respect to the marked music.
If @var{mark} is not given or specified as @var{\\default}, it is
-replaced by an automatically generated sequence number. If a symbol
-@var{grob-name} is specified, then grobs of that type will be marked
-if they have @var{music} as their ultimate cause; by default all grobs
-having @var{music} as their @emph{direct} cause will be marked,
-similar to the way @code{\\tweak} works.
-
-If @var{music} is given as @code{\\default}, a footnote event
-affecting @emph{all} grobs matching @var{grob-name} at a given time
-step is generated. This may be required for creating footnotes on
-time signatures, clefs, and other items not cooperating with
-@code{\\tweak}.
+replaced by an automatically generated sequence number. If @var{item}
+is a symbol list of form @samp{Grob} or @samp{Context.Grob}, then
+grobs of that type will be marked at the current time step in the
+given context (default @code{Bottom}).
+
+If @var{item} is music, the music will get a footnote attached to a
+grob immediately attached to the event, like @var{\\tweak} does. For
+attaching a footnote to an @emph{indirectly} caused grob, write
+@code{\\single\\footnote}, use @var{item} to specify the grob, and
+follow it with the music to annotate.
Like with @code{\\tweak}, if you use a footnote on a following
post-event, the @code{\\footnote} command itself needs to be attached
'Y-offset (cdr offset)
'automatically-numbered (not mark)
'text (or mark (make-null-markup))
- 'footnote-text footnote
- 'symbol (or grob-name '()))))
- (cond (music
- (set! (ly:music-property music 'tweaks)
- (acons (if grob-name
- (cons grob-name 'footnote-music)
- 'footnote-music)
- mus
- (ly:music-property music 'tweaks)))
- music)
- (grob-name mus)
- (else
- (ly:input-warning location
- (_ "\\footnote requires music or grob-name"))
- (make-music 'Music)))))
+ 'footnote-text footnote)))
+ #{ \tweak footnote-music #mus #item #}))
grace =
#(def-grace-function startGraceMusic stopGraceMusic
harmonics played on a fretted instrument by touching the strings at @var{fret}.")
#{
\set harmonicDots = ##t
- \override TabNoteHead #'stencil = #(tab-note-head::print-custom-fret-label (number->string fret))
- \override NoteHead #'Y-extent = #(ly:make-unpure-pure-container ly:grob::stencil-height
+ \temporary \override TabNoteHead.stencil = #(tab-note-head::print-custom-fret-label (number->string fret))
+ \temporary \override NoteHead.Y-extent = #(ly:make-unpure-pure-container ly:grob::stencil-height
(lambda (grob start end)
(ly:grob::stencil-height grob)))
- \override NoteHead #'stencil = #(lambda (grob) (ly:grob-set-property! grob 'style 'harmonic-mixed)
+ \temporary \override NoteHead.stencil = #(lambda (grob) (ly:grob-set-property! grob 'style 'harmonic-mixed)
(ly:note-head::print grob))
- $(make-harmonic
+ #(make-harmonic
(calc-harmonic-pitch (fret->pitch (number->string fret)) music))
\unset harmonicDots
- \revert TabNoteHead #'stencil
- \revert NoteHead #'Y-extent
- \revert NoteHead #'stencil
+ \revert TabNoteHead.stencil
+ \revert NoteHead.Y-extent
+ \revert NoteHead.stencil
#})
harmonicByRatio = #(define-music-function (parser location ratio music) (number? ly:music?)
given through @var{ratio}.")
#{
\set harmonicDots = ##t
- \override TabNoteHead #'stencil = #(tab-note-head::print-custom-fret-label (ratio->fret ratio))
- \override NoteHead #'Y-extent = #(ly:make-unpure-pure-container ly:grob::stencil-height
+ \temporary \override TabNoteHead.stencil = #(tab-note-head::print-custom-fret-label (ratio->fret ratio))
+ \temporary \override NoteHead.Y-extent = #(ly:make-unpure-pure-container ly:grob::stencil-height
(lambda (grob start end)
(ly:grob::stencil-height grob)))
- \override NoteHead #'stencil = #(lambda (grob) (ly:grob-set-property! grob 'style 'harmonic-mixed)
+ \temporary \override NoteHead.stencil = #(lambda (grob) (ly:grob-set-property! grob 'style 'harmonic-mixed)
(ly:note-head::print grob))
- $(make-harmonic
+ #(make-harmonic
(calc-harmonic-pitch (ratio->pitch ratio) music))
\unset harmonicDots
- \revert TabNoteHead #'stencil
- \revert NoteHead #'Y-extent
- \revert NoteHead #'stencil
+ \revert TabNoteHead.stencil
+ \revert NoteHead.Y-extent
+ \revert NoteHead.stencil
#})
hide =
-#(define-music-function (parser location item) (string-or-music?)
+#(define-music-function (parser location item) (symbol-list-or-music?)
(_i "Set @var{item}'s @samp{transparent} property to @code{#t},
making it invisible while still retaining its dimensions.
-If @var{item} is a string, the result is an override for the grob name
+If @var{item} is a symbol list of form @code{GrobName} or
+@code{Context.GrobName}, the result is an override for the grob name
specified by it. If @var{item} is a music expression, the result is
the same music expression with an appropriate tweak applied to it.")
- (if (string? item)
- #{ \override $item #'transparent = ##t #}
- #{ \tweak #'transparent ##t $item #}))
+ (if (ly:music? item)
+ #{ \tweak transparent ##t #item #}
+ #{ \override #item . transparent = ##t #}))
inStaffSegno =
#(define-music-function (parser location) ()
keepWithTag =
-#(define-music-function (parser location tag music) (symbol? ly:music?)
- (_i "Include only elements of @var{music} that are tagged with @var{tag}.")
+#(define-music-function (parser location tag music)
+ (symbol-list-or-symbol? ly:music?)
+ (_i "Include only elements of @var{music} that are either untagged
+or tagged with one of the tags in @var{tag}. @var{tag} may be either
+a single symbol or a list of symbols.")
(music-filter
- (lambda (m)
- (let* ((tags (ly:music-property m 'tags))
- (res (memq tag tags)))
- (or
- (eq? tags '())
- res)))
+ (if (symbol? tag)
+ (lambda (m)
+ (let ((music-tags (ly:music-property m 'tags)))
+ (or (null? music-tags)
+ (memq tag music-tags))))
+ (lambda (m)
+ (let ((music-tags (ly:music-property m 'tags)))
+ (or (null? music-tags)
+ (any (lambda (t) (memq t music-tags)) tag)))))
music))
key =
'pitch pitch))
omit =
-#(define-music-function (parser location item) (string-or-music?)
+#(define-music-function (parser location item) (symbol-list-or-music?)
(_i "Set @var{item}'s @samp{stencil} property to @code{#f},
effectively omitting it without taking up space.
-If @var{item} is a string, the result is an override for the grob name
+If @var{item} is a symbol list of form @code{GrobName} or
+@code{Context.GrobName}, the result is an override for the grob name
specified by it. If @var{item} is a music expression, the result is
the same music expression with an appropriate tweak applied to it.")
- (if (string? item)
- #{ \override $item #'stencil = ##f #}
- #{ \tweak #'stencil ##f $item #}))
+ (if (ly:music? item)
+ #{ \tweak stencil ##f #item #}
+ #{ \override #item . stencil = ##f #}))
once =
#(define-music-function (parser location music) (ly:music?)
(override-time-signature-setting time-signature setting)))
overrideProperty =
-#(define-music-function (parser location name property value)
- (string? symbol? scheme?)
+#(define-music-function (parser location grob-property-path value)
+ (symbol-list? scheme?)
- (_i "Set @var{property} to @var{value} in all grobs named @var{name}.
-The @var{name} argument is a string of the form @code{\"Context.GrobName\"}
-or @code{\"GrobName\"}.")
+ (_i "Set the grob property specified by @var{grob-property-path} to
+@var{value}. @var{grob-property-path} is a symbol list of the form
+@code{Context.GrobName.property} or @code{GrobName.property}, possibly
+with subproperties given as well.")
+ (let ((p (check-grob-path grob-property-path parser location
+ #:default 'Bottom
+ #:min 3)))
+ (if p
+ (make-music 'ApplyOutputEvent
+ 'context-type (first p)
+ 'procedure
+ (lambda (grob orig-context context)
+ (if (equal?
+ (cdr (assoc 'name (ly:grob-property grob 'meta)))
+ (second p))
+ (ly:grob-set-nested-property!
+ grob (cddr p) value))))
+ (make-music 'Music))))
- (let ((name-components (string-split name #\.))
- (context-name 'Bottom)
- (grob-name #f))
- (if (> 2 (length name-components))
- (set! grob-name (string->symbol (car name-components)))
- (begin
- (set! grob-name (string->symbol (list-ref name-components 1)))
- (set! context-name (string->symbol (list-ref name-components 0)))))
- (make-music 'ApplyOutputEvent
- 'context-type context-name
- 'procedure
- (lambda (grob orig-context context)
- (if (equal?
- (cdr (assoc 'name (ly:grob-property grob 'meta)))
- grob-name)
- (set! (ly:grob-property grob property) value))))))
'element music))
removeWithTag =
-#(define-music-function (parser location tag music) (symbol? ly:music?)
- (_i "Remove elements of @var{music} that are tagged with @var{tag}.")
+#(define-music-function (parser location tag music)
+ (symbol-list-or-symbol? ly:music?)
+ (_i "Remove elements of @var{music} that are tagged with one of the
+tags in @var{tag}. @var{tag} may be either a single symbol or a list
+of symbols.")
(music-filter
- (lambda (m)
- (let* ((tags (ly:music-property m 'tags))
- (res (memq tag tags)))
- (not res)))
+ (if (symbol? tag)
+ (lambda (m)
+ (not (memq tag (ly:music-property m 'tags))))
+ (lambda (m)
+ (let ((music-tags (ly:music-property m 'tags)))
+ (or (null? music-tags)
+ (not (any (lambda (t) (memq t music-tags)) tag))))))
music))
resetRelativeOctave =
shape =
#(define-music-function (parser location offsets item)
- (list? string-or-music?)
+ (list? symbol-list-or-music?)
(_i "Offset control-points of @var{item} by @var{offsets}. The
argument is a list of number pairs or list of such lists. Each
element of a pair represents an offset to one of the coordinates of a
(if (>= total-found 2)
(helper siblings offsets)
(offset-control-points (car offsets)))))
- (if (ly:music? item)
- #{
- \tweak #'control-points #shape-curve $item
- #}
- #{
- \once \override $item #'control-points = #shape-curve
- #}))
+ #{ \tweak control-points #shape-curve #item #})
shiftDurations =
#(define-music-function (parser location dur dots arg)
#(define-music-function (parser location overrides music)
(ly:music? ly:music?)
(_i "Convert @var{overrides} to tweaks and apply them to @var{music}.
-This does not convert @code{\\revert}, @code{\\set} or @code{\\unset}
-and ignores nested overrides.")
+This does not convert @code{\\revert}, @code{\\set} or @code{\\unset}.")
(set! (ly:music-property music 'tweaks)
(fold-some-music
(lambda (m) (eq? (ly:music-property m 'name)
((ly:music-property m 'grob-property #f) => list)
(else
(ly:music-property m 'grob-property-path)))))
- (if (pair? (cdr p))
- tweaks ;ignore nested properties
- (acons (cons (ly:music-property m 'symbol) ;grob name
- (car p)) ;grob property
- (ly:music-property m 'grob-value)
- tweaks))))
+ (acons (cons (ly:music-property m 'symbol) ;grob name
+ (if (pair? (cdr p))
+ p ;grob property path
+ (car p))) ;grob property
+ (ly:music-property m 'grob-value)
+ tweaks)))
(ly:music-property music 'tweaks)
overrides))
music)
(_i "Set the system stretch, by reading the 'system-stretch property of
the `parameters' assoc list.")
#{
- \overrideProperty #"Score.NonMusicalPaperColumn"
- #'line-break-system-details
+ \overrideProperty Score.NonMusicalPaperColumn.line-break-system-details
#(list (cons 'alignment-extra-space (cdr (assoc 'system-stretch parameters)))
(cons 'system-Y-extent (cdr (assoc 'system-Y-extent parameters))))
#})
styledNoteHeads =
#(define-music-function (parser location style heads music)
- (symbol? list-or-symbol? ly:music?)
+ (symbol? symbol-list-or-symbol? ly:music?)
(_i "Set @var{heads} in @var{music} to @var{style}.")
(style-note-heads heads style music))
tag =
-#(define-music-function (parser location tag arg) (symbol? ly:music?)
-
- (_i "Add @var{tag} to the @code{tags} property of @var{arg}.")
+#(define-music-function (parser location tag music) (symbol-list-or-symbol? ly:music?)
+ (_i "Tag the following @var{music} with @var{tag} and return the
+result, by adding the single symbol or symbol list @var{tag} to the
+@code{tags} property of @var{music}.")
(set!
- (ly:music-property arg 'tags)
- (cons tag
- (ly:music-property arg 'tags)))
- arg)
+ (ly:music-property music 'tags)
+ ((if (symbol? tag) cons append)
+ tag
+ (ly:music-property music 'tags)))
+ music)
+
+temporary =
+#(define-music-function (parser location music)
+ (ly:music?)
+ (_i "Make any @code{\\override} in @var{music} replace an existing
+grob property value only temporarily, restoring the old value when a
+corresponding @code{\\revert} is executed. This is achieved by
+clearing the @samp{pop-first} property normally set on
+@code{\\override}s.
+
+An @code{\\override}/@/@code{\\revert} sequence created by using
+@code{\\temporary} and @code{\\undo} on the same music containing
+overrides will cancel out perfectly or cause a@tie{}warning.
+
+Non-property-related music is ignored, warnings are generated for any
+property-changing music that isn't an @code{\\override}.")
+ (define warned #f)
+ (for-some-music
+ (lambda (m)
+ (and (or (music-is-of-type? m 'layout-instruction-event)
+ (music-is-of-type? m 'context-specification)
+ (music-is-of-type? m 'apply-context)
+ (music-is-of-type? m 'time-signature-music))
+ (case (ly:music-property m 'name)
+ ((OverrideProperty)
+ (if (ly:music-property m 'pop-first #f)
+ (set! (ly:music-property m 'pop-first) '()))
+ (if (ly:music-property m 'once #f)
+ (set! (ly:music-property m 'once) '()))
+ #t)
+ ((ContextSpeccedMusic)
+ #f)
+ (else
+ (if (not warned)
+ (begin
+ (ly:input-warning location (_ "Cannot make ~a revertible")
+ (ly:music-property m 'name))
+ (set! warned #t)))
+ #t))))
+ music)
+ music)
time =
#(define-music-function (parser location beat-structure fraction)
'Staff))
tweak =
-#(define-music-function (parser location grob prop value music)
- ((string?) symbol? scheme? ly:music?)
- (_i "Add a tweak to the following @var{music}.
-Layout objects created by @var{music} get their property @var{prop}
-set to @var{value}. If @var{grob} is specified, like with
+#(define-music-function (parser location prop value item)
+ (symbol-list-or-symbol? scheme? symbol-list-or-music?)
+ (_i "Add a tweak to the following @var{item}, usually music.
+Layout objects created by @var{item} get their property @var{prop}
+set to @var{value}. If @var{prop} has the form @samp{Grob.property}, like with
@example
-\\tweak Accidental #'color #red cis'
+\\tweak Accidental.color #red cis'
@end example
an indirectly created grob (@samp{Accidental} is caused by
@samp{NoteHead}) can be tweaked; otherwise only directly created grobs
-are affected.")
- (if (not (object-property prop 'backend-type?))
- (begin
- (ly:input-warning location (_ "cannot find property type-check for ~a") prop)
- (ly:warning (_ "doing assignment anyway"))))
- (set!
- (ly:music-property music 'tweaks)
- (acons (if grob (cons (string->symbol grob) prop) prop)
- value
- (ly:music-property music 'tweaks)))
- music)
+are affected.
+
+As a special case, @var{item} may be a symbol list specifying a grob
+path, in which case @code{\\once\\override} is called on it instead of
+creating tweaked music. This is mainly useful when using
+@code{\\tweak} as as a component for building other functions.
+
+@var{prop} can contain additional elements in which case a nested
+property (inside of an alist) is tweaked.")
+ (if (ly:music? item)
+ (let ((p (check-grob-path prop parser location
+ #:start 1
+ #:default #t
+ #:min 2)))
+ (if p
+ (set! (ly:music-property item 'tweaks)
+ (acons (cond ((pair? (cddr p)) p)
+ ((symbol? (car p))
+ (cons (car p) (cadr p)))
+ (else (cadr p)))
+ value
+ (ly:music-property item 'tweaks))))
+ item)
+ ;; We could just throw this at \override and let it sort this
+ ;; out on its own, but this way we should get better error
+ ;; diagnostics.
+ (let ((a (check-grob-path item parser location
+ #:default 'Bottom #:min 2 #:max 2))
+ (b (check-grob-path prop parser location
+ #:start 2)))
+ (if (and a b)
+ #{ \once\override #(append a b) = #value #}
+ (make-music 'Music)))))
+
+undo =
+#(define-music-function (parser location music)
+ (ly:music?)
+ (_i "Convert @code{\\override} and @code{\\set} in @var{music} to
+@code{\\revert} and @code{\\unset}, respectively. Any reverts and
+unsets already in @var{music} cause a warning. Non-property-related music is ignored.")
+ (define warned #f)
+ (let loop
+ ((music music))
+ (let
+ ((lst
+ (fold-some-music
+ (lambda (m) (or (music-is-of-type? m 'layout-instruction-event)
+ (music-is-of-type? m 'context-specification)
+ (music-is-of-type? m 'apply-context)
+ (music-is-of-type? m 'time-signature-music)))
+ (lambda (m overrides)
+ (case (ly:music-property m 'name)
+ ((OverrideProperty)
+ (cons
+ (make-music 'RevertProperty
+ 'symbol (ly:music-property m 'symbol)
+ 'grob-property-path
+ (cond
+ ((ly:music-property m 'grob-property #f) => list)
+ (else
+ (ly:music-property m 'grob-property-path))))
+ overrides))
+ ((PropertySet)
+ (cons
+ (make-music 'PropertyUnset
+ 'symbol (ly:music-property m 'symbol))
+ overrides))
+ ((ContextSpeccedMusic)
+ (cons
+ (make-music 'ContextSpeccedMusic
+ 'element (loop (ly:music-property m 'element))
+ 'context-type (ly:music-property m 'context-type))
+ overrides))
+ (else
+ (if (not warned)
+ (begin
+ (ly:input-warning location (_ "Cannot revert ~a")
+ (ly:music-property m 'name))
+ (set! warned #t)))
+ overrides)))
+ '()
+ music)))
+ (cond
+ ((null? lst) (make-music 'Music))
+ ((null? (cdr lst)) (car lst))
+ (else (make-sequential-music lst))))))
unfoldRepeats =
#(define-music-function (parser location music) (ly:music?)