Janek Warchoł <janek.lilyp...@gmail.com> writes: > 2014-10-12 12:45 GMT+02:00 David Kastrup <d...@gnu.org>: >> I'm not even sure I understand _how_ you want the relativization to >> happen. One after the other? > > If you mean \musicII should be relativized after \music, that's > roughly what i want. > >> In that case, you can use >> >> voiceDivisi = >> #(define-music-function (parser location m1 m2) (ly:music? ly:music?) >> (make-relative (m1 m2) #{ #m1 #m2 #} >> #{ >> \tag divI { $m1 } >> \tag divII { $m2 } >> \tag together << { \dynamicUp $m1 } \\ { \dynamicDown $m2 } >> >> #})) > > Seems to work! :) > >> > How should i work around this? Maybe instead of using tags i should >> > write a function with a switch statement inside? I know that i can >> > put \relative command inside \voiceDivisi, but i'd like to avoid this >> > as it would add a lot of typing. >> >> It seems like the ingenuity of my make-relative macro never really >> caught on... > > I've found https://code.google.com/p/lilypond/issues/detail?id=3118 > and looked at input/regression/make-relative.ly but i don't think i > really understand what it does (and how).
Probably neither do I. Let's see. (defmacro-public make-relative (variables reference music) "The list of pitch or music variables in @var{variables} is used as a sequence for creating relativable music from @var{music}. When the constructed music is used outside of @code{\\relative}, it just reflects plugging in the @var{variables} into @var{music}. The action inside of @code{\\relative}, however, is determined by first relativizing the surrogate @var{reference} with the variables plugged in and then using the variables relativized as a side effect of relativizing @var{reference} for evaluating @var{music}. Since pitches don't have the object identity required for tracing the effect of the reference call, they are replaced @emph{only} for the purpose of evaluating @var{reference} with simple pitched note events. The surrogate @var{reference} expression has to be written with that in mind. In addition, it must @emph{not} contain @emph{copies} of music that is supposed to be relativized but rather the @emph{originals}. This @emph{includes} the pitch expressions. As a rule, inside of @code{#@{@dots{}#@}} variables must @emph{only} be introduced using @code{#}, never via the copying construct @code{$}. The reference expression will usually just be a sequential or chord expression naming all variables in sequence, implying that following music will be relativized according to the resulting pitch of the last or first variable, respectively. Since the usual purpose is to create more complex music from general arguments and since music expression parts must not occur more than once, one @emph{does} generally need to use copying operators in the @emph{replacement} expression @var{music} when using an argument more than once there. Using an argument more than once in @var{reference}, in contrast, does not make sense. There is another fine point to mind: @var{music} must @emph{only} contain freshly constructed elements or copied constructs. This will be the case anyway for regular LilyPond code inside of @code{#@{@dots{}#@}}, but any other elements (apart from the @var{variables} themselves which are already copied) must be created or copied as well. The reason is that it is usually permitted to change music in-place as long as one does a @var{ly:music-deep-copy} on it, and such a copy of the whole resulting expression will @emph{not} be able to copy variables/values inside of closures where the information for relativization is being stored. " That's some DOC string alright. So how does it work? Short of the doc string, the definition is (defmacro-public make-relative (variables reference music) (define ((make-relative::to-relative-callback variables music-call ref-call) music pitch) (let* ((ref-vars (map (lambda (v) (if (ly:pitch? v) (make-music 'NoteEvent 'pitch v) (ly:music-deep-copy v))) variables)) (after-pitch (ly:make-music-relative! (apply ref-call ref-vars) pitch)) (actual-vars (map (lambda (v r) (if (ly:pitch? v) (ly:music-property r 'pitch) r)) variables ref-vars)) (rel-music (apply music-call actual-vars))) (set! (ly:music-property music 'element) rel-music) after-pitch)) `(make-music 'RelativeOctaveMusic 'to-relative-callback (,make-relative::to-relative-callback (list ,@variables) (lambda ,variables ,music) (lambda ,variables ,reference)) 'element ,music)) So it creates "RelativeOctaveMusic" (which is just a wrapper for absolute and/or relativized music) but with an additional to-relative callback. When used outside of \relative, the music is used verbatim (as 'element field). So in absolute mode, << ... \\ ... >> or anything else should work. But if the music is of form #{ ... #}, each copy of that music is interpreted separately, so the changes done to 'element ,music don't propagate to (lambda ,variables ,music). So voicify-music will not in generally reach in there unless you do something like (let ((mus #{ << #m1 \\ #m2 >> #})) (make-relative () #{ #m1 #m2 #} mus)) In that case, the relation of the m1 and m2 used in the input no longer travel into the macro via the macro parameters but via the variables itself. I have no actual idea what this would do, really. At any rate, you are better off not putting _anything_ into the argument of make-relative that would require scorification (like << \\ >> or chord repeats or pitch-less durations) for now. This is really hairy stuff, and maybe I did not properly think it through. Still, it tends to produce better results than most other approaches. -- David Kastrup _______________________________________________ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user