]> git.donarmstrong.com Git - lilypond.git/blobdiff - scm/music-functions.scm
Reinstate James and Keith (deleted in error)
[lilypond.git] / scm / music-functions.scm
index f425eb17385f63edcc5bca8b2677b488155a6dd9..1f8b593318f1bb409d468c906d2fdfd938d8c53e 100644 (file)
@@ -1,11 +1,22 @@
-;;;; music-functions.scm --
+;;;; This file is part of LilyPond, the GNU music typesetter.
 ;;;;
 ;;;;
-;;;;  source file of the GNU LilyPond music typesetter
-;;;; 
-;;;; (c) 1998--2008 Jan Nieuwenhuizen <janneke@gnu.org>
+;;;; Copyright (C) 1998--2010 Jan Nieuwenhuizen <janneke@gnu.org>
 ;;;;                 Han-Wen Nienhuys <hanwen@xs4all.nl>
 ;;;;                 Han-Wen Nienhuys <hanwen@xs4all.nl>
+;;;;
+;;;; LilyPond is free software: you can redistribute it and/or modify
+;;;; it under the terms of the GNU General Public License as published by
+;;;; the Free Software Foundation, either version 3 of the License, or
+;;;; (at your option) any later version.
+;;;;
+;;;; LilyPond is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 
 
-;; (use-modules (ice-9 optargs)) 
+;; (use-modules (ice-9 optargs))
 
 ;;; ly:music-property with setter
 ;;; (ly:music-property my-music 'elements)
 
 ;;; ly:music-property with setter
 ;;; (ly:music-property my-music 'elements)
   (make-procedure-with-setter ly:grob-property
                              ly:grob-set-property!))
 
   (make-procedure-with-setter ly:grob-property
                              ly:grob-set-property!))
 
+(define-public ly:grob-object
+  (make-procedure-with-setter ly:grob-object
+                             ly:grob-set-object!))
+
+(define-public ly:grob-parent
+  (make-procedure-with-setter ly:grob-parent
+                             ly:grob-set-parent!))
+
 (define-public ly:prob-property
   (make-procedure-with-setter ly:prob-property
                              ly:prob-set-property!))
 
 (define-public ly:prob-property
   (make-procedure-with-setter ly:prob-property
                              ly:prob-set-property!))
 
