Skip to content

Commit 439be7e

Browse files
authored
Merge pull request #156 from openlilylib/acb
pedal decorations
2 parents bc712e0 + d222034 commit 439be7e

File tree

2 files changed

+224
-0
lines changed

2 files changed

+224
-0
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
\version "2.19.50"
2+
3+
\header {
4+
snippet-title = "Pedal Decorations"
5+
snippet-author = "Andrew Bernard"
6+
snippet-author-email = "andrew.bernard@gmail.com"
7+
snippet-source = ""
8+
snippet-description = \markup {
9+
Add arbitrary cautionary text to pedal brackets on the left hand side,
10+
and optionally continuation arrows on the right hand side as well.
11+
}
12+
tags = "pedal, bracket, arrow, cautionary"
13+
status = "ready"
14+
}
15+
16+
17+
% Pedal bracket decorations - text on LHS and arrows on RHS.
18+
% Andrew Bernard
19+
% With thanks to Thomas Morley for spanner bounds code.
20+
21+
pedalWithArrowsAndTextCallback =
22+
#(define-scheme-function (lhs-text use-arrows)
23+
(string? boolean?)
24+
"lhs-text - text to decorate LHS of bracket.
25+
use-arrows - boolean: use arrows on RHS if true."
26+
27+
(define (make-arrow-path arrow-length arrowhead-height arrowhead-width)
28+
"Draw arrow with triangular arrowhead."
29+
(list
30+
'moveto 0 0
31+
'lineto arrow-length 0
32+
'lineto arrow-length (/ arrowhead-width 2)
33+
'lineto (+ arrow-length arrowhead-height) 0
34+
'lineto arrow-length (- (/ arrowhead-width 2))
35+
'lineto arrow-length 0
36+
'closepath
37+
))
38+
39+
(lambda (grob)
40+
41+
;; function to modify the individual grob part
42+
(define add-decorations
43+
(lambda (g list-length)
44+
(let* (
45+
;; unpack the argument
46+
(index (car g))
47+
(grobber (cadr g))
48+
(last (= index list-length))
49+
50+
;; get the default-stencil and its x-dimension and x-length.
51+
(stil (ly:piano-pedal-bracket::print grobber))
52+
(stil-x-extent (ly:stencil-extent stil X))
53+
(stil-x-length (interval-length stil-x-extent))
54+
55+
;; make arrow for the rhs end
56+
(new-stil (if (and use-arrows (not last))
57+
(begin
58+
(let* (
59+
(thickness 0.1)
60+
(arrowhead-height 1.0)
61+
(arrowhead-width 1.0)
62+
(arrow-length 1.0)
63+
(arrow
64+
(make-path-stencil
65+
(make-arrow-path
66+
arrow-length
67+
arrowhead-height
68+
arrowhead-width)
69+
thickness 1 1 #t)))
70+
(ly:stencil-combine-at-edge stil X RIGHT arrow -2)))
71+
stil))
72+
73+
;; make text for the lhs end
74+
(text-stil
75+
(grob-interpret-markup grobber
76+
(markup
77+
#:line
78+
(#:abs-fontsize
79+
6
80+
(#:sans
81+
(#:upright
82+
(#:whiteout (#:box (#:pad-markup 0.3 lhs-text)))))))))
83+
84+
;; get a list of spanners bounded by PianoPedalBrackets
85+
;; left-bound, which is PaperColumn or NonMusicalPaperColumn
86+
(left-bound-spanners
87+
(ly:grob-array->list
88+
(ly:grob-object
89+
(ly:spanner-bound grobber LEFT)
90+
'bounded-by-me)))
91+
92+
;; filter left-bound-spanners for PianoPedalBrackets
93+
(piano-pedal-brackets
94+
(filter
95+
(lambda (gr)
96+
(grob::has-interface gr 'piano-pedal-bracket-interface))
97+
left-bound-spanners))
98+
99+
;; delete identical PianoPedalBracket from piano-pedal-brackets
100+
;; TODO `delete-duplicates' may be expensive, see guile-manual
101+
;; find another method
102+
(bounded-piano-brackets-per-column
103+
(delete-duplicates piano-pedal-brackets))
104+
105+
;; only add text-stil, if current Column does not have two
106+
;; PianoPedalBrackets
107+
;; TODO is this condition really sufficient?
108+
(new-stil
109+
(if (= (length bounded-piano-brackets-per-column) 2)
110+
new-stil
111+
(ly:stencil-stack new-stil X LEFT text-stil -6))))
112+
113+
(ly:grob-set-property! grobber 'stencil new-stil))))
114+
115+
(let* (
116+
;; get broken pieces, or the single unbroken grob
117+
(orig (ly:grob-original grob))
118+
(pieces (ly:spanner-broken-into orig))
119+
(pieces (if (null? pieces)
120+
(list orig)
121+
pieces))
122+
(pieces-indexed-list (zip (iota (length pieces) 1) pieces))
123+
(pieces-length (length pieces)))
124+
125+
;; We want arrows on all segments but the last, and text on all segments,
126+
;; so we have to pass some notion of list index to the function doing the
127+
;; decorating. Hence the ziplist combining grob segment and index in pairs.
128+
129+
(let loop ((count 0))
130+
(if (< count pieces-length)
131+
(begin
132+
(add-decorations (list-ref pieces-indexed-list count) pieces-length)
133+
(loop (+ count 1))))))))
134+
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
\version "2.19.50"
2+
3+
\include "./definitions.ily"
4+
5+
% example usage
6+
pedalWithArrowsAndTextPed =
7+
\override Score.PianoPedalBracket.after-line-breaking = #(pedalWithArrowsAndTextCallback "(ped)" #t)
8+
9+
pedalWithArrowsAndTextHalfPed =
10+
\override Score.PianoPedalBracket.after-line-breaking = #(pedalWithArrowsAndTextCallback "½ ped" #t)
11+
12+
pedalWithArrowsAndTextThreeP =
13+
\override Score.PianoPedalBracket.after-line-breaking = #(pedalWithArrowsAndTextCallback "3P" #t)
14+
15+
pedalWithArrowsAndTextUC =
16+
\override Score.PianoPedalBracket.after-line-breaking = #(pedalWithArrowsAndTextCallback "UC" #t)
17+
18+
pedalWithTextPed =
19+
\override Score.PianoPedalBracket.after-line-breaking = #(pedalWithArrowsAndTextCallback "(ped)" #f)
20+
21+
% example music
22+
23+
treble = {
24+
\clef treble
25+
\time 4/4
26+
c'4 c' c' c'
27+
c' c' c' c'
28+
}
29+
30+
bass = {
31+
\clef bass
32+
\time 4/4
33+
34+
c4
35+
\pedalWithArrowsAndTextHalfPed
36+
c\sustainOn c c
37+
c c c c
38+
\break
39+
c c c c
40+
\break
41+
c c c^\sustainOff\sustainOn c
42+
\break
43+
c c c c
44+
\break
45+
c c\sustainOff\sustainOn c c
46+
\break
47+
c c c c
48+
\break
49+
c c c c\sustainOff
50+
c c c c
51+
\break
52+
% turn off decorations
53+
\revert Score.PianoPedalBracket.after-line-breaking
54+
c c\sustainOn c c
55+
c c c c
56+
\break
57+
c c c\sustainOff c
58+
\pedalWithArrowsAndTextThreeP
59+
c\sustainOn c c\sustainOff
60+
c\sustainOn
61+
\break
62+
c c c c
63+
c c c c\sustainOff
64+
\break
65+
c
66+
\pedalWithArrowsAndTextUC
67+
c\sustainOn c c
68+
c c c\sustainOff
69+
\pedalWithTextPed
70+
c\sustainOn
71+
\break
72+
c c c c
73+
c c c\sustainOff c
74+
}
75+
76+
\score {
77+
78+
\new PianoStaff
79+
<<
80+
\new Staff = "treble" { \treble }
81+
\new Staff = "bass" { \bass }
82+
>>
83+
84+
\layout {
85+
\context {
86+
\Score
87+
pedalSustainStyle = #'bracket
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)