@knownissues
Only the contents of the first @code{Voice} occurring in an
-@code{\addQuote} command will be considered for quotation, so the music
-expression must not contain @code{\new} and @code{\context Voice}
-statements which would switch to a different Voice. Quoting grace notes
+@code{\addQuote} command will be considered for quotation, so if the music
+expression contains @code{\new} or @code{\context Voice}
+statements, their contents will not be quoted. Quoting grace notes
is unsupported and may cause LilyPond to crash whereas quoting nested
triplets may result in poor notation.
-\version "2.15.6"
+\version "2.15.9"
\header {
texidoc = "@code{\\quoteDuring} and @code{\\cueDuring} shall properly quote
-voices that create a sub-voice. The sub-voice will not be quoted, though.
+voices that create a sub-voice. The sub-voice will not be quoted, though.
+Exceptions are sections of parallel music @code{<< @{...@} \\ @{...@} >>},
+which will be quoted.
"
}
-
+% Simple case, normal sub-voice
quoteMe = \relative c' {
c4 c
\new Voice {
c4 c
}
}
-\addQuote quoteMe \quoteMe
+\addQuote "quoteMe" \quoteMe
+% Also works if wrapped with \new Voice
+\addQuote "quoteMeA" \new Voice \quoteMe
+
+% Also works with voice directly inside relative
+quoteMeI = \relative c' \new Voice {
+ c4 c4
+}
+\addQuote "quoteMeI" \quoteMeI
+
+% Quoting music with some parallel sections (identical rhythm)
+quoteMeII = \relative c' {
+ c4 c
+ << { d4 e4 } \\ { c4 b4 } >>
+ c4
+}
+\addQuote "quoteMeII" \quoteMeII
-\relative c'' {
- c4 \cueDuring #"quoteMe" #DOWN { r4 } % <- show a cue note from quoteMe
- c4 \cueDuring #"quoteMe" #DOWN { r4 } % <- no cue note due to sub-voice
+% Quoting music with some parallel sections (different rhythm)
+quoteMeIII = \relative c' {
+ c4 c
+ << { d4 e4 } \\ { c4. b8 } >>
+ c4
}
+\addQuote "quoteMeIII" \quoteMeIII
+
+
+
+
+<<
+ \new Staff \relative c'' {
+ c4 \cueDuring #"quoteMe" #DOWN { r4 }
+ c4 \cueDuring #"quoteMe" #DOWN { r4 } % <- no cue note due to sub-voice
+ }
+ \new Staff \relative c'' {
+ c4 \cueDuring #"quoteMeA" #DOWN { r4 }
+ c4 \cueDuring #"quoteMeA" #DOWN { r4 } % <- no cue note due to sub-voice
+ }
+ \new Staff \relative c'' {
+ c4 \cueDuring #"quoteMeI" #DOWN { r4 }
+ c4
+ }
+ \new Staff \relative c'' {
+ c4 \cueDuring #"quoteMeII" #DOWN { r4 }
+ c4 \cueDuring #"quoteMeII" #DOWN { r4 } % <- quoted parallel notes
+ }
+ \new Staff \relative c'' {
+ c4 \cueDuring #"quoteMeIII" #DOWN { r4 }
+ c4 \cueDuring #"quoteMeIII" #DOWN { r4 } % <- quoted parallel notes
+ }
+>>
(set! (ly:music-property music 'quoted-events) quoted-vector)
(set! (ly:music-property music 'iterator-ctor)
ly:quote-iterator::constructor))
- (ly:warning (_ "cannot find quoted music: `~S'") quoted-name)))
+ (ly:music-message music (ly:format (_ "cannot find quoted music: `~S'") quoted-name))))
music))
(define-public (add-quotable parser name mus)
(let* ((tab (eval 'musicQuotes (current-module)))
- ;; If a Voice is passed, use its contents:
- (contents (if (equal? (ly:music-property mus 'name) 'ContextSpeccedMusic)
- (ly:music-property mus 'element)
- mus))
(voicename (get-next-unique-voice-name))
- ;; recording-group-emulate returns an assoc list, so hand it a
- ;; proper unique context name and extract that key:
- (context-list (recording-group-emulate (context-spec-music contents 'Voice voicename)
- (ly:parser-lookup parser 'partCombineListener)))
- (quote-contents (if (assoc voicename context-list)
- (assoc-get voicename context-list)
- '())))
-
- (if quote-contents
- (hash-set! tab name (list->vector (reverse! quote-contents '()))))))
+ ;; recording-group-emulate returns an assoc list (reversed!), so
+ ;; hand it a proper unique context name and extract that key:
+ (ctx-spec (context-spec-music mus 'Voice voicename))
+ (listener (ly:parser-lookup parser 'partCombineListener))
+ (context-list (reverse (recording-group-emulate ctx-spec listener)))
+ (raw-voice (assoc voicename context-list))
+ (quote-contents (if (pair? raw-voice) (cdr raw-voice) '())))
+
+ ;; If the context-specced quoted music does not contain anything, try to
+ ;; use the first child, i.e. the next in context-list after voicename
+ ;; That's the case e.g. for \addQuote "x" \relative c \new Voice {...}
+ (if (null? quote-contents)
+ (let find-non-empty ((current-tail (member raw-voice context-list)))
+ ;; if voice has contents, use them, otherwise check next ctx
+ (cond ((null? current-tail) #f)
+ ((and (pair? (car current-tail))
+ (pair? (cdar current-tail)))
+ (set! quote-contents (cdar current-tail)))
+ (else (find-non-empty (cdr current-tail))))))
+
+ (if (not (null? quote-contents))
+ (hash-set! tab name (list->vector (reverse! quote-contents '())))
+ (ly:music-message mus (ly:format (_ "quoted music `~a' is empty") name)))))