]> git.donarmstrong.com Git - lilypond.git/blobdiff - ly/music-functions-init.ly
convert-ly: Exit with error status when errors occur.
[lilypond.git] / ly / music-functions-init.ly
index 59a11264f7c741d84d3c854494adfd3f8cdfad2c..4fa31929d4ef9e2188ba5745612b092c870143e7 100644 (file)
@@ -18,7 +18,7 @@
 %%%% 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.15.18"
+\version "2.16.0"
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -36,7 +36,7 @@ acciaccatura =
    (_i "Create an acciaccatura from the following music expression"))
 
 %% keep these two together
-"instrument-definitions" = #'()
+instrument-definitions = #'()
 addInstrumentDefinition =
 #(define-void-function
    (parser location name lst) (string? list?)
@@ -85,6 +85,37 @@ markups), or inside a score.")
               'elements (list (make-music 'PageTurnEvent
                                           '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)
+          #}
+          (begin
+            (ly:input-warning location (_ "not a spanner name, `~a'") grob-name)
+            (make-music 'SequentialMusic 'void #t))))))
+
 appendToTag =
 #(define-music-function (parser location tag more music)
    (symbol? ly:music? ly:music?)
@@ -227,7 +258,7 @@ as @code{\\compoundMeter #'((3 2 8))} or shorter
                         (ly:moment-main-denominator mlen))))
   #{
     \once \override Staff.TimeSignature #'stencil = #(lambda (grob)
-               (grob-interpret-markup grob (format-compound-time args)))
+      (grob-interpret-markup grob (format-compound-time args)))
     \set Timing.timeSignatureFraction = $timesig
     \set Timing.baseMoment = $beat
     \set Timing.beatStructure = $beatGrouping
@@ -235,11 +266,22 @@ as @code{\\compoundMeter #'((3 2 8))} or shorter
     \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
+#})
 
 cueClef =
 #(define-music-function (parser location type) (string?)
   (_i "Set the current cue clef to @var{type}.")
   (make-cue-clef-set type))
+
 cueClefUnset =
 #(define-music-function (parser location) ()
   (_i "Unset the current cue clef.")
@@ -293,27 +335,22 @@ endSpanners =
 #(define-music-function (parser location music) (ly:music?)
    (_i "Terminate the next spanner prematurely after exactly one note
 without the need of a specific end spanner.")
-   (if (memq (ly:music-property music 'name) '(EventChord NoteEvent))
-       (let* ((start-span-evs (filter (lambda (ev)
-                                       (equal? (ly:music-property ev 'span-direction)
-                                               START))
-                                     (extract-typed-music music 'span-event)))
-             (stop-span-evs
-              (map (lambda (m)
-                     (let ((c (music-clone m)))
-                       (set! (ly:music-property c 'span-direction) STOP)
-                       c))
-                   start-span-evs))
-             (end-ev-chord (make-music 'EventChord
-                                       'elements stop-span-evs))
-             (total (make-music 'SequentialMusic
-                                'elements (list music
-                                                end-ev-chord))))
-        total)
-
-       (begin
-        (ly:input-message location (_ "argument endSpanners is not an EventChord: ~a") music)
-        music)))
+   (let* ((start-span-evs (filter (lambda (ev)
+                                   (equal? (ly:music-property ev 'span-direction)
+                                           START))
+                                 (extract-typed-music music 'span-event)))
+         (stop-span-evs
+          (map (lambda (m)
+                 (let ((c (music-clone m)))
+                   (set! (ly:music-property c 'span-direction) STOP)
+                   c))
+               start-span-evs))
+         (end-ev-chord (make-music 'EventChord
+                                   'elements stop-span-evs))
+         (total (make-music 'SequentialMusic
+                            'elements (list music
+                                            end-ev-chord))))
+     total))
 
 eventChords =
 #(define-music-function (parser location music) (ly:music?)
@@ -342,23 +379,49 @@ 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 '()))))
+     (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)))))
 
 grace =
 #(def-grace-function startGraceMusic stopGraceMusic
@@ -412,6 +475,31 @@ given through @var{ratio}.")
     \revert NoteHead #'stencil
   #})
 
+hide =
+#(define-music-function (parser location item) (string-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
+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 #}))
+
+inStaffSegno =
+#(define-music-function (parser location) ()
+   (_i "Put the segno variant 'varsegno' at this position into the staff,
+compatible with the repeat command.")
+   (make-music 'ApplyContext
+               'procedure
+               (lambda (ctx)
+                 (let ((score-ctx (ly:context-find ctx 'Score)))
+                   (if (ly:context? score-ctx)
+                     (let ((old-rc (ly:context-property score-ctx 'repeatCommands '())))
+                       (if (eq? (memq 'segno-display old-rc) #f)
+                         (ly:context-set-property! score-ctx 'repeatCommands (cons 'segno-display old-rc)))))))))
+
 instrumentSwitch =
 #(define-music-function
    (parser location name) (string?)
@@ -588,6 +676,18 @@ octaveCheck =
    (make-music 'RelativeOctaveCheck
                'pitch pitch))
 
+omit =
+#(define-music-function (parser location item) (string-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
+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 #}))
+
 once =
 #(define-music-function (parser location music) (ly:music?)
    (_i "Set @code{once} to @code{#t} on all layout instruction events in @var{music}.")
@@ -991,11 +1091,17 @@ a context modification duplicating their effect.")
               (cons* 'push
                      (ly:music-property m 'symbol)
                      (ly:music-property m 'grob-value)
-                     (ly:music-property m 'grob-property-path)))
+                      (cond
+                       ((ly:music-property m 'grob-property #f) => list)
+                       (else
+                        (ly:music-property m 'grob-property-path)))))
              ((RevertProperty)
               (cons* 'pop
                      (ly:music-property m 'symbol)
-                     (ly:music-property m 'grob-property-path)))))
+                      (cond
+                       ((ly:music-property m 'grob-property #f) => list)
+                       (else
+                        (ly:music-property m 'grob-property-path)))))))
           (case (ly:music-property m 'name)
             ((ApplyContext)
              (ly:add-context-mod mods
@@ -1012,6 +1118,55 @@ a context modification duplicating their effect.")
      (musicop music)
      mods))
 
+shape =
+#(define-music-function (parser location offsets item)
+   (list? string-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
+control-point.  If @var{item} is a string, the result is
+@code{\\once\\override} for the specified grob type.  If @var{item} is
+a music expression, the result is the same music expression with an
+appropriate tweak applied.")
+   (define (shape-curve grob)
+     (let* ((orig (ly:grob-original grob))
+            (siblings (if (ly:spanner? grob)
+                          (ly:spanner-broken-into orig) '()))
+            (total-found (length siblings))
+            (function (assoc-get 'control-points
+                                 (reverse (ly:grob-basic-properties grob))))
+            (coords (function grob)))
+
+       (define (offset-control-points offsets)
+         (if (null? offsets)
+             coords
+             (map
+               (lambda (x y) (coord-translate x y))
+               coords offsets)))
+
+       (define (helper sibs offs)
+         (if (pair? offs)
+             (if (eq? (car sibs) grob)
+                 (offset-control-points (car offs))
+                 (helper (cdr sibs) (cdr offs)))
+             coords))
+
+       ;; we work with lists of lists
+       (if (or (null? offsets)
+               (not (list? (car offsets))))
+           (set! offsets (list offsets)))
+
+       (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
+       #}))
+
 shiftDurations =
 #(define-music-function (parser location dur dots arg)
    (integer? integer? ly:music?)
@@ -1022,6 +1177,31 @@ shiftDurations =
     (lambda (x)
       (shift-one-duration-log x dur dots)) arg))
 
+single =
+#(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.")
+   (set! (ly:music-property music 'tweaks)
+         (fold-some-music
+          (lambda (m) (eq? (ly:music-property m 'name)
+                           'OverrideProperty))
+          (lambda (m tweaks)
+            (let ((p (cond
+                      ((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))))
+          (ly:music-property music 'tweaks)
+          overrides))
+   music)
+
 skip =
 #(define-music-function (parser location dur) (ly:duration?)
   (_i "Skip forward by @var{dur}.")
@@ -1119,21 +1299,71 @@ 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)
 
+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} are ignored and not converted.")
+   (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)))
+            (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 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?)