]> git.donarmstrong.com Git - lilypond.git/blob - scm/lily-library.scm
Merge branch 'master' of git://git.sv.gnu.org/lilypond
[lilypond.git] / scm / lily-library.scm
1 ;;;;
2 ;;;; lily-library.scm -- utilities
3 ;;;;
4 ;;;;  source file of the GNU LilyPond music typesetter
5 ;;;; 
6 ;;;; (c) 1998--2006 Jan Nieuwenhuizen <janneke@gnu.org>
7 ;;;; Han-Wen Nienhuys <hanwen@xs4all.nl>
8
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10 ;; constants.
11
12 (define-public X 0)
13 (define-public Y 1)
14 (define-safe-public START -1)
15 (define-safe-public STOP 1)
16 (define-public LEFT -1)
17 (define-public RIGHT 1)
18 (define-public UP 1)
19 (define-public DOWN -1)
20 (define-public CENTER 0)
21
22 (define-safe-public DOUBLE-FLAT-QTS -4)
23 (define-safe-public THREE-Q-FLAT-QTS -3)
24 (define-safe-public FLAT-QTS -2)
25 (define-safe-public SEMI-FLAT-QTS -1)
26 (define-safe-public NATURAL-QTS 0)
27 (define-safe-public SEMI-SHARP-QTS 1)
28 (define-safe-public SHARP-QTS 2)
29 (define-safe-public THREE-Q-SHARP-QTS 3)
30 (define-safe-public DOUBLE-SHARP-QTS 4)
31 (define-safe-public SEMI-TONE-QTS 2)
32
33 (define-safe-public DOUBLE-FLAT  -1)
34 (define-safe-public THREE-Q-FLAT -3/4)
35 (define-safe-public FLAT -1/2)
36 (define-safe-public SEMI-FLAT -1/4)
37 (define-safe-public NATURAL 0)
38 (define-safe-public SEMI-SHARP 1/4)
39 (define-safe-public SHARP 1/2)
40 (define-safe-public THREE-Q-SHARP 3/4)
41 (define-safe-public DOUBLE-SHARP 1)
42 (define-safe-public SEMI-TONE 1/2)
43
44 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45 ;; moments
46
47 (define-public ZERO-MOMENT (ly:make-moment 0 1)) 
48
49 (define-public (moment-min a b)
50   (if (ly:moment<? a b) a b))
51
52
53 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
54 ;; arithmetic
55 (define-public (average x . lst)
56   (/ (+ x (apply + lst)) (1+ (length lst))))
57
58 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
59 ;; lily specific variables.
60
61 (define-public default-script-alist '())
62
63
64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
65 ;; parser <-> output hooks.
66
67 ;; parser stuff.
68 (define-public (print-music-as-book parser music)
69   (let* ((head (ly:parser-lookup parser '$defaultheader))
70          (book (ly:make-book (ly:parser-lookup parser '$defaultpaper)
71                              head (scorify-music music parser))))
72     (print-book-with-defaults parser book)))
73
74 (define-public (print-score-as-book parser score)
75   (let* ((head (ly:parser-lookup parser '$defaultheader))
76          (book (ly:make-book (ly:parser-lookup parser '$defaultpaper)
77                              head score)))
78     (print-book-with-defaults parser book)))
79
80 (define-public (print-score parser score)
81   (let* ((head (ly:parser-lookup parser '$defaultheader))
82          (book (ly:make-book (ly:parser-lookup parser '$defaultpaper)
83                              head score)))
84     (ly:parser-print-score parser book)))
85                 
86 (define-public (collect-scores-for-book parser score)
87   (ly:parser-define!
88    parser 'toplevel-scores
89    (cons score (ly:parser-lookup parser 'toplevel-scores))))
90
91 (define-public (scorify-music music parser)
92   
93   (for-each (lambda (func)
94               (set! music (func music parser)))
95             toplevel-music-functions)
96
97   (ly:make-score music))
98
99 (define-public (collect-music-for-book parser music)
100   ;; discard music if its 'void property is true.
101   (let ((void-music (ly:music-property music 'void)))
102     (if (or (null? void-music) (not void-music))
103         (collect-scores-for-book parser (scorify-music music parser)))))
104
105
106 (define-public (print-book-with-defaults parser book)
107   (let*
108       ((paper (ly:parser-lookup parser '$defaultpaper))
109        (layout (ly:parser-lookup parser '$defaultlayout))
110        (count (ly:parser-lookup parser 'output-count))
111        (base (ly:parser-output-name parser)))
112
113     (if (not (integer? count))
114         (set! count 0))
115
116     (if (> count 0)
117         (set! base (format #f "~a-~a" base count)))
118
119     (ly:parser-define! parser 'output-count (1+ count))
120     (ly:book-process book paper layout base)
121     ))
122
123 (define-public (print-score-with-defaults parser score)
124   (let*
125       ((paper (ly:parser-lookup parser '$defaultpaper))
126        (count (ly:parser-lookup parser 'output-count))
127        (base (ly:parser-output-name parser)))
128
129     (if (not (integer? count))
130         (set! count 0))
131
132     (if (> count 0)
133         (set! base (format #f "~a-~a" base count)))
134
135     (ly:parser-define! parser 'output-count (1+ count))
136
137     (if (not (ly:score-error? score))
138         (let*
139             ((header (ly:score-header score))
140              (output-defs (ly:score-output-defs score))
141              (layout-defs (filter  (lambda (d) (eq? #t (ly:output-def-lookup d 'is-layout)))
142                                   output-defs))
143              (midi-defs (filter (lambda (d)  (eq? #t (ly:output-def-lookup d 'is-midi)))
144                                 output-defs))
145              (music (ly:score-music score))
146              (layout-def (if (null? layout-defs)
147                              (ly:parser-lookup parser '$defaultlayout)
148                              (car layout-defs))))
149
150           (if (not (module? header))
151               (set! header (ly:parser-lookup parser '$defaultheader)))
152              
153           (ly:render-music-as-systems
154            music layout-def paper header base)
155
156           (if (pair? midi-defs)
157               (ly:performance-write (ly:format-output (ly:run-translator music (car midi-defs)))
158                                     (format #f "~a.midi" base)
159                                     ))
160               
161     ))))
162
163
164
165
166
167 ;;;;;;;;;;;;;;;;
168 ;; alist
169
170 (define-public assoc-get ly:assoc-get)
171
172 (define-public (uniqued-alist alist acc)
173   (if (null? alist) acc
174       (if (assoc (caar alist) acc)
175           (uniqued-alist (cdr alist) acc)
176           (uniqued-alist (cdr alist) (cons (car alist) acc)))))
177
178 (define-public (alist<? x y)
179   (string<? (symbol->string (car x))
180             (symbol->string (car y))))
181
182 (define-public (chain-assoc x alist-list)
183   (if (null? alist-list)
184       #f
185       (let* ((handle (assoc x (car alist-list))))
186         (if (pair? handle)
187             handle
188             (chain-assoc x (cdr alist-list))))))
189
190 (define-public (chain-assoc-get x alist-list . default)
191   "Return ALIST entry for X. Return DEFAULT (optional, else #f) if not
192 found."
193
194   (define (helper x alist-list default)
195     (if (null? alist-list)
196         default
197         (let* ((handle (assoc x (car alist-list))))
198           (if (pair? handle)
199               (cdr handle)
200               (helper x (cdr alist-list) default)))))
201
202   (helper x alist-list
203           (if (pair? default) (car default) #f)))
204
205 (define (map-alist-vals func list)
206   "map FUNC over the vals of  LIST, leaving the keys."
207   (if (null?  list)
208       '()
209       (cons (cons  (caar list) (func (cdar list)))
210             (map-alist-vals func (cdr list)))))
211
212 (define (map-alist-keys func list)
213   "map FUNC over the keys of an alist LIST, leaving the vals. "
214   (if (null?  list)
215       '()
216       (cons (cons (func (caar list)) (cdar list))
217             (map-alist-keys func (cdr list)))))
218
219 (define-public (first-member members lst)
220   "Return first successful MEMBER of member from MEMBERS in LST."
221   (if (null? members)
222       #f
223       (let ((m (member (car members) lst)))
224         (if m m (first-member (cdr members) lst)))))
225
226 (define-public (first-assoc keys lst)
227   "Return first successful ASSOC of key from KEYS in LST."
228   (if (null? keys)
229       #f
230       (let ((k (assoc (car keys) lst)))
231         (if k k (first-assoc (cdr keys) lst)))))
232
233 (define-public (flatten-alist alist)
234   (if (null? alist)
235       '()
236       (cons (caar alist)
237             (cons (cdar alist)
238                   (flatten-alist (cdr alist))))))
239
240 ;;;;;;;;;;;;;;;;
241 ;; vector
242
243 (define-public (vector-for-each proc vec)
244   (do
245       ((i 0 (1+ i)))
246       ((>= i (vector-length vec)) vec)
247     (vector-set! vec i (proc (vector-ref vec i)))))
248
249 ;;;;;;;;;;;;;;;;
250 ;; hash
251
252 (if (not (defined? 'hash-table?)) ;; guile 1.6 compat
253     (begin
254       (define hash-table? vector?)
255       (define-public (hash-for-each proc tab)
256         (hash-fold (lambda (k v prior)
257                      (proc k v)
258                      #f)
259                    #f
260                    tab))
261       (define-public (hash-table->alist t)
262         "Convert table t to list"
263         (apply append (vector->list t))))
264
265     ;; native hashtabs.
266     (begin
267       (define-public (hash-table->alist t)
268         (hash-fold (lambda (k v acc) (acons  k v  acc))
269                    '() t))))
270
271 ;; todo: code dup with C++. 
272 (define-safe-public (alist->hash-table lst)
273   "Convert alist to table"
274   (let ((m (make-hash-table (length lst))))
275     (map (lambda (k-v) (hashq-set! m (car k-v) (cdr k-v))) lst)
276     m))
277
278 ;;;;;;;;;;;;;;;;
279 ;; list
280
281 (define (functional-or . rest)
282   (if (pair? rest)
283       (or (car rest)
284            (apply functional-and (cdr rest)))
285       #f))
286
287 (define (functional-and . rest)
288   (if (pair? rest)
289       (and (car rest)
290            (apply functional-and (cdr rest)))
291       #t))
292
293 (define (split-list lst n)
294   "Split LST in N equal sized parts"
295   
296   (define (helper todo acc-vector k)
297     (if (null? todo)
298         acc-vector
299         (begin
300           (if (< k 0)
301               (set! k (+ n k)))
302             
303           (vector-set! acc-vector k (cons (car todo) (vector-ref acc-vector k)))
304           (helper (cdr todo) acc-vector (1- k)))))
305
306   (helper lst (make-vector n '()) (1- n)))
307
308 (define (list-element-index lst x)
309   (define (helper todo k)
310     (cond
311      ((null? todo) #f)
312      ((equal? (car todo) x) k)
313      (else
314       (helper (cdr todo) (1+ k)))))
315
316   (helper lst 0))
317
318 (define-public (count-list lst)
319   "Given lst (E1 E2 .. ) return ((E1 . 1) (E2 . 2) ... )  "
320
321   (define (helper l acc count)
322     (if (pair? l)
323         (helper (cdr l) (cons (cons (car l) count) acc) (1+ count))
324         acc))
325
326
327   (reverse (helper lst '() 1)))
328   
329 (define-public (list-join lst intermediate)
330   "put INTERMEDIATE  between all elts of LST."
331
332   (fold-right
333    (lambda (elem prev)
334             (if (pair? prev)
335                 (cons  elem (cons intermediate prev))
336                 (list elem)))
337           '() lst))
338
339 (define-public (filtered-map proc lst)
340   (filter
341    (lambda (x) x)
342    (map proc lst)))
343
344
345 (define (flatten-list lst)
346   "Unnest LST" 
347   (if (null? lst)
348       '()
349       (if (pair? (car lst))
350           (append (flatten-list (car lst)) (flatten-list  (cdr lst)))
351           (cons (car lst) (flatten-list (cdr lst))))))
352
353 (define (list-minus a b)
354   "Return list of elements in A that are not in B."
355   (lset-difference eq? a b))
356
357 (define-public (uniq-list lst)
358   "Uniq LST, assuming that it is sorted"
359
360   (reverse! 
361    (fold (lambda (x acc)
362            (if (null? acc)
363                (list x)
364                (if (eq? x (car acc))
365                    acc
366                    (cons x acc))))
367          '() lst) '()))
368
369 (define (split-at-predicate predicate lst)
370  "Split LST = (a_1 a_2 ... a_k b_1 ... b_k)
371   into L1 = (a_1 ... a_k ) and L2 =(b_1 .. b_k) 
372   Such that (PREDICATE a_i a_{i+1}) and not (PREDICATE a_k b_1).
373   L1 is copied, L2 not.
374
375   (split-at-predicate (lambda (x y) (= (- y x) 2)) '(1 3 5 9 11) (cons '() '()))"
376  
377  ;; " Emacs is broken
378
379  (define (inner-split predicate lst acc)
380    (cond
381     ((null? lst) acc)
382     ((null? (cdr lst))
383      (set-car! acc (cons (car lst) (car acc)))
384      acc)
385     ((predicate (car lst) (cadr lst))
386      (set-car! acc (cons (car lst) (car acc)))
387      (inner-split predicate (cdr lst) acc))
388     (else
389      (set-car! acc (cons (car lst) (car acc)))
390      (set-cdr! acc (cdr lst))
391      acc)))
392  
393  (let* ((c (cons '() '())))
394    (inner-split predicate lst  c)
395    (set-car! c (reverse! (car c)))
396    c))
397
398 (define-public (split-list-by-separator lst sep?)
399    "(display (split-list-by-separator '(a b c / d e f / g) (lambda (x) (equal? x '/))))
400    =>
401    ((a b c) (d e f) (g))
402   "
403    ;; " Emacs is broken
404    (define (split-one sep?  lst acc)
405      "Split off the first parts before separator and return both parts."
406      (if (null? lst)
407          (cons acc '())
408          (if (sep? (car lst))
409              (cons acc (cdr lst))
410              (split-one sep? (cdr lst) (cons (car lst) acc)))))
411    
412    (if (null? lst)
413        '()
414        (let* ((c (split-one sep? lst '())))
415          (cons (reverse! (car c) '()) (split-list-by-separator (cdr c) sep?)))))
416
417 (define-public (offset-add a b)
418   (cons (+ (car a) (car b))
419         (+ (cdr a) (cdr b)))) 
420
421 (define-public (offset-flip-y o)
422   (cons (car o) (- (cdr o))))
423
424 (define-public (offset-scale o scale)
425   (cons (* (car o) scale)
426         (* (cdr o) scale)))
427
428 (define-public (ly:list->offsets accum coords)
429   (if (null? coords)
430       accum
431       (cons (cons (car coords) (cadr coords))
432             (ly:list->offsets accum (cddr coords)))))
433
434 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
435 ;; numbers
436
437 (if (not (defined? 'nan?)) ;; guile 1.6 compat
438     (define-public (nan? x) (not (or (< 0.0 x)
439                                      (> 0.0 x)
440                                      (= 0.0 x)))))
441
442 (if (not (defined? 'inf?))
443     (define-public (inf? x) (= (/ 1.0 x) 0.0)))
444
445 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
446 ;; intervals
447
448 (define-public (interval-length x)
449   "Length of the number-pair X, when an interval"
450   (max 0 (- (cdr x) (car x))))
451
452 (define-public interval-start car)
453 (define-public (ordered-cons a b)
454   (cons (min a b)
455         (max a b)))
456
457 (define-public interval-end cdr)
458
459 (define-public (interval-index interval dir)
460   "Interpolate INTERVAL between between left (DIR=-1) and right (DIR=+1)"
461   
462   (* (+  (interval-start interval) (interval-end interval)
463          (* dir (- (interval-end interval) (interval-start interval))))
464      0.5))
465
466 (define-public (interval-center x)
467   "Center the number-pair X, when an interval"
468   (if (interval-empty? x)
469       0.0
470       (/ (+ (car x) (cdr x)) 2)))
471
472 (define-public interval-start car)
473 (define-public interval-end cdr)
474 (define-public (interval-translate iv amount)
475   (cons (+ amount (car iv))
476         (+ amount (cdr iv))))
477
478 (define (other-axis a)
479   (remainder (+ a 1) 2))
480
481 (define-public (interval-widen iv amount)
482    (cons (- (car iv) amount)
483          (+ (cdr iv) amount)))
484
485
486 (define-public (interval-empty? iv)
487    (> (car iv) (cdr iv)))
488
489 (define-public (interval-union i1 i2)
490    (cons (min (car i1) (car i2))
491          (max (cdr i1) (cdr i2))))
492
493 (define-public (interval-sane? i)
494   (not (or  (nan? (car i))
495             (inf? (car i))
496             (nan? (cdr i))
497             (inf? (cdr i))
498             (> (car i) (cdr i)))))
499
500
501 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
502 ;;
503
504
505 (define-public (string-encode-integer i)
506   (cond
507    ((= i  0) "o")
508    ((< i 0)   (string-append "n" (string-encode-integer (- i))))
509    (else (string-append
510           (make-string 1 (integer->char (+ 65 (modulo i 26))))
511           (string-encode-integer (quotient i 26))))))
512
513 (define-public (ly:numbers->string lst)
514   (string-join (map ly:number->string lst) " "))
515
516 (define (number->octal-string x)
517   (let* ((n (inexact->exact x))
518          (n64 (quotient n 64))
519          (n8 (quotient (- n (* n64 64)) 8)))
520     (string-append
521      (number->string n64)
522      (number->string n8)
523      (number->string (remainder (- n (+ (* n64 64) (* n8 8))) 8)))))
524
525 (define-public (ly:inexact->string x radix)
526   (let ((n (inexact->exact x)))
527     (number->string n radix)))
528
529 (define-public (ly:number-pair->string c)
530   (string-append (ly:number->string (car c)) " "
531                  (ly:number->string (cdr c))))
532
533
534 (define-public (write-me message x)
535   "Return X.  Display MESSAGE and write X.  Handy for debugging,
536 possibly turned off."
537   (display message) (write x) (newline) x)
538 ;;  x)
539
540 (define-public (stderr string . rest)
541   (apply format (cons (current-error-port) (cons string rest)))
542   (force-output (current-error-port)))
543
544 (define-public (debugf string . rest)
545   (if #f
546       (apply stderr (cons string rest))))
547
548 (define (index-cell cell dir)
549   (if (equal? dir 1)
550       (cdr cell)
551       (car cell)))
552
553 (define (cons-map f x)
554   "map F to contents of X"
555   (cons (f (car x)) (f (cdr x))))
556
557 (define-public (list-insert-separator lst between)
558   "Create new list, inserting BETWEEN between elements of LIST"
559   (define (conc x y )
560     (if (eq? y #f)
561         (list x)
562         (cons x  (cons between y))))
563   (fold-right conc #f lst))
564
565 (define-public (string-regexp-substitute a b str)
566   (regexp-substitute/global #f a str 'pre b 'post)) 
567
568 (define (regexp-split str regex)
569   (define matches '())
570   (define end-of-prev-match 0)
571   (define (notice match)
572
573     (set! matches (cons (substring (match:string match)
574                                    end-of-prev-match
575                                    (match:start match))
576                         matches))
577     (set! end-of-prev-match (match:end match)))
578
579   (regexp-substitute/global #f regex str notice 'post)
580
581   (if (< end-of-prev-match (string-length str))
582       (set!
583        matches
584        (cons (substring str end-of-prev-match (string-length str)) matches)))
585
586    (reverse matches))
587
588 ;;;;;;;;;;;;;;;;
589 ; other
590 (define (sign x)
591   (if (= x 0)
592       0
593       (if (< x 0) -1 1)))
594
595 (define-public (car< a b) (< (car a) (car b)))
596
597 (define-public (symbol<? lst r)
598   (string<? (symbol->string lst) (symbol->string r)))
599
600 (define-public (symbol-key<? lst r)
601   (string<? (symbol->string (car lst)) (symbol->string (car r))))
602
603 ;;
604 ;; don't confuse users with #<procedure .. > syntax. 
605 ;; 
606 (define-public (scm->string val)
607   (if (and (procedure? val) (symbol? (procedure-name val)))
608       (symbol->string (procedure-name val))
609       (string-append
610        (if (self-evaluating? val) "" "'")
611        (call-with-output-string (lambda (port) (display val port))))))
612
613 (define-public (!= lst r)
614   (not (= lst r)))
615
616 (define-public lily-unit->bigpoint-factor
617   (cond
618    ((equal? (ly:unit) "mm") (/ 72.0 25.4))
619    ((equal? (ly:unit) "pt") (/ 72.0 72.27))
620    (else (ly:error (_ "unknown unit: ~S") (ly:unit)))))
621
622 (define-public lily-unit->mm-factor
623   (* 25.4 (/ lily-unit->bigpoint-factor 72)))
624
625 ;;; FONT may be font smob, or pango font string...
626 (define-public (font-name-style font)
627       ;; FIXME: ughr, (ly:font-name) sometimes also has Style appended.
628       (let* ((font-name (ly:font-name font))
629              (full-name (if font-name font-name (ly:font-file-name font)))
630              (name-style (string-split full-name #\-)))
631         ;; FIXME: ughr, barf: feta-alphabet is actually emmentaler
632         (if (string-prefix? "feta-alphabet" full-name)
633             (list "emmentaler"
634                   (substring  full-name (string-length "feta-alphabet")))
635             (if (not (null? (cdr name-style)))
636             name-style
637             (append name-style '("Regular"))))))
638
639 (define-public (modified-font-metric-font-scaling font)
640   (let* ((designsize (ly:font-design-size font))
641          (magnification (* (ly:font-magnification font)))
642          (scaling (* magnification designsize)))
643     (debugf "scaling:~S\n" scaling)
644     (debugf "magnification:~S\n" magnification)
645     (debugf "design:~S\n" designsize)
646     scaling))
647
648 (define-public (version-not-seen-message input-file-name)
649   (ly:message
650    (string-append
651     input-file-name ": 0: " (_ "warning: ")
652    (format #f
653            (_ "no \\version statement found, please add~afor future compatibility")
654            (format #f "\n\n\\version ~s\n\n" (lilypond-version))))))
655
656 (define-public (old-relative-not-used-message input-file-name)
657   (ly:message
658    (string-append
659     input-file-name ": 0: " (_ "warning: ")
660     (_ "old relative compatibility not used"))))