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);
85 Molecule proto_ledger_line =
86 Lookup::roundfilledbox (ledger_line, blotdiameter);
88 Molecule proto_ledger_line = // if you like it the old way
89 Lookup::filledbox (ledger_line);
93 proto_ledger_line.set_empty (true);
95 Direction dir = (Direction)sign (pos);
96 Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
99 for (int i = 0; i < lines_i; i++)
101 Molecule ledger_line (proto_ledger_line);
102 ledger_line.translate_axis (-dir * inter_f * i * 2 + offs, Y_AXIS);
103 molecule.add_molecule (ledger_line);
111 internal_brew_molecule (Grob *me, bool ledger_take_space)
113 SCM style = me->get_grob_property ("style");
114 if (!gh_symbol_p (style))
120 ugh: use gh_call () / scm_apply ().
122 UGH: use grob-property.
124 SCM log = gh_int2scm (Rhythmic_head::balltype_i (me));
125 SCM exp = scm_list_n (ly_symbol2scm ("find-notehead-symbol"), log,
126 ly_quote_scm (style),
128 String name = "noteheads-" + ly_scm2string (scm_primitive_eval (exp));
129 Molecule out = Font_interface::get_default_font (me)->find_by_name (name);
131 int interspaces = Staff_symbol_referencer::line_count (me)-1;
132 int pos = (int)rint (Staff_symbol_referencer::position_f (me));
133 if (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.
178 Note_head::head_extent (Grob *me, Axis a)
180 return internal_brew_molecule (me, false).extent (a);
185 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
188 Note_head::brew_ez_molecule (SCM smob)
190 Grob *me = unsmob_grob (smob);
191 int l = Rhythmic_head::balltype_i (me);
195 SCM cause = me->get_grob_property ("cause");
196 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
197 Pitch* pit = unsmob_pitch (spitch);
200 s[0] = (pit->notename_i_ + 2)%7 + 'a';
201 s[0] = toupper (s[0]);
203 SCM charstr = ly_str02scm (s);
205 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
210 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
213 int pos = (int)rint (Staff_symbol_referencer::position_f (me));
214 int interspaces = Staff_symbol_referencer::line_count (me)-1;
215 if (abs (pos) - interspaces > 1)
217 Interval hd = m.extent (X_AXIS);
218 Real hw = hd.length ()/4;
219 Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
220 m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
223 return m.smobbed_copy ();
228 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
230 SCM v = me->get_grob_property ("stem-attachment-function");
232 if (!gh_procedure_p (v))
235 SCM st = me->get_grob_property ("style");
236 SCM result = gh_apply (v, scm_list_n (st, SCM_UNDEFINED));
238 if (!gh_pair_p (result))
241 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
243 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
246 ADD_INTERFACE (Note_head,"note-head-interface",
248 "accidental-grob style stem-attachment-function");