Spaces:
Sleeping
Sleeping
;;;; This file is part of LilyPond, the GNU music typesetter. | |
;;;; | |
;;;; Copyright (C) 2000--2020 Jan Nieuwenhuizen <[email protected]> | |
;;;; | |
;;;; LilyPond is free software: you can redistribute it and/or modify | |
;;;; it under the terms of the GNU General Public License as published by | |
;;;; the Free Software Foundation, either version 3 of the License, or | |
;;;; (at your option) any later version. | |
;;;; | |
;;;; LilyPond is distributed in the hope that it will be useful, | |
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
;;;; GNU General Public License for more details. | |
;;;; | |
;;;; You should have received a copy of the GNU General Public License | |
;;;; along with LilyPond. If not, see <http://www.gnu.org/licenses/>. | |
;; Determine whether an auto beam should be extended to the right | |
;; of the current stem. We start anywhere, except mid-measure in | |
;; 3/4 time. We end according to the follwing rules, in order of | |
;; decreasing priority: | |
;; | |
;; 1. end <type> | |
;; 2. end <greater type> | |
;; 3. if 1-2 not specified, end at beatStructure intervals | |
;; | |
;; Rationale: | |
;; | |
;; [user override] | |
;; 1. override for specific duration type | |
;; 2. overrides apply to shorter durations | |
;; | |
;; defined in scm/time-signature-settings.scm: | |
;; 1. Default grouping for common time signatures | |
(define-public (default-auto-beam-check context dir measure-pos test-beam) | |
(define (get name default) | |
(let ((value (ly:context-property context name))) | |
(if (not (null? value)) value default))) | |
(define (ending-moments group-list base-length) | |
(let ((beat 0)) | |
(map-in-order (lambda (x) | |
(set! beat (+ beat x)) | |
(* base-length beat)) | |
group-list))) | |
(define (larger-setting type sorted-alist) | |
(assoc type sorted-alist <=)) | |
(define (beat-end? moment beat-endings) | |
(pair? (memv moment beat-endings))) ;; member returns a list if found, not #t | |
;; Start of actual auto-beam test routine | |
;; | |
;; | |
;; Don't start auto beams on grace notes | |
(and (or (zero? (ly:moment-grace (ly:context-now context))) | |
(!= dir START)) | |
(let* ((base-length (cond ((get 'baseMoment #f) => ly:moment-main) | |
(else 1/4))) | |
(measure-length (cond ((get 'measureLength #f) => ly:moment-main) | |
(else 1))) | |
(time-signature-fraction | |
(get 'timeSignatureFraction '(4 . 4))) | |
(beat-structure (get 'beatStructure '(1 1 1 1))) | |
(beat-endings (ending-moments beat-structure base-length)) | |
(exceptions (sort (map | |
(lambda (a) | |
(if (pair? (car a)) | |
(cons (/ (caar a) (cdar a)) | |
(cdr a)) | |
a)) | |
(assoc-get 'end | |
(get 'beamExceptions '()) | |
'())) | |
car<)) | |
(function (if (= dir START) 'begin 'end)) | |
(beam-half-measure (get 'beamHalfMeasure #t)) | |
(type (ly:moment-main test-beam)) | |
(non-grace (ly:moment-main measure-pos)) | |
(pos (if (negative? non-grace) | |
(+ measure-length non-grace) | |
non-grace)) | |
(type-grouping (assoc-get type exceptions '())) | |
(default-rule (and (null? type-grouping) | |
(larger-setting type exceptions))) | |
(default-grouping (and default-rule (cdr default-rule))) | |
(default-beat-length (and default-rule (car default-rule))) | |
(exception-grouping (if (null? type-grouping) | |
default-grouping | |
type-grouping)) | |
(grouping-moment (if (null? type-grouping) | |
default-beat-length | |
type)) | |
(exception-moments (and exception-grouping | |
(ending-moments | |
exception-grouping grouping-moment)))) | |
(if (= dir START) | |
;; Start rules -- #t if beam is allowed to start | |
(or beam-half-measure ;; Start anywhere, but option for mid-measure | |
(not (= (+ pos pos) measure-length)) | |
(not (= 3 (car time-signature-fraction))) ;; in triple meter | |
(not (= (denominator type) ;; when the beamed note is 1/6 of a measure | |
(* 2 (cdr time-signature-fraction))))) | |
;; End rules -- #t if beam is required to end | |
(or (zero? pos) ;; end at measure beginning | |
(if exception-grouping | |
(beat-end? pos exception-moments) ;; check exception rule | |
(beat-end? pos beat-endings))))))) ;; no exception, so check beat ending | |
(define-public (extract-beam-exceptions music) | |
"Creates a value useful for setting @code{beamExceptions} from @var{music}." | |
(define (car> a b) (> (car a) (car b))) | |
(define (beatify! lst) | |
;; takes a collection of end points, sorts them, and returns the | |
;; non-zero differences as beaming pattern | |
(let ((s (sort-list! lst <))) | |
(remove! zero? | |
(map - s (cons 0 s))))) | |
(let ((res '())) | |
(let analyze ((m (unfold-repeats-fully (event-chord-reduce music))) | |
(pos 0)) | |
;; enter beam ends from m starting at pos into res, return new pos | |
(cond ((music-is-of-type? m 'bar-check) 0) | |
((music-is-of-type? m 'simultaneous-music) | |
(fold (lambda (m prev) (max (analyze m pos) prev)) | |
pos | |
(ly:music-property m 'elements))) | |
((not (music-is-of-type? m 'rhythmic-event)) | |
(let ((elt (ly:music-property m 'element))) | |
(fold analyze | |
(if (ly:music? elt) (analyze elt pos) pos) | |
(ly:music-property m 'elements)))) | |
;; Have rhythmic event. | |
((any | |
(lambda (art) | |
(and (music-is-of-type? art 'beam-event) | |
(= (ly:music-property art 'span-direction START) STOP))) | |
(ly:music-property m 'articulations)) | |
(let* ((len (duration-length (ly:music-property m 'duration))) | |
(pos (+ pos len)) | |
(ass (assv len res))) | |
(cond ((or (zero? len) (not (integer? (/ pos len)))) | |
(ly:warning m (_ "Beam end fits no pattern"))) | |
(ass | |
(set-cdr! ass (cons (/ pos len) (cdr ass)))) | |
(else | |
(set! res (cons (list len (/ pos len)) res)))) | |
pos)) | |
(else | |
(+ pos (duration-length (ly:music-property m 'duration)))))) | |
;; takes the output from the loop, generates actual beam exceptions | |
(list | |
(cons 'end | |
(map! | |
(lambda (l) | |
(cons (car l) | |
(beatify! (cdr l)))) | |
(sort-list! res car>)))))) | |