1 ;;;; This file is part of LilyPond, the GNU music typesetter.
3 ;;;; Copyright (C) 2000--2014 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-list! lst <)))
122 (map - s (cons 0 s)))))
124 (let analyze ((m (unfold-repeats-fully (event-chord-reduce music)))
126 ;; enter beam ends from m starting at pos into res, return new pos
127 (cond ((music-is-of-type? m 'bar-check) 0)
128 ((music-is-of-type? m 'simultaneous-music)
129 (fold (lambda (m prev) (max (analyze m pos) prev))
131 (ly:music-property m 'elements)))
132 ((not (music-is-of-type? m 'rhythmic-event))
133 (let ((elt (ly:music-property m 'element)))
135 (if (ly:music? elt) (analyze elt pos) pos)
136 (ly:music-property m 'elements))))
137 ;; Have rhythmic event.
140 (and (music-is-of-type? art 'beam-event)
141 (= (ly:music-property art 'span-direction START) STOP)))
142 (ly:music-property m 'articulations))
143 (let* ((len (duration-length (ly:music-property m 'duration)))
145 (ass (assv len res)))
146 (cond ((or (zero? len) (not (integer? (/ pos len))))
147 (ly:warning m (_ "Beam end fits no pattern")))
149 (set-cdr! ass (cons (/ pos len) (cdr ass))))
151 (set! res (cons (list len (/ pos len)) res))))
154 (+ pos (duration-length (ly:music-property m 'duration))))))
156 ;; takes the output from the loop, generates actual beam exceptions
163 (sort-list! res car>))))))