]> git.donarmstrong.com Git - lilypond.git/blobdiff - ly/music-functions-init.ly
Make \footnote work via \tweak
[lilypond.git] / ly / music-functions-init.ly
index a22292657fcb968b480df290ee347acea9253d18..21f6c51fd7a511bf0db3529dbea5ed19edd4d840 100644 (file)
@@ -178,7 +178,7 @@ barNumberCheck =
                                         cbn n))))))
 
 bendAfter =
-#(define-music-function (parser location delta) (real?)
+#(define-event-function (parser location delta) (real?)
    (_i "Create a fall or doit of pitch interval @var{delta}.")
    (make-music 'BendAfterEvent
               'delta-step delta))
@@ -186,13 +186,13 @@ bendAfter =
 bookOutputName =
 #(define-void-function (parser location newfilename) (string?)
    (_i "Direct output for the current book block to @var{newfilename}.")
-   (set! book-filename newfilename))
+   (set! (paper-variable parser #f 'output-filename) newfilename))
 
 bookOutputSuffix =
 #(define-void-function (parser location newsuffix) (string?)
    (_i "Set the output filename suffix for the current book block to
 @var{newsuffix}.")
-   (set! book-output-suffix newsuffix))
+   (set! (paper-variable parser #f 'output-suffix) newsuffix))
 
 %% \breathe is defined as a music function rather than an event identifier to
 %% ensure it gets useful input location information: as an event identifier,
@@ -315,7 +315,12 @@ without the need of a specific end spanner.")
         (ly:input-message location (_ "argument endSpanners is not an EventChord: ~a") music)
         music)))
 
-
+eventChords =
+#(define-music-function (parser location music) (ly:music?)
+   (_i "Compatibility function wrapping @code{EventChord} around
+isolated rhythmic events occuring since version 2.15.28, after
+expanding repeat chords @samp{q}.")
+   (event-chord-wrap! music parser))
 
 featherDurations=
 #(define-music-function (parser location factor argument) (ly:moment? ly:music?)
@@ -337,23 +342,46 @@ featherDurations=
      argument))
 
 footnote =
