2 notehead.cc -- implement Note_head
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
13 #include "note-head.hh"
15 #include "font-interface.hh"
16 #include "molecule.hh"
17 #include "musical-request.hh"
18 #include "rhythmic-head.hh"
21 Note_head contains the code for printing note heads.
25 It also contains the ledger lines, for historical reasons. Ledger
26 lines are somewhat of a PITA. In some cases, they take up no space, in
27 some cases they don't:
31 - when ledgered notes are juxtaposed: there should be some white
32 space between the ledger lines.
34 - when accidentals are near: the accidentals should not be on the
37 [both tips by Heinz Stolba from Universal Edition].
39 DO NOT take space into account:
41 - for basically everything else, e.g. swapping ledgered notes on
42 clustered chords, spacing between ledgered and unledgered notes.
44 TODO: fix this. It is not feasible to have a special grob for
45 ledgers, since you basically don't know if there will be ledgers,
46 unless you know at interpretation phase already 1. the Y-position,
47 2. the number of staff lines. It's not yet specced when both pieces
48 of information are there, so for now, it is probably better to build
49 special support for ledgers into the accidental and separation-item
52 (Besides a separate ledger seems overkill. For what else would
57 #include "staff-symbol-referencer.hh"
60 build a ledger line for small pieces.
63 Note_head::ledger_line (Grob *me, Interval xwid)
65 Drul_array<Molecule> endings;
66 endings[LEFT] = Font_interface::get_default_font (me)->find_by_name ("noteheads-ledgerending");
67 Molecule *e = &endings[LEFT];
70 Real thick = e->extent (Y_AXIS).length ();
71 Real len = e->extent (X_AXIS).length () - thick;
76 endings[d].translate_axis (xwid[d] - endings[d].extent (X_AXIS)[d], X_AXIS);
77 total.add_molecule (endings[d]);
78 } while ((flip (&d)) != LEFT);
80 Real xpos = xwid [LEFT] + len;
82 while (xpos + len + thick /2 <= xwid[RIGHT])
84 e->translate_axis (len, X_AXIS);
85 total.add_molecule (*e);
94 Note_head::ledger_lines (Grob*me,
96 int count, Direction dir, Interval idw)
98 Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
108 Molecule ledger (ledger_line (me, idw));
111 ledger.set_empty (true);
113 Real offs = (Staff_symbol_referencer::on_staffline (me))
118 for (int i=0; i < count; i++)
121 s.translate_axis (-dir * inter_f * i*2 + offs,
123 legs.add_molecule (s);
130 internal_brew_molecule (Grob *me, bool ledger_take_space)
132 int sz = Staff_symbol_referencer::line_count (me)-1;
133 int p = (int) rint (Staff_symbol_referencer::position_f (me));
134 int streepjes_i = abs (p) < sz
138 SCM style = me->get_grob_property ("style");
139 if (!gh_symbol_p (style))
145 ugh: use gh_call () / scm_apply ().
147 UGH: use grob-property.
149 SCM log = gh_int2scm (Rhythmic_head::balltype_i (me));
150 SCM exp = scm_list_n (ly_symbol2scm ("find-notehead-symbol"), log,
151 ly_quote_scm (style),
153 String name = "noteheads-" + ly_scm2string (scm_primitive_eval (exp));
154 Molecule out = Font_interface::get_default_font (me)->find_by_name (name);
158 Direction dir = (Direction)sign (p);
159 Interval hd = out.extent (X_AXIS);
160 Real left_ledger_protusion = hd.length ()/4;
161 Real right_ledger_protusion = left_ledger_protusion;
163 if (unsmob_grob(me->get_grob_property ("accidentals-grob")))
166 make a little room for accidentals.
168 TODO: this will look silly if a chord has ledger lines,
169 and only the bottom note has an accidental.
172 left_ledger_protusion *= 0.66;
173 right_ledger_protusion *= 0.9;
176 Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
177 hd[RIGHT] + right_ledger_protusion);
178 out.add_molecule (Note_head::ledger_lines (me, ledger_take_space,
179 streepjes_i, dir, l_extents));
185 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
187 Note_head::brew_molecule (SCM smob)
189 Grob *me = unsmob_grob (smob);
192 ledgers don't take space. See top of file.
194 return internal_brew_molecule (me, false).smobbed_copy ();
198 Compute the width the head without ledgers.
201 Note_head::head_extent (Grob *me, Axis a)
203 return internal_brew_molecule (me, false).extent (a);
207 Note_head::has_interface (Grob*m)
209 return m&& m->has_interface (ly_symbol2scm ("note-head-interface"));
213 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
216 Note_head::brew_ez_molecule (SCM smob)
218 Grob *me = unsmob_grob (smob);
219 int l = Rhythmic_head::balltype_i (me);
223 SCM cause = me->get_grob_property ("cause");
224 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
225 Pitch* pit = unsmob_pitch (spitch);
228 s[0] = (pit->notename_i_ + 2)%7 + 'a';
229 s[0] = toupper (s[0]);
231 SCM charstr = ly_str02scm (s);
233 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
238 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
240 int p = (int) rint (Staff_symbol_referencer::position_f (me));
242 int sz = Staff_symbol_referencer::line_count (me)-1;
243 int streepjes_i = abs (p) < sz
249 Direction dir = (Direction)sign (p);
250 Interval hd = m.extent (X_AXIS);
251 Real hw = hd.length ()/4;
252 m.add_molecule (ledger_lines (me, false, streepjes_i, dir,
253 Interval (hd[LEFT] - hw,
257 return m.smobbed_copy ();
262 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
264 SCM v = me->get_grob_property ("stem-attachment-function");
266 if (!gh_procedure_p (v))
269 SCM st = me->get_grob_property ("style");
270 SCM result = gh_apply (v, scm_list_n (st, SCM_UNDEFINED));
272 if (!gh_pair_p (result))
275 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
277 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
280 ADD_INTERFACE (Note_head,"note-head-interface",
282 "accidentals-grob style stem-attachment-function");