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->get_paper ()->get_var ("ledgerlinethickness"));
77 Real blotdiameter = ledgerlinethickness;
78 // (me->get_paper ()->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::get_balltype (me));
120 SCM exp = scm_list_n (ly_symbol2scm ("find-notehead-symbol"), log,
121 ly_quote_scm (style),
123 SCM scm_pair = scm_primitive_eval (exp);
124 SCM scm_font_char = ly_car (scm_pair);
125 SCM scm_font_family = ly_cdr (scm_pair);
126 String font_char = "noteheads-" + ly_scm2string (scm_font_char);
127 String font_family = ly_scm2string (scm_font_family);
129 me->set_grob_property("font-family", ly_symbol2scm (font_family.to_str0 ()));
131 Font_interface::get_default_font (me)->find_by_name (font_char);
134 warning (_f("Symbol not found, ", font_char.to_str0()));
137 int interspaces = Staff_symbol_referencer::line_count (me)-1;
138 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
139 if (abs (pos) - interspaces > 1)
141 Interval hd = out.extent (X_AXIS);
142 Real left_ledger_protusion = hd.length ()/4;
143 Real right_ledger_protusion = left_ledger_protusion;
145 if (unsmob_grob(me->get_grob_property ("accidental-grob")))
148 make a little room for accidentals.
150 TODO: this will look silly if a chord has ledger lines,
151 and only the bottom note has an accidental.
154 left_ledger_protusion *= 0.66;
155 right_ledger_protusion *= 0.9;
158 Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
159 hd[RIGHT] + right_ledger_protusion);
160 out.add_molecule (Note_head::brew_ledger_lines (me, pos, interspaces,
168 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
170 Note_head::brew_molecule (SCM smob)
172 Grob *me = unsmob_grob (smob);
175 ledgers don't take space. See top of file.
177 return internal_brew_molecule (me, false).smobbed_copy ();
181 Compute the width the head without ledgers.
183 -- there used to be some code from the time that ledgers
184 did take space. Nowadays, we can simply take the standard extent.
187 Note_head::head_extent (Grob *me, Axis a)
189 Molecule * mol = me->get_molecule();
190 return mol ? mol ->extent (a) : Interval(0,0);
195 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
198 Note_head::brew_ez_molecule (SCM smob)
200 Grob *me = unsmob_grob (smob);
201 int l = Note_head::get_balltype (me);
205 SCM cause = me->get_grob_property ("cause");
206 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
207 Pitch* pit = unsmob_pitch (spitch);
210 s[0] = (pit->notename_ + 2)%7 + 'a';
211 s[0] = toupper (s[0]);
213 SCM charstr = scm_makfrom0str (s);
215 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
220 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
223 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
224 int interspaces = Staff_symbol_referencer::line_count (me)-1;
225 if (abs (pos) - interspaces > 1)
227 Interval hd = m.extent (X_AXIS);
228 Real hw = hd.length ()/4;
229 Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
230 m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
233 return m.smobbed_copy ();
238 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
240 SCM v = me->get_grob_property ("stem-attachment-function");
242 if (!gh_procedure_p (v))
245 SCM st = me->get_grob_property ("style");
246 SCM log = gh_int2scm (get_balltype (me));
247 SCM result = gh_apply (v, scm_list_n (st, log, SCM_UNDEFINED));
249 if (!gh_pair_p (result))
252 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
254 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
259 Note_head::get_balltype (Grob*me)
261 SCM s = me->get_grob_property ("duration-log");
262 return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
265 ADD_INTERFACE (Note_head,"note-head-interface",
267 "accidental-grob style stem-attachment-function");