1 ;;;; This file is part of LilyPond, the GNU music typesetter.
3 ;;;; Copyright (C) 2000--2012 Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;; LilyPond is free software: you can redistribute it and/or modify
6 ;;;; it under the terms of the GNU General Public License as published by
7 ;;;; the Free Software Foundation, either version 3 of the License, or
8 ;;;; (at your option) any later version.
10 ;;;; LilyPond is distributed in the hope that it will be useful,
11 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ;;;; GNU General Public License for more details.
15 ;;;; You should have received a copy of the GNU General Public License
16 ;;;; along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
18 ;; Determine whether an auto beam should be extended to the right
19 ;; of the current stem. We start anywhere, except mid-measure in
20 ;; 3/4 time. We end according to the follwing rules, in order of
21 ;; decreasing priority:
24 ;; 2. end <greater type>
25 ;; 3. if 1-2 not specified, end at beatStructure intervals
30 ;; 1. override for specific duration type
31 ;; 2. overrides apply to shorter durations
33 ;; defined in scm/time-signature-settings.scm:
34 ;; 1. Default grouping for common time signatures
36 (define-public (default-auto-beam-check context dir measure-pos test-beam)
37 (define (get name default)
38 (let ((value (ly:context-property context name)))
39 (if (not (null? value)) value default)))
41 (define (ending-moments group-list start-beat base-length)
42 (if (null? group-list)
44 (let ((new-start (+ start-beat (car group-list))))
45 (cons (* new-start base-length)
46 (ending-moments (cdr group-list) new-start base-length)))))
48 (define (larger-setting type sorted-alist)
49 (assoc type sorted-alist <=))
51 (define (beat-end? moment beat-endings)
52 (pair? (memv moment beat-endings))) ;; member returns a list if found, not #t
54 ;; Start of actual auto-beam test routine
57 ;; Don't start auto beams on grace notes
58 (and (or (zero? (ly:moment-grace (ly:context-now context)))
60 (let* ((base-length (cond ((get 'baseMoment #f) => ly:moment-main)
62 (measure-length (cond ((get 'measureLength #f) => ly:moment-main)
64 (time-signature-fraction
65 (get 'timeSignatureFraction '(4 . 4)))
66 (beat-structure (get 'beatStructure '(1 1 1 1)))
67 (beat-endings (ending-moments beat-structure 0 base-length))
68 (exceptions (sort (map
71 (cons (/ (caar a) (cdar a))
75 (get 'beamExceptions '())
78 (function (if (= dir START) 'begin 'end))
79 (beam-half-measure (get 'beamHalfMeasure #t))
80 (type (ly:moment-main test-beam))
81 (non-grace (ly:moment-main measure-pos))
82 (pos (if (negative? non-grace)
83 (+ measure-length non-grace)
85 (type-grouping (assoc-get type exceptions '()))
86 (default-rule (and (null? type-grouping)
87 (larger-setting type exceptions)))
88 (default-grouping (and default-rule (cdr default-rule)))
89 (default-beat-length (and default-rule (car default-rule)))
90 (exception-grouping (if (null? type-grouping)
93 (grouping-moment (if (null? type-grouping)
96 (exception-moments (and exception-grouping
98 exception-grouping 0 grouping-moment))))
101 ;; Start rules -- #t if beam is allowed to start
102 (or beam-half-measure ;; Start anywhere, but option for mid-measure
103 (not (= (+ pos pos) measure-length))
104 (not (= 3 (car time-signature-fraction))) ;; in triple meter
105 (not (= (denominator type) ;; when the beamed note is 1/6 of a measure
106 (* 2 (cdr time-signature-fraction)))))
107 ;; End rules -- #t if beam is required to end
108 (or (zero? pos) ;; end at measure beginning
109 (if exception-grouping
110 (beat-end? pos exception-moments) ;; check exception rule
111 (beat-end? pos beat-endings))))))) ;; no exception, so check beat ending
114 (define-public (extract-beam-exceptions music)
115 "Creates a value useful for setting @code{beamExceptions} from @var{music}."
116 (define (car> a b) (> (car a) (car b)))
117 (define (beatify lst)
118 ;; takes a collection of end points, sorts them, and returns the
119 ;; non-zero differences as beaming pattern
120 (let ((s (sort lst <)))
122 (map - s (cons 0 s)))))
123 ;; TODO: let this do something useful with simultaneous music.
125 ((lst (extract-typed-music (unfold-repeats-fully (event-chord-reduce music))
126 '(rhythmic-event bar-check)))
133 (cons (cons (numerator (car l)) (denominator (car l)))
136 ((music-is-of-type? (car lst) 'bar-check)
137 (loop (cdr lst) 0 res))
138 ;; Have rhythmic event.
141 (and (music-is-of-type? art 'beam-event)
142 (= (ly:music-property art 'span-direction START) STOP)))
143 (ly:music-property (car lst) 'articulations))
144 (let* ((dur (ly:music-property (car lst) 'duration))
145 (len (if (ly:duration? dur) (duration-length dur) 0))
147 (ass (assoc len res)))
148 (cond ((or (zero? len) (not (integer? (/ pos len))))
149 (ly:warning (car lst) (_ "Beam end fits no pattern"))
150 (loop (cdr lst) pos res))
152 (set-cdr! ass (cons (/ pos len) (cdr ass)))
153 (loop (cdr lst) pos res))
155 (loop (cdr lst) pos (cons (list len (/ pos len)) res))))))
157 (let* ((dur (ly:music-property (car lst) 'duration))
158 (len (if (ly:duration? dur) (duration-length dur) 0)))