lilypond-devel
[Top][All Lists]
Advanced

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

Re: Writing multiple-voiced music in chords -- adjusting the syntax or f


From: Aaron Hill
Subject: Re: Writing multiple-voiced music in chords -- adjusting the syntax or finding a magic trick?
Date: Tue, 28 Jun 2022 22:40:00 -0700

On 2022-06-28 7:10 pm, Aaron Hill wrote:
Implementing \seriesMusic amounts to [...]

Proof of concept below, but note that this code lacks any safety/sanity checks.

%%%%
\version "2.22.0"

%% BEGIN FUNCTION DEFINITION

#(define (sequential-music? arg)
  (and (ly:music? arg)
       (music-is-of-type? arg 'sequential-music)))

seriesMusic =
#(define-void-function
  (voice-ids music)
  (symbol-list? sequential-music?)

  (define (non-positive-moment? mom) (moment<=? mom ZERO-MOMENT))
  (define (split-music-by-moment music)
    (let loop ((result '())
               (buffer '())
               (remaining (ly:music-property music 'elements)))
      (if (null? remaining)
        result
        (let* ((next (ly:music-deep-copy (car remaining)))
               (remaining (cdr remaining))
               (buffer (append buffer (list next)))
               (music (make-sequential-music buffer))
               (length (ly:music-length music)))
          (if (non-positive-moment? length)
            (loop result buffer remaining)
            (loop (append result (list (cons length buffer)))
                  '() remaining))))))

  (define voice-count (length voice-ids))
  (define (next-index index) (modulo (1+ index) voice-count))

  (define (assign-music-to-voices music)
    (let loop ((index 0)
               (voices (make-list voice-count (cons ZERO-MOMENT '())))
               (unassigned (split-music-by-moment music)))
      (if (= 0 index)
        (let* ((moments (map car voices))
               (least (reduce moment-min ZERO-MOMENT moments)))
          (set! voices
            (map (lambda (entry)
                   (cons (ly:moment-sub (car entry) least) (cdr entry)))
              voices))))
      (if (null? unassigned) (map cdr voices)
        (let ((voice (list-ref voices index)))
          (if (non-positive-moment? (car voice))
            (let ((next (car unassigned)))
              (list-set! voices index
                (cons (car next) (append (cdr voice) (cdr next))))
              (set! unassigned (cdr unassigned))))
          (loop (next-index index) voices unassigned)))))

  (for-each
    (lambda (id elems)
      (ly:parser-define! id (make-sequential-music elems)))
    voice-ids
    (assign-music-to-voices music)))

%% END FUNCTION DEFINITION

\seriesMusic lowerB, lowerA, upperB, upperA {
  | c1  g2  c'2. e'2~
        a4       \tuplet 3/2 { e4 f g }
        r4  c4(
  | d1  f1  a2   f4--
                 e2^\markup \italic "rit."
            b2)
                 d4_.
  | c1  g1  c1   \tweak color #red <e g>1\fermata
}

%% Ties, slurs, articulations appear to work.
%% Chords and tweaks also seem good.
%% Embedded sequential music (e.g. \tuplet) works,
%%   but this usage resembles \parallelMusic and
%%   does not allow the individual notes within
%%   to interleave with the other voices.

\score {
  \new PianoStaff <<
    \new Staff { \clef treble
      << \relative \upperA \\ \relative \upperB >>
    }
    \new Staff { \clef bass
      << \relative \lowerA \\ \relative \lowerB >>
    }
  >>

  \layout {} \midi { \tempo 4 = 90 }
}
%%%%

I will probably not be able to spend any more time on this, so you will have to take this as-is. Perhaps if others find this input method viable, then they can pick up the reins.

At a minimum, you should be able to play around and determine whether it helps (or hinders) your workflow. I would recommend comparing it to \parallelMusic, as that is the officially supported system.


-- Aaron Hill

Attachment: series-music.cropped.png
Description: PNG image


reply via email to

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