From 7ff6dd85ed40475f01a0b2847354aa1d486f053b Mon Sep 17 00:00:00 2001 From: Dan Eble Date: Mon, 7 Sep 2015 18:14:14 -0400 Subject: [PATCH] Issue 913: improve \partcombine when parts have unequal lengths Add terminal entries to Voice-state arrays at the moment the last event ends. This also improves Issue 1677 by engraving notes that were missing; however, it does not resolve it because the rests are still wrong. --- .../part-combine-unequal-lengths.ly | 14 ++++++ scm/part-combiner.scm | 50 +++++++++++++++---- 2 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 input/regression/part-combine-unequal-lengths.ly diff --git a/input/regression/part-combine-unequal-lengths.ly b/input/regression/part-combine-unequal-lengths.ly new file mode 100644 index 0000000000..b21a2aa965 --- /dev/null +++ b/input/regression/part-combine-unequal-lengths.ly @@ -0,0 +1,14 @@ +\version "2.19.28" + +\header { + texidoc ="The part combiner can combine parts of unequal lengths." +} + +\layout { ragged-right = ##t } + +\new Staff { %% based on the example in Issue 913 + c'1 + \partcombine { e' r } { c' } + \partcombine { b' } {} + \partcombine {} { f' } +} diff --git a/scm/part-combiner.scm b/scm/part-combiner.scm index 85548030ec..71b5e56526 100644 --- a/scm/part-combiner.scm +++ b/scm/part-combiner.scm @@ -39,6 +39,20 @@ (display (span-state x) file) (display "\n" file)) +;; Return the duration of the longest event in the Voice-state. +(define-method (duration (vs )) + (define (duration-max event d1) + (let ((d2 (ly:event-property event 'duration #f))) + (if d2 + (if (ly:duration)) + (ly:moment-add (moment vs) (ly:duration-length (duration vs)))) + (define-method (note-events (vs )) (define (f? x) (ly:in-event-class? x 'note-event)) @@ -129,16 +143,32 @@ return the previous voice state." (if p (span-state p) '()))) (define (make-voice-states evl) - (let ((vec (list->vector (map (lambda (v) - (make - #:moment (caar v) - #:tuning (cdar v) - #:events (map car (cdr v)))) - evl)))) - (do ((i 0 (1+ i))) - ((= i (vector-length vec)) vec) - (slot-set! (vector-ref vec i) 'vector-index i) - (slot-set! (vector-ref vec i) 'state-vector vec)))) + (let* ((states (map (lambda (v) + (make + #:moment (caar v) + #:tuning (cdar v) + #:events (map car (cdr v)))) + (reverse evl)))) + + ;; add an entry with no events at the moment the last event ends + (if (pair? states) + (let ((last-real-event (car states))) + (set! states + (cons (make + #:moment (end-moment last-real-event) + #:tuning (tuning last-real-event) + #:events '()) + states)))) + + ;; TODO: Add an entry at +inf.0 and see if it allows us to remove + ;; the many instances of conditional code handling the case that + ;; there is no voice state at a given moment. + + (let ((vec (list->vector (reverse! states)))) + (do ((i 0 (1+ i))) + ((= i (vector-length vec)) vec) + (slot-set! (vector-ref vec i) 'vector-index i) + (slot-set! (vector-ref vec i) 'state-vector vec))))) (define (make-split-state vs1 vs2) "Merge lists VS1 and VS2, containing Voice-state objects into vector -- 2.39.2