2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2000--2015 Jan Nieuwenhuizen <janneke@gnu.org>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "arpeggio.hh"
23 #include "font-interface.hh"
25 #include "international.hh"
27 #include "output-def.hh"
28 #include "pointer-group-interface.hh"
29 #include "staff-symbol-referencer.hh"
30 #include "staff-symbol.hh"
35 get_squiggle (Grob *me)
37 Font_metric *fm = Font_interface::get_default_font (me);
38 Stencil squiggle = fm->find_by_name ("scripts.arpeggio");
44 Arpeggio::get_common_y (Grob *me)
48 extract_grob_set (me, "stems", stems);
49 for (vsize i = 0; i < stems.size (); i++)
51 Grob *stem = stems[i];
52 common = common->common_refpoint (Staff_symbol_referencer::get_staff_symbol (stem),
59 MAKE_SCHEME_CALLBACK (Arpeggio, calc_cross_staff, 1);
61 Arpeggio::calc_cross_staff (SCM grob)
63 Grob *me = unsmob<Grob> (grob);
65 extract_grob_set (me, "stems", stems);
68 for (vsize i = 0; i < stems.size (); i++)
71 vag = Grob::get_vertical_axis_group (stems[i]);
74 if (vag != Grob::get_vertical_axis_group (stems[i]))
82 MAKE_SCHEME_CALLBACK (Arpeggio, calc_positions, 1);
84 Arpeggio::calc_positions (SCM grob)
86 Grob *me = unsmob<Grob> (grob);
87 Grob *common = get_common_y (me);
92 Using stems here is not very convenient; should store noteheads
93 instead, and also put them into the support. Now we will mess up
94 in vicinity of a collision.
97 Real my_y = me->relative_coordinate (common, Y_AXIS);
99 extract_grob_set (me, "stems", stems);
100 for (vsize i = 0; i < stems.size (); i++)
102 Grob *stem = stems[i];
103 Grob *ss = Staff_symbol_referencer::get_staff_symbol (stem);
104 Interval iv = Stem::head_positions (stem);
105 iv *= Staff_symbol_referencer::staff_space (me) / 2.0;
106 Real staff_y = ss ? ss->relative_coordinate (common, Y_AXIS) : 0.0;
107 heads.unite (iv + staff_y - my_y);
110 heads *= 1 / Staff_symbol_referencer::staff_space (me);
112 return ly_interval2scm (heads);
115 MAKE_SCHEME_CALLBACK (Arpeggio, print, 1);
117 Arpeggio::print (SCM smob)
119 Grob *me = unsmob<Grob> (smob);
120 Interval heads = robust_scm2interval (me->get_property ("positions"),
122 * Staff_symbol_referencer::staff_space (me);
124 if (heads.is_empty () || heads.length () < 0.5)
126 if (to_boolean (me->get_property ("transparent")))
129 This is part of a cross-staff/-voice span-arpeggio,
130 so we need to ensure `heads' is large enough to encompass
131 a single trill-element since the span-arpeggio depends on
132 its children to prevent collisions.
134 heads.unite (get_squiggle (me).extent (Y_AXIS));
138 me->warning (_ ("no heads for arpeggio found?"));
144 SCM ad = me->get_property ("arpeggio-direction");
145 Direction dir = CENTER;
146 if (is_direction (ad))
150 Stencil squiggle (get_squiggle (me));
153 Compensate for rounding error which may occur when a chord
154 reaches the center line, resulting in an extra squiggle
155 being added to the arpeggio stencil. This value is appreciably
156 larger than the rounding error, which is in the region of 1e-16
157 for a global-staff-size of 20, but small enough that it does not
158 interfere with smaller staff sizes.
160 const Real epsilon = 1e-3;
165 Font_metric *fm = Font_interface::get_default_font (me);
166 arrow = fm->find_by_name ("scripts.arpeggio.arrow." + ::to_string (dir));
167 heads[dir] -= dir * arrow.extent (Y_AXIS).length ();
170 while (mol.extent (Y_AXIS).length () + epsilon < heads.length ())
171 mol.add_at_edge (Y_AXIS, UP, squiggle, 0.0);
173 mol.translate_axis (heads[LEFT], Y_AXIS);
175 mol.add_at_edge (Y_AXIS, dir, arrow, 0);
177 return mol.smobbed_copy ();
180 /* Draws a vertical bracket to the left of a chord
181 Chris Jackson <chris@fluffhouse.org.uk> */
183 MAKE_SCHEME_CALLBACK (Arpeggio, brew_chord_bracket, 1);
185 Arpeggio::brew_chord_bracket (SCM smob)
187 Grob *me = unsmob<Grob> (smob);
188 Interval heads = robust_scm2interval (me->get_property ("positions"),
190 * Staff_symbol_referencer::staff_space (me);
193 = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"))
194 * robust_scm2double (me->get_property ("thickness"), 1);
195 Real sp = 1.5 * Staff_symbol_referencer::staff_space (me);
196 Real dy = heads.length () + sp;
197 Real x = robust_scm2double (me->get_property ("protrusion"), 0.4);
199 Stencil mol (Lookup::bracket (Y_AXIS, Interval (0, dy), th, x, th));
200 mol.translate_axis (heads[LEFT] - sp / 2.0, Y_AXIS);
201 return mol.smobbed_copy ();
204 MAKE_SCHEME_CALLBACK (Arpeggio, brew_chord_slur, 1);
206 Arpeggio::brew_chord_slur (SCM smob)
208 Grob *me = unsmob<Grob> (smob);
209 SCM dash_definition = me->get_property ("dash-definition");
210 Interval heads = robust_scm2interval (me->get_property ("positions"),
212 * Staff_symbol_referencer::staff_space (me);
215 = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"))
216 * robust_scm2double (me->get_property ("line-thickness"), 1.0);
218 = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"))
219 * robust_scm2double (me->get_property ("thickness"), 1.0);
220 Real dy = heads.length ();
222 Real height_limit = 1.5;
224 Bezier curve = slur_shape (dy, height_limit, ratio);
227 Stencil mol (Lookup::slur (curve, th, lt, dash_definition));
228 mol.translate_axis (heads[LEFT], Y_AXIS);
229 return mol.smobbed_copy ();
233 We have to do a callback, because print () triggers a
234 vertical alignment if it is cross-staff.
236 MAKE_SCHEME_CALLBACK (Arpeggio, width, 1);
238 Arpeggio::width (SCM smob)
240 Grob *me = unsmob<Grob> (smob);
241 return ly_interval2scm (get_squiggle (me).extent (X_AXIS));
244 MAKE_SCHEME_CALLBACK (Arpeggio, pure_height, 3);
246 Arpeggio::pure_height (SCM smob, SCM, SCM)
248 Grob *me = unsmob<Grob> (smob);
249 if (to_boolean (me->get_property ("cross-staff")))
250 return ly_interval2scm (Interval ());
252 return Grob::stencil_height (smob);
255 ADD_INTERFACE (Arpeggio,
256 "Functions and settings for drawing an arpeggio symbol.",
259 "arpeggio-direction "
260 "dash-definition " // TODO: make apply to non-slur arpeggios
264 "script-priority " // TODO: make around-note-interface