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 (Interval xwid, Grob *me)
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 (idw, me));
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 hw = hd.length ()/4;
161 out.add_molecule (Note_head::ledger_lines (me, ledger_take_space, streepjes_i, dir,
162 Interval (hd[LEFT] - hw,
169 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
171 Note_head::brew_molecule (SCM smob)
173 Grob *me = unsmob_grob (smob);
176 ledgers don't take space. See top of file.
178 return internal_brew_molecule (me, false).smobbed_copy ();
182 Compute the width the head without ledgers.
185 Note_head::head_extent (Grob *me, Axis a)
187 return internal_brew_molecule (me, false).extent (a);
191 Note_head::has_interface (Grob*m)
193 return m&& m->has_interface (ly_symbol2scm ("note-head-interface"));
197 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
200 Note_head::brew_ez_molecule (SCM smob)
202 Grob *me = unsmob_grob (smob);
203 int l = Rhythmic_head::balltype_i (me);
207 SCM cause = me->get_grob_property ("cause");
208 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
209 Pitch* pit = unsmob_pitch (spitch);
212 s[0] = (pit->notename_i_ + 2)%7 + 'a';
213 s[0] = toupper (s[0]);
215 SCM charstr = ly_str02scm (s);
217 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
222 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
224 int p = (int) rint (Staff_symbol_referencer::position_f (me));
226 int sz = Staff_symbol_referencer::line_count (me)-1;
227 int streepjes_i = abs (p) < sz
233 Direction dir = (Direction)sign (p);
234 Interval hd = m.extent (X_AXIS);
235 Real hw = hd.length ()/4;
236 m.add_molecule (ledger_lines (me, false, streepjes_i, dir,
237 Interval (hd[LEFT] - hw,
241 return m.smobbed_copy ();
246 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
248 SCM v = me->get_grob_property ("stem-attachment-function");
250 if (!gh_procedure_p (v))
253 SCM st = me->get_grob_property ("style");
254 SCM result = gh_apply (v, scm_list_n (st, SCM_UNDEFINED));
256 if (!gh_pair_p (result))
259 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
261 return gh_number_p (result) ? gh_scm2double (result) : 0.0;