lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Incomplete final bar with \parallelMusic


From: David Kastrup
Subject: Re: Incomplete final bar with \parallelMusic
Date: Tue, 09 Jun 2015 11:46:36 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

David Kastrup <address@hidden> writes:

> Stephen MacNeil <address@hidden> writes:
>
>> what about
>>
>>  \set Score.measureLength = #(ly:make-moment 2/4)
>>
>>
>> as far as i know \partial is only for the beginning and from then on you
>> use ly:make-moment
>
> Has been changed with several issues, the last probably being issue 4056
> <URL:https://code.google.com/p/lilypond/issues/detail?id=4056> in
> version 2.19.12.  But it was already _supposed_ to work after issue 3645
> <URL:https://code.google.com/p/lilypond/issues/detail?id=3645> available
> in 2.19.0 and 2.18.1.
>
> At any rate, being able to end on an incomplete bar in \parallelMusic
> seems like a desirable feature, so
>
> <URL:https://code.google.com/p/lilypond/issues/detail?id=4426>

This change has been committed to LilyPond and will appear in version
2.19.22 once it is released.  In the mean time, you can copy and paste
the patched version of parallelMusic into your source code.

parallelMusic =
#(define-void-function (voice-ids music) (list? ly:music?)
   (_i "Define parallel music sequences, separated by '|' (bar check signs),
and assign them to the identifiers provided in @var{voice-ids}.

@var{voice-ids}: a list of music identifiers (symbols containing only letters)

@var{music}: a music sequence, containing BarChecks as limiting expressions.

Example:

@verbatim
  \\parallelMusic #'(A B C) {
    c c | d d | e e |
    d d | e e | f f |
  }
<==>
  A = { c c | d d | }
  B = { d d | e e | }
  C = { e e | f f | }
@end verbatim

The last bar checks in a sequence are not copied to the result in
order to facilitate ending the last entry at non-bar boundaries.
")
   (define voice-count (length voice-ids))
   (define (bar-check? m)
     "Checks whether m is a bar check."
     (eq? (ly:music-property m 'name) 'BarCheck))
   (define (recurse-and-split-list lst)
     "Return either a list of music lists split along barchecks, or @code{#f}."
     (if (any bar-check? lst)
         (let* ((voices (apply circular-list (make-list voice-count '())))
                (current-voices voices)
                (current-sequence '()))
           ;;
           ;; utilities
           (define (push-music m)
             "Push the music expression into the current sequence"
             (set! current-sequence (cons m current-sequence)))
           (define (change-voice)
             "Store the previously built sequence into the current voice and
change to the following voice."
             (set-car! current-voices
                       (cons current-sequence
                             (car current-voices)))
             (set! current-sequence '())
             (set! current-voices (cdr current-voices)))
           (for-each (lambda (m)
                       (let ((split? (recurse-and-split m)))
                         (if split?
                             (for-each
                              (lambda (m)
                                (push-music m)
                                (change-voice))
                              split?)
                             (begin
                               (push-music m)
                               (if (bar-check? m) (change-voice))))))
                     lst)
           (if (pair? current-sequence) (change-voice))
           ;; Un-circularize voices
           (set! voices (list-head voices voice-count))

           ;; Remove trailing bar checks to facilitate ending a
           ;; sequence on a non-bar, reverse partial sequences and sequences
           (set! voices (map!
                         (lambda (l)
                           (map! reverse!
                                 (reverse!
                                  (if (and (pair? l) (pair? (car l))
                                           (bar-check? (caar l)))
                                      (cons (cdar l) (cdr l))
                                      l))))
                         voices))

           ;; check sequence length
           (apply for-each (lambda seqs
                             (define (seq-len seq)
                               (reduce ly:moment-add
                                       (ly:make-moment 0)
                                       (map ly:music-length seq)))
                             (let ((moment-reference (seq-len (car seqs))))
                               (for-each (lambda (seq)
                                           (if (not (equal? (seq-len seq)
                                                            moment-reference))
                                               (ly:music-warning
                                                (if (pair? seq)
                                                    (last seq)
                                                    (caar seqs))
                                                (_ "Bars in parallel music 
don't have the same length"))))
                                         seqs)))
                  voices)
           (map concatenate! voices))
         (let ((deeper (map recurse-and-split lst)))
           (and (any pair? deeper)
                (apply zip (map
                            (lambda (m split)
                              (or split
                                  (ly:music-deep-copy (make-list voice-count 
m))))
                            lst deeper))))))
   (define (recurse-and-split music)
     "This returns either a list of music split along barchecks, or
@code{#f}."
     (let* ((elt (ly:music-property music 'element))
            (elts (ly:music-property music 'elements))
            (split-elt (and (ly:music? elt) (recurse-and-split elt)))
            (split-elts (and (pair? elts) (recurse-and-split-list elts))))
       (and (or split-elt split-elts)
            (map
             (lambda (e es)
               (apply music-clone music
                      (append
                       ;; reassigning the origin of the parent only
                       ;; makes sense if the first expression in the
                       ;; result is from a distributed origin
                       (let ((origin
                              (if (ly:music? elt)
                                  (and (ly:music? e) (ly:music-property e 
'origin #f))
                                  (and (pair? es) (ly:music-property (car es) 
'origin #f)))))
                         (if origin (list 'origin origin) '()))
                       (if (ly:music? e) (list 'element e) '())
                       (if (pair? es) (list 'elements es) '()))))
             (or split-elt (circular-list #f))
             (or split-elts (circular-list #f))))))
   (let ((voices (recurse-and-split music)))
     (if voices
         ;;
         ;; bind voice identifiers to the voices
         (for-each (lambda (voice-id voice)
                     (ly:parser-define! (*parser*) voice-id voice))
                   voice-ids voices)
         (ly:music-warning music
                           (_ "ignoring parallel music without barchecks")))))
Huh.  That's actually a bit much to type in manually.

-- 
David Kastrup

reply via email to

[Prev in Thread] Current Thread [Next in Thread]