]> git.donarmstrong.com Git - lilypond.git/blobdiff - scm/music-functions.scm
Make chord repeats q ignore <>
[lilypond.git] / scm / music-functions.scm
index 8e9a7658de0c0ff4007f1cd16a692842bae6b473..559eae3c3ff300e04e2a0eed635ea678e32d37ff 100644 (file)
@@ -62,8 +62,9 @@ First it recurses over the children, then the function is applied to
 @var{music}."
   (let ((es (ly:music-property music 'elements))
        (e (ly:music-property music 'element)))
-    (set! (ly:music-property music 'elements)
-         (map (lambda (y) (music-map function y)) es))
+    (if (pair? es)
+       (set! (ly:music-property music 'elements)
+             (map (lambda (y) (music-map function y)) es)))
     (if (ly:music? e)
        (set! (ly:music-property music 'element)
              (music-map function  e)))
@@ -311,8 +312,7 @@ through MUSIC."
 calculate the number of slashes based on the durations.  Returns @code{0}
 if durations in @var{music} vary, allowing slash beats and double-percent
 beats to be distinguished."
-  (let* ((durs (map (lambda (elt)
-                     (duration-of-note elt))
+  (let* ((durs (map duration-of-note
                    (extract-named-music music '(EventChord NoteEvent
                                                 RestEvent SkipEvent))))
         (first-dur (car durs)))
@@ -424,6 +424,33 @@ in @var{grob}."
     TrillSpanner))
 
 (define-safe-public (make-voice-props-set n)
+  (make-sequential-music
+   (append
+    (map (lambda (x) (make-grob-property-set x 'direction
+                                                 (if (odd? n) -1 1)))
+        direction-polyphonic-grobs)
+    (list
+     (make-property-set 'graceSettings
+                       ;; TODO: take this from voicedGraceSettings or similar.
+                       '((Voice Stem font-size -3)
+                         (Voice Flag font-size -3)
+                         (Voice NoteHead font-size -3)
+                         (Voice TabNoteHead font-size -4)
+                         (Voice Dots font-size -3)
+                         (Voice Stem length-fraction 0.8)
+                         (Voice Stem no-stem-extend #t)
+                         (Voice Beam beam-thickness 0.384)
+                         (Voice Beam length-fraction 0.8)
+                         (Voice Accidental font-size -4)
+                         (Voice AccidentalCautionary font-size -4)
+                         (Voice Script font-size -3)
+                         (Voice Fingering font-size -8)
+                         (Voice StringNumber font-size -8)))
+
+     (make-grob-property-set 'NoteColumn 'horizontal-shift (quotient n 2))
+     (make-grob-property-set 'MultiMeasureRest 'staff-position (if (odd? n) -4 4))))))
+
+(define-safe-public (make-voice-props-override n)
   (make-sequential-music
    (append
     (map (lambda (x) (make-grob-property-override x 'direction
@@ -626,7 +653,11 @@ respective predecessor chord."
        (let ((chord-repeat (ly:music-property music 'duration)))
          (cond
           ((not (ly:duration? chord-repeat))
-           music)
+           (if (any (lambda (m) (ly:duration?
+                                 (ly:music-property m 'duration)))
+                    (ly:music-property music 'elements))
+               music
+               last-chord))
           (last-chord
            (set! (ly:music-property music 'duration) '())
            (copy-repeat-chord last-chord music chord-repeat event-types)
@@ -954,7 +985,7 @@ set to the @code{location} parameter."
                      (if (null? clef)
                          (make-music 'Music)
                          (make-cue-clef-set clef))
-                     (context-spec-music (make-voice-props-set cue-voice) 'CueVoice "cue")
+                     (context-spec-music (make-voice-props-override cue-voice) 'CueVoice "cue")
                      quote-music
                      (context-spec-music (make-voice-props-revert) 'CueVoice "cue")
                      (if (null? clef)
@@ -963,7 +994,7 @@ set to the @code{location} parameter."
              (set! main-music
                    (make-sequential-music
                     (list
-                     (make-voice-props-set main-voice)
+                     (make-voice-props-override main-voice)
                      main-music
                      (make-voice-props-revert))))
              (set! (ly:music-property quote-music 'element) main-music)))
@@ -1594,35 +1625,110 @@ Entries that conform with the current key signature are not invalidated."
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(define-public (map-some-music map? music)
+  "Walk through @var{music}, transform all elements calling @var{map?}
+and only recurse if this returns @code{#f}."
+  (let loop ((music music))
+    (or (map? music)
+       (let ((elt (ly:music-property music 'element))
+             (elts (ly:music-property music 'elements))
+             (arts (ly:music-property music 'articulations)))
+         (if (ly:music? elt)
+             (set! (ly:music-property music 'element)
+                   (loop elt)))
+         (if (pair? elts)
+             (set! (ly:music-property music 'elements)
+                   (map loop elts)))
+         (if (pair? arts)
+             (set! (ly:music-property music 'articulations)
+                   (map loop arts)))
+         music))))
+
+(define-public (for-some-music stop? music)
+  "Walk through @var{music}, process all elements calling @var{stop?}
+and only recurse if this returns @code{#f}."
+  (let loop ((music music))
+    (if (not (stop? music))
+       (let ((elt (ly:music-property music 'element)))
+         (if (ly:music? elt)
+             (loop elt))
+         (for-each loop (ly:music-property music 'elements))
+         (for-each loop (ly:music-property music 'articulations))))))
+
+(define-public (fold-some-music pred? proc init music)
+  "This works recursively on music like @code{fold} does on a list,
+calling @samp{(@var{pred?} music)} on every music element.  If
+@code{#f} is returned for an element, it is processed recursively
+with the same initial value of @samp{previous}, otherwise
+@samp{(@var{proc} music previous)} replaces @samp{previous}
+and no recursion happens.
+The top @var{music} is processed using @var{init} for @samp{previous}."
+  (let loop ((music music) (previous init))
+    (if (pred? music)
+       (proc music previous)
+       (fold loop
+             (fold loop
+                   (let ((elt (ly:music-property music 'element)))
+                     (if (null? elt)
+                         previous
+                         (loop elt previous)))
+                   (ly:music-property music 'elements))
+             (ly:music-property music 'articulations)))))
+
+(define-public (extract-music music pred?)
+  "Return a flat list of all music matching @var{pred?} inside of
+@var{music}, not recursing into matches themselves."
+  (reverse! (fold-some-music pred? cons '() music)))
+
 (define-public (extract-named-music music music-name)
-  "Return a flat list of all music named @var{music-name} from @var{music}."
-  (if (not (list? music-name))
-      (set! music-name (list music-name)))
-  (if (ly:music? music)
-      (if (memq (ly:music-property music 'name) music-name)
-         (list music)
-         (let ((arts (ly:music-property music 'articulations)))
-           (append-map!
-            (lambda (x) (extract-named-music x music-name))
-            (if (pair? arts)
-                arts
-                (cons (ly:music-property music 'element)
-                      (ly:music-property music 'elements))))))
-      '()))
+  "Return a flat list of all music named @var{music-name} (either a
+single event symbol or a list of alternatives) inside of @var{music},
+not recursing into matches themselves."
+  (extract-music
+   music
+   (if (cheap-list? music-name)
+       (lambda (m) (memq (ly:music-property m 'name) music-name))
+       (lambda (m) (eq? (ly:music-property m 'name) music-name)))))
 
 (define-public (extract-typed-music music type)
-  "Return a flat list of all music with @var{type} from @var{music}."
-  (if (ly:music? music)
-      (if (music-is-of-type? music type)
-         (list music)
-         (let ((arts (ly:music-property music 'articulations)))
-           (append-map!
-            (lambda (x) (extract-typed-music x type))
-            (if (pair? arts)
-                arts
-                (cons (ly:music-property music 'element)
-                      (ly:music-property music 'elements))))))
-      '()))
+  "Return a flat list of all music with @var{type} (either a single
+type symbol or a list of alternatives) inside of @var{music}, not
+recursing into matches themselves."
+  (extract-music
+   music
+   (if (cheap-list? type)
+       (lambda (m)
+        (any (lambda (t) (music-is-of-type? m t)) type))
+       (lambda (m) (music-is-of-type? m type)))))
+
+(define*-public (event-chord-wrap! music #:optional parser)
+  "Wrap isolated rhythmic events and non-postevent events in
+@var{music} inside of an @code{EventChord}.  If the optional
+@var{parser} argument is given, chord repeats @samp{q} are expanded
+using the default settings.  Otherwise, you need to cater for them
+yourself."
+  (map-some-music
+   (lambda (m)
+     (cond ((music-is-of-type? m 'event-chord)
+           (if (pair? (ly:music-property m 'articulations))
+               (begin
+                 (set! (ly:music-property m 'elements)
+                       (append (ly:music-property m 'elements)
+                               (ly:music-property m 'articulations)))
+                 (set! (ly:music-property m 'articulations) '())))
+           m)
+          ((music-is-of-type? m 'rhythmic-event)
+           (let ((arts (ly:music-property m 'articulations)))
+             (if (pair? arts)
+                 (set! (ly:music-property m 'articulations) '()))
+             (make-event-chord (cons m arts))))
+          (else #f)))
+   (if parser
+       (expand-repeat-chords!
+       (cons 'rhythmic-event
+             (ly:parser-lookup parser '$chord-repeat-events))
+       music)
+       music)))
 
 (define-public (event-chord-notes event-chord)
   "Return a list of all notes from @var{event-chord}."