[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Voice switching étude
From: |
Dan Eble |
Subject: |
Re: Voice switching étude |
Date: |
Fri, 2 Jan 2015 15:07:13 -0500 |
On Dec 10, 2014, at 23:52 , Dan Eble <address@hidden> wrote:
>
> Here’s a trick: routing music to different voices without using the
> Part_combine_iterator. Instead, it uses the same infrastructure as for staff
> switching.
updated to generate per-part \change commands from the split list generated by
\partcombine
—
Dan
\version "2.19.15"
% These are the parts that will be combined. The explicit \change
% commands mimic \partcombineApart; they override the automated
% decisions and send each part to its own voice.
one = \relative { f'4 b b \change Voice = "1" b }
two = \relative { b'4 b f \change Voice = "2" f }
% Generate a split list using \partcombine. Context changes in the
% input parts cause warnings, so strip them for this step.
killContextChanges =
#(define-music-function
(parser location music) (ly:music?)
(music-filter
(lambda (m) (not (eq? (ly:music-property m 'name) 'ContextChange)))
music))
combined = \partcombine \killContextChanges \one \killContextChanges \two
%
% Translate the split list to a sequence of \change commands for each part.
%
#(define part-one-slot-map
;; each entry is (split state . context id)
'((apart . 1)
(apart-silence . 1)
(chords . shared)
(silence1 . shared)
(silence2 . null)
(solo1 . shared)
(solo2 . null)
(unisono . shared)
(unisilence . shared)))
#(define part-two-slot-map
;; each entry is (split state . context id)
'((apart . 2)
(apart-silence . 2)
(chords . shared)
(silence1 . null)
(silence2 . shared)
(solo1 . null)
(solo2 . shared)
(unisono . null)
(unisilence . null)))
voiceChanges =
#(define-music-function (parser location slot-map partcombinemusic)
(list? ly:music?)
(let ((m (list))
(prevMoment ZERO-MOMENT)
(prevSlot (assq-ref slot-map 'apart)))
(define (handle-split split)
(let* ((moment (car split))
(slot (assq-ref slot-map (cdr split))))
(if (not (eq? prevSlot slot))
(let ((dur (ly:moment-sub moment prevMoment)))
(if (not (equal? dur ZERO-MOMENT))
(set! m (cons (make-music 'SkipEvent
'duration (make-duration-of-length dur)) m)))
(set! m (cons (make-music 'ContextChange
'change-to-id (symbol->string slot)
'change-to-type 'Voice) m))
(set! prevMoment moment)
(set! prevSlot slot)))
))
(for-each handle-split (ly:music-property partcombinemusic 'split-list))
(make-sequential-music (reverse! m))))
oneChanges = \voiceChanges #part-one-slot-map \combined
twoChanges = \voiceChanges #part-two-slot-map \combined
%#(display (ly:music-property combined 'split-list))
%\displayMusic \oneChanges
%\displayMusic \twoChanges
% Wrap each part in a "Part" context which can be moved from one Voice
% context to another.
%
% A hierarchy such as Staff/VoiceSlot/Voice might make more sense in
% musical terms than Staff/Voice/Part.
\layout {
\context {
\name "Part"
\type "Engraver_group"
}
\context {
\Voice
\accepts "Part"
}
}
\score {
\new Staff <<
\new Voice = "1" \with { \voiceOne } <<
\new Part << \oneChanges \one >>
>>
\new Voice = "2" \with { \voiceTwo } <<
\new Part << \twoChanges \two >>
>>
\new Voice = "shared" \with { \override NoteHead.color = #red } <<
% Contexts need to be kept alive in order to change to them.
#(skip-of-length one)
#(skip-of-length two)
>>
\new NullVoice = "null" <<
#(skip-of-length one)
#(skip-of-length two)
>>
>>
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: Voice switching étude,
Dan Eble <=