(staff_eligible): new function.
[lilypond.git] / lily / note-head.cc
blob4c291ae32d9c107f799ada95b4daa30724799c13
1 /*
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>
7 */
8 #include <math.h>
9 #include <ctype.h>
11 #include "misc.hh"
12 #include "dots.hh"
13 #include "note-head.hh"
14 #include "warn.hh"
15 #include "font-interface.hh"
16 #include "molecule.hh"
17 #include "event.hh"
18 #include "rhythmic-head.hh"
19 #include "staff-symbol-referencer.hh"
20 #include "lookup.hh"
21 #include "paper-def.hh"
24 Note_head contains the code for printing note heads.
26 Ledger lines:
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:
32 DO take space:
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
38 ledger lines
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
53 code.
55 (Besides a separate ledger seems overkill. For what else would
56 it be useful?)
61 TODO: ledger lines are also a property of the staff. Maybe move them
62 to there?
64 Molecule
65 Note_head::brew_ledger_lines (Grob *me,
66 int pos,
67 int interspaces,
68 Interval x_extent,
69 bool take_space)
71 Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
72 int lines_i = abs (pos) < interspaces
73 ? 0
74 : (abs (pos) - interspaces) / 2;
75 Molecule molecule = Molecule();
77 if (lines_i)
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")));
83 Interval y_extent =
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);
91 if (!take_space)
92 proto_ledger_line.set_empty (true);
94 Direction dir = (Direction)sign (pos);
95 Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
96 ? 0.0
97 : -dir * inter_f;
98 for (int i = 0; i < lines_i; 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);
106 return molecule;
109 Molecule
110 internal_brew_molecule (Grob *me, bool ledger_take_space)
112 SCM style = me->get_grob_property ("style");
113 if (!gh_symbol_p (style))
115 return Molecule ();
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);
125 if (out.empty_b())
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));
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,
154 l_extents,
155 ledger_take_space));
157 return out;
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.
179 Interval
180 Note_head::head_extent (Grob *me, Axis a)
182 Molecule * mol = me->get_molecule();
183 return mol ? mol ->extent (a) : Interval(0,0);
188 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
191 Note_head::brew_ez_molecule (SCM smob)
193 Grob *me = unsmob_grob (smob);
194 int l = Note_head::get_balltype (me);
196 int b = (l >= 2);
198 SCM cause = me->get_grob_property ("cause");
199 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
200 Pitch* pit = unsmob_pitch (spitch);
202 char s[2] = "a";
203 s[0] = (pit->get_notename () + 2)%7 + 'a';
204 s[0] = toupper (s[0]);
206 SCM charstr = scm_makfrom0str (s);
208 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
209 charstr,
210 gh_int2scm (b),
211 gh_int2scm (1-b),
212 SCM_UNDEFINED);
213 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
214 Molecule m (bx, at);
216 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
217 int interspaces = Staff_symbol_referencer::line_count (me)-1;
218 if (abs (pos) - interspaces > 1)
220 Interval hd = m.extent (X_AXIS);
221 Real hw = hd.length ()/4;
222 Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
223 m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
226 return m.smobbed_copy ();
230 Real
231 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
233 SCM v = me->get_grob_property ("stem-attachment-function");
235 if (!gh_procedure_p (v))
236 return 0.0;
238 SCM st = me->get_grob_property ("style");
239 SCM log = gh_int2scm (get_balltype (me));
240 SCM result = gh_apply (v, scm_list_n (st, log, SCM_UNDEFINED));
242 if (!gh_pair_p (result))
243 return 0.0;
245 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
247 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
251 Note_head::get_balltype (Grob*me)
253 SCM s = me->get_grob_property ("duration-log");
254 return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
257 ADD_INTERFACE (Note_head,"note-head-interface",
258 "Note head",
259 "glyph-name-procedure accidental-grob style stem-attachment-function");