]> git.donarmstrong.com Git - lilypond.git/blob - scm/auto-beam.scm
Merge branch 'master' of carldsorensen@git.sv.gnu.org:/srv/git/lilypond into fret...
[lilypond.git] / scm / auto-beam.scm
1 ;;;; auto-beam.scm -- Auto-beam-engraver settings
2 ;;;;
3 ;;;; source file of the GNU LilyPond music typesetter
4 ;;;;
5 ;;;; (c) 2000--2009 Jan Nieuwenhuizen <janneke@gnu.org>
6
7 ;;; specify generic beam end times
8
9 ;;; format:
10 ;;;
11 ;;;   function shortest-duration-in-beam time-signature
12 ;;;
13 ;;; where
14 ;;;
15 ;;;     function = begin or end
16 ;;;     shortest-duration-in-beam = numerator denominator; e.g.: 1 16
17 ;;;     time-signature = numerator denominator, e.g.: 4 4
18 ;;;
19 ;;; unspecified or wildcard entries for duration or time-signature
20 ;;; are given by * *
21
22 ;;; maybe do:  '(end shortest-1 16 time-3 4) ?
23
24 (define-public default-auto-beam-settings
25   `(
26     ;; in 2 2 time:
27     ;;  use beatLength for all except 32nd notes
28     ;;  end beams with 32nd notes each 1 4 beat
29
30     ((end 1 32 2 2) . ,(ly:make-moment 1 4))
31     ((end 1 32 2 2) . ,(ly:make-moment 2 4))
32     ((end 1 32 2 2) . ,(ly:make-moment 3 4))
33
34     ;; in 3 2 time:
35     ;;   use beatLength for all except 16th and 32nd notes
36     ;;   end beams with 16th notes each 1 4 beat
37     ;;   end beams with 32nd notes each 1 8 beat
38
39     ((end 1 16 3 2) . ,(ly:make-moment 1 4))
40     ((end 1 16 3 2) . ,(ly:make-moment 2 4))
41     ((end 1 16 3 2) . ,(ly:make-moment 3 4))
42     ((end 1 16 3 2) . ,(ly:make-moment 4 4))
43     ((end 1 16 3 2) . ,(ly:make-moment 5 4))
44
45     ((end 1 32 3 2) . ,(ly:make-moment 1 8))
46     ((end 1 32 3 2) . ,(ly:make-moment 2 8))
47     ((end 1 32 3 2) . ,(ly:make-moment 3 8))
48     ((end 1 32 3 2) . ,(ly:make-moment 4 8))
49     ((end 1 32 3 2) . ,(ly:make-moment 5 8))
50     ((end 1 32 3 2) . ,(ly:make-moment 6 8))
51     ((end 1 32 3 2) . ,(ly:make-moment 7 8))
52     ((end 1 32 3 2) . ,(ly:make-moment 8 8))
53     ((end 1 32 3 2) . ,(ly:make-moment 9 8))
54     ((end 1 32 3 2) . ,(ly:make-moment 10 8))
55     ((end 1 32 3 2) . ,(ly:make-moment 11 8))
56
57     ;; in 2 4 time:
58     ;;   use beatLength for all except 32nd notes
59     ;;   end beams with 32nd notes each 1 8 beat
60
61     ((end 1 32 2 4) . ,(ly:make-moment 1 8))
62     ((end 1 32 2 4) . ,(ly:make-moment 2 8))
63     ((end 1 32 2 4) . ,(ly:make-moment 3 8))
64
65     ;; in 3 4 time:
66     ;;   override beatLength which would end beams at 1 4 beats
67     ;;   end beams with 16th notes each 1 4 beat
68     ;;   end beams with 32nd notes each 1 8 beat
69
70     ((end * * 3 4) . ,(ly:make-moment 3 4))
71     ((end 1 16 3 4) . ,(ly:make-moment 1 4))
72     ((end 1 16 3 4) . ,(ly:make-moment 2 4))
73     ((end 1 32 3 4) . ,(ly:make-moment 1 8))
74     ((end 1 32 3 4) . ,(ly:make-moment 2 8))
75     ((end 1 32 3 4) . ,(ly:make-moment 3 8))
76     ((end 1 32 3 4) . ,(ly:make-moment 4 8))
77     ((end 1 32 3 4) . ,(ly:make-moment 5 8))
78
79     ;; in common time:
80     ;;   override beatLength which would end beams at 1 4 beats
81     ;;   end all beams at 1 2 beat
82     ;;   end beams with 8th triplets each 1 4 beat
83     ;;   end beams with 16th notes each 1 4 beat
84     ;;   end beams with 32nd notes each 1 8 beat
85
86     ((end * * 4 4) . ,(ly:make-moment 1 2))
87
88     ((end 1 12 4 4) . ,(ly:make-moment 1 4))
89     ((end 1 12 4 4) . ,(ly:make-moment 3 4))
90
91     ((end 1 16 4 4) . ,(ly:make-moment 1 4))
92     ((end 1 16 4 4) . ,(ly:make-moment 3 4))
93
94     ((end 1 32 4 4) . ,(ly:make-moment 1 8))
95     ((end 1 32 4 4) . ,(ly:make-moment 2 8))
96     ((end 1 32 4 4) . ,(ly:make-moment 3 8))
97     ((end 1 32 4 4) . ,(ly:make-moment 5 8))
98     ((end 1 32 4 4) . ,(ly:make-moment 6 8))
99     ((end 1 32 4 4) . ,(ly:make-moment 7 8))
100
101     ;; in 3 8 time:
102     ;;   override beatLength which would end beams at 1 8 beats
103
104     ((end * * 3 8) . ,(ly:make-moment 3 8))
105
106     ;; in 4 8 time
107     ;;   override beatLength which would end beams at 1 8 beats
108     ;;   end all beams at 1 4 beat
109     ;;   end beams with 32nd notes each 1 8 beat
110
111     ((end * * 4 8) . ,(ly:make-moment 1 4))
112     ((end 1 32 4 8) . ,(ly:make-moment 1 8))
113     ((end 1 32 4 8) . ,(ly:make-moment 3 8))
114
115     ;; in 6 8, 9 8 and 12 8 time:
116     ;;   use beatGrouping for all except 32nd notes
117     ;;   end beams with 32nd notes each 1 8 beat
118
119     ((end 1 32 6 8) . ,(ly:make-moment 1 8))
120     ((end 1 32 6 8) . ,(ly:make-moment 2 8))
121     ((end 1 32 6 8) . ,(ly:make-moment 3 8))
122     ((end 1 32 6 8) . ,(ly:make-moment 4 8))
123     ((end 1 32 6 8) . ,(ly:make-moment 5 8))
124
125     ((end 1 32 9 8) . ,(ly:make-moment 1 8))
126     ((end 1 32 9 8) . ,(ly:make-moment 2 8))
127     ((end 1 32 9 8) . ,(ly:make-moment 3 8))
128     ((end 1 32 9 8) . ,(ly:make-moment 4 8))
129     ((end 1 32 9 8) . ,(ly:make-moment 5 8))
130     ((end 1 32 9 8) . ,(ly:make-moment 6 8))
131     ((end 1 32 9 8) . ,(ly:make-moment 7 8))
132     ((end 1 32 9 8) . ,(ly:make-moment 8 8))
133
134     ((end 1 32 12 8) . ,(ly:make-moment 1 8))
135     ((end 1 32 12 8) . ,(ly:make-moment 2 8))
136     ((end 1 32 12 8) . ,(ly:make-moment 3 8))
137     ((end 1 32 12 8) . ,(ly:make-moment 4 8))
138     ((end 1 32 12 8) . ,(ly:make-moment 5 8))
139     ((end 1 32 12 8) . ,(ly:make-moment 6 8))
140     ((end 1 32 12 8) . ,(ly:make-moment 7 8))
141     ((end 1 32 12 8) . ,(ly:make-moment 8 8))
142     ((end 1 32 12 8) . ,(ly:make-moment 9 8))
143     ((end 1 32 12 8) . ,(ly:make-moment 10 8))
144     ((end 1 32 12 8) . ,(ly:make-moment 11 8))
145
146     ;; in 4 16 time
147     ;;   end all beams each 1 8 beat
148
149     ((end * * 4 16) . ,(ly:make-moment 1 8))
150
151     ))
152
153 (define (override-property-setting context property setting value)
154   "Like the C++ code that executes \\override, but without type
155 checking. "
156   (ly:context-set-property!
157    context property
158    (cons (cons setting value) (ly:context-property context property))))
159
160 (define (revert-property-setting context property setting)
161   "Like the C++ code that executes \revert, but without type
162 checking. "
163
164   (define (revert-member alist entry new)
165     "Return ALIST, with ENTRY removed.  ALIST is not modified, instead
166 a fresh copy of the list-head is made."
167     (cond
168      ((null? alist) new)
169      ((equal? (car alist) entry) (revert-member (cdr alist) entry new))
170      (else (revert-member (cdr alist) entry (cons (car alist) new)))))
171
172   (ly:context-set-property!
173    context property
174    (revert-member (ly:context-property context property) setting '())))
175
176 (define-public (override-auto-beam-setting setting num den . rest)
177   (ly:export
178    (context-spec-music
179     (make-apply-context (lambda (c)
180         (override-property-setting
181          c 'autoBeamSettings
182          setting (ly:make-moment num den))))
183     (if (and (pair? rest) (symbol? (car rest)))
184         (car rest)
185         'Voice))))
186
187 (define-public (score-override-auto-beam-setting setting num den)
188   (override-auto-beam-setting setting num den 'Score))
189
190 (define-public (revert-auto-beam-setting setting num den . rest)
191   (ly:export
192    (context-spec-music
193     (make-apply-context
194       (lambda (c)
195         (revert-property-setting
196          c 'autoBeamSettings
197          (cons setting (ly:make-moment num den)))))
198     (if (and (pair? rest) (symbol? (car rest)))
199         (car rest)
200         'Voice))))
201
202 ;;  Determine end moment for auto beaming (or begin moment, but mostly
203 ;;  0== anywhere).  In order of decreasing priority:
204 ;;
205 ;;  1. end <type>   *     *
206 ;;  2. end   *      *     *
207 ;;  3. end <type> <num> <den>
208 ;;  4. end   *    <num> <den>
209 ;;  5. if 1-4 not specified, begin anywhere, end at time determined by
210 ;;          beatGrouping and beatLength:
211 ;;     if beatGrouping and beatLength are consistent with measureLength,
212 ;;        use beatGrouping to determine end of beams.
213 ;;     if beatGrouping and beatLength are inconsistent with measureLength,
214 ;;        use beatLength to determine end of beams.
215 ;;
216 ;;  Rationale:
217 ;;
218 ;;  [user override]
219 ;;  1. override for specific duration type
220 ;;  2. generic override
221 ;;
222 ;;  [to be defined in config file]
223 ;;  3. exceptions for specific time signature, for specific duration type
224 ;;  4. exceptions for specific time signature
225 ;;  5. easy catch-all rule for non-specified measure types
226
227
228 (define-public (default-auto-beam-check context dir test)
229   (define (get name default)
230     (let ((value (ly:context-property context name)))
231       (if (not (null? value)) value default)))
232
233   (define (ending-moments group-list start-beat beat-length)
234     (if (null? group-list)
235         '()
236         (let ((new-start (+ start-beat (car group-list))))
237           (cons (ly:moment-mul (ly:make-moment new-start 1) beat-length)
238                 (ending-moments (cdr group-list) new-start beat-length)))))
239
240   (define (make-end-settings time ending-list moment-den)
241     (if (null? ending-list)
242         '()
243         (cons (cons (append '(end * *) time)
244                     (ly:make-moment (car ending-list) moment-den))
245               (make-end-settings time (cdr ending-list) moment-den))))
246   
247   ;; Don't start auto beams on grace notes
248   (if (and (!= (ly:moment-grace-numerator (ly:context-now context)) 0)
249            (= dir START))
250       #f
251       (let* ((beat-length (get 'beatLength (ly:make-moment 1 4)))
252              (measure-length (get 'measureLength (ly:make-moment 1 1)))
253              (measure-pos (get 'measurePosition ZERO-MOMENT))
254              (beat-grouping (get 'beatGrouping '()))
255              (settings (get 'autoBeamSettings '()))
256              (function (list (if (= dir START) 'begin 'end)))
257              ;; Calculate implied time signature based on measureLength
258              ;; and beatLength for default value in get
259              (num-mom (ly:moment-div measure-length beat-length))
260              (num (inexact->exact
261                     (round (/ (ly:moment-main-numerator num-mom)
262                               (ly:moment-main-denominator num-mom)))))
263              (den (ly:moment-main-denominator beat-length))
264              (time-signature-fraction 
265                (get 'timeSignatureFraction (cons num den)))
266              (time (list (car time-signature-fraction)
267                          (cdr time-signature-fraction)))
268              (type (list (ly:moment-main-numerator test)
269                          (ly:moment-main-denominator test)))
270              (pos (if (>= (ly:moment-main-numerator measure-pos) 0)
271                       measure-pos
272                       (ly:moment-add measure-length measure-pos)))
273              (grouping-moments (ending-moments beat-grouping 0 beat-length))
274              ;; Calculate implied measure length from beatGrouping
275              ;; and beatLength
276              (grouping-length (if (null? grouping-moments)
277                                   ZERO-MOMENT
278                                   (list-ref grouping-moments 
279                                             (1- (length grouping-moments)))))
280              (lst (list
281                     ;; Hmm, should junk user-override feature,
282                     ;; or split this in user-override and config section?
283                     (append function type '(* *))
284                     (append function '(* * * *))
285                     (append function type time)
286                     (append function '(* *) time)))
287              (predefined-setting (first-assoc lst settings)))
288          (if (or
289                 ;; always begin or end beams at beginning/ending of measure
290                 (= (ly:moment-main-numerator pos) 0)
291                 (first-member (map (lambda (x) (cons x pos)) lst) settings))
292              #t
293              (if (= dir START)
294                  ;; if no entry matches our function + time or type,
295                  ;; start anywhere
296                  (not predefined-setting)
297                  ;; if entry matches our function + time or type, check moment
298                  (if predefined-setting
299                     (equal? measure-pos (cdr predefined-setting))
300                     ;; if measure-length matches grouping-length, use
301                     ;; grouping moments, else use beat-length
302                     (if (equal? measure-length grouping-length)
303                         (member measure-pos grouping-moments)
304                         (= (ly:moment-main-denominator
305                            (ly:moment-div pos beat-length)) 1))))))))