-#(define-music-function (parser location text offset grob-name footnote)
-   ((markup?) number-pair? (symbol? '()) markup?)
-   (_i "Attach @var{text} at @var{offset} with @var{text} referring to
-@var{footnote}.  If @var{text} is given as @code{\\default}, use
-autonumbering instead.  Note that, for this to take effect,
-auto-numbering must be turned on in the paper block.  Otherwise, no
-number will appear.  Footnotes are applied like articulations.  If a
-symbol @var{grob-name} is specified, all grobs of that kind at the
-current time step are affected.")
-   (make-music
-    'FootnoteEvent
-    'X-offset (car offset)
-    'Y-offset (cdr offset)
-    'automatically-numbered (not text)
-    'text (or text (make-null-markup))
-    'footnote-text footnote
-    'symbol grob-name))
+#(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
+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}.
+
+Like with @code{\\tweak}, if you use a footnote on a following
+post-event, the @code{\\footnote} command itself needs to be attached
+to the preceding note or rest as a post-event with @code{-}.")
+   (let ((mus (make-music
+              'FootnoteEvent
+              'X-offset (car offset)
+              'Y-offset (cdr offset)
+              'automatically-numbered (not mark)
+              'text (or mark (make-null-markup))
+              'footnote-text footnote
+              'symbol (or grob-name '()))))
+     (if music
+        (begin
+          (set! (ly:music-property music 'tweaks)
+                (acons (if grob-name
+                           (cons grob-name 'footnote-music)
+                           'footnote-music)
+                       mus
+                       (ly:music-property music 'tweaks)))
+          music)
+        mus)))
 
 grace =
 #(def-grace-function startGraceMusic stopGraceMusic
@@ -369,37 +397,43 @@ in the format of @code{all-grob-descriptions}.")
         descriptions)))
 
 harmonicByFret = #(define-music-function (parser location fret music) (number? ly:music?)
-  (_i "Convert @var{music} into harmonics; the resulting notes resemble
-harmonics played on a fretted instrument by touching the strings above @var{fret}.")
-  (let* ((fret (number->string fret))
-         (pitch (fret->pitch fret)))
-        (make-sequential-music
-         (list
-          #{
-            \override TabNoteHead #'stencil = #(tab-note-head::print-custom-fret-label fret)
-          #}
-          (make-harmonic
-            (calc-harmonic-pitch pitch music))
-          #{
-            \revert TabNoteHead #'stencil
-          #}))))
+  (_i "Convert @var{music} into mixed harmonics; the resulting notes resemble
+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
+                                       (lambda (grob start end)
+                                               (ly:grob::stencil-height grob)))
+    \override NoteHead #'stencil = #(lambda (grob) (ly:grob-set-property! grob 'style 'harmonic-mixed)
+                                            (ly:note-head::print grob))
+    $(make-harmonic
+       (calc-harmonic-pitch (fret->pitch (number->string fret)) music))
+    \unset harmonicDots
+    \revert TabNoteHead #'stencil
+    \revert NoteHead #'Y-extent
+    \revert NoteHead #'stencil
+  #})
 
 harmonicByRatio = #(define-music-function (parser location ratio music) (number? ly:music?)
-    (_i "Convert @var{music} into harmonics; the resulting notes resemble
-harmonics played on a fretted instrument by touching the strings above the point
+    (_i "Convert @var{music} into mixed harmonics; the resulting notes resemble
+harmonics played on a fretted instrument by touching the strings at the point
 given through @var{ratio}.")
-  (let ((pitch (ratio->pitch ratio))
-        (fret (ratio->fret ratio)))
-       (make-sequential-music
-        (list
-         #{
-           \override TabNoteHead #'stencil = #(tab-note-head::print-custom-fret-label fret)
-         #}
-         (make-harmonic
-           (calc-harmonic-pitch pitch music))
-         #{
-            \revert TabNoteHead #'stencil
-         #}))))
+  #{
+    \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
+                                       (lambda (grob start end)
+                                               (ly:grob::stencil-height grob)))
+    \override NoteHead #'stencil = #(lambda (grob) (ly:grob-set-property! grob 'style 'harmonic-mixed)
+                                            (ly:note-head::print grob))
+    $(make-harmonic
+      (calc-harmonic-pitch (ratio->pitch ratio) music))
+    \unset harmonicDots
+    \revert TabNoteHead #'stencil
+    \revert NoteHead #'Y-extent
+    \revert NoteHead #'stencil
+  #})
 
 instrumentSwitch =
 #(define-music-function
@@ -692,7 +726,9 @@ Example:
 ")
    (let* ((voices (apply circular-list (make-list (length voice-ids) (list))))
          (current-voices voices)
-         (current-sequence (list)))
+         (current-sequence (list))
+         (original music)
+         (wrapper #f))
      ;;
      ;; utilities
      (define (push-music m)
@@ -718,6 +754,16 @@ Example:
                       (let ((origins (remove not (map music-origin
                                                       (ly:music-property music 'elements)))))
                         (and (not (null? origins)) (car origins)))))))
+     (while (music-is-of-type? music 'music-wrapper-music)
+           (set! wrapper music)
+           (set! music (ly:music-property wrapper 'element)))
+     (if wrapper
+        (set! (ly:music-property wrapper 'element)
+                                 (make-music 'SequentialMusic
+                                             'origin location))
+        (set! original
+              (make-music 'SequentialMusic
+                          'origin location)))
      ;;
      ;; first, split the music and fill in voices
      ;; We flatten direct layers of SequentialMusic since they are
@@ -758,9 +804,12 @@ Example:
      ;; bind voice identifiers to the voices
      (for-each (lambda (voice-id voice)
            (ly:parser-define! parser voice-id
-                              (make-music 'SequentialMusic
-                                          'origin location
-                                          'elements voice)))
+                              (let ((v (ly:music-deep-copy original)))
+                                (set! (ly:music-property
+                                       (car (extract-named-music
+                                             v 'SequentialMusic))
+                                       'elements) voice)
+                                v)))
          voice-ids voices)))
 
 parenthesize =
@@ -926,7 +975,7 @@ for time signatures of @var{time-signature}.")
    (revert-time-signature-setting time-signature))
 
 rightHandFinger =
-#(define-music-function (parser location finger) (number-or-string?)
+#(define-event-function (parser location finger) (number-or-string?)
    (_i "Apply @var{finger} as a fingering indication.")
 
    (make-music
@@ -962,21 +1011,27 @@ a context modification duplicating their effect.")
               (list 'unset
                     (ly:music-property m 'symbol)))
              ((OverrideProperty)
-              (list 'push
-                    (ly:music-property m 'symbol)
-                    (ly:music-property m 'grob-property-path)
-                    (ly:music-property m 'grob-value)))
+              (cons* 'push
+                     (ly:music-property m 'symbol)
+                     (ly:music-property m 'grob-value)
+                     (ly:music-property m 'grob-property-path)))
              ((RevertProperty)
-              (list 'pop
-                    (ly:music-property m 'symbol)
-                    (ly:music-property m 'grob-property-path)))))
+              (cons* 'pop
+                     (ly:music-property m 'symbol)
+                     (ly:music-property m 'grob-property-path)))))
           (case (ly:music-property m 'name)
-            ((SequentialMusic SimultaneousMusic)
-             (for-each musicop (ly:music-property m 'elements)))
+            ((ApplyContext)
+             (ly:add-context-mod mods
+                                 (list 'apply
+                                       (ly:music-property m 'procedure))))
             ((ContextSpeccedMusic)
              (if (or (not ctx)
                      (eq? ctx (ly:music-property m 'context-type)))
-                 (musicop (ly:music-property m 'element)))))))
+                 (musicop (ly:music-property m 'element))))
+            (else
+             (let ((callback (ly:music-property m 'elements-callback)))
+               (if (procedure? callback)
+                   (for-each musicop (callback m))))))))
      (musicop music)
      mods))
 
@@ -1087,21 +1142,27 @@ transposition =
     'Staff))
 
 tweak =
-#(define-music-function (parser location sym val arg)
-   (symbol? scheme? ly:music?)
-   (_i "Add @code{sym . val} to the @code{tweaks} property of @var{arg}.")
-
-   (if (equal? (object-property sym 'backend-type?) #f)
+#(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
+@example
+\\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") sym)
+        (ly:input-warning location (_ "cannot find property type-check for ~a") prop)
         (ly:warning (_ "doing assignment anyway"))))
    (set!
-    (ly:music-property arg 'tweaks)
-    (acons sym val
-          (ly:music-property arg 'tweaks)))
-   arg)
-
-
+    (ly:music-property music 'tweaks)
+    (acons (if grob (cons (string->symbol grob) prop) prop)
+          value
+          (ly:music-property music 'tweaks)))
+   music)
 
 unfoldRepeats =
 #(define-music-function (parser location music) (ly:music?)