* lily/music-iterator.cc (quit, do_quit): new function: break link
[lilypond.git] / lily / note-head.cc
blob16c58ebaea15aa1137b235a6ea3dc07e50862290
1 /*
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>
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 "musical-request.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();
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),
122 SCM_UNDEFINED);
123 SCM scm_font_char = scm_primitive_eval (exp);
124 String font_char = "noteheads-" + ly_scm2string (scm_font_char);
126 Font_metric * fm = Font_interface::get_default_font (me);
127 Molecule out = fm->find_by_name (font_char);
128 if (out.empty_b())
130 me->warning (_f ("note head `%s' not found", font_char.to_str0 ()));
133 int interspaces = Staff_symbol_referencer::line_count (me)-1;
134 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
135 if (abs (pos) - interspaces > 1)
137 Interval hd = out.extent (X_AXIS);
138 Real left_ledger_protusion = hd.length ()/4;
139 Real right_ledger_protusion = left_ledger_protusion;
141 if (unsmob_grob(me->get_grob_property ("accidental-grob")))
144 make a little room for accidentals.
146 TODO: this will look silly if a chord has ledger lines,
147 and only the bottom note has an accidental.
150 left_ledger_protusion *= 0.66;
151 right_ledger_protusion *= 0.9;
154 Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
155 hd[RIGHT] + right_ledger_protusion);
156 out.add_molecule (Note_head::brew_ledger_lines (me, pos, interspaces,
157 l_extents,
158 ledger_take_space));
160 return out;
164 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
166 Note_head::brew_molecule (SCM smob)
168 Grob *me = unsmob_grob (smob);
171 ledgers don't take space. See top of file.
173 return internal_brew_molecule (me, false).smobbed_copy ();
177 Compute the width the head without ledgers.
179 -- there used to be some code from the time that ledgers
180 did take space. Nowadays, we can simply take the standard extent.
182 Interval
183 Note_head::head_extent (Grob *me, Axis a)
185 Molecule * mol = me->get_molecule();
186 return mol ? mol ->extent (a) : Interval(0,0);
191 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
194 Note_head::brew_ez_molecule (SCM smob)
196 Grob *me = unsmob_grob (smob);
197 int l = Note_head::get_balltype (me);
199 int b = (l >= 2);
201 SCM cause = me->get_grob_property ("cause");
202 SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
203 Pitch* pit = unsmob_pitch (spitch);
205 char s[2] = "a";
206 s[0] = (pit->notename_ + 2)%7 + 'a';
207 s[0] = toupper (s[0]);
209 SCM charstr = scm_makfrom0str (s);
211 SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
212 charstr,
213 gh_int2scm (b),
214 gh_int2scm (1-b),
215 SCM_UNDEFINED);
216 Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
217 Molecule m (bx, at);
219 int pos = (int)rint (Staff_symbol_referencer::get_position (me));
220 int interspaces = Staff_symbol_referencer::line_count (me)-1;
221 if (abs (pos) - interspaces > 1)
223 Interval hd = m.extent (X_AXIS);
224 Real hw = hd.length ()/4;
225 Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
226 m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
229 return m.smobbed_copy ();
233 Real
234 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
236 SCM v = me->get_grob_property ("stem-attachment-function");
238 if (!gh_procedure_p (v))
239 return 0.0;
241 SCM st = me->get_grob_property ("style");
242 SCM log = gh_int2scm (get_balltype (me));
243 SCM result = gh_apply (v, scm_list_n (st, log, SCM_UNDEFINED));
245 if (!gh_pair_p (result))
246 return 0.0;
248 result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
250 return gh_number_p (result) ? gh_scm2double (result) : 0.0;
254 Note_head::get_balltype (Grob*me)
256 SCM s = me->get_grob_property ("duration-log");
257 return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
260 ADD_INTERFACE (Note_head,"note-head-interface",
261 "Note head",
262 "accidental-grob style stem-attachment-function");