+(define-public ly:context-property
+  (make-procedure-with-setter ly:context-property
+                             ly:context-set-property!))
+
 (define-public (music-map function music)
   "Apply @var{function} to @var{music} and all of the music it contains.
 
 (define-public (music-map function music)
   "Apply @var{function} to @var{music} and all of the music it contains.
 
@@ -36,7 +59,7 @@ First it recurses over the children, then the function is applied to MUSIC.
 "
   (let ((es (ly:music-property music 'elements))
        (e (ly:music-property music 'element)))
 "
   (let ((es (ly:music-property music 'elements))
        (e (ly:music-property music 'element)))
-    (set! (ly:music-property music 'elements) 
+    (set! (ly:music-property music 'elements)
          (map (lambda (y) (music-map function y)) es))
     (if (ly:music? e)
        (set! (ly:music-property music 'element)
          (map (lambda (y) (music-map function y)) es))
     (if (ly:music? e)
        (set! (ly:music-property music 'element)
@@ -45,7 +68,7 @@ First it recurses over the children, then the function is applied to MUSIC.
 
 (define-public (music-filter pred? music)
   "Filter out music expressions that do not satisfy PRED."
 
 (define-public (music-filter pred? music)
   "Filter out music expressions that do not satisfy PRED."
-  
+
   (define (inner-music-filter pred? music)
     "Recursive function."
     (let* ((es (ly:music-property music 'elements))
   (define (inner-music-filter pred? music)
     "Recursive function."
     (let* ((es (ly:music-property music 'elements))
@@ -76,7 +99,7 @@ First it recurses over the children, then the function is applied to MUSIC.
   "Display music, not done with music-map for clarity of presentation."
 
   (display music)
   "Display music, not done with music-map for clarity of presentation."
 
   (display music)
-  (display ": { ")  
+  (display ": { ")
   (let ((es (ly:music-property music 'elements))
        (e (ly:music-property music 'element)))
     (display (ly:music-mutable-properties music))
   (let ((es (ly:music-property music 'elements))
        (e (ly:music-property music 'element)))
     (display (ly:music-mutable-properties music))
@@ -96,7 +119,7 @@ First it recurses over the children, then the function is applied to MUSIC.
 ;;;
 (define (markup-expression->make-markup markup-expression)
   "Transform `markup-expression' into an equivalent, hopefuly readable, scheme expression.
 ;;;
 (define (markup-expression->make-markup markup-expression)
   "Transform `markup-expression' into an equivalent, hopefuly readable, scheme expression.
-For instance, 
+For instance,
   \\markup \\bold \\italic hello
 ==>
   (markup #:line (#:bold (#:italic (#:simple \"hello\"))))"
   \\markup \\bold \\italic hello
 ==>
   (markup #:line (#:bold (#:italic (#:simple \"hello\"))))"
@@ -111,7 +134,7 @@ For instance,
          ((and (not (string? arg)) (markup? arg)) ;; a markup
           (inner-markup->make-markup arg))
          (else                                  ;; scheme arg
          ((and (not (string? arg)) (markup? arg)) ;; a markup
           (inner-markup->make-markup arg))
          (else                                  ;; scheme arg
-          arg)))
+          (music->make-music arg))))
   (define (inner-markup->make-markup mrkup)
     (if (string? mrkup)
        `(#:simple ,mrkup)
   (define (inner-markup->make-markup mrkup)
     (if (string? mrkup)
        `(#:simple ,mrkup)
@@ -131,7 +154,7 @@ that is, for a music expression, a (make-music ...) form."
         (markup-expression->make-markup obj))
        (;; music expression
         (ly:music? obj)
         (markup-expression->make-markup obj))
        (;; music expression
         (ly:music? obj)
-        `(make-music 
+        `(make-music
           ',(ly:music-property obj 'name)
           ,@(apply append (map (lambda (prop)
                                   `(',(car prop)
           ',(ly:music-property obj 'name)
           ,@(apply append (map (lambda (prop)
                                   `(',(car prop)
@@ -170,7 +193,7 @@ that is, for a music expression, a (make-music ...) form."
         `(list ,@(map music->make-music obj)))
        (;; a pair
         (pair? obj)
         `(list ,@(map music->make-music obj)))
        (;; a pair
         (pair? obj)
-        `(cons ,(music->make-music (car obj)) 
+        `(cons ,(music->make-music (car obj))
                ,(music->make-music (cdr obj))))
        (else
         obj)))
                ,(music->make-music (cdr obj))))
        (else
         obj)))
@@ -204,8 +227,8 @@ Returns `obj'.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (define-public (shift-one-duration-log music shift dot)
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (define-public (shift-one-duration-log music shift dot)
-  "  add SHIFT to duration-log of 'duration in music and optionally 
-  a dot to any note encountered. This scales the music up by a factor 
+  "  add SHIFT to duration-log of 'duration in music and optionally
+  a dot to any note encountered. This scales the music up by a factor
   2^shift * (2 - (1/2)^dot)"
   (let ((d (ly:music-property music 'duration)))
     (if (ly:duration? d)
   2^shift * (2 - (1/2)^dot)"
   (let ((d (ly:music-property music 'duration)))
     (if (ly:duration? d)
@@ -223,6 +246,20 @@ Returns `obj'.
 
 (define-public (make-repeat name times main alts)
   "create a repeat music expression, with all properties initialized properly"
 
 (define-public (make-repeat name times main alts)
   "create a repeat music expression, with all properties initialized properly"
+  (define (first-note-duration music)
+    "Finds the duration of the first NoteEvent by searching depth-first
+through MUSIC."
+    (if (memq 'note-event (ly:music-property music 'types))
+       (ly:music-property music 'duration)
+       (let loop ((elts (if (ly:music? (ly:music-property music 'element))
+                            (list (ly:music-property music 'element))
+                            (ly:music-property music 'elements))))
+         (and (pair? elts)
+              (let ((dur (first-note-duration (car elts))))
+                (if (ly:duration? dur)
+                    dur
+                    (loop (cdr elts))))))))
+
   (let ((talts (if (< times (length alts))
                   (begin
                     (ly:warning (_ "More alternatives than repeats.  Junking excess alternatives"))
   (let ((talts (if (< times (length alts))
                   (begin
                     (ly:warning (_ "More alternatives than repeats.  Junking excess alternatives"))
@@ -232,26 +269,33 @@ Returns `obj'.
     (set! (ly:music-property r 'element) main)
     (set! (ly:music-property r 'repeat-count) (max times 1))
     (set! (ly:music-property r 'elements) talts)
     (set! (ly:music-property r 'element) main)
     (set! (ly:music-property r 'repeat-count) (max times 1))
     (set! (ly:music-property r 'elements) talts)
-    (if (equal? name "tremolo")
-       (let* ((dots (1- (logcount times)))
-              (mult (/ (* times (ash 1 dots)) (1- (ash 2 dots))))
-              (shift (- (ly:intlog2 (floor mult)))))
+    (if (and (equal? name "tremolo")
+            (or (pair? (ly:music-property main 'elements))
+                (ly:music? (ly:music-property main 'element))))
+       ;; This works for single-note and multi-note tremolos!
+       (let* ((children (if (music-is-of-type? main 'sequential-music)
+                            ;; \repeat tremolo n { ... }
+                            (length (ly:music-property main 'elements))
+                            ;; \repeat tremolo n c4
+                            1))
+              ;; # of dots is equal to the 1 in bitwise representation (minus 1)!
+              (dots (1- (logcount (* times children))))
+              ;; The remaining missing multiplicator to scale the notes by
+              ;; times * children
+              (mult (/ (* times children (ash 1 dots)) (1- (ash 2 dots))))
+              (shift (- (ly:intlog2 (floor mult))))
+              (note-duration (first-note-duration r))
+              (duration-log (if (ly:duration? note-duration)
+                                (ly:duration-log note-duration)
+                                1))
+              (tremolo-type (ash 1 duration-log)))
+         (set! (ly:music-property r 'tremolo-type) tremolo-type)
          (if (not (integer?  mult))
               (ly:warning (_ "invalid tremolo repeat count: ~a") times))
          (if (not (integer?  mult))
               (ly:warning (_ "invalid tremolo repeat count: ~a") times))
-         (if (memq 'sequential-music (ly:music-property main 'types))
-             ;; \repeat "tremolo" { c4 d4 }
-             (let ((children (length (ly:music-property main 'elements))))
-
-               ;; fixme: should be more generic.
-               (if (and (not (= children 2))
-                        (not (= children 1)))
-                   (ly:warning (_ "expecting 2 elements for chord tremolo, found ~a") children))
-               (ly:music-compress r (ly:make-moment 1 children))
-               (shift-duration-log r
-                                   (if (= children 2)  (1- shift) shift)
-                                   dots))
-             ;; \repeat "tremolo" c4
-             (shift-duration-log r shift dots)))
+         ;; Adjust the time of the notes
+         (ly:music-compress r (ly:make-moment 1 children))
+         ;; Adjust the displayed note durations
+         (shift-duration-log r shift dots))
        r)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        r)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -272,39 +316,38 @@ Returns `obj'.
 ;; repeats.
 
 (define-public (unfold-repeats music)
 ;; repeats.
 
 (define-public (unfold-repeats music)
-  "
-This function replaces all repeats  with unfold repeats. "
+  "This function replaces all repeats with unfolded repeats."
 
   (let ((es (ly:music-property music 'elements))
 
   (let ((es (ly:music-property music 'elements))
-       (e  (ly:music-property music 'element))
-       )
-    (if (memq 'repeated-music (ly:music-property music 'types))
-       (let*
-           ((props (ly:music-mutable-properties music))
-            (old-name (ly:music-property music 'name))
-            (flattened  (flatten-alist props)))
+       (e (ly:music-property music 'element)))
 
 
+    (if (memq 'repeated-music (ly:music-property music 'types))
+       (let* ((props (ly:music-mutable-properties music))
+              (old-name (ly:music-property music 'name))
+              (flattened (flatten-alist props)))
          (set! music (apply make-music (cons 'UnfoldedRepeatedMusic
                                              flattened)))
 
          (if (equal? old-name 'TremoloRepeatedMusic)
              (let* ((seq-arg? (memq 'sequential-music
                                     (ly:music-property e 'types)))
          (set! music (apply make-music (cons 'UnfoldedRepeatedMusic
                                              flattened)))
 
          (if (equal? old-name 'TremoloRepeatedMusic)
              (let* ((seq-arg? (memq 'sequential-music
                                     (ly:music-property e 'types)))
-                    (count  (ly:music-property music 'repeat-count))
+                    (count (ly:music-property music 'repeat-count))
                     (dot-shift (if (= 0 (remainder count 3))
                     (dot-shift (if (= 0 (remainder count 3))
-                                   -1 0)))
+                                   -1 0))
+                    (child-count (if seq-arg?
+                                     (length (ly:music-property e 'elements))
+                                     0)))
 
                (if (= 0 -1)
                    (set! count (* 2 (quotient count 3))))
 
                (if (= 0 -1)
                    (set! count (* 2 (quotient count 3))))
-               
-               (shift-duration-log music (+ (if seq-arg? 1 0)
+
+               (shift-duration-log music (+ (if (= 2 child-count)
+                                                1 0)
                                             (ly:intlog2 count)) dot-shift)
                                             (ly:intlog2 count)) dot-shift)
-               
+
                (if seq-arg?
                (if seq-arg?
-                   (ly:music-compress e (ly:make-moment (length (ly:music-property
-                                                                 e 'elements)) 1)))))))
-         
-    
+                   (ly:music-compress e (ly:make-moment child-count 1)))))))
+
     (if (pair? es)
        (set! (ly:music-property music 'elements)
              (map unfold-repeats es)))
     (if (pair? es)
        (set! (ly:music-property music 'elements)
              (map unfold-repeats es)))
@@ -326,8 +369,7 @@ i.e.  this is not an override"
              'pop-first #t))
 
 (define-public (make-grob-property-override grob gprop val)
              'pop-first #t))
 
 (define-public (make-grob-property-override grob gprop val)
-  "Make a Music expression that sets GPROP to VAL in GROB. Does a pop first,
-i.e.  this is not an override"
+  "Make a Music expression that overrides GPROP to VAL in GROB."
   (make-music 'OverrideProperty
              'symbol grob
              'grob-property gprop
   (make-music 'OverrideProperty
              'symbol grob
              'grob-property gprop
@@ -364,15 +406,20 @@ i.e.  this is not an override"
                        ;; TODO: take this from voicedGraceSettings or similar.
                        '((Voice Stem font-size -3)
                          (Voice NoteHead font-size -3)
                        ;; TODO: take this from voicedGraceSettings or similar.
                        '((Voice Stem 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 Dots font-size -3)
                          (Voice Stem length-fraction 0.8)
                          (Voice Stem no-stem-extend #t)
-                         (Voice Beam thickness 0.384)
+                         (Voice Beam beam-thickness 0.384)
                          (Voice Beam length-fraction 0.8)
                          (Voice Beam length-fraction 0.8)
-                         (Voice Accidental font-size -4)))
-    
+                         (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 'NoteColumn 'horizontal-shift (quotient n 2))
-     (make-grob-property-set 'MultiMeasureRest 'staff-position (if (odd? n) -4 4)))))) 
+     (make-grob-property-set 'MultiMeasureRest 'staff-position (if (odd? n) -4 4))))))
 
 (define-safe-public (make-voice-props-revert)
   (make-sequential-music
 
 (define-safe-public (make-voice-props-revert)
   (make-sequential-music
@@ -444,80 +491,24 @@ i.e.  this is not an override"
   (make-music 'PropertyUnset
              'symbol sym))
 
   (make-music 'PropertyUnset
              'symbol sym))
 
-(define-public (make-ottava-set octavation)
-  (let ((m (make-music 'ApplyContext)))
-    (define (ottava-modify context)
-      "Either reset middleCPosition to the stored original, or remember
-old middleCPosition, add OCTAVATION to middleCPosition, and set
-OTTAVATION to `8va', or whatever appropriate."     
-      (if (number? (ly:context-property         context 'middleCOffset))
-         (let ((where (ly:context-property-where-defined context 'middleCOffset)))
-           (ly:context-unset-property where 'middleCOffset)
-           (ly:context-unset-property where 'ottavation)))
-
-      (let* ((offset (* -7 octavation))
-            (string (cdr (assoc octavation '((2 . "15ma")
-                                             (1 . "8va")
-                                             (0 . #f)
-                                             (-1 . "8vb")
-                                             (-2 . "15mb"))))))
-       (ly:context-set-property! context 'middleCOffset offset)
-       (ly:context-set-property! context 'ottavation string)
-       (ly:set-middle-C! context)))
-    (set! (ly:music-property m 'procedure) ottava-modify)
-    (context-spec-music m 'Staff)))
-
-(define-public (set-octavation ottavation)
-  (ly:export (make-ottava-set ottavation)))
-
-(define-public (make-time-signature-set num den . rest)
-  "Set properties for time signature NUM/DEN.  Rest can contain a list
-of beat groupings "
-
-  (define (standard-beat-grouping num den)
-
-    "Some standard subdivisions for time signatures."
-    (let*
-       ((key (cons num den))
-        (entry (assoc key '(((6 . 8) . (3 3))
-                        ((5 . 8) . (3 2))
-                        ((9 . 8) . (3 3 3))
-                        ((12 . 8) . (3 3 3 3))
-                        ((8 . 8) . (3 3 2))
-                        ))))
-
-      (if entry
-         (cdr entry)
-         '())))    
-  
-  (let* ((set1 (make-property-set 'timeSignatureFraction (cons num den)))
-        (beat (ly:make-moment 1 den))
-        (len  (ly:make-moment num den))
-        (set2 (make-property-set 'beatLength beat))
-        (set3 (make-property-set 'measureLength len))
-        (set4 (make-property-set 'beatGrouping (if (pair? rest)
-                                                   (car rest)
-                                                   (standard-beat-grouping num den))))
-        (basic  (list set1 set2 set3 set4)))
-    (descend-to-context
-     (context-spec-music (make-sequential-music basic) 'Timing) 'Score)))
-
-(define-public (make-mark-set label)
-  "Make the music for the \\mark command."  
-  (let* ((set (if (integer? label)
-                 (context-spec-music (make-property-set 'rehearsalMark label)
-                                     'Score)
-                 #f))
-        (ev (make-music 'MarkEvent))
-        (ch (make-event-chord (list ev))))
-    (if set
-       (make-sequential-music (list set ch))
-       (begin
-         (set! (ly:music-property ev 'label) label)
-         ch))))
+;;; Need to keep this definition for \time calls from parser
+(define-public (make-time-signature-set num den)
+  "Set properties for time signature NUM/DEN."
+  (make-music 'TimeSignatureMusic
+              'numerator num
+              'denominator den
+              'beat-structure '()))
 
 
+;;; Used for calls that include beat-grouping setting
 (define-public (set-time-signature num den . rest)
 (define-public (set-time-signature num den . rest)
-  (ly:export (apply make-time-signature-set `(,num ,den . ,rest))))
+  "Set properties for time signature @var{num/den}.
+If @var{rest} is present, it is used to set
+@code{beatStructure}."
+  (ly:export
+   (make-music 'TimeSignatureMusic
+              'numerator num
+              'denominator den
+              'beat-structure (if (null? rest) rest (car rest)))))
 
 (define-safe-public (make-articulation name)
   (make-music 'ArticulationEvent
 
 (define-safe-public (make-articulation name)
   (make-music 'ArticulationEvent
@@ -532,8 +523,43 @@ of beat groupings "
   (make-music type
              'span-direction span-dir))
 
   (make-music type
              'span-direction span-dir))
 
-(define-public (set-mus-properties! m alist)
-  "Set all of ALIST as properties of M." 
+(define-public (override-head-style heads style)
+  "Override style for @var{heads} to @var{style}."
+  (make-sequential-music
+    (if (pair? heads)
+        (map (lambda (h)
+              (make-grob-property-override h 'style style))
+         heads)
+        (list (make-grob-property-override heads 'style style)))))
+
+(define-public (revert-head-style heads)
+  "Revert style for @var{heads}."
+  (make-sequential-music
+    (if (pair? heads)
+        (map (lambda (h)
+              (make-grob-property-revert h 'style))
+         heads)
+        (list (make-grob-property-revert heads 'style)))))
+
+(define-public (style-note-heads heads style music)
+ "Set @var{style} for all @var{heads} in @var{music}.  Works both
+inside of and outside of chord construct."
+  ;; are we inside a <...>?
+  (if (eq? (ly:music-property music 'name) 'NoteEvent)
+      ;; yes -> use a tweak
+      (begin
+        (set! (ly:music-property music 'tweaks)
+              (acons 'style style (ly:music-property music 'tweaks)))
+        music)
+      ;; not in <...>, so use overrides
+      (make-sequential-music
+        (list
+          (override-head-style heads style)
+          music
+          (revert-head-style heads)))))
+
+ (define-public (set-mus-properties! m alist)
+  "Set all of ALIST as properties of M."
   (if (pair? alist)
       (begin
        (set! (ly:music-property m (caar alist)) (cdar alist))
   (if (pair? alist)
       (begin
        (set! (ly:music-property m (caar alist)) (cdar alist))
@@ -559,7 +585,7 @@ of beat groupings "
             (make-sequential-music
              (list (make-voice-props-set number)
                    (make-simultaneous-music (car lst))))
             (make-sequential-music
              (list (make-voice-props-set number)
                    (make-simultaneous-music (car lst))))
-            'Voice  (number->string (1+ number)))
+            'Bottom  (number->string (1+ number)))
            (voicify-list (cdr lst) (1+ number)))))
 
 (define (voicify-chord ch)
            (voicify-list (cdr lst) (1+ number)))))
 
 (define (voicify-chord ch)
@@ -588,12 +614,10 @@ of beat groupings "
 (define-public (empty-music)
   (ly:export (make-music 'Music)))
 
 (define-public (empty-music)
   (ly:export (make-music 'Music)))
 
-;; Make a function that checks score element for being of a specific type. 
+;; Make a function that checks score element for being of a specific type.
 (define-public (make-type-checker symbol)
   (lambda (elt)
 (define-public (make-type-checker symbol)
   (lambda (elt)
-    ;;(display symbol)
-    ;;(eq? #t (ly:grob-property elt symbol))
-    (not (eq? #f (memq symbol (ly:grob-property elt 'interfaces))))))
+    (grob::has-interface elt symbol)))
 
 (define-public ((outputproperty-compatibility func sym val) grob g-context ao-context)
   (if (func grob)
 
 (define-public ((outputproperty-compatibility func sym val) grob g-context ao-context)
   (if (func grob)
@@ -607,13 +631,13 @@ of beat groupings "
 
 "
   (let ((meta (ly:grob-property grob 'meta)))
 
 "
   (let ((meta (ly:grob-property grob 'meta)))
-    (if (equal?  (cdr (assoc 'name meta)) grob-name)
+    (if (equal? (assoc-get 'name meta) grob-name)
        (set! (ly:grob-property grob symbol) val))))
 
 
 ;;
 (define-public (smart-bar-check n)
        (set! (ly:grob-property grob symbol) val))))
 
 
 ;;
 (define-public (smart-bar-check n)
-  "Make         a bar check that checks for a specific bar number. 
+  "Make         a bar check that checks for a specific bar number.
 "
   (let ((m (make-music 'ApplyContext)))
     (define (checker tr)
 "
   (let ((m (make-music 'ApplyContext)))
     (define (checker tr)
@@ -708,11 +732,11 @@ SkipEvent. Useful for extracting parts from crowded scores"
   (define (delete-prop context)
     (let* ((where (ly:context-property-where-defined context 'graceSettings))
           (current (ly:context-property where 'graceSettings))
   (define (delete-prop context)
     (let* ((where (ly:context-property-where-defined context 'graceSettings))
           (current (ly:context-property where 'graceSettings))
-           (prop-settings (filter 
+           (prop-settings (filter
                             (lambda(x) (sym-grob-context? x sym grob context-name))
                             (lambda(x) (sym-grob-context? x sym grob context-name))
-                            current)) 
+                            current))
           (new-settings current))
           (new-settings current))
-      (for-each (lambda(x) 
+      (for-each (lambda(x)
                  (set! new-settings (delete x new-settings)))
                prop-settings)
       (ly:context-set-property! where 'graceSettings new-settings)))
                  (set! new-settings (delete x new-settings)))
                prop-settings)
       (ly:context-set-property! where 'graceSettings new-settings)))
@@ -720,8 +744,10 @@ SkipEvent. Useful for extracting parts from crowded scores"
 
 
 
 
 
 
-(defmacro-public def-grace-function (start stop)
+(defmacro-public def-grace-function (start stop . docstring)
+  "Helper macro for defining grace music"
   `(define-music-function (parser location music) (ly:music?)
   `(define-music-function (parser location music) (ly:music?)
+     ,@docstring
      (make-music 'GraceMusic
                 'origin location
                 'element (make-music 'SequentialMusic
      (make-music 'GraceMusic
                 'origin location
                 'element (make-music 'SequentialMusic
@@ -735,37 +761,52 @@ Syntax:
   (define-music-function (parser location arg1 arg2 ...) (arg1-type? arg2-type? ...)
     ...function body...)
 "
   (define-music-function (parser location arg1 arg2 ...) (arg1-type? arg2-type? ...)
     ...function body...)
 "
-  `(ly:make-music-function (list ,@signature)
-                          (lambda (,@args)
-                            ,@body)))
+(if (and (pair? body) (pair? (car body)) (eqv? '_i (caar body)))
+      ;; When the music function definition contains a i10n doc string,
+      ;; (_i "doc string"), keep the literal string only
+      (let ((docstring (cadar body))
+           (body (cdr body)))
+       `(ly:make-music-function (list ,@signature)
+                                (lambda (,@args)
+                                  ,docstring
+                                  ,@body)))
+      `(ly:make-music-function (list ,@signature)
+                              (lambda (,@args)
+                                ,@body))))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (define-public (cue-substitute quote-music)
   "Must happen after quote-substitute."
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (define-public (cue-substitute quote-music)
   "Must happen after quote-substitute."
-  
+
   (if (vector? (ly:music-property quote-music 'quoted-events))
       (let* ((dir (ly:music-property quote-music 'quoted-voice-direction))
   (if (vector? (ly:music-property quote-music 'quoted-events))
       (let* ((dir (ly:music-property quote-music 'quoted-voice-direction))
+            (clef (ly:music-property quote-music 'quoted-music-clef))
             (main-voice (if (eq? 1 dir) 1 0))
             (cue-voice (if (eq? 1 dir) 0 1))
             (main-music (ly:music-property quote-music 'element))
             (return-value quote-music))
 
        (if (or (eq? 1 dir) (eq? -1 dir))
             (main-voice (if (eq? 1 dir) 1 0))
             (cue-voice (if (eq? 1 dir) 0 1))
             (main-music (ly:music-property quote-music 'element))
             (return-value quote-music))
 
        (if (or (eq? 1 dir) (eq? -1 dir))
-           
+
            ;; if we have stem dirs, change both quoted and main music
            ;; to have opposite stems.
            (begin
              (set! return-value
            ;; if we have stem dirs, change both quoted and main music
            ;; to have opposite stems.
            (begin
              (set! return-value
-
                    ;; cannot context-spec Quote-music, since context
                    ;; for the quotes is determined in the iterator.
                    (make-sequential-music
                     (list
                    ;; cannot context-spec Quote-music, since context
                    ;; for the quotes is determined in the iterator.
                    (make-sequential-music
                     (list
+                     (if (null? clef)
+                         (make-music 'Music)
+                         (make-cue-clef-set clef))
                      (context-spec-music (make-voice-props-set cue-voice) 'CueVoice "cue")
                      quote-music
                      (context-spec-music (make-voice-props-set cue-voice) 'CueVoice "cue")
                      quote-music
-                     (context-spec-music (make-voice-props-revert)  'CueVoice "cue"))))
+                     (context-spec-music (make-voice-props-revert) 'CueVoice "cue")
+                     (if (null? clef)
+                         (make-music 'Music)
+                         (make-cue-clef-unset)))))
              (set! main-music
                    (make-sequential-music
                     (list
              (set! main-music
                    (make-sequential-music
                     (list
@@ -783,7 +824,7 @@ Syntax:
                            (hash-ref quote-tab quoted-name #f)
                            #f)))
 
                            (hash-ref quote-tab quoted-name #f)
                            #f)))
 
-    
+
     (if (string? quoted-name)
        (if (vector? quoted-vector)
            (begin
     (if (string? quoted-name)
        (if (vector? quoted-vector)
            (begin
@@ -810,7 +851,7 @@ Syntax:
     (if (and (ly:music? m)
             (eq? (ly:music-property m 'error-found) #t))
        (set! found #t)))
     (if (and (ly:music? m)
             (eq? (ly:music-property m 'error-found) #t))
        (set! found #t)))
-  
+
   (for-each signal (ly:music-property music 'elements))
   (signal (ly:music-property music 'element))
 
   (for-each signal (ly:music-property music 'elements))
   (signal (ly:music-property music 'element))
 
@@ -829,32 +870,21 @@ Syntax:
   (ly:moment-main-numerator moment)
   (ly:moment-main-denominator moment)))
 
   (ly:moment-main-numerator moment)
   (ly:moment-main-denominator moment)))
 
-(define (skip-this moment)
- "set skipTypesetting, make SkipMusic of the given MOMENT length,
- and then unset skipTypesetting."
+(define (make-skipped moment bool)
+ "Depending on BOOL, set or unset skipTypesetting,
+then make SkipMusic of the given MOMENT length, and
+then revert skipTypesetting."
  (make-sequential-music
   (list
  (make-sequential-music
   (list
-   (context-spec-music (make-property-set 'skipTypesetting #t)
+   (context-spec-music (make-property-set 'skipTypesetting bool)
     'Score)
    (make-music 'SkipMusic 'duration
     (make-duration-of-length moment))
     'Score)
    (make-music 'SkipMusic 'duration
     (make-duration-of-length moment))
-   (context-spec-music (make-property-set 'skipTypesetting #f)
-    'Score))))
-
-(define (unskip-this moment)
- "unset skipTypesetting, make SkipMusic of the given MOMENT length,
- and then set skipTypesetting."
- (make-sequential-music
-  (list
-   (context-spec-music (make-property-set 'skipTypesetting #f)
-    'Score)
-   (make-music 'SkipMusic 'duration
-    (make-duration-of-length moment))
-   (context-spec-music (make-property-set 'skipTypesetting #t)
+   (context-spec-music (make-property-set 'skipTypesetting (not bool))
     'Score))))
 
 (define (skip-as-needed music parser)
     'Score))))
 
 (define (skip-as-needed music parser)
- "Replace MUSIC by
 "Replace MUSIC by
  << {  \\set skipTypesetting = ##f
  LENGTHOF(\\showFirstLength)
  \\set skipTypesetting = ##t
  << {  \\set skipTypesetting = ##f
  LENGTHOF(\\showFirstLength)
  \\set skipTypesetting = ##t
@@ -865,51 +895,56 @@ Syntax:
  When only showFirstLength is set,
  the 'length property of the music is
  overridden to speed up compiling."
  When only showFirstLength is set,
  the 'length property of the music is
  overridden to speed up compiling."
- (let*
-  ((show-last (ly:parser-lookup parser 'showLastLength))
-   (show-first (ly:parser-lookup parser 'showFirstLength)))
-  (cond
-
-   ;; both properties may be set.
-   ((and (ly:music? show-first) (ly:music? show-last))
-    (let*
-     ((orig-length (ly:music-length music))
-      (skip-length (ly:moment-sub orig-length (ly:music-length show-last)))
-      (begin-length (ly:music-length show-first)))
-     (make-simultaneous-music
-      (list
-       (make-sequential-music
-        (list
-         (skip-this skip-length)
-         ;; let's draw a separator between the beginning and the end
-         (context-spec-music (make-property-set 'whichBar "||")
-          'Timing)))
-       (unskip-this begin-length)
-       music))))
-
-   ;; we may only want to print the last length
-   ((ly:music? show-last)
-    (let*
-     ((orig-length (ly:music-length music))
-      (skip-length (ly:moment-sub orig-length (ly:music-length show-last))))
-     (make-simultaneous-music
-      (list
-       (skip-this skip-length)
-       music))))
-
-   ;; we may only want to print the beginning; in this case
-   ;; only the first length will be processed (much faster).
-   ((ly:music? show-first)
-    (let*
-     ((orig-length (ly:music-length music))
-      (begin-length (ly:music-length show-first)))
-     ;; the first length must not exceed the original length.
-     (if (ly:moment<? begin-length orig-length)
-      (set! (ly:music-property music 'length)
-       (ly:music-length show-first)))
-     music))
-
-   (else music))))
+  (let*
+      ((show-last (ly:parser-lookup parser 'showLastLength))
+       (show-first (ly:parser-lookup parser 'showFirstLength))
+       (show-last-length (if (ly:music? show-last)
+                             (ly:music-length show-last)
+                             #f))
+       (show-first-length (if (ly:music? show-first)
+                              (ly:music-length show-first)
+                              #f))
+       (orig-length (ly:music-length music)))
+
+    ;;FIXME: if using either showFirst- or showLastLength,
+    ;; make sure that skipBars is not set.
+
+    (cond
+
+     ;; both properties may be set.
+     ((and show-first-length show-last-length)
+      (let
+          ((skip-length (ly:moment-sub orig-length show-last-length)))
+        (make-simultaneous-music
+         (list
+          (make-sequential-music
+           (list
+            (make-skipped skip-length #t)
+            ;; let's draw a separator between the beginning and the end
+            (context-spec-music (make-property-set 'whichBar "||")
+                                'Timing)))
+          (make-skipped show-first-length #f)
+          music))))
+
+     ;; we may only want to print the last length
+     (show-last-length
+      (let
+          ((skip-length (ly:moment-sub orig-length show-last-length)))
+        (make-simultaneous-music
+         (list
+          (make-skipped skip-length #t)
+          music))))
+
+     ;; we may only want to print the beginning; in this case
+     ;; only the first length will be processed (much faster).
+     (show-first-length
+      ;; the first length must not exceed the original length.
+      (if (ly:moment<? show-first-length orig-length)
+          (set! (ly:music-property music 'length)
+                show-first-length))
+      music)
+
+     (else music))))
 
 
 (define-public toplevel-music-functions
 
 
 (define-public toplevel-music-functions
@@ -920,33 +955,139 @@ Syntax:
    (lambda (music parser)
 
      (music-map (quote-substitute (ly:parser-lookup parser 'musicQuotes))  music))
    (lambda (music parser)
 
      (music-map (quote-substitute (ly:parser-lookup parser 'musicQuotes))  music))
-   
+
    ;; switch-on-debugging
    (lambda (x parser) (music-map cue-substitute x))
    ;; switch-on-debugging
    (lambda (x parser) (music-map cue-substitute x))
+
    (lambda (x parser)
      (skip-as-needed x parser)
    )))
 
    (lambda (x parser)
      (skip-as-needed x parser)
    )))
 
+;;;;;;;;;;
+;;; general purpose music functions
+
+(define (shift-octave pitch octave-shift)
+  (_i "Add @var{octave-shift} to the octave of @var{pitch}.")
+  (ly:make-pitch
+     (+ (ly:pitch-octave pitch) octave-shift)
+     (ly:pitch-notename pitch)
+     (ly:pitch-alteration pitch)))
+
 
 ;;;;;;;;;;;;;;;;;
 ;; lyrics
 
 
 ;;;;;;;;;;;;;;;;;
 ;; lyrics
 
-(define (apply-durations lyric-music durations) 
+(define (apply-durations lyric-music durations)
   (define (apply-duration music)
     (if (and (not (equal? (ly:music-length music) ZERO-MOMENT))
             (ly:duration?  (ly:music-property music 'duration)))
        (begin
          (set! (ly:music-property music 'duration) (car durations))
          (set! durations (cdr durations)))))
   (define (apply-duration music)
     (if (and (not (equal? (ly:music-length music) ZERO-MOMENT))
             (ly:duration?  (ly:music-property music 'duration)))
        (begin
          (set! (ly:music-property music 'duration) (car durations))
          (set! durations (cdr durations)))))
-  
+
   (music-map apply-duration lyric-music))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; accidentals
 
   (music-map apply-duration lyric-music))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; accidentals
 
-(define-public ((make-accidental-rule octaveness lazyness) context pitch barnum measurepos)
+(define (recent-enough? bar-number alteration-def laziness)
+  (if (or (number? alteration-def)
+         (equal? laziness #t))
+      #t
+      (<= bar-number (+ (cadr alteration-def) laziness))))
+
+(define (is-tied? alteration-def)
+  (let* ((def (if (pair? alteration-def)
+                (car alteration-def)
+                alteration-def)))
+
+    (if (equal? def 'tied) #t #f)))
+
+(define (extract-alteration alteration-def)
+  (cond ((number? alteration-def)
+        alteration-def)
+       ((pair? alteration-def)
+        (car alteration-def))
+       (else 0)))
+
+(define (check-pitch-against-signature context pitch barnum laziness octaveness)
+  "Checks the need for an accidental and a @q{restore} accidental against
+@code{localKeySignature}. The @var{laziness} is the number of measures
+for which reminder accidentals are used (i.e., if @var{laziness} is zero,
+only cancel accidentals in the same measure; if @var{laziness} is three,
+we cancel accidentals up to three measures after they first appear.
+@var{octaveness} is either @code{'same-octave} or @code{'any-octave} and
+specifies whether accidentals should be canceled in different octaves."
+  (let* ((ignore-octave (cond ((equal? octaveness 'any-octave) #t)
+                             ((equal? octaveness 'same-octave) #f)
+                             (else
+                              (ly:warning (_ "Unknown octaveness type: ~S ") octaveness)
+                              (ly:warning (_ "Defaulting to 'any-octave."))
+                              #t)))
+        (key-sig (ly:context-property context 'keySignature))
+        (local-key-sig (ly:context-property context 'localKeySignature))
+        (notename (ly:pitch-notename pitch))
+        (octave (ly:pitch-octave pitch))
+        (pitch-handle (cons octave notename))
+        (need-restore #f)
+        (need-accidental #f)
+        (previous-alteration #f)
+        (from-other-octaves #f)
+        (from-same-octave (assoc-get pitch-handle local-key-sig))
+        (from-key-sig (assoc-get notename local-key-sig)))
+
+    ;; If no key signature match is found from localKeySignature, we may have a custom
+    ;; type with octave-specific entries of the form ((octave . pitch) alteration)
+    ;; instead of (pitch . alteration).  Since this type cannot coexist with entries in
+    ;; localKeySignature, try extracting from keySignature instead.
+    (if (equal? from-key-sig #f)
+       (set! from-key-sig (assoc-get pitch-handle key-sig)))
+
+    ;; loop through localKeySignature to search for a notename match from other octaves
+    (let loop ((l local-key-sig))
+      (if (pair? l)
+         (let ((entry (car l)))
+           (if (and (pair? (car entry))
+                    (= (cdar entry) notename))
+               (set! from-other-octaves (cdr entry))
+               (loop (cdr l))))))
+
+    ;; find previous alteration-def for comparison with pitch
+    (cond
+     ;; from same octave?
+     ((and (eq? ignore-octave #f)
+          (not (equal? from-same-octave #f))
+          (recent-enough? barnum from-same-octave laziness))
+      (set! previous-alteration from-same-octave))
+
+     ;; from any octave?
+     ((and (eq? ignore-octave #t)
+          (not (equal? from-other-octaves #f))
+          (recent-enough? barnum from-other-octaves laziness))
+      (set! previous-alteration from-other-octaves))
+
+     ;; not recent enough, extract from key signature/local key signature
+     ((not (equal? from-key-sig #f))
+      (set! previous-alteration from-key-sig)))
+
+    (if (is-tied? previous-alteration)
+       (set! need-accidental #t)
+
+       (let* ((prev-alt (extract-alteration previous-alteration))
+              (this-alt (ly:pitch-alteration pitch)))
+
+         (if (not (= this-alt prev-alt))
+             (begin
+               (set! need-accidental #t)
+               (if (and (not (= this-alt 0))
+                        (or (< (abs this-alt) (abs prev-alt))
+                            (< (* prev-alt this-alt) 0)))
+                   (set! need-restore #t))))))
+
+    (cons need-restore need-accidental)))
+
+(define-public ((make-accidental-rule octaveness laziness) context pitch barnum measurepos)
   "Creates an accidental rule that makes its decision based on the octave of the note
   and a laziness value.
   octaveness is either 'same-octave or 'any-octave and defines whether the rule should
   "Creates an accidental rule that makes its decision based on the octave of the note
   and a laziness value.
   octaveness is either 'same-octave or 'any-octave and defines whether the rule should
@@ -954,13 +1095,12 @@ Syntax:
   normal way to typeset accidentals - an accidental is made if the alteration is different
   from the last active pitch in the same octave. 'any-octave looks at the last active pitch
   in any octave.
   normal way to typeset accidentals - an accidental is made if the alteration is different
   from the last active pitch in the same octave. 'any-octave looks at the last active pitch
   in any octave.
-  lazyness states over how many bars an accidental should be remembered.
+  laziness states over how many bars an accidental should be remembered.
   0 is default - accidental lasts over 0 bar lines, that is, to the end of current measure.
   A positive integer means that the accidental lasts over that many bar lines.
   -1 is 'forget immediately', that is, only look at key signature.
   #t is forever."
   0 is default - accidental lasts over 0 bar lines, that is, to the end of current measure.
   A positive integer means that the accidental lasts over that many bar lines.
   -1 is 'forget immediately', that is, only look at key signature.
   #t is forever."
-  (let ((keysig (ly:context-property context 'localKeySignature)))
-    (ly:find-accidentals-simple keysig pitch barnum lazyness octaveness)))
+  (check-pitch-against-signature context pitch barnum laziness octaveness))
 
 (define (key-entry-notename entry)
   "Return the pitch of an entry in localKeySignature. The entry is either of the form
 
 (define (key-entry-notename entry)
   "Return the pitch of an entry in localKeySignature. The entry is either of the form
@@ -1113,6 +1253,29 @@ use GrandStaff as a context. "
                                           ,(make-accidental-rule 'same-octave 1)
                                           ,neo-modern-accidental-rule)
                                   context))
                                           ,(make-accidental-rule 'same-octave 1)
                                           ,neo-modern-accidental-rule)
                                   context))
+      ((equal? style 'neo-modern-voice)
+       (set-accidentals-properties #f
+                                  `(Voice ,(make-accidental-rule 'same-octave 0)
+                                          ,(make-accidental-rule 'any-octave 0)
+                                          ,(make-accidental-rule 'same-octave 1)
+                                          ,neo-modern-accidental-rule
+                                    Staff ,(make-accidental-rule 'same-octave 0)
+                                          ,(make-accidental-rule 'any-octave 0)
+                                          ,(make-accidental-rule 'same-octave 1)
+                                     ,neo-modern-accidental-rule)
+                                  '()
+                                  context))
+      ((equal? style 'neo-modern-voice-cautionary)
+       (set-accidentals-properties #f
+                                  `(Voice ,(make-accidental-rule 'same-octave 0))
+                                  `(Voice ,(make-accidental-rule 'any-octave 0)
+                                          ,(make-accidental-rule 'same-octave 1)
+                                          ,neo-modern-accidental-rule
+                                    Staff ,(make-accidental-rule 'same-octave 0)
+                                          ,(make-accidental-rule 'any-octave 0)
+                                          ,(make-accidental-rule 'same-octave 1)
+                                          ,neo-modern-accidental-rule)
+                                  context))
       ;; Accidentals as they were common in dodecaphonic music with no tonality.
       ;; Each note gets one accidental.
       ((equal? style 'dodecaphonic)
       ;; Accidentals as they were common in dodecaphonic music with no tonality.
       ;; Each note gets one accidental.
       ((equal? style 'dodecaphonic)
@@ -1167,14 +1330,14 @@ use GrandStaff as a context. "
                                   pcontext))
 
       ;; same as modern, but cautionary accidentals are printed for all sharp or flat
                                   pcontext))
 
       ;; same as modern, but cautionary accidentals are printed for all sharp or flat
-      ;; tones specified by the key signature.  
+      ;; tones specified by the key signature.
        ((equal? style 'teaching)
        (set-accidentals-properties #f
                                    `(Staff ,(make-accidental-rule 'same-octave 0))
                                    `(Staff ,(make-accidental-rule 'same-octave 1)
                                           ,teaching-accidental-rule)
                                   context))
        ((equal? style 'teaching)
        (set-accidentals-properties #f
                                    `(Staff ,(make-accidental-rule 'same-octave 0))
                                    `(Staff ,(make-accidental-rule 'same-octave 1)
                                           ,teaching-accidental-rule)
                                   context))
-      
+
       ;; do not set localKeySignature when a note alterated differently from
       ;; localKeySignature is found.
       ;; Causes accidentals to be printed at every note instead of
       ;; do not set localKeySignature when a note alterated differently from
       ;; localKeySignature is found.
       ;; Causes accidentals to be printed at every note instead of
@@ -1211,7 +1374,7 @@ use GrandStaff as a context. "
 
 (define-public (mmrest-of-length mus)
   "Create a mmrest of exactly the same length as MUS."
 
 (define-public (mmrest-of-length mus)
   "Create a mmrest of exactly the same length as MUS."
-  
+
   (let* ((skip
          (make-multi-measure-rest
           (ly:make-duration 0 0) '())))
   (let* ((skip
          (make-multi-measure-rest
           (ly:make-duration 0 0) '())))
@@ -1227,7 +1390,7 @@ use GrandStaff as a context. "
     (if (pair? evs)
        (ly:music-property (car evs) 'pitch)
        #f)))
     (if (pair? evs)
        (ly:music-property (car evs) 'pitch)
        #f)))
-       
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (define-public (extract-named-music music music-name)
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (define-public (extract-named-music music music-name)
@@ -1243,7 +1406,7 @@ from @code{music}."
                         (extract-named-music elt music-name)
                         (if (null? elts)
                             '()
                         (extract-named-music elt music-name)
                         (if (null? elts)
                             '()
-                            (map (lambda(x) 
+                            (map (lambda(x)
                                     (extract-named-music x music-name ))
                              elts)))))
               '())))
                                     (extract-named-music x music-name ))
                              elts)))))
               '())))