问题
Currently I write lilypond code that looks like this:
\version "2.14.2"
P = #parenthesize
\relative c, {
\clef bass
<c \P c'> <e \P e'> <g \P g'>2 <c, \P c'>4 <d \P d'> <e \P e'>2
}
where I repeatedly mean 'this note, together with the same note one octave higher, parenthesized'.
I'd like a way to abbreviate this, so that I can write something like this:
\version "2.14.2"
poct = ...
\relative c, {
\clef bass
\poct c \poct e \poct g2 \poct c,4 \poct d \poct e2
}
As suggested in a helpful answer to an earlier question of mine, I have tried to use a music function, but there is no way I can get this to work. The closest I can get is
poct = #(define-music-function
(parser location note)
(ly:music?)
#{
<< $note \transpose c c \parenthesize $note >>
#})
but this uses <<
.. >>
instead of <
.. >
, which does not render the way I want (and with warnings), and I have no idea why the \transpose c c
actually transposes anything.
Finally, tangentially related, when experimenting with music functions I found it even impossible just to create a music function that mimicks \repeat unfold 2
; the following jumps down an octave between the third and fourth c
:
\version "2.14.2"
double = #(define-music-function
(parser location note)
(ly:music?)
#{
$note $note
#})
\relative c, {
\clef bass
\double c \double e \double g2 \double c,4 \double d \double e2
}
回答1:
Ok, so here is a function I created for you, which will allow you to repeat single pitches. The only catch is that it won't use the \relative
notation. This is because, in relative notation, the following sequence of notes c' c' c'
will obviously be one octave higher than the preceding one. Unfortunately I still could not find a way to have a function such as \function #3 c'
that would output c' c c
. That said, here is my function and some examples:
\version "2.17.28"
times = #(define-music-function
(parser location N note)
(integer? ly:music?)
(cond
((>= N 2)
#{ \repeat unfold $N { \absolute $note } #}
)
((= N 1)
#{ \absolute $note #}
)
)
)
{
a4 \times #3 b4
R1
\times #4 { c'8 d' }
R1
\times #1 { c''1 }
}
So the syntax is simply \times #"number of repetition" { ...music... }
. If only one note is to be repeated, you can omit both {
and }
: \times #"number of repetition" "single note"
.
You can use this function in the middle of a \relative
passage, but then you should enter the pitches for the function as absolute pitches. Have a look:
\version "2.17.28"
times = #(define-music-function
(parser location N note)
(integer? ly:music?)
(cond
((>= N 2)
#{ \repeat unfold $N { \absolute $note } #}
)
((= N 1)
#{ \absolute $note #}
)
)
)
\relative c'' {
c4 d \times #4 e'' f g
}
Note that all notes above are in the same octave. The octave position the note f
is also NOT influenced by this function, it is influenced by the note preceding the function, i.e., the d
.
For sure there is a way to write a better code for this, but I wasn't able to do the trick with neither any \relative
nor \transpose
commands.
And here is some attempt to help you with your parenthesized octave (same function above but with some small alterations):
\version "2.17.28"
timesP = #(define-music-function
(parser location N note)
(integer? ly:music?)
(cond
((>= N 2)
#{
<<
\repeat unfold $N { \absolute $note }
\transpose c c' \repeat unfold $N { \absolute \parenthesize $note }
>>
#}
)
((= N 1)
#{
<<
\absolute $note
{ \transpose c c' \parenthesize $note }
>>
#}
)
)
)
{
a4 \timesP #3 b4
\timesP #8 c'16
\timesP #2 g4
\timesP #4 { c'8 d' } % no parenthesis here because there are two notes as arguments...
\timesP #1 { c''1 } % no parenthesis here because of the { }
}
\relative c'' {
c4 d \timesP #4 e'' f g
}
There are still some catches here: this function will only parenthesize when the argument is a single note written without { }
. This is well commented on the code above.
I hope this will help you somehow. If I come across the solution for the octave transposition problem here, I will update this answer.
回答2:
I just got this answer from David Kastrup, one of the developers of LilyPond:
The "octave transposition" happens because basically \transpose c c is the same as \absolute (as LilyPond does not apply \relative to transposed music).
\absolute is not necessary in connection with \repeat unfold: \repeat unfold knows how to deal with relative music.
Version 2.14.2 is awfully old. At any rate, there is currently issue http://code.google.com/p/lilypond/issues/detail?id=3673 in the LilyPond tracker, and the respective code can be found at https://codereview.appspot.com/30890043/diff/40001/scm/music-functions.scm
And there we get indeed into Scheme programming. The respective defmacro-public would likely work even in 2.14 though #{ #} might not work properly.
With that definition, your double definition would become:
double = #(define-music-function (parser location note) (ly:music?) (make-relative (note) note #{ $note $note #}))
and would then work in both absolute and relative mode. If the 2.14 #{ #} does not jibe with make-relative, writing (make-sequential-music (list (ly:music-deep-copy note) (ly:music-deep-copy note))) should serve as a Scheme replacement.
The original problem becomes easier to understand once you realize that it's just a simple code replacement, so \relative { \double c' } becomes \relative { c' c' } using different octaves. The make-relative macro will to the \relative operation only on a single note, and then paste the results into the music expression.
回答3:
Based on the code in your question and the answer from David Kastrup quoted in another reply, I built the following code to turn notes into chords with the same note one octave higher, not parenthesized:
#(define (octavate-pitch pitch octaves)
(ly:make-pitch
(+ (ly:pitch-octave pitch) octaves)
(ly:pitch-notename pitch)
(ly:pitch-alteration pitch)))
#(define (articulation-is-of-type? art type)
(string=? (ly:music-property art 'articulation-type) type))
#(define (copy-articulation? art)
(cond ((music-is-of-type? art 'tie-event)
#t)
((and (music-is-of-type? art 'articulation-event)
(articulation-is-of-type? art "fermata"))
#f)
; TODO add more cases
(else
#f)))
#(define (octNote note)
(if (null? (ly:music-property note 'pitch))
note
(make-relative (note) note
(let ((note2 (ly:music-deep-copy note))
(pitch (ly:music-property note 'pitch)))
(set! (ly:music-property note2 'pitch)
(octavate-pitch pitch 1))
(set! (ly:music-property note2 'articulations)
(filter copy-articulation? (ly:music-property note2 'articulations)))
(make-event-chord (list note note2))))))
oct = #(define-music-function
(parser location music)
(ly:music?)
(music-map octNote music))
It can be applied to an individual note or a full music expression:
\relative c' \oct {
c d e f |
g2 g |
}
It also works in the opposite order, \oct \relative c' { … }
.
To parenthesize the added note, replace the last reference to note2
in octNote
with (parenthesize note2)
– I just prefer the non-parenthesized version for my own use. (You should probably rename the functions to octPNote
and octP
in that case, to avoid confusion. I briefly tried to write octPNote
as a function that calls octNote
and post-processes the result to parenthesize the second note, but wasn’t successful.)
You will also almost certainly need to expand the copy-articulation?
predicate – ties and fermate are just the two kinds of articulation I encountered. (It defaults to not copying unknown articulations, so if the predicate is incomplete you’ll see it as missing articulations on the copied note.)
来源:https://stackoverflow.com/questions/19464086/how-to-abbreviate-note-with-the-same-note-an-octave-higher-parenthesized-in-l