Reviewers: ,
Description:
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.
Please review this at https://codereview.appspot.com/267790043/
Affected files (+52, -10 lines):
A input/regression/part-combine-unequal-lengths.ly
M scm/part-combiner.scm
Index: 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
0000000000000000000000000000000000000000..8b7c23bd3bf8f8650bfb54a8d6f074db3288eadd
--- /dev/null
+++ b/input/regression/part-combine-unequal-lengths.ly
@@ -0,0 +1,13 @@
+\version "2.19.27"
+
+\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' }
+ c'
+}
Index: scm/part-combiner.scm
diff --git a/scm/part-combiner.scm b/scm/part-combiner.scm
index
85548030ecaddb33cde537a8c4d731d3b9afedaf..d7361864b7ed6c2262509bfe88b0482719a26854
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 <Voice-state>))
+ (define (duration-max event d1)
+ (let ((d2 (ly:event-property event 'duration #f)))
+ (if d2
+ (if (ly:duration<? d1 d2) d2 d1)
+ d1)))
+
+ (fold duration-max (ly:make-duration 0 0 0) (events vs)))
+
+;; Return the moment that the longest event in the Voice-state ends.
+(define-method (end-moment (vs <Voice-state>))
+ (ly:moment-add (moment vs) (ly:duration-length (duration vs))))
+
(define-method (note-events (vs <Voice-state>))
(define (f? x)
(ly:in-event-class? x 'note-event))
@@ -129,16 +143,31 @@ return the previous voice state."
(if p (span-state p) '())))
(define (make-voice-states evl)
- (let ((vec (list->vector (map (lambda (v)
- (make <Voice-state>
- #: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 <Voice-state>
+ #:moment (caar v)
+ #:tuning (cdar v)
+ #:events (map car (cdr v))))
+ (reverse evl)))
+ (last-real-event (car states)))
+
+ ;; add an entry with no events at the moment the last event ends
+ (set! states
+ (cons (make <Voice-state>
+ #: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
_______________________________________________
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel