]> git.donarmstrong.com Git - lilypond.git/blob - scm/lily-library.scm
Issue 3580: Replace unwarranted uses of map with for-each and other Scheme cleanups
[lilypond.git] / scm / lily-library.scm
1 ;;;; This file is part of LilyPond, the GNU music typesetter.
2 ;;;;
3 ;;;; Copyright (C) 1998--2012 Jan Nieuwenhuizen <janneke@gnu.org>
4 ;;;; Han-Wen Nienhuys <hanwen@xs4all.nl>
5 ;;;;
6 ;;;; LilyPond is free software: you can redistribute it and/or modify
7 ;;;; it under the terms of the GNU General Public License as published by
8 ;;;; the Free Software Foundation, either version 3 of the License, or
9 ;;;; (at your option) any later version.
10 ;;;;
11 ;;;; LilyPond is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ;;;; GNU General Public License for more details.
15 ;;;;
16 ;;;; You should have received a copy of the GNU General Public License
17 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18
19 ;; for take, drop, take-while, list-index, and find-tail:
20 (use-modules (srfi srfi-1))
21
22 ;; for define-safe-public when byte-compiling using Guile V2
23 (use-modules (scm safe-utility-defs))
24
25 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26 ;; constants.
27
28 (define-public X 0)
29 (define-public Y 1)
30 (define-safe-public START -1)
31 (define-safe-public STOP 1)
32 (define-public LEFT -1)
33 (define-public RIGHT 1)
34 (define-public UP 1)
35 (define-public DOWN -1)
36 (define-public CENTER 0)
37
38 (define-safe-public DOUBLE-FLAT-QTS -4)
39 (define-safe-public THREE-Q-FLAT-QTS -3)
40 (define-safe-public FLAT-QTS -2)
41 (define-safe-public SEMI-FLAT-QTS -1)
42 (define-safe-public NATURAL-QTS 0)
43 (define-safe-public SEMI-SHARP-QTS 1)
44 (define-safe-public SHARP-QTS 2)
45 (define-safe-public THREE-Q-SHARP-QTS 3)
46 (define-safe-public DOUBLE-SHARP-QTS 4)
47 (define-safe-public SEMI-TONE-QTS 2)
48
49 (define-safe-public DOUBLE-FLAT  -1)
50 (define-safe-public THREE-Q-FLAT -3/4)
51 (define-safe-public FLAT -1/2)
52 (define-safe-public SEMI-FLAT -1/4)
53 (define-safe-public NATURAL 0)
54 (define-safe-public SEMI-SHARP 1/4)
55 (define-safe-public SHARP 1/2)
56 (define-safe-public THREE-Q-SHARP 3/4)
57 (define-safe-public DOUBLE-SHARP 1)
58 (define-safe-public SEMI-TONE 1/2)
59
60 (define-safe-public INFINITY-INT 1000000)
61
62 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
63 ;; moments
64
65 (define-public ZERO-MOMENT (ly:make-moment 0 1))
66
67 (define-public (moment-min a b)
68   (if (ly:moment<? a b) a b))
69
70 (define-public (moment<=? a b)
71   (or (equal? a b)
72       (ly:moment<? a b)))
73
74 (define-public (fraction->moment fraction)
75   (if (null? fraction)
76       ZERO-MOMENT
77       (ly:make-moment (car fraction) (cdr fraction))))
78
79 (define-public (moment->fraction moment)
80   (cons (ly:moment-main-numerator moment)
81         (ly:moment-main-denominator moment)))
82
83 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
84 ;; durations
85
86 (define-public (duration-log-factor lognum)
87   "Given a logarithmic duration number, return the length of the duration,
88 as a number of whole notes."
89   (or (and (exact? lognum) (integer? lognum))
90       (scm-error 'wrong-type-arg "duration-log-factor" "Not an integer: ~S" (list lognum) #f))
91   (if (<= lognum 0)
92       (ash 1 (- lognum))
93       (/ (ash 1 lognum))))
94
95 (define-public (duration-dot-factor dotcount)
96   "Given a count of the dots used to extend a musical duration, return
97 the numeric factor by which they increase the duration."
98   (or (and (exact? dotcount) (integer? dotcount) (>= dotcount 0))
99       (scm-error 'wrong-type-arg "duration-dot-factor" "Not a count: ~S" (list dotcount) #f))
100   (- 2 (/ (ash 1 dotcount))))
101
102 (define-public (duration-length dur)
103   "Return the overall length of a duration, as a number of whole
104 notes.  (Not to be confused with ly:duration-length, which returns a
105 less-useful moment object.)"
106   (ly:moment-main (ly:duration-length dur)))
107
108 (define-public (duration-visual dur)
109   "Given a duration object, return the visual part of the duration (base
110 note length and dot count), in the form of a duration object with
111 non-visual scale factor 1."
112   (ly:make-duration (ly:duration-log dur) (ly:duration-dot-count dur) 1))
113
114 (define-public (duration-visual-length dur)
115   "Given a duration object, return the length of the visual part of the
116 duration (base note length and dot count), as a number of whole notes."
117   (duration-length (duration-visual dur)))
118
119 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
120 ;; arithmetic
121 (define-public (average x . lst)
122   (/ (+ x (apply + lst)) (1+ (length lst))))
123
124 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
125 ;; parser <-> output hooks.
126
127 (define-public (collect-bookpart-for-book parser book-part)
128   "Toplevel book-part handler."
129   (define (add-bookpart book-part)
130     (ly:parser-define!
131      parser 'toplevel-bookparts
132      (cons book-part (ly:parser-lookup parser 'toplevel-bookparts))))
133   ;; If toplevel scores have been found before this \bookpart,
134   ;; add them first to a dedicated bookpart
135   (if (pair? (ly:parser-lookup parser 'toplevel-scores))
136       (begin
137         (add-bookpart (ly:make-book-part
138                        (ly:parser-lookup parser 'toplevel-scores)))
139         (ly:parser-define! parser 'toplevel-scores (list))))
140   (add-bookpart book-part))
141
142 (define-public (collect-scores-for-book parser score)
143   (ly:parser-define!
144    parser 'toplevel-scores
145    (cons score (ly:parser-lookup parser 'toplevel-scores))))
146
147 (define-public (collect-music-aux score-handler parser music)
148   (define (music-property symbol)
149     (ly:music-property music symbol #f))
150   (cond ((music-property 'page-marker)
151          ;; a page marker: set page break/turn permissions or label
152          (let ((label (music-property 'page-label)))
153            (if (symbol? label)
154                (score-handler (ly:make-page-label-marker label))))
155          (for-each (lambda (symbol)
156                      (let ((permission (music-property symbol)))
157                        (if (symbol? permission)
158                            (score-handler
159                             (ly:make-page-permission-marker symbol
160                                                             (if (eq? 'forbid permission)
161                                                                 '()
162                                                                 permission))))))
163                    '(line-break-permission page-break-permission
164                                            page-turn-permission)))
165         ((not (music-property 'void))
166          ;; a regular music expression: make a score with this music
167          ;; void music is discarded
168          (score-handler (scorify-music music parser)))))
169
170 (define-public (collect-music-for-book parser music)
171   "Top-level music handler."
172   (collect-music-aux (lambda (score)
173                        (collect-scores-for-book parser score))
174                      parser
175                      music))
176
177 (define-public (collect-book-music-for-book parser book music)
178   "Book music handler."
179   (collect-music-aux (lambda (score)
180                        (ly:book-add-score! book score))
181                      parser
182                      music))
183
184 (define-public (scorify-music music parser)
185   "Preprocess @var{music}."
186   (ly:make-score
187    (fold (lambda (f m) (f m parser))
188          music
189          toplevel-music-functions)))
190
191 (define (get-current-filename parser book)
192   "return any suffix value for output filename allowing for settings by
193 calls to bookOutputName function"
194   (or (paper-variable parser book 'output-filename)
195       (ly:parser-output-name parser)))
196
197 (define (get-current-suffix parser book)
198   "return any suffix value for output filename allowing for settings by calls to
199 bookoutput function"
200   (let ((book-output-suffix (paper-variable parser book 'output-suffix)))
201     (if (not (string? book-output-suffix))
202         (ly:parser-lookup parser 'output-suffix)
203         book-output-suffix)))
204
205 (define-public current-outfile-name #f)  ; for use by regression tests
206
207 (define (get-outfile-name parser book)
208   "return current filename for generating backend output files"
209   ;; user can now override the base file name, so we have to use
210   ;; the file-name concatenated with any potential output-suffix value
211   ;; as the key to out internal a-list
212   (let* ((base-name (get-current-filename parser book))
213          (output-suffix (get-current-suffix parser book))
214          (alist-key (format #f "~a~a" base-name output-suffix))
215          (counter-alist (ly:parser-lookup parser 'counter-alist))
216          (output-count (assoc-get alist-key counter-alist 0))
217          (result base-name))
218     ;; Allow all ASCII alphanumerics, including accents
219     (if (string? output-suffix)
220         (set! result
221               (format #f "~a-~a"
222                       result
223                       (string-regexp-substitute
224                        "[^-[:alnum:]]"
225                        "_"
226                        output-suffix))))
227
228     ;; assoc-get call will always have returned a number
229     (if (> output-count 0)
230         (set! result (format #f "~a-~a" result output-count)))
231
232     (ly:parser-define!
233      parser 'counter-alist
234      (assoc-set! counter-alist alist-key (1+ output-count)))
235     (set! current-outfile-name result)
236     result))
237
238 (define (print-book-with parser book process-procedure)
239   (let* ((paper (ly:parser-lookup parser '$defaultpaper))
240          (layout (ly:parser-lookup parser '$defaultlayout))
241          (outfile-name (get-outfile-name parser book)))
242     (process-procedure book paper layout outfile-name)))
243
244 (define-public (print-book-with-defaults parser book)
245   (print-book-with parser book ly:book-process))
246
247 (define-public (print-book-with-defaults-as-systems parser book)
248   (print-book-with parser book ly:book-process-to-systems))
249
250 ;; Add a score to the current bookpart, book or toplevel
251 (define-public (add-score parser score)
252   (cond
253    ((ly:parser-lookup parser '$current-bookpart)
254     ((ly:parser-lookup parser 'bookpart-score-handler)
255      (ly:parser-lookup parser '$current-bookpart) score))
256    ((ly:parser-lookup parser '$current-book)
257     ((ly:parser-lookup parser 'book-score-handler)
258      (ly:parser-lookup parser '$current-book) score))
259    (else
260     ((ly:parser-lookup parser 'toplevel-score-handler) parser score))))
261
262 (define-public paper-variable
263   (let
264       ((get-papers
265         (lambda (parser book)
266           (append (if (and book (ly:output-def? (ly:book-paper book)))
267                       (list (ly:book-paper book))
268                       '())
269                   (ly:parser-lookup parser '$papers)
270                   (list (ly:parser-lookup parser '$defaultpaper))))))
271     (make-procedure-with-setter
272      (lambda (parser book symbol)
273        (any (lambda (p) (ly:output-def-lookup p symbol #f))
274             (get-papers parser book)))
275      (lambda (parser book symbol value)
276        (ly:output-def-set-variable!
277         (car (get-papers parser book))
278         symbol value)))))
279
280 (define-public (add-text parser text)
281   (add-score parser (list text)))
282
283 (define-public (add-music parser music)
284   (collect-music-aux (lambda (score)
285                        (add-score parser score))
286                      parser
287                      music))
288
289 (define-public (context-mod-from-music parser music)
290   (let ((warn #t) (mods (ly:make-context-mod)))
291     (let loop ((m music))
292       (if (music-is-of-type? m 'layout-instruction-event)
293           (let ((symbol (ly:music-property m 'symbol)))
294             (ly:add-context-mod
295              mods
296              (case (ly:music-property m 'name)
297                ((PropertySet)
298                 (list 'assign
299                       symbol
300                       (ly:music-property m 'value)))
301                ((PropertyUnset)
302                 (list 'unset symbol))
303                ((OverrideProperty)
304                 (cons* 'push
305                        symbol
306                        (ly:music-property m 'grob-value)
307                        (cond
308                         ((ly:music-property m 'grob-property #f) => list)
309                         (else
310                          (ly:music-property m 'grob-property-path)))))
311                ((RevertProperty)
312                 (cons* 'pop
313                        symbol
314                        (cond
315                         ((ly:music-property m 'grob-property #f) => list)
316                         (else
317                          (ly:music-property m 'grob-property-path))))))))
318           (case (ly:music-property m 'name)
319             ((ApplyContext)
320              (ly:add-context-mod mods
321                                  (list 'apply
322                                        (ly:music-property m 'procedure))))
323             ((ContextSpeccedMusic)
324              (loop (ly:music-property m 'element)))
325             (else
326              (let ((callback (ly:music-property m 'elements-callback)))
327                (if (procedure? callback)
328                    (for-each loop (callback m))
329                    (if (and warn (ly:duration? (ly:music-property m 'duration)))
330                        (begin
331                          (ly:music-warning
332                           music
333                           (_ "Music unsuitable for context-mod"))
334                          (set! warn #f)))))))))
335     mods))
336
337 (define-public (context-defs-from-music parser output-def music)
338   (let ((warn #t))
339     (let loop ((m music) (mods #f))
340       ;; The parser turns all sets, overrides etc into something
341       ;; wrapped in ContextSpeccedMusic.  If we ever get a set,
342       ;; override etc that is not wrapped in ContextSpeccedMusic, the
343       ;; user has created it in Scheme himself without providing the
344       ;; required wrapping.  In that case, using #f in the place of a
345       ;; context modification results in a reasonably recognizable
346       ;; error.
347       (if (music-is-of-type? m 'layout-instruction-event)
348           (ly:add-context-mod
349            mods
350            (case (ly:music-property m 'name)
351              ((PropertySet)
352               (list 'assign
353                     (ly:music-property m 'symbol)
354                     (ly:music-property m 'value)))
355              ((PropertyUnset)
356               (list 'unset
357                     (ly:music-property m 'symbol)))
358              ((OverrideProperty)
359               (cons* 'push
360                      (ly:music-property m 'symbol)
361                      (ly:music-property m 'grob-value)
362                      (cond
363                       ((ly:music-property m 'grob-property #f) => list)
364                       (else
365                        (ly:music-property m 'grob-property-path)))))
366              ((RevertProperty)
367               (cons* 'pop
368                      (ly:music-property m 'symbol)
369                      (cond
370                       ((ly:music-property m 'grob-property #f) => list)
371                       (else
372                        (ly:music-property m 'grob-property-path)))))))
373           (case (ly:music-property m 'name)
374             ((ApplyContext)
375              (ly:add-context-mod mods
376                                  (list 'apply
377                                        (ly:music-property m 'procedure))))
378             ((ContextSpeccedMusic)
379              ;; Use let* here to let defs catch up with modifications
380              ;; to the context defs made in the recursion
381              (let* ((mods (loop (ly:music-property m 'element)
382                                 (ly:make-context-mod)))
383                     (defs (ly:output-find-context-def
384                            output-def (ly:music-property m 'context-type))))
385                (if (null? defs)
386                    (ly:music-warning
387                     music
388                     (ly:format (_ "Cannot find context-def \\~a")
389                                (ly:music-property m 'context-type)))
390                    (for-each
391                     (lambda (entry)
392                       (ly:output-def-set-variable!
393                        output-def (car entry)
394                        (ly:context-def-modify (cdr entry) mods)))
395                     defs))))
396             (else
397              (let ((callback (ly:music-property m 'elements-callback)))
398                (if (procedure? callback)
399                    (fold loop mods (callback m))
400                    (if (and warn (ly:duration? (ly:music-property m 'duration)))
401                        (begin
402                          (ly:music-warning
403                           music
404                           (_ "Music unsuitable for output-def"))
405                          (set! warn #f))))))))
406       mods)))
407
408
409 ;;;;;;;;;;;;;;;;
410 ;; alist
411
412 (define-public assoc-get ly:assoc-get)
413
414 (define-public chain-assoc-get ly:chain-assoc-get)
415
416 (define-public (uniqued-alist alist acc)
417   (if (null? alist) acc
418       (if (assoc (caar alist) acc)
419           (uniqued-alist (cdr alist) acc)
420           (uniqued-alist (cdr alist) (cons (car alist) acc)))))
421
422 (define-public (alist<? x y)
423   (string<? (symbol->string (car x))
424             (symbol->string (car y))))
425
426 (define (map-alist-vals func list)
427   "map FUNC over the vals of LIST, leaving the keys."
428   (if (null?  list)
429       '()
430       (cons (cons  (caar list) (func (cdar list)))
431             (map-alist-vals func (cdr list)))))
432
433 (define (map-alist-keys func list)
434   "map FUNC over the keys of an alist LIST, leaving the vals."
435   (if (null?  list)
436       '()
437       (cons (cons (func (caar list)) (cdar list))
438             (map-alist-keys func (cdr list)))))
439
440 (define-public (first-member members lst)
441   "Return first successful member (of member) from @var{members} in
442 @var{lst}."
443   (any (lambda (m) (member m lst)) members))
444
445 (define-public (first-assoc keys lst)
446   "Return first successful assoc of key from @var{keys} in @var{lst}."
447   (any (lambda (k) (assoc k lst)) keys))
448
449 (define-public (flatten-alist alist)
450   (if (null? alist)
451       '()
452       (cons (caar alist)
453             (cons (cdar alist)
454                   (flatten-alist (cdr alist))))))
455
456 (define-public (map-selected-alist-keys function keys alist)
457   "Return @var{alist} with @var{function} applied to all of the values
458 in list @var{keys}.
459
460 For example:
461 @example
462 @code{guile> (map-selected-alist-keys - '(a b) '((a . 1) (b . -2) (c . 3) (d . 4)))}
463 @code{((a . -1) (b . 2) (c . 3) (d . 4)}
464 @end example"
465   (define (map-selected-alist-keys-helper key alist)
466     (map
467      (lambda (pair)
468        (if (equal? key (car pair))
469            (cons key (function (cdr pair)))
470            pair))
471      alist))
472   (fold map-selected-alist-keys-helper alist keys))
473
474 ;;;;;;;;;;;;;;;;
475 ;; vector
476
477 (define-public (vector-for-each proc vec)
478   (do
479       ((i 0 (1+ i)))
480       ((>= i (vector-length vec)) vec)
481     (vector-set! vec i (proc (vector-ref vec i)))))
482
483 ;;;;;;;;;;;;;;;;
484 ;; hash
485
486 (define-public (hash-table->alist t)
487   (hash-fold acons '() t))
488
489 ;; todo: code dup with C++.
490 (define-safe-public (alist->hash-table lst)
491   "Convert alist to table"
492   (let ((m (make-hash-table (length lst))))
493     (for-each (lambda (k-v) (hashq-set! m (car k-v) (cdr k-v))) lst)
494     m))
495
496 ;;;;;;;;;;;;;;;;
497 ;; list
498
499 (define (functional-or . rest)
500   (any identity rest))
501
502 (define (functional-and . rest)
503   (every identity rest))
504
505 (define (split-list lst n)
506   "Split LST in N equal sized parts"
507
508   (define (helper todo acc-vector k)
509     (if (null? todo)
510         acc-vector
511         (begin
512           (if (< k 0)
513               (set! k (+ n k)))
514
515           (vector-set! acc-vector k (cons (car todo) (vector-ref acc-vector k)))
516           (helper (cdr todo) acc-vector (1- k)))))
517
518   (helper lst (make-vector n '()) (1- n)))
519
520 (define (list-element-index lst x)
521   (list-index (lambda (m) (equal? m x)) lst))
522
523 (define-public (count-list lst)
524   "Given @var{lst} as @code{(E1 E2 .. )}, return
525 @code{((E1 . 1) (E2 . 2) ... )}."
526   (map cons lst (iota (length lst) 1)))
527
528 (define-public (list-join lst intermediate)
529   "Put @var{intermediate} between all elts of @var{lst}."
530
531   (fold-right
532    (lambda (elem prev)
533      (if (pair? prev)
534          (cons  elem (cons intermediate prev))
535          (list elem)))
536    '() lst))
537
538 (define-public filtered-map filter-map)
539
540 (define-public (flatten-list x)
541   "Unnest list."
542   (let loop ((x x) (tail '()))
543     (cond ((list? x) (fold-right loop tail x))
544           ((not (pair? x)) (cons x tail))
545           (else (loop (car x) (loop (cdr x) tail))))))
546
547 (define (list-minus a b)
548   "Return list of elements in A that are not in B."
549   (lset-difference eq? a b))
550
551 (define-public (uniq-list lst)
552   "Uniq @var{lst}, assuming that it is sorted.  Uses @code{equal?}
553 for comparisons."
554
555   (reverse!
556    (fold (lambda (x acc)
557            (if (null? acc)
558                (list x)
559                (if (equal? x (car acc))
560                    acc
561                    (cons x acc))))
562          '() lst) '()))
563
564 (define (split-at-predicate pred lst)
565   "Split LST into two lists at the first element that returns #f for
566   (PRED previous_element element).  Return the two parts as a pair.
567   Example: (split-at-predicate < '(1 2 3 2 1)) ==> ((1 2 3) . (2 1))"
568   (let ((i (and (pair? lst)
569                 (list-index (lambda (x y) (not (pred x y)))
570                             lst
571                             (cdr lst)))))
572     (if i
573         (call-with-values
574             (lambda () (split-at lst (1+ i)))
575           cons)
576         (list lst))))
577
578 (define-public (split-list-by-separator lst pred)
579   "Split @var{lst} at each element that satisfies @var{pred}, and return
580 the parts (with the separators removed) as a list of lists.  For example,
581 executing @samp{(split-list-by-separator '(a 0 b c 1 d) number?)} returns
582 @samp{((a) (b c) (d))}."
583   (call-with-values (lambda () (break pred lst))
584     (lambda (head tail)
585       (cons head
586             (if (null? tail)
587                 tail
588                 (split-list-by-separator (cdr tail) pred))))))
589
590 (define-public (offset-add a b)
591   (cons (+ (car a) (car b))
592         (+ (cdr a) (cdr b))))
593
594 (define-public (offset-flip-y o)
595   (cons (car o) (- (cdr o))))
596
597 (define-public (offset-scale o scale)
598   (cons (* (car o) scale)
599         (* (cdr o) scale)))
600
601 (define-public (ly:list->offsets accum coords)
602   (if (null? coords)
603       accum
604       (cons (cons (car coords) (cadr coords))
605             (ly:list->offsets accum (cddr coords)))))
606
607 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
608 ;; intervals
609
610 (define-public empty-interval '(+inf.0 . -inf.0))
611
612 (define-public (symmetric-interval expr)
613   (cons (- expr) expr))
614
615 (define-public (interval-length x)
616   "Length of the number-pair @var{x}, if an interval."
617   (max 0 (- (cdr x) (car x))))
618
619 (define-public (ordered-cons a b)
620   (cons (min a b)
621         (max a b)))
622
623 (define-public (interval-bound interval dir)
624   ((if (= dir RIGHT) cdr car) interval))
625
626 (define-public (interval-index interval dir)
627   "Interpolate @var{interval} between between left (@var{dir}=-1) and
628 right (@var{dir}=+1)."
629
630   (* (+  (interval-start interval) (interval-end interval)
631          (* dir (- (interval-end interval) (interval-start interval))))
632      0.5))
633
634 (define-public (interval-center x)
635   "Center the number-pair @var{x}, if an interval."
636   (if (interval-empty? x)
637       0.0
638       (/ (+ (car x) (cdr x)) 2)))
639
640 (define-public interval-start car)
641
642 (define-public interval-end cdr)
643
644 (define (other-axis a)
645   (remainder (+ a 1) 2))
646
647 (define-public (interval-scale iv factor)
648   (cons (* (car iv) factor)
649         (* (cdr iv) factor)))
650
651 (define-public (interval-widen iv amount)
652   (cons (- (car iv) amount)
653         (+ (cdr iv) amount)))
654
655 (define-public (interval-empty? iv)
656   (> (car iv) (cdr iv)))
657
658 (define-public (interval-union i1 i2)
659   (cons
660    (min (car i1) (car i2))
661    (max (cdr i1) (cdr i2))))
662
663 (define-public (interval-intersection i1 i2)
664   (cons
665    (max (car i1) (car i2))
666    (min (cdr i1) (cdr i2))))
667
668 (define-public (interval-sane? i)
669   (not (or  (nan? (car i))
670             (inf? (car i))
671             (nan? (cdr i))
672             (inf? (cdr i))
673             (> (car i) (cdr i)))))
674
675 (define-public (add-point interval p)
676   (cons (min (interval-start interval) p)
677         (max (interval-end interval) p)))
678
679 (define-public (reverse-interval iv)
680   (cons (cdr iv) (car iv)))
681
682 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
683 ;; coordinates
684
685 (define coord-x car)
686 (define coord-y cdr)
687
688 (define (coord-operation operator operand coordinate)
689   (if (pair? operand)
690       (cons (operator (coord-x operand) (coord-x coordinate))
691             (operator (coord-y operand) (coord-y coordinate)))
692       (cons (operator operand (coord-x coordinate))
693             (operator operand (coord-y coordinate)))))
694
695 (define (coord-apply function coordinate)
696   (if (pair? function)
697       (cons
698        ((coord-x function) (coord-x coordinate))
699        ((coord-y function) (coord-y coordinate)))
700       (cons
701        (function (coord-x coordinate))
702        (function (coord-y coordinate)))))
703
704 (define-public (coord-translate coordinate amount)
705   (coord-operation + amount coordinate))
706
707 (define-public (coord-scale coordinate amount)
708   (coord-operation * amount coordinate))
709
710 (define-public (coord-rotate coordinate degrees-in-radians)
711   (let*
712       ((coordinate
713         (cons
714          (exact->inexact (coord-x coordinate))
715          (exact->inexact (coord-y coordinate))))
716        (radius
717         (sqrt
718          (+ (* (coord-x coordinate) (coord-x coordinate))
719             (* (coord-y coordinate) (coord-y coordinate)))))
720        (angle (angle-0-2pi (atan (coord-y coordinate) (coord-x coordinate)))))
721     (cons
722      (* radius (cos (+ angle degrees-in-radians)))
723      (* radius (sin (+ angle degrees-in-radians))))))
724
725 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
726 ;; trig
727
728 (define-public PI (* 4 (atan 1)))
729
730 (define-public TWO-PI (* 2 PI))
731
732 (define-public PI-OVER-TWO (/ PI 2))
733
734 (define-public THREE-PI-OVER-TWO (* 3 PI-OVER-TWO))
735
736 (define-public (cyclic-base-value value cycle)
737   "Take @var{value} and modulo-maps it between 0 and base @var{cycle}."
738   (if (< value 0)
739       (cyclic-base-value (+ value cycle) cycle)
740       (if (>= value cycle)
741           (cyclic-base-value (- value cycle) cycle)
742           value)))
743
744 (define-public (angle-0-2pi angle)
745   "Take @var{angle} (in radians) and maps it between 0 and 2pi."
746   (cyclic-base-value angle TWO-PI))
747
748 (define-public (angle-0-360 angle)
749   "Take @var{angle} (in degrees) and maps it between 0 and 360 degrees."
750   (cyclic-base-value angle 360.0))
751
752 (define-public PI-OVER-180  (/ PI 180))
753
754 (define-public (degrees->radians angle-degrees)
755   "Convert the given angle from degrees to radians."
756   (* angle-degrees PI-OVER-180))
757
758 (define-public (ellipse-radius x-radius y-radius angle)
759   (/
760    (* x-radius y-radius)
761    (sqrt
762     (+ (* (expt y-radius 2)
763           (* (cos angle) (cos angle)))
764        (* (expt x-radius 2)
765           (* (sin angle) (sin angle)))))))
766
767 (define-public (polar->rectangular radius angle-in-degrees)
768   "Return polar coordinates (@var{radius}, @var{angle-in-degrees})
769 as rectangular coordinates @ode{(x-length . y-length)}."
770
771   (let ((complex (make-polar
772                   radius
773                   (degrees->radians angle-in-degrees))))
774     (cons
775      (real-part complex)
776      (imag-part complex))))
777
778 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
779 ;; string
780
781 (define-public (string-endswith s suffix)
782   (equal? suffix (substring s
783                             (max 0 (- (string-length s) (string-length suffix)))
784                             (string-length s))))
785
786 (define-public (string-startswith s prefix)
787   (equal? prefix (substring s 0 (min (string-length s) (string-length prefix)))))
788
789 (define-public (string-encode-integer i)
790   (cond
791    ((= i  0) "o")
792    ((< i 0)   (string-append "n" (string-encode-integer (- i))))
793    (else (string-append
794           (make-string 1 (integer->char (+ 65 (modulo i 26))))
795           (string-encode-integer (quotient i 26))))))
796
797 (define (number->octal-string x)
798   (let* ((n (inexact->exact x))
799          (n64 (quotient n 64))
800          (n8 (quotient (- n (* n64 64)) 8)))
801     (string-append
802      (number->string n64)
803      (number->string n8)
804      (number->string (remainder (- n (+ (* n64 64) (* n8 8))) 8)))))
805
806 (define-public (ly:inexact->string x radix)
807   (let ((n (inexact->exact x)))
808     (number->string n radix)))
809
810 (define-public (ly:number-pair->string c)
811   (string-append (ly:number->string (car c)) " "
812                  (ly:number->string (cdr c))))
813
814 (define-public (dir-basename file . rest)
815   "Strip suffixes in @var{rest}, but leave directory component for
816 @var{file}."
817   (define (inverse-basename x y) (basename y x))
818   (simple-format #f "~a/~a" (dirname file)
819                  (fold inverse-basename file rest)))
820
821 (define-public (write-me message x)
822   "Return @var{x}.  Display @var{message} and write @var{x}.
823 Handy for debugging, possibly turned off."
824   (display message) (write x) (newline) x)
825 ;;  x)
826
827 (define-public (stderr string . rest)
828   (apply format (cons (current-error-port) (cons string rest)))
829   (force-output (current-error-port)))
830
831 (define-public (debugf string . rest)
832   (if #f
833       (apply stderr (cons string rest))))
834
835 (define (index-cell cell dir)
836   (if (equal? dir 1)
837       (cdr cell)
838       (car cell)))
839
840 (define (cons-map f x)
841   "map F to contents of X"
842   (cons (f (car x)) (f (cdr x))))
843
844 (define-public (list-insert-separator lst between)
845   "Create new list, inserting @var{between} between elements of @var{lst}."
846   (define (conc x y )
847     (if (eq? y #f)
848         (list x)
849         (cons x  (cons between y))))
850   (fold-right conc #f lst))
851
852 (define-public (string-regexp-substitute a b str)
853   (regexp-substitute/global #f a str 'pre b 'post))
854
855 (define (regexp-split str regex)
856   (define matches '())
857   (define end-of-prev-match 0)
858   (define (notice match)
859
860     (set! matches (cons (substring (match:string match)
861                                    end-of-prev-match
862                                    (match:start match))
863                         matches))
864     (set! end-of-prev-match (match:end match)))
865
866   (regexp-substitute/global #f regex str notice 'post)
867
868   (if (< end-of-prev-match (string-length str))
869       (set!
870        matches
871        (cons (substring str end-of-prev-match (string-length str)) matches)))
872
873   (reverse matches))
874
875 ;;;;;;;;;;;;;;;;
876 ;; other
877
878 (define (sign x)
879   (if (= x 0)
880       0
881       (if (< x 0) -1 1)))
882
883 (define-public (binary-search start end getter target-val)
884   (_i "Find the index between @var{start} and @var{end} (an integer)
885 which produces the closest match to @var{target-val} if
886 applied to function @var{getter}.")
887   (if (<= end start)
888       start
889       (let* ((compare (quotient (+ start end) 2))
890              (get-val (getter compare)))
891         (cond
892          ((< target-val get-val)
893           (set! end (1- compare)))
894          ((< get-val target-val)
895           (set! start (1+ compare))))
896         (binary-search start end getter target-val))))
897
898 (define-public (car< a b)
899   (< (car a) (car b)))
900
901 (define-public (car<= a b)
902   (<= (car a) (car b)))
903
904 (define-public (symbol<? lst r)
905   (string<? (symbol->string lst) (symbol->string r)))
906
907 (define-public (symbol-key<? lst r)
908   (string<? (symbol->string (car lst)) (symbol->string (car r))))
909
910 (define-public (eval-carefully symbol module . default)
911   "Check whether all symbols in expr @var{symbol} are reachable
912 in module @var{module}.  In that case evaluate, otherwise
913 print a warning and set an optional @var{default}."
914   (let* ((unavailable? (lambda (sym)
915                          (not (module-defined? module sym))))
916          (sym-unavailable
917           (filter
918            unavailable?
919            (filter symbol? (flatten-list symbol)))))
920     (if (null? sym-unavailable)
921         (eval symbol module)
922         (let* ((def (and (pair? default) (car default))))
923           (ly:programming-error
924            "cannot evaluate ~S in module ~S, setting to ~S"
925            (object->string symbol)
926            (object->string module)
927            (object->string def))
928           def))))
929
930 ;;
931 ;; don't confuse users with #<procedure .. > syntax.
932 ;;
933 (define-public (scm->string val)
934   (if (and (procedure? val)
935            (symbol? (procedure-name val)))
936       (symbol->string (procedure-name val))
937       (string-append
938        (if (self-evaluating? val)
939            (if (string? val)
940                "\""
941                "")
942            "'")
943        (call-with-output-string (lambda (port) (display val port)))
944        (if (string? val)
945            "\""
946            ""))))
947
948 (define-public (!= lst r)
949   (not (= lst r)))
950
951 (define-public lily-unit->bigpoint-factor
952   (cond
953    ((equal? (ly:unit) "mm") (/ 72.0 25.4))
954    ((equal? (ly:unit) "pt") (/ 72.0 72.27))
955    (else (ly:error (_ "unknown unit: ~S") (ly:unit)))))
956
957 (define-public lily-unit->mm-factor
958   (* 25.4 (/ lily-unit->bigpoint-factor 72)))
959
960 ;;; FONT may be font smob, or pango font string...
961 (define-public (font-name-style font)
962   (if (string? font)
963       (string-downcase font)
964       (let* ((font-name (ly:font-name font))
965              (full-name (if font-name font-name (ly:font-file-name font))))
966         (string-downcase full-name))))
967
968 (define-public (modified-font-metric-font-scaling font)
969   (let* ((designsize (ly:font-design-size font))
970          (magnification (* (ly:font-magnification font)))
971          (scaling (* magnification designsize)))
972     (debugf "scaling:~S\n" scaling)
973     (debugf "magnification:~S\n" magnification)
974     (debugf "design:~S\n" designsize)
975     scaling))
976
977 (define-public (version-not-seen-message input-file-name)
978   (ly:warning-located
979    (ly:format "~a:1" input-file-name)
980    (_ "no \\version statement found, please add~afor future compatibility")
981    (format #f "\n\n\\version ~s\n\n" (lilypond-version))))