From 183e094c0d1414bc8af7ccc4c53ac0f9a039d6d3 Mon Sep 17 00:00:00 2001 From: David Nalesnik Date: Sun, 19 Oct 2014 09:00:15 -0500 Subject: [PATCH] Improvements to measure counter This patch adds no new functionality to the measure counter, but there are improvements to the code. The stencil callback has been shortened, as there is no need to search for columns which are already available as the bounds of broken spanners. It has also been moved to scm/output-lib.scm, where other such functions are. The engraver has been streamlined by the removal of an unnecessary variable and levels of nesting. Comments have been revised. --- scm/music-functions.scm | 60 ----------------------- scm/output-lib.scm | 43 ++++++++++++++++ scm/scheme-engravers.scm | 103 +++++++++++++++++---------------------- 3 files changed, 88 insertions(+), 118 deletions(-) diff --git a/scm/music-functions.scm b/scm/music-functions.scm index aad473c7f0..db39742e21 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -2237,66 +2237,6 @@ of list @var{arg}." (car arg)))) (export value-for-spanner-piece) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; measure counter - -(define (measure-counter-stencil grob) - "Print a number for a measure count. The number is centered using -the extents of @code{BreakAlignment} grobs associated with -@code{NonMusicalPaperColumn} grobs. In the case of an unbroken measure, these -columns are the left and right bounds of a @code{MeasureCounter} spanner. -Broken measures are numbered in parentheses." - (let* ((orig (ly:grob-original grob)) - (siblings (ly:spanner-broken-into orig)) ; have we been split? - (bounds (ly:grob-array->list (ly:grob-object grob 'columns))) - (refp (ly:grob-system grob)) - ;; we use the first and/or last NonMusicalPaperColumn grob(s) of - ;; a system in the event that a MeasureCounter spanner is broken - (all-cols (ly:grob-array->list (ly:grob-object refp 'columns))) - (all-cols - (filter - (lambda (col) (eq? #t (ly:grob-property col 'non-musical))) - all-cols)) - (left-bound - (if (or (null? siblings) ; spanner is unbroken - (eq? grob (car siblings))) ; or the first piece - (car bounds) - (car all-cols))) - (right-bound - (if (or (null? siblings) - (eq? grob (car (reverse siblings)))) - (car (reverse bounds)) - (car (reverse all-cols)))) - (elts-L (ly:grob-array->list (ly:grob-object left-bound 'elements))) - (elts-R (ly:grob-array->list (ly:grob-object right-bound 'elements))) - (break-alignment-L - (filter - (lambda (elt) (grob::has-interface elt 'break-alignment-interface)) - elts-L)) - (break-alignment-R - (filter - (lambda (elt) (grob::has-interface elt 'break-alignment-interface)) - elts-R)) - (break-alignment-L-ext (ly:grob-extent (car break-alignment-L) refp X)) - (break-alignment-R-ext (ly:grob-extent (car break-alignment-R) refp X)) - (num (markup (number->string (ly:grob-property grob 'count-from)))) - (num - (if (or (null? siblings) - (eq? grob (car siblings))) - num - (make-parenthesize-markup num))) - (num (grob-interpret-markup grob num)) - (num (ly:stencil-aligned-to num X (ly:grob-property grob 'self-alignment-X))) - (num - (ly:stencil-translate-axis - num - (+ (interval-length break-alignment-L-ext) - (* 0.5 - (- (car break-alignment-R-ext) - (cdr break-alignment-L-ext)))) - X))) - num)) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The following are used by the \offset function diff --git a/scm/output-lib.scm b/scm/output-lib.scm index 6a385fd72a..0250271250 100644 --- a/scm/output-lib.scm +++ b/scm/output-lib.scm @@ -1361,6 +1361,49 @@ parent or the parent has no setting." (interval-union '(0 . 0) (cons smaller larger))) '(0 . 0)))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; measure counter + +(define (measure-counter-stencil grob) + "Print a number for a measure count. The number is centered using +the extents of @code{BreakAlignment} grobs associated with the left and +right bounds of a @code{MeasureCounter} spanner. Broken measures are +numbered in parentheses." + (let* ((num (markup (number->string (ly:grob-property grob 'count-from)))) + (orig (ly:grob-original grob)) + (siblings (ly:spanner-broken-into orig)) ; have we been split? + (num + (if (or (null? siblings) + (eq? grob (car siblings))) + num + (make-parenthesize-markup num))) + (num (grob-interpret-markup grob num)) + (num (ly:stencil-aligned-to num X (ly:grob-property grob 'self-alignment-X))) + (left-bound (ly:spanner-bound grob LEFT)) + (right-bound (ly:spanner-bound grob RIGHT)) + (elts-L (ly:grob-array->list (ly:grob-object left-bound 'elements))) + (elts-R (ly:grob-array->list (ly:grob-object right-bound 'elements))) + (break-alignment-L + (filter + (lambda (elt) (grob::has-interface elt 'break-alignment-interface)) + elts-L)) + (break-alignment-R + (filter + (lambda (elt) (grob::has-interface elt 'break-alignment-interface)) + elts-R)) + (refp (ly:grob-system grob)) + (break-alignment-L-ext (ly:grob-extent (car break-alignment-L) refp X)) + (break-alignment-R-ext (ly:grob-extent (car break-alignment-R) refp X)) + (num + (ly:stencil-translate-axis + num + (+ (interval-length break-alignment-L-ext) + (* 0.5 + (- (car break-alignment-R-ext) + (cdr break-alignment-L-ext)))) + X))) + num)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; make-engraver helper macro diff --git a/scm/scheme-engravers.scm b/scm/scheme-engravers.scm index 0766cbc19c..ccb1fb5b0d 100644 --- a/scm/scheme-engravers.scm +++ b/scm/scheme-engravers.scm @@ -21,78 +21,65 @@ aid for counting repeated measures. There is no requirement that the affected measures be repeated, however. The user delimits the area to receive a count with @code{\\startMeasureCount} and -@code{\\stopMeasureCount}. - -Each element of a count is a spanner, and a count is thus a series of -spanners. Each spanner is bounded by the first @code{CommandColumn} of -successive measures, and boundaries are shared by adjoining spanners." +@code{\\stopMeasureCount}." (let ((count-spanner '()) ; a single element of the count (go? #f) ; is the count in progress? (stop? #f) ; do we end the count? (last-measure-seen 0) - (new-measure? #f) (elapsed 0)) (make-engraver - (listeners ((measure-counter-event engraver event) - (set! last-measure-seen (ly:context-property context 'currentBarNumber)) - (set! new-measure? #t) - (cond - ((and (= START (ly:event-property event 'span-direction)) - go?) - (begin - (set! stop? #t) - (ly:input-warning - (ly:event-property event 'origin) - "count not ended before another begun"))) - ((= START (ly:event-property event 'span-direction)) - (set! go? #t)) - ((= STOP (ly:event-property event 'span-direction)) - (begin - (set! stop? #t) - (set! go? #f)))))) + (listeners + ((measure-counter-event engraver event) + (cond + ((and (= START (ly:event-property event 'span-direction)) + go?) + (set! stop? #t) + (ly:input-warning + (ly:event-property event 'origin) + "count not ended before another begun")) + ((= START (ly:event-property event 'span-direction)) + (set! go? #t) + ;; initialize one less so first measure receives a count spanner + (set! last-measure-seen + (1- (ly:context-property context 'currentBarNumber)))) + ((= STOP (ly:event-property event 'span-direction)) + (set! stop? #t) + (set! go? #f))))) ((process-music trans) (let ((col (ly:context-property context 'currentCommandColumn)) (now (ly:context-property context 'measurePosition)) (current-bar (ly:context-property context 'currentBarNumber))) - ;; If the counter has been started, make sure we're in a new bar - ;; before finishing a count-spanner and starting a new one. - ;; Since we consider all CommandColumns encountered, we need this - ;; check so that a count-spanner is not created for each pair. - (if (and (ly:grob? count-spanner) - (> current-bar last-measure-seen)) - (set! new-measure? #t)) - (if new-measure? + ;; Each measure of a count receives a new spanner, which is bounded + ;; by the first "command column" of that measure and the following one. + ;; The possibility of initial grace notes (negative measure position) + ;; is considered. + (if (and (> current-bar last-measure-seen) + (moment<=? now ZERO-MOMENT)) (begin - ;; Check if we have the first column of the measure. - ;; The possibility of initial grace notes is considered. - (if (moment<=? now ZERO-MOMENT) + ;; Finish the previous count-spanner if there is one. + (if (ly:grob? count-spanner) + (begin + (ly:spanner-set-bound! count-spanner RIGHT col) + (ly:pointer-group-interface::add-grob count-spanner 'columns col) + (ly:engraver-announce-end-grob trans count-spanner col) + (set! count-spanner '()))) + ;; If count is over, reset variables. + (if stop? (begin - ;; If we have the first column, finish the previous - ;; counter-spanner (if there is one). - (if (ly:grob? count-spanner) - (begin - (ly:spanner-set-bound! count-spanner RIGHT col) - (ly:pointer-group-interface::add-grob count-spanner 'columns col) - (ly:engraver-announce-end-grob trans count-spanner col) - (set! count-spanner '()))) - ;; if count is over, reset variables - (if stop? - (begin - (set! elapsed 0) - (set! stop? #f))) - ;; if count is in progress, begin a counter object - (if go? - (let* ((c (ly:engraver-make-grob trans 'MeasureCounter col)) - (counter (ly:grob-property c 'count-from))) - (ly:spanner-set-bound! c LEFT col) - (ly:pointer-group-interface::add-grob c 'columns col) - (set! (ly:grob-property c 'count-from) (+ counter elapsed)) - (set! count-spanner c) - (set! elapsed (1+ elapsed)))) - (set! new-measure? #f))))) - (set! last-measure-seen current-bar))) + (set! elapsed 0) + (set! stop? #f))) + ;; If count is in progress, begin a count-spanner. + (if go? + (let* ((c (ly:engraver-make-grob trans 'MeasureCounter col)) + (counter (ly:grob-property c 'count-from))) + (ly:spanner-set-bound! c LEFT col) + (ly:pointer-group-interface::add-grob c 'columns col) + (set! (ly:grob-property c 'count-from) (+ counter elapsed)) + (set! count-spanner c) + (set! elapsed (1+ elapsed)))))) + (set! last-measure-seen current-bar))) ((finalize trans) (if go? -- 2.39.2