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),
81 +0.5*(ledgerlinethickness));
82 Box ledger_line (x_extent, y_extent);
84 Molecule proto_ledger_line =
85 Lookup::roundfilledbox (ledger_line, blotdiameter);
88 proto_ledger_line.set_empty (true);
90 Direction dir = (Direction)sign (pos);
91 Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
94 for (int i = 0; i < lines_i; i++)
96 Molecule ledger_line (proto_ledger_line);
97 ledger_line.translate_axis (-dir * inter_f * i * 2 + offs, Y_AXIS);
98 molecule.add_molecule (ledger_line);
106 internal_brew_molecule (Grob *me, bool ledger_take_space)
108 SCM style = me->get_grob_property ("style");
109 if (!gh_symbol_p (style))
115 ugh: use gh_call () / scm_apply ().
117 UGH: use grob-property.
119 SCM log = gh_int2scm (Note_head::balltype_i (me));
120 SCM exp = scm_list_n (ly_symbol2scm ("find-notehead-symbol"), log,
121 ly_quote_scm (style),
123 String name = "noteheads-" + ly_scm2string (scm_primitive_eval (exp));
124 Molecule out = Font_interface::get_default_font (me)->find_by_name (name);
127 warning (_f("Symbol not found, ", name.ch_C()));
130 int interspaces = Staff_symbol_referencer::line_count (me)-1;
131 int pos = (int)rint (Staff_symbol_referencer::position_f (me));
132 if (abs (pos) - interspaces > 1)
134 Interval hd = out.extent (X_AXIS);
135 Real left_ledger_protusion = hd.length ()/4;
136 Real right_ledger_protusion = left_ledger_protusion;
138 if (unsmob_grob(me->get_grob_property ("accidental-grob")))
141 make a little room for accidentals.
143 TODO: this will look silly if a chord has ledger lines,
144 and only the bottom note has an accidental.
147 left_ledger_protusion *= 0.66;
148 right_ledger_protusion *= 0.9;
151 Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
152 hd[RIGHT] + right_ledger_protusion);
153 out.add_molecule (Note_head::brew_ledger_lines (me, pos, interspaces,
161 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
163 Note_head::brew_molecule (SCM smob)
165 Grob *me = unsmob_grob (smob);
168 ledgers don't take space. See top of file.
170 return internal_brew_molecule (me, false).smobbed_copy ();
174 Compute the width the head without ledgers.
176 -- there used to be some code from the time that ledgers
177 did take space. Nowadays, we can simply take the standard extent.
180 Note_head::head_extent (Grob *me, Axis a)
182 return me->get_molecule()->extent (a);
187 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
190 Note_head::brew_ez_molecule (SCM smob)
192 Grob *me = unsmob_grob (smob);
193 int l = Note_head::balltype_i (me);
197 SCM cause = me->get_grob_property ("cause");
198 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
199 Pitch* pit = unsmob_pitch (spitch);
202 s[0] = (pit->notename_i_ + 2)%7 + 'a';
203 s[0] = toupper (s[0]);
205 SCM charstr = ly_str02scm (s);
207 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
212 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
215 int pos = (int)rint (Staff_symbol_referencer::position_f (me));
216 int interspaces = Staff_symbol_referencer::line_count (me)-1;
217 if (abs (pos) - interspaces > 1)
219 Interval hd = m.extent (X_AXIS);
220 Real hw = hd.length ()/4;
221 Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
222 m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
225 return m.smobbed_copy ();
230 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
232 SCM v = me->get_grob_property ("stem-attachment-function");
234 if (!gh_procedure_p (v))
237 SCM st = me->get_grob_property ("style");
238 SCM result = gh_apply (v, scm_list_n (st, SCM_UNDEFINED));
240 if (!gh_pair_p (result))
243 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
245 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
250 Note_head::balltype_i (Grob*me)
252 SCM s = me->get_grob_property ("duration-log");
253 return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
256 ADD_INTERFACE (Note_head,"note-head-interface",
258 "accidental-grob style stem-attachment-function");