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"
19 #include "staff-symbol-referencer.hh"
21 #include "paper-def.hh"
24 Note_head contains the code for printing note heads.
28 It also contains the ledger lines, for historical reasons. Ledger
29 lines are somewhat of a PITA. In some cases, they take up no space, in
30 some cases they don't:
34 - when ledgered notes are juxtaposed: there should be some white
35 space between the ledger lines.
37 - when accidentals are near: the accidentals should not be on the
40 [both tips by Heinz Stolba from Universal Edition].
42 DO NOT take space into account:
44 - for basically everything else, e.g. swapping ledgered notes on
45 clustered chords, spacing between ledgered and unledgered notes.
47 TODO: fix this. It is not feasible to have a special grob for
48 ledgers, since you basically don't know if there will be ledgers,
49 unless you know at interpretation phase already 1. the Y-position,
50 2. the number of staff lines. It's not yet specced when both pieces
51 of information are there, so for now, it is probably better to build
52 special support for ledgers into the accidental and separation-item
55 (Besides a separate ledger seems overkill. For what else would
61 Note_head::brew_ledger_lines (Grob *me,
67 Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
68 int lines_i = abs (pos) < interspaces
70 : (abs (pos) - interspaces) / 2;
71 Molecule molecule = Molecule();
75 Real ledgerlinethickness =
76 (me->paper_l ()->get_var ("ledgerlinethickness"));
77 Real blotdiameter = ledgerlinethickness;
78 // (me->paper_l ()->get_var ("blotdiameter"));
80 Interval (-0.5*(ledgerlinethickness - blotdiameter),
81 +0.5*(ledgerlinethickness - blotdiameter));
82 Box ledger_line (x_extent, y_extent);
84 // FIXME: Currently need blotdiameter factor 2.0 to compensate
85 // for error somewhere else. (Maybe draw_box confuses radius
88 Molecule proto_ledger_line =
89 Lookup::roundfilledbox (ledger_line, ledgerlinethickness );
91 Molecule proto_ledger_line = // if you like it the old way
92 Lookup::filledbox (ledger_line);
96 proto_ledger_line.set_empty (true);
98 Direction dir = (Direction)sign (pos);
99 Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
102 for (int i = 0; i < lines_i; i++)
104 Molecule ledger_line (proto_ledger_line);
105 ledger_line.translate_axis (-dir * inter_f * i * 2 + offs, Y_AXIS);
106 molecule.add_molecule (ledger_line);
114 internal_brew_molecule (Grob *me, bool ledger_take_space)
116 SCM style = me->get_grob_property ("style");
117 if (!gh_symbol_p (style))
123 ugh: use gh_call () / scm_apply ().
125 UGH: use grob-property.
127 SCM log = gh_int2scm (Rhythmic_head::balltype_i (me));
128 SCM exp = scm_list_n (ly_symbol2scm ("find-notehead-symbol"), log,
129 ly_quote_scm (style),
131 String name = "noteheads-" + ly_scm2string (scm_primitive_eval (exp));
132 Molecule out = Font_interface::get_default_font (me)->find_by_name (name);
134 int interspaces = Staff_symbol_referencer::line_count (me)-1;
135 int pos = (int)rint (Staff_symbol_referencer::position_f (me));
136 if (abs (pos) - interspaces > 1)
138 Interval hd = out.extent (X_AXIS);
139 Real left_ledger_protusion = hd.length ()/4;
140 Real right_ledger_protusion = left_ledger_protusion;
142 if (unsmob_grob(me->get_grob_property ("accidentals-grob")))
145 make a little room for accidentals.
147 TODO: this will look silly if a chord has ledger lines,
148 and only the bottom note has an accidental.
151 left_ledger_protusion *= 0.66;
152 right_ledger_protusion *= 0.9;
155 Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
156 hd[RIGHT] + right_ledger_protusion);
157 out.add_molecule (Note_head::brew_ledger_lines (me, pos, interspaces,
165 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
167 Note_head::brew_molecule (SCM smob)
169 Grob *me = unsmob_grob (smob);
172 ledgers don't take space. See top of file.
174 return internal_brew_molecule (me, false).smobbed_copy ();
178 Compute the width the head without ledgers.
181 Note_head::head_extent (Grob *me, Axis a)
183 return internal_brew_molecule (me, false).extent (a);
187 Note_head::has_interface (Grob*m)
189 return m&& m->has_interface (ly_symbol2scm ("note-head-interface"));
193 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
196 Note_head::brew_ez_molecule (SCM smob)
198 Grob *me = unsmob_grob (smob);
199 int l = Rhythmic_head::balltype_i (me);
203 SCM cause = me->get_grob_property ("cause");
204 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
205 Pitch* pit = unsmob_pitch (spitch);
208 s[0] = (pit->notename_i_ + 2)%7 + 'a';
209 s[0] = toupper (s[0]);
211 SCM charstr = ly_str02scm (s);
213 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
218 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
221 int pos = (int)rint (Staff_symbol_referencer::position_f (me));
222 int interspaces = Staff_symbol_referencer::line_count (me)-1;
223 if (abs (pos) - interspaces > 1)
225 Interval hd = m.extent (X_AXIS);
226 Real hw = hd.length ()/4;
227 Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
228 m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
231 return m.smobbed_copy ();
236 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
238 SCM v = me->get_grob_property ("stem-attachment-function");
240 if (!gh_procedure_p (v))
243 SCM st = me->get_grob_property ("style");
244 SCM result = gh_apply (v, scm_list_n (st, SCM_UNDEFINED));
246 if (!gh_pair_p (result))
249 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
251 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
254 ADD_INTERFACE (Note_head,"note-head-interface",
256 "accidentals-grob style stem-attachment-function");