2 notehead.cc -- implement Note_head
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
13 #include "note-head.hh"
15 #include "font-interface.hh"
16 #include "molecule.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 TODO: ledger lines are also a property of the staff. Maybe move them
65 Note_head::brew_ledger_lines (Grob *me,
71 Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
72 int line_count = (abs (pos) < interspaces)
74 : (abs (pos) - interspaces) / 2;
75 Molecule molecule = Molecule();
79 Real ledgerlinethickness =
80 (me->get_paper ()->get_realvar (ly_symbol2scm ("ledgerlinethickness")));
81 Real blotdiameter = ledgerlinethickness;
82 // (me->get_paper ()->get_realvar (ly_symbol2scm ("blotdiameter")));
84 Interval (-0.5*(ledgerlinethickness),
85 +0.5*(ledgerlinethickness));
86 Box ledger_line (x_extent, y_extent);
88 Molecule proto_ledger_line =
89 Lookup::round_filled_box (ledger_line, blotdiameter);
92 proto_ledger_line.set_empty (true);
94 Direction dir = (Direction)sign (pos);
95 Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
98 for (int i = 0; i < line_count; i++)
100 Molecule ledger_line (proto_ledger_line);
101 ledger_line.translate_axis (-dir * inter_f * i * 2 + offs, Y_AXIS);
102 molecule.add_molecule (ledger_line);
110 internal_brew_molecule (Grob *me, bool ledger_take_space)
112 SCM style = me->get_grob_property ("style");
113 if (!gh_symbol_p (style))
118 SCM log = gh_int2scm (Note_head::get_balltype (me));
119 SCM proc = me->get_grob_property ("glyph-name-procedure");
120 SCM scm_font_char = scm_call_2 (proc, log, style);
121 String font_char = "noteheads-" + ly_scm2string (scm_font_char);
123 Font_metric * fm = Font_interface::get_default_font (me);
124 Molecule out = fm->find_by_name (font_char);
127 me->warning (_f ("note head `%s' not found", font_char.to_str0 ()));
130 int interspaces = Staff_symbol_referencer::line_count (me)-1;
131 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
133 && abs (pos) - interspaces > 1)
135 Interval hd = out.extent (X_AXIS);
136 Real left_ledger_protusion = hd.length ()/4;
137 Real right_ledger_protusion = left_ledger_protusion;
139 if (unsmob_grob(me->get_grob_property ("accidental-grob")))
142 make a little room for accidentals.
144 TODO: this will look silly if a chord has ledger lines,
145 and only the bottom note has an accidental.
148 left_ledger_protusion *= 0.66;
149 right_ledger_protusion *= 0.9;
152 Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
153 hd[RIGHT] + right_ledger_protusion);
154 out.add_molecule (Note_head::brew_ledger_lines (me, pos, interspaces,
162 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
164 Note_head::brew_molecule (SCM smob)
166 Grob *me = unsmob_grob (smob);
169 ledgers don't take space. See top of file.
171 return internal_brew_molecule (me, false).smobbed_copy ();
175 Compute the width the head without ledgers.
177 -- there used to be some code from the time that ledgers
178 did take space. Nowadays, we can simply take the standard extent.
181 Note_head::head_extent (Grob *me, Axis a)
183 Molecule * mol = me->get_molecule();
184 return mol ? mol ->extent (a) : Interval(0,0);
189 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
192 Note_head::brew_ez_molecule (SCM smob)
194 Grob *me = unsmob_grob (smob);
195 int l = Note_head::get_balltype (me);
199 SCM cause = me->get_grob_property ("cause");
200 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
201 Pitch* pit = unsmob_pitch (spitch);
204 s[0] = (pit->get_notename () + 2)%7 + 'a';
205 s[0] = toupper (s[0]);
207 SCM charstr = scm_makfrom0str (s);
209 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
214 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
217 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
218 int interspaces = Staff_symbol_referencer::line_count (me)-1;
219 if (abs (pos) - interspaces > 1)
221 Interval hd = m.extent (X_AXIS);
222 Real hw = hd.length ()/4;
223 Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
224 m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
227 return m.smobbed_copy ();
232 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
234 SCM v = me->get_grob_property ("stem-attachment-function");
236 if (!gh_procedure_p (v))
239 SCM st = me->get_grob_property ("style");
240 SCM log = gh_int2scm (get_balltype (me));
241 SCM result = gh_apply (v, scm_list_n (st, log, SCM_UNDEFINED));
243 if (!gh_pair_p (result))
246 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
248 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
252 Note_head::get_balltype (Grob*me)
254 SCM s = me->get_grob_property ("duration-log");
255 return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
258 ADD_INTERFACE (Note_head,"note-head-interface",
260 "glyph-name-procedure accidental-grob style stem-attachment-function");