]> git.donarmstrong.com Git - lilypond.git/blobdiff - scm/lily-library.scm
Reformat some files to let emacs do its work correctly.
[lilypond.git] / scm / lily-library.scm
index a9098fd1f8520dc96011897d31bc7f4e8e4199fd..48ee33cf50f20be5dca07da805bfa6e2d7d28dcf 100644 (file)
 ;;;; You should have received a copy of the GNU General Public License
 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 
-; for take, drop, take-while, list-index, and find-tail:
+;; for take, drop, take-while, list-index, and find-tail:
 (use-modules (srfi srfi-1))
 
-; for define-safe-public when byte-compiling using Guile V2
+;; for define-safe-public when byte-compiling using Guile V2
 (use-modules (scm safe-utility-defs))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -57,6 +57,8 @@
 (define-safe-public DOUBLE-SHARP 1)
 (define-safe-public SEMI-TONE 1/2)
 
+(define-safe-public INFINITY-INT 1000000)
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; moments
 
   (cons (ly:moment-main-numerator moment)
         (ly:moment-main-denominator moment)))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; durations
+
+(define-public (duration-log-factor lognum)
+"Given a logarithmic duration number, return the length of the duration,
+as a number of whole notes."
+  (or (and (exact? lognum) (integer? lognum))
+    (scm-error 'wrong-type-arg "duration-log-factor" "Not an integer: ~S" (list lognum) #f))
+  (if (<= lognum 0)
+    (ash 1 (- lognum))
+    (/ (ash 1 lognum))))
+
+(define-public (duration-dot-factor dotcount)
+"Given a count of the dots used to extend a musical duration, return
+the numeric factor by which they increase the duration."
+  (or (and (exact? dotcount) (integer? dotcount) (>= dotcount 0))
+    (scm-error 'wrong-type-arg "duration-dot-factor" "Not a count: ~S" (list dotcount) #f))
+  (- 2 (/ (ash 1 dotcount))))
+
+(define-public (duration-length dur)
+"Return the overall length of a duration, as a number of whole notes.
+(Not to be confused with ly:duration-length, which returns a less-useful
+moment object.)"
+  (ly:moment-main (ly:duration-length dur)))
+
+(define-public (duration-visual dur)
+"Given a duration object, return the visual part of the duration (base
+note length and dot count), in the form of a duration object with
+non-visual scale factor 1."
+  (ly:make-duration (ly:duration-log dur) (ly:duration-dot-count dur) 1))
+
+(define-public (duration-visual-length dur)
+"Given a duration object, return the length of the visual part of the
+duration (base note length and dot count), as a number of whole notes."
+  (duration-length (duration-visual dur)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; arithmetic
 (define-public (average x . lst)
 
 (define-public (collect-music-aux score-handler parser music)
   (define (music-property symbol)
-    (let ((value (ly:music-property music symbol)))
-      (if (not (null? value))
-         value
-         #f)))
+    (ly:music-property music symbol #f))
   (cond ((music-property 'page-marker)
         ;; a page marker: set page break/turn permissions or label
-        (begin
-          (let ((label (music-property 'page-label)))
-            (if (symbol? label)
-                (score-handler (ly:make-page-label-marker label))))
-          (for-each (lambda (symbol)
-                      (let ((permission (music-property symbol)))
-                        (if (symbol? permission)
-                            (score-handler
-                             (ly:make-page-permission-marker symbol
-                                                             (if (eqv? 'forbid permission)
-                                                                 '()
-                                                                 permission))))))
-                    (list 'line-break-permission 'page-break-permission
-                          'page-turn-permission))))
-       ((not (music-property 'void))
+         (let ((label (music-property 'page-label)))
+           (if (symbol? label)
+               (score-handler (ly:make-page-label-marker label))))
+         (for-each (lambda (symbol)
+                     (let ((permission (music-property symbol)))
+                       (if (symbol? permission)
+                           (score-handler
+                            (ly:make-page-permission-marker symbol
+                                                            (if (eq? 'forbid permission)
+                                                                '()
+                                                                permission))))))
+                   '(line-break-permission page-break-permission
+                                           page-turn-permission)))
+        ((not (music-property 'void))
         ;; a regular music expression: make a score with this music
         ;; void music is discarded
         (score-handler (scorify-music music parser)))))
 
 (define-public (scorify-music music parser)
   "Preprocess @var{music}."
-
-  (for-each (lambda (func)
-             (set! music (func music parser)))
-           toplevel-music-functions)
-
-  (ly:make-score music))
-
+  (ly:make-score
+   (fold (lambda (f m) (f m parser))
+         music
+         toplevel-music-functions)))
 
 (define (get-current-filename parser book)
   "return any suffix value for output filename allowing for settings by
 calls to bookOutputName function"
-  (let ((book-filename (paper-variable parser book 'output-filename)))
-    (if (not book-filename)
-       (ly:parser-output-name parser)
-       book-filename)))
+  (or (paper-variable parser book 'output-filename)
+      (ly:parser-output-name parser)))
 
 (define (get-current-suffix parser book)
   "return any suffix value for output filename allowing for settings by calls to
@@ -257,16 +286,56 @@ bookoutput function"
                      parser
                     music))
 
+(define-public (context-mod-from-music parser music)
+  (let ((warn #t) (mods (ly:make-context-mod)))
+    (let loop ((m music))
+      (if (music-is-of-type? m 'layout-instruction-event)
+         (let ((symbol (ly:music-property m 'symbol)))
+           (ly:add-context-mod
+            mods
+            (case (ly:music-property m 'name)
+              ((PropertySet)
+               (list 'assign
+                     symbol
+                     (ly:music-property m 'value)))
+              ((PropertyUnset)
+               (list 'unset symbol))
+              ((OverrideProperty)
+               (cons* 'push
+                      symbol
+                      (ly:music-property m 'grob-value)
+                       (cond
+                        ((ly:music-property m 'grob-property #f) => list)
+                        (else
+                         (ly:music-property m 'grob-property-path)))))
+               ((RevertProperty)
+               (cons* 'pop
+                      symbol
+                       (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
+                                (list 'apply
+                                      (ly:music-property m 'procedure))))
+           ((ContextSpeccedMusic)
+            (loop (ly:music-property m 'element)))
+           (else
+            (let ((callback (ly:music-property m 'elements-callback)))
+              (if (procedure? callback)
+                  (for-each loop (callback m))
+                  (if (and warn (ly:duration? (ly:music-property m 'duration)))
+                      (begin
+                        (ly:music-warning
+                         music
+                         (_ "Music unsuitable for context-mod"))
+                        (set! warn #f)))))))))
+    mods))
+
 (define-public (context-defs-from-music parser output-def music)
-  (let ((bottom 'Voice) (warn #t))
-    (define (get-bottom sym)
-      (or
-       (let ((def (ly:output-def-lookup output-def sym #f)))
-       (and def
-            (let ((def-child (ly:context-def-lookup def 'default-child #f)))
-              (and def-child
-                   (get-bottom def-child)))))
-       sym))
+  (let ((warn #t))
     (let loop ((m music) (mods #f))
       ;; The parser turns all sets, overrides etc into something
       ;; wrapped in ContextSpeccedMusic.  If we ever get a set,
@@ -287,39 +356,53 @@ bookoutput function"
              (list 'unset
                    (ly:music-property m 'symbol)))
             ((OverrideProperty)
-             (list 'push
-                   (ly:music-property m 'symbol)
-                   (ly:music-property m 'grob-value)
-                   (ly:music-property m 'grob-property-path)))
+             (cons* 'push
+                    (ly:music-property m 'symbol)
+                    (ly:music-property m 'grob-value)
+                     (cond
+                      ((ly:music-property m 'grob-property #f) => list)
+                      (else
+                       (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)
+                     (cond
+                      ((ly:music-property m 'grob-property #f) => list)
+                      (else
+                       (ly:music-property m 'grob-property-path)))))))
          (case (ly:music-property m 'name)
-           ((SequentialMusic SimultaneousMusic)
-            (fold loop mods (ly:music-property m 'elements)))
+           ((ApplyContext)
+            (ly:add-context-mod mods
+                                (list 'apply
+                                      (ly:music-property m 'procedure))))
            ((ContextSpeccedMusic)
-            (let ((sym (ly:music-property m 'context-type)))
-              (if (eq? sym 'Bottom)
-                  (set! sym bottom)
-                  (set! bottom (get-bottom sym)))
-              (let ((def (ly:output-def-lookup output-def sym)))
-                (if (ly:context-def? def)
-                    (ly:output-def-set-variable!
-                     output-def sym
-                     (ly:context-def-modify
-                      def
-                      (loop (ly:music-property m 'element)
-                            (ly:make-context-mod))))
-                    (ly:music-warning
-                     music
-                     (ly:format (_ "Cannot find context-def \\~a") sym))))))
-           (else (if (and warn (ly:duration? (ly:music-property m 'duration)))
-                     (begin
-                       (ly:music-warning
-                        music
-                        (_ "Music unsuitable for output-def"))
-                       (set! warn #f))))))
+            ;; Use let* here to let defs catch up with modifications
+            ;; to the context defs made in the recursion
+            (let* ((mods (loop (ly:music-property m 'element)
+                               (ly:make-context-mod)))
+                   (defs (ly:output-find-context-def
+                          output-def (ly:music-property m 'context-type))))
+              (if (null? defs)
+                  (ly:music-warning
+                   music
+                   (ly:format (_ "Cannot find context-def \\~a")
+                              (ly:music-property m 'context-type)))
+                  (for-each
+                   (lambda (entry)
+                     (ly:output-def-set-variable!
+                      output-def (car entry)
+                      (ly:context-def-modify (cdr entry) mods)))
+                   defs))))
+           (else
+            (let ((callback (ly:music-property m 'elements-callback)))
+              (if (procedure? callback)
+                  (fold loop mods (callback m))
+                  (if (and warn (ly:duration? (ly:music-property m 'duration)))
+                      (begin
+                        (ly:music-warning
+                         music
+                         (_ "Music unsuitable for output-def"))
+                        (set! warn #f))))))))
       mods)))
 
 
@@ -357,17 +440,11 @@ bookoutput function"
 (define-public (first-member members lst)
   "Return first successful member (of member) from @var{members} in
 @var{lst}."
-  (if (null? members)
-      #f
-      (let ((m (member (car members) lst)))
-       (if m m (first-member (cdr members) lst)))))
+  (any (lambda (m) (member m lst)) members))
 
 (define-public (first-assoc keys lst)
   "Return first successful assoc of key from @var{keys} in @var{lst}."
-  (if (null? keys)
-      #f
-      (let ((k (assoc (car keys) lst)))
-       (if k k (first-assoc (cdr keys) lst)))))
+  (any (lambda (k) (assoc k lst)) keys))
 
 (define-public (flatten-alist alist)
   (if (null? alist)
@@ -423,30 +500,23 @@ For example:
 ;; hash
 
 (define-public (hash-table->alist t)
-  (hash-fold (lambda (k v acc) (acons  k v  acc))
-            '() t))
+  (hash-fold acons '() t))
 
 ;; todo: code dup with C++.
 (define-safe-public (alist->hash-table lst)
   "Convert alist to table"
   (let ((m (make-hash-table (length lst))))
-    (map (lambda (k-v) (hashq-set! m (car k-v) (cdr k-v))) lst)
+    (for-each (lambda (k-v) (hashq-set! m (car k-v) (cdr k-v))) lst)
     m))
 
 ;;;;;;;;;;;;;;;;
 ;; list
 
 (define (functional-or . rest)
-  (if (pair? rest)
-      (or (car rest)
-          (apply functional-or (cdr rest)))
-      #f))
+  (any identity rest))
 
 (define (functional-and . rest)
-  (if (pair? rest)
-      (and (car rest)
-          (apply functional-and (cdr rest)))
-      #t))
+  (every identity rest))
 
 (define (split-list lst n)
   "Split LST in N equal sized parts"
@@ -464,26 +534,12 @@ For example:
   (helper lst (make-vector n '()) (1- n)))
 
 (define (list-element-index lst x)
-  (define (helper todo k)
-    (cond
-     ((null? todo) #f)
-     ((equal? (car todo) x) k)
-     (else
-      (helper (cdr todo) (1+ k)))))
-
-  (helper lst 0))
+  (list-index (lambda (m) (equal? m x)) lst))
 
 (define-public (count-list lst)
   "Given @var{lst} as @code{(E1 E2 .. )}, return
 @code{((E1 . 1) (E2 . 2) ... )}."
-
-  (define (helper l acc count)
-    (if (pair? l)
-       (helper (cdr l) (cons (cons (car l) count) acc) (1+ count))
-       acc))
-
-
-  (reverse (helper lst '() 1)))
+  (map cons lst (iota (length lst) 1)))
 
 (define-public (list-join lst intermediate)
   "Put @var{intermediate} between all elts of @var{lst}."
@@ -528,28 +584,27 @@ for comparisons."
   "Split LST into two lists at the first element that returns #f for
   (PRED previous_element element).  Return the two parts as a pair.
   Example: (split-at-predicate < '(1 2 3 2 1)) ==> ((1 2 3) . (2 1))"
-  (if (null? lst)
-      (list lst)
-      (let ((i (list-index (lambda (x y) (not (pred x y)))
-                          lst
-                          (cdr lst))))
-        (if i
-            (cons (take lst (1+ i)) (drop lst (1+ i)))
-            (list lst)))))
+  (let ((i (and (pair? lst)
+                (list-index (lambda (x y) (not (pred x y)))
+                            lst
+                            (cdr lst)))))
+    (if i
+        (call-with-values
+            (lambda () (split-at lst (1+ i)))
+          cons)
+        (list lst))))
 
 (define-public (split-list-by-separator lst pred)
   "Split @var{lst} at each element that satisfies @var{pred}, and return
 the parts (with the separators removed) as a list of lists.  For example,
 executing @samp{(split-list-by-separator '(a 0 b c 1 d) number?)} returns
 @samp{((a) (b c) (d))}."
-  (let loop ((result '()) (lst lst))
-    (if (and lst (not (null? lst)))
-        (loop
-          (append result
-                  (list (take-while (lambda (x) (not (pred x))) lst)))
-          (let ((tail (find-tail pred lst)))
-            (if tail (cdr tail) #f)))
-       result)))
+  (call-with-values (lambda () (break pred lst))
+    (lambda (head tail)
+      (cons head
+            (if (null? tail)
+                tail
+                (split-list-by-separator (cdr tail) pred))))))
 
 (define-public (offset-add a b)
   (cons (+ (car a) (car b))
@@ -608,6 +663,10 @@ right (@var{dir}=+1)."
 (define (other-axis a)
   (remainder (+ a 1) 2))
 
+(define-public (interval-scale iv factor)
+  (cons (* (car iv) factor)
+    (* (cdr iv) factor)))
+
 (define-public (interval-widen iv amount)
   (cons (- (car iv) amount)
     (+ (cdr iv) amount)))
@@ -873,13 +932,10 @@ in module @var{module}.  In that case evaluate, otherwise
 print a warning and set an optional @var{default}."
   (let* ((unavailable? (lambda (sym)
                          (not (module-defined? module sym))))
-        (sym-unavailable (if (pair? symbol)
-                             (filter
-                               unavailable?
-                               (filter symbol? (flatten-list symbol)))
-                             (if (unavailable? symbol)
-                                  #t
-                                  '()))))
+        (sym-unavailable
+          (filter
+           unavailable?
+           (filter symbol? (flatten-list symbol)))))
     (if (null? sym-unavailable)
         (eval symbol module)
         (let* ((def (and (pair? default) (car default))))
@@ -939,11 +995,6 @@ print a warning and set an optional @var{default}."
 
 (define-public (version-not-seen-message input-file-name)
   (ly:warning-located
-    (ly:format "~a:0" input-file-name)
+    (ly:format "~a:1" input-file-name)
     (_ "no \\version statement found, please add~afor future compatibility")
     (format #f "\n\n\\version ~s\n\n" (lilypond-version))))
-
-(define-public (old-relative-not-used-message input-file-name)
-  (ly:warning-located
-    (ly:format "~a:0" input-file-name)
-    (_ "old relative compatibility not used")))