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>
13 #include "note-head.hh"
15 #include "font-interface.hh"
16 #include "molecule.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
))
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
);
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
,
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.
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
);
194 SCM cause
= me
->get_grob_property ("cause");
195 SCM spitch
= unsmob_music (cause
)->get_mus_property ("pitch");
196 Pitch
* pit
= unsmob_pitch (spitch
);
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"),
209 Box
bx (Interval (0, 1.0), Interval (-0.5, 0.5));
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 ();
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
))
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
))
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",
255 "glyph-name-procedure accidental-grob style stem-attachment-function");