* input/regression/ambitus.ly: move file.
[lilypond.git] / lily / note-head.cc
bloba703d13db5a3c75e76f87f567ae6fb19998d4408
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?)
60 Molecule
61 Note_head::brew_ledger_lines (Grob *me,
62 int pos,
63 int interspaces,
64 Interval x_extent,
65 bool take_space)
67 Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
68 int lines_i = abs (pos) < interspaces
69 ? 0
70 : (abs (pos) - interspaces) / 2;
71 Molecule molecule = Molecule();
73 if (lines_i)
75 Real ledgerlinethickness =
76 (me->get_paper ()->get_var ("ledgerlinethickness"));
77 Real blotdiameter = ledgerlinethickness;
78 // (me->get_paper ()->get_var ("blotdiameter"));
79 Interval y_extent =
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);
87 if (!take_space)
88 proto_ledger_line.set_empty (true);
90 Direction dir = (Direction)sign (pos);
91 Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
92 ? 0.0
93 : -dir * inter_f;
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);
102 return molecule;
105 Molecule
106 internal_brew_molecule (Grob *me, bool ledger_take_space)
108 SCM style = me->get_grob_property ("style");
109 if (!gh_symbol_p (style))
111 return Molecule();
114 SCM log = gh_int2scm (Note_head::get_balltype (me));
115 SCM proc = me->get_grob_property ("glyph-name-procedure");
116 SCM scm_font_char = scm_call_2 (proc, log, style);
117 String font_char = "noteheads-" + ly_scm2string (scm_font_char);
119 Font_metric * fm = Font_interface::get_default_font (me);
120 Molecule out = fm->find_by_name (font_char);
121 if (out.empty_b())
123 me->warning (_f ("note head `%s' not found", font_char.to_str0 ()));
126 int interspaces = Staff_symbol_referencer::line_count (me)-1;
127 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
128 if (abs (pos) - interspaces > 1)
130 Interval hd = out.extent (X_AXIS);
131 Real left_ledger_protusion = hd.length ()/4;
132 Real right_ledger_protusion = left_ledger_protusion;
134 if (unsmob_grob(me->get_grob_property ("accidental-grob")))
137 make a little room for accidentals.
139 TODO: this will look silly if a chord has ledger lines,
140 and only the bottom note has an accidental.
143 left_ledger_protusion *= 0.66;
144 right_ledger_protusion *= 0.9;
147 Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
148 hd[RIGHT] + right_ledger_protusion);
149 out.add_molecule (Note_head::brew_ledger_lines (me, pos, interspaces,
150 l_extents,
151 ledger_take_space));
153 return out;
157 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
159 Note_head::brew_molecule (SCM smob)
161 Grob *me = unsmob_grob (smob);
164 ledgers don't take space. See top of file.
166 return internal_brew_molecule (me, false).smobbed_copy ();
170 Compute the width the head without ledgers.
172 -- there used to be some code from the time that ledgers
173 did take space. Nowadays, we can simply take the standard extent.
175 Interval
176 Note_head::head_extent (Grob *me, Axis a)
178 Molecule * mol = me->get_molecule();
179 return mol ? mol ->extent (a) : Interval(0,0);
184 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
187 Note_head::brew_ez_molecule (SCM smob)
189 Grob *me = unsmob_grob (smob);
190 int l = Note_head::get_balltype (me);
192 int b = (l >= 2);
194 SCM cause = me->get_grob_property ("cause");
195 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
196 Pitch* pit = unsmob_pitch (spitch);
198 char s[2] = "a";
199 s[0] = (pit->get_notename () + 2)%7 + 'a';
200 s[0] = toupper (s[0]);
202 SCM charstr = scm_makfrom0str (s);
204 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
205 charstr,
206 gh_int2scm (b),
207 gh_int2scm (1-b),
208 SCM_UNDEFINED);
209 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
210 Molecule m (bx, at);
212 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
213 int interspaces = Staff_symbol_referencer::line_count (me)-1;
214 if (abs (pos) - interspaces > 1)
216 Interval hd = m.extent (X_AXIS);
217 Real hw = hd.length ()/4;
218 Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
219 m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
222 return m.smobbed_copy ();
226 Real
227 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
229 SCM v = me->get_grob_property ("stem-attachment-function");
231 if (!gh_procedure_p (v))
232 return 0.0;
234 SCM st = me->get_grob_property ("style");
235 SCM log = gh_int2scm (get_balltype (me));
236 SCM result = gh_apply (v, scm_list_n (st, log, SCM_UNDEFINED));
238 if (!gh_pair_p (result))
239 return 0.0;
241 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
243 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
247 Note_head::get_balltype (Grob*me)
249 SCM s = me->get_grob_property ("duration-log");
250 return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
253 ADD_INTERFACE (Note_head,"note-head-interface",
254 "Note head",
255 "glyph-name-procedure accidental-grob style stem-attachment-function");