[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
series-music.cropped.png
Description: PNG image