X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scm%2Flily-library.scm;h=6fb605b25066d01dc24ce490058846caa6f773f6;hb=eebafce7c459edf00becf210acc06ce36eb80462;hp=572972169f0d45687a4e7b0c03e50259a4be3a85;hpb=caf6f697cc296afe42de14fc7296e3a27f8e1cf9;p=lilypond.git diff --git a/scm/lily-library.scm b/scm/lily-library.scm index 572972169f..6fb605b250 100644 --- a/scm/lily-library.scm +++ b/scm/lily-library.scm @@ -1,10 +1,20 @@ +;;;; This file is part of LilyPond, the GNU music typesetter. ;;;; -;;;; lily-library.scm -- utilities +;;;; Copyright (C) 1998--2011 Jan Nieuwenhuizen +;;;; Han-Wen Nienhuys ;;;; -;;;; source file of the GNU LilyPond music typesetter +;;;; 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. ;;;; -;;;; (c) 1998--2009 Jan Nieuwenhuizen -;;;; Han-Wen Nienhuys +;;;; 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 . ; for take, drop, take-while, list-index, and find-tail: (use-modules (srfi srfi-1)) @@ -56,6 +66,15 @@ (or (equal? a b) (ly:momentmoment fraction) + (if (null? fraction) + ZERO-MOMENT + (ly:make-moment (car fraction) (cdr fraction)))) + +(define-public (moment->fraction moment) + (cons (ly:moment-main-numerator moment) + (ly:moment-main-denominator moment))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; arithmetic (define-public (average x . lst) @@ -135,33 +154,59 @@ (ly:make-score music)) -(define (get-outfile-name parser base) - (let* ((output-suffix (ly:parser-lookup parser 'output-suffix)) +(define (get-current-filename parser) + "return any suffix value for output filename allowing for settings by +calls to bookOutputName function" + (let ((book-filename (ly:parser-lookup parser 'book-filename))) + (if (not book-filename) + (ly:parser-output-name parser) + book-filename))) + +(define (get-current-suffix parser) + "return any suffix value for output filename allowing for settings by calls to +bookoutput function" + (let ((book-output-suffix (ly:parser-lookup parser 'book-output-suffix))) + (if (not (string? book-output-suffix)) + (ly:parser-lookup parser 'output-suffix) + book-output-suffix))) + +(define-public current-outfile-name #f) ; for use by regression tests + +(define (get-outfile-name parser) + "return current filename for generating backend output files" + ;; user can now override the base file name, so we have to use + ;; the file-name concatenated with any potential output-suffix value + ;; as the key to out internal a-list + (let* ((base-name (get-current-filename parser)) + (output-suffix (get-current-suffix parser)) + (alist-key (format "~a~a" base-name output-suffix)) (counter-alist (ly:parser-lookup parser 'counter-alist)) - (output-count (assoc-get output-suffix counter-alist 0)) - (result base)) + (output-count (assoc-get alist-key counter-alist 0)) + (result base-name)) ;; Allow all ASCII alphanumerics, including accents (if (string? output-suffix) - (set! result (format "~a-~a" - base (string-regexp-substitute - "[^-[:alnum:]]" "_" output-suffix)))) + (set! result + (format "~a-~a" + result + (string-regexp-substitute + "[^-[:alnum:]]" + "_" + output-suffix)))) ;; assoc-get call will always have returned a number (if (> output-count 0) - (set! result (format #f "~a-~a" result output-count))) + (set! result (format #f "~a-~a" result output-count))) (ly:parser-define! - parser 'counter-alist - (assoc-set! counter-alist output-suffix (1+ output-count))) + parser 'counter-alist + (assoc-set! counter-alist alist-key (1+ output-count))) + (set! current-outfile-name result) result)) (define (print-book-with parser book process-procedure) (let* ((paper (ly:parser-lookup parser '$defaultpaper)) (layout (ly:parser-lookup parser '$defaultlayout)) - (count (ly:parser-lookup parser 'output-count)) - (base (ly:parser-output-name parser)) - (outfile-name (get-outfile-name parser base))) - + (outfile-name (get-outfile-name parser))) (process-procedure book paper layout outfile-name))) (define-public (print-book-with-defaults parser book) @@ -217,7 +262,7 @@ (map-alist-vals func (cdr list))))) (define (map-alist-keys func list) - "map FUNC over the keys of an alist LIST, leaving the vals. " + "map FUNC over the keys of an alist LIST, leaving the vals." (if (null? list) '() (cons (cons (func (caar list)) (cdar list)) @@ -244,6 +289,36 @@ (cons (cdar alist) (flatten-alist (cdr alist)))))) +(define (assoc-remove key alist) + "Remove key (and its corresponding value) from an alist. + Different than assoc-remove! because it is non-destructive." + (define (assoc-crawler key l r) + (if (null? r) + l + (if (equal? (caar r) key) + (append l (cdr r)) + (assoc-crawler key (append l `(,(car r))) (cdr r))))) + (assoc-crawler key '() alist)) + +(define-public (map-selected-alist-keys function keys alist) + "Returns alist with function applied to all of the values in list keys. + For example: + @code{guile> (map-selected-alist-keys - '(a b) '((a . 1) (b . -2) (c . 3) (d . 4)))} + @code{((a . -1) (b . 2) (c . 3) (d . 4))}" + (define (map-selected-alist-keys-helper function key alist) + (map + (lambda (pair) + (if (equal? key (car pair)) + (cons key (function (cdr pair))) + pair)) + alist)) + (if (null? keys) + alist + (map-selected-alist-keys + function + (cdr keys) + (map-selected-alist-keys-helper function (car keys) alist)))) + ;;;;;;;;;;;;;;;; ;; vector @@ -273,7 +348,7 @@ (define (functional-or . rest) (if (pair? rest) (or (car rest) - (apply functional-and (cdr rest))) + (apply functional-or (cdr rest))) #f)) (define (functional-and . rest) @@ -308,7 +383,7 @@ (helper lst 0)) (define-public (count-list lst) - "Given lst (E1 E2 .. ) return ((E1 . 1) (E2 . 2) ... ) " + "Given lst (E1 E2 .. ), return ((E1 . 1) (E2 . 2) ... )." (define (helper l acc count) (if (pair? l) @@ -333,7 +408,7 @@ (lambda (x) x) (map proc lst))) -(define (flatten-list x) +(define-public (flatten-list x) "Unnest list." (cond ((null? x) '()) ((not (pair? x)) (list x)) @@ -345,7 +420,7 @@ (lset-difference eq? a b)) (define-public (uniq-list lst) - "Uniq LST, assuming that it is sorted. Uses equal? for comparisons." + "Uniq LST, assuming that it is sorted. Uses equal? for comparisons." (reverse! (fold (lambda (x acc) @@ -358,7 +433,7 @@ (define (split-at-predicate pred lst) "Split LST into two lists at the first element that returns #f for - (PRED previous_element element). Return the two parts as a pair. + (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) @@ -371,7 +446,7 @@ (define-public (split-list-by-separator lst pred) "Split LST at each element that satisfies PRED, and return the parts - (with the separators removed) as a list of lists. Example: + (with the separators removed) as a list of lists. Example: (split-list-by-separator '(a 0 b c 1 d) number?) ==> ((a) (b c) (d))" (let loop ((result '()) (lst lst)) (if (and lst (not (null? lst))) @@ -399,17 +474,6 @@ (cons (cons (car coords) (cadr coords)) (ly:list->offsets accum (cddr coords))))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; numbers - -(if (not (defined? 'nan?)) ;; guile 1.6 compat - (define-public (nan? x) (not (or (< 0.0 x) - (> 0.0 x) - (= 0.0 x))))) - -(if (not (defined? 'inf?)) - (define-public (inf? x) (= (/ 1.0 x) 0.0))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; intervals @@ -446,27 +510,25 @@ (define-public interval-end cdr) -(define-public (interval-translate iv amount) - (cons (+ amount (car iv)) - (+ amount (cdr iv)))) - (define (other-axis a) (remainder (+ a 1) 2)) (define-public (interval-widen iv amount) - (cons (- (car iv) amount) - (+ (cdr iv) amount))) + (cons (- (car iv) amount) + (+ (cdr iv) amount))) (define-public (interval-empty? iv) (> (car iv) (cdr iv))) (define-public (interval-union i1 i2) - (cons (min (car i1) (car i2)) - (max (cdr i1) (cdr i2)))) + (cons + (min (car i1) (car i2)) + (max (cdr i1) (cdr i2)))) (define-public (interval-intersection i1 i2) - (cons (max (car i1) (car i2)) - (min (cdr i1) (cdr i2)))) + (cons + (max (car i1) (car i2)) + (min (cdr i1) (cdr i2)))) (define-public (interval-sane? i) (not (or (nan? (car i)) @@ -479,6 +541,104 @@ (cons (min (interval-start interval) p) (max (interval-end interval) p))) +(define-public (reverse-interval iv) + (cons (cdr iv) (car iv))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; coordinates + +(define coord-x car) +(define coord-y cdr) + +(define (coord-operation operator operand coordinate) + (if (pair? operand) + (cons (operator (coord-x operand) (coord-x coordinate)) + (operator (coord-y operand) (coord-y coordinate))) + (cons (operator operand (coord-x coordinate)) + (operator operand (coord-y coordinate))))) + +(define (coord-apply function coordinate) + (if (pair? function) + (cons + ((coord-x function) (coord-x coordinate)) + ((coord-y function) (coord-y coordinate))) + (cons + (function (coord-x coordinate)) + (function (coord-y coordinate))))) + +(define-public (coord-translate coordinate amount) + (coord-operation + amount coordinate)) + +(define-public (coord-scale coordinate amount) + (coord-operation * amount coordinate)) + +(define-public (coord-rotate coordinate degrees-in-radians) + (let* + ((coordinate + (cons + (exact->inexact (coord-x coordinate)) + (exact->inexact (coord-y coordinate)))) + (radius + (sqrt + (+ (* (coord-x coordinate) (coord-x coordinate)) + (* (coord-y coordinate) (coord-y coordinate))))) + (angle (angle-0-2pi (atan (coord-y coordinate) (coord-x coordinate))))) + (cons + (* radius (cos (+ angle degrees-in-radians))) + (* radius (sin (+ angle degrees-in-radians)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; trig + +(define-public PI (* 4 (atan 1))) + +(define-public TWO-PI (* 2 PI)) + +(define-public PI-OVER-TWO (/ PI 2)) + +(define-public THREE-PI-OVER-TWO (* 3 PI-OVER-TWO)) + +(define-public (cyclic-base-value value cycle) + "Takes a value and modulo-maps it between 0 and base." + (if (< value 0) + (cyclic-base-value (+ value cycle) cycle) + (if (>= value cycle) + (cyclic-base-value (- value cycle) cycle) + value))) + +(define-public (angle-0-2pi angle) + "Takes an angle in radians and maps it between 0 and 2pi." + (cyclic-base-value angle TWO-PI)) + +(define-public (angle-0-360 angle) + "Takes an angle in radians and maps it between 0 and 2pi." + (cyclic-base-value angle 360.0)) + +(define-public PI-OVER-180 (/ PI 180)) + +(define-public (degrees->radians angle-degrees) + "Convert the given angle from degrees to radians" + (* angle-degrees PI-OVER-180)) + +(define-public (ellipse-radius x-radius y-radius angle) + (/ + (* x-radius y-radius) + (sqrt + (+ (* (expt y-radius 2) + (* (cos angle) (cos angle))) + (* (expt x-radius 2) + (* (sin angle) (sin angle))))))) + +(define-public (polar->rectangular radius angle-in-degrees) + "Convert polar coordinate @code{radius} and @code{angle-in-degrees} + to (x-length . y-length)" + (let ((complex (make-polar + radius + (degrees->radians angle-in-degrees)))) + (cons + (real-part complex) + (imag-part complex)))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; string @@ -601,6 +761,9 @@ applied to function @var{getter}.") (define-public (car< a b) (< (car a) (car b))) +(define-public (car<= a b) + (<= (car a) (car b))) + (define-public (symbolstring lst) (symbol->string r))) @@ -609,8 +772,8 @@ applied to function @var{getter}.") (define-public (eval-carefully symbol module . default) "Check if all symbols in expr SYMBOL are reachable - in module MODULE. In that case evaluate, otherwise - print a warning and set an optional DEFAULT." +in module MODULE. In that case evaluate, otherwise +print a warning and set an optional DEFAULT." (let* ((unavailable? (lambda (sym) (not (module-defined? module sym)))) (sym-unavailable (if (pair? symbol) @@ -662,19 +825,11 @@ applied to function @var{getter}.") ;;; FONT may be font smob, or pango font string... (define-public (font-name-style font) - ;; FIXME: ughr, barf: feta-alphabet is actually emmentaler - (if (and (string? font) - (string-prefix? "feta-alphabet" font)) - (string-append "emmentaler" - "-" - (substring font - (string-length "feta-alphabet") - (string-length font))) + (if (string? font) + (string-downcase font) (let* ((font-name (ly:font-name font)) (full-name (if font-name font-name (ly:font-file-name font)))) - (if (string-prefix? "Aybabtu" full-name) - "aybabtu" - (string-downcase full-name))))) + (string-downcase full-name)))) (define-public (modified-font-metric-font-scaling font) (let* ((designsize (ly:font-design-size font))