4
4
source file of the GNU LilyPond music typesetter
6
(c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
6
(c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
11
#include "staff-symbol.hh"
9
#include "note-head.hh"
13
#include <algorithm> // min, max
16
#include "directional-element-interface.hh"
14
#include "note-head.hh"
16
18
#include "font-interface.hh"
19
#include "international.hh"
23
#include "output-def.hh"
19
24
#include "rhythmic-head.hh"
20
25
#include "staff-symbol-referencer.hh"
22
#include "paper-def.hh"
26
#include "staff-symbol.hh"
25
Note_head contains the code for printing note heads.
29
It also contains the ledger lines, for historical reasons. Ledger
30
lines are somewhat of a PITA. In some cases, they take up no space, in
31
some cases they don't:
35
- when ledgered notes are juxtaposed: there should be some white
36
space between the ledger lines.
38
- when accidentals are near: the accidentals should not be on the
41
[both tips by Heinz Stolba from Universal Edition].
43
DO NOT take space into account:
45
- for basically everything else, e.g. swapping ledgered notes on
46
clustered chords, spacing between ledgered and unledgered notes.
48
TODO: fix this. It is not feasible to have a special grob for
49
ledgers, since you basically don't know if there will be ledgers,
50
unless you know at interpretation phase already 1. the Y-position,
51
2. the number of staff lines. It's not yet specced when both pieces
52
of information are there, so for now, it is probably better to build
53
special support for ledgers into the accidental and separation-item
56
(Besides a separate ledger seems overkill. For what else would
30
clean up the mess left by ledger line handling.
62
TODO: ledger lines are also a property of the staff. Maybe move them
66
Note_head::brew_ledger_lines (Grob *me,
73
Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
74
Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
75
int line_count = (abs (pos) < interspaces)
77
: (abs (pos) - interspaces) / 2;
78
Stencil stencil = Stencil ();
83
Real ledgerlinethickness =
84
Staff_symbol::get_ledger_line_thickness (staff);
85
Real blotdiameter = ledgerlinethickness;
87
Interval (-0.5*(ledgerlinethickness),
88
+0.5*(ledgerlinethickness));
89
Stencil proto_ledger_line =
90
Lookup::round_filled_box (Box (x_extent, y_extent), blotdiameter);
92
x_extent[LEFT] += left_shorten;
93
Stencil proto_first_line =
94
Lookup::round_filled_box (Box (x_extent, y_extent), blotdiameter);
98
proto_ledger_line.set_empty (true);
99
proto_first_line.set_empty (true);
102
Direction dir = (Direction)sign (pos);
103
Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
107
for (int i = 0; i < line_count; i++)
109
Stencil ledger_line ((i == 0)
113
ledger_line.translate_axis (-dir * inter_f * i * 2 + offs, Y_AXIS);
114
stencil.add_stencil (ledger_line);
122
internal_print (Grob *me, bool with_ledgers)
124
SCM style = me->get_property ("style");
125
if (!gh_symbol_p (style))
130
SCM log = gh_int2scm (Note_head::get_balltype (me));
131
SCM proc = me->get_property ("glyph-name-procedure");
132
SCM scm_font_char = scm_call_2 (proc, log, style);
133
String font_char = "noteheads-" + ly_scm2string (scm_font_char);
135
Font_metric * fm = Font_interface::get_default_font (me);
136
Stencil out = fm->find_by_name (font_char);
139
me->warning (_f ("note head `%s' not found", font_char.to_str0 ()));
142
int interspaces = Staff_symbol_referencer::line_count (me)-1;
143
int pos = Staff_symbol_referencer::get_rounded_position (me);
144
if (with_ledgers && interspaces >= 0
145
&& abs (pos) - interspaces > 1)
147
Interval ledger_size = out.extent (X_AXIS);
148
ledger_size.widen ( ledger_size.length ()/4);
150
Real left_shorten =0.0;
151
if (Grob * g = unsmob_grob (me->get_property ("accidental-grob")))
154
make a little room for accidentals.
156
TODO: this will look silly if a chord has ledger lines,
157
and only the bottom note has an accidental.
160
Grob *common = g->common_refpoint (me, X_AXIS);
162
linear_combination (Drul_array<Real> (me->extent (common, X_AXIS)[LEFT],
163
g->extent (common, X_AXIS)[RIGHT]),
167
left_shorten = (-ledger_size[LEFT] + d) >? 0 ;
170
TODO: shorten 2 ledger lines for the case natural +
175
out.add_stencil (Note_head::brew_ledger_lines (me, pos, interspaces,
33
internal_print (Grob *me, string *font_char)
35
SCM style = me->get_property ("style");
36
if (!scm_is_symbol (style))
37
style = ly_symbol2scm ("default");
39
string suffix = to_string (min (robust_scm2int (me->get_property ("duration-log"), 2), 2));
40
if (style != ly_symbol2scm ("default"))
42
SCM gn = me->get_property ("glyph-name");
43
if (scm_is_string (gn))
44
suffix = ly_scm2string (gn);
47
Font_metric *fm = Font_interface::get_default_font (me);
49
string idx = "noteheads.s" + suffix;
51
Stencil out = fm->find_by_name (idx);
54
string prefix = "noteheads.";
55
Grob *stem = unsmob_grob (me->get_object ("stem"));
56
Direction stem_dir = stem ? get_grob_direction (stem) : CENTER;
58
if (stem_dir == CENTER)
59
programming_error ("must have stem dir for note head");
61
idx = prefix + ((stem_dir == UP) ? "u" : "d") + suffix;
62
out = fm->find_by_name (idx);
67
me->warning (_f ("note head `%s' not found", idx.c_str ()));
68
out = Stencil (Box (Interval (0, 0), Interval (0, 0)), SCM_EOL);
184
MAKE_SCHEME_CALLBACK (Note_head,print,1);
186
Note_head::print (SCM smob)
188
Grob *me = unsmob_grob (smob);
191
ledgers don't take space. See top of file.
193
return internal_print (me, true).smobbed_copy ();
197
Compute the width the head without ledgers.
199
-- there used to be some code from the time that ledgers
200
did take space. Nowadays, we can simply take the standard extent.
77
TODO: make stem X-parent of notehead.
203
Note_head::head_extent (Grob *me, Axis a)
205
SCM brewer = me->get_property ("print-function");
206
if (brewer == Note_head::print_proc)
208
Stencil mol = internal_print (me, false);
210
if (!mol.is_empty ())
211
return mol.extent (a);
215
Stencil * mol = me->get_stencil ();
217
return mol->extent (a) ;
220
return Interval (0,0);
224
This is necessary to prevent a cyclic dependency: the appearance of
225
the ledgers depends on positioning, so the Grob::get_stencil () can
226
not be used for determining the note head extent.
229
MAKE_SCHEME_CALLBACK (Note_head,extent,2);
231
Note_head::extent (SCM smob, SCM axis)
233
Grob *me = unsmob_grob (smob);
235
return ly_interval2scm (head_extent (me, (Axis) gh_scm2int (axis)));
238
MAKE_SCHEME_CALLBACK (Note_head,brew_ez_stencil,1);
240
Note_head::brew_ez_stencil (SCM smob)
242
Grob *me = unsmob_grob (smob);
243
int l = Note_head::get_balltype (me);
247
SCM cause = me->get_property ("cause");
248
SCM spitch = unsmob_music (cause)->get_property ("pitch");
249
Pitch* pit = unsmob_pitch (spitch);
251
SCM idx = gh_int2scm (pit->get_notename ());
252
SCM names = me->get_property ("note-names");
253
SCM charstr = SCM_EOL;
254
if (gh_vector_p (names))
255
charstr = scm_vector_ref (names, idx);
259
s[0] = (pit->get_notename () + 2)%7 + 'a';
260
s[0] = toupper (s[0]);
261
charstr = scm_makfrom0str (s);
264
SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
269
Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
272
int pos = Staff_symbol_referencer::get_rounded_position (me);
273
int interspaces = Staff_symbol_referencer::line_count (me)-1;
274
if (abs (pos) - interspaces > 1)
276
Interval hd = m.extent (X_AXIS);
277
hd.widen ( hd.length ()/4);
278
m.add_stencil (brew_ledger_lines (me, pos, interspaces, hd, 0, false));
281
return m.smobbed_copy ();
79
MAKE_SCHEME_CALLBACK (Note_head, stem_x_shift, 1);
81
Note_head::stem_x_shift (SCM smob)
83
Grob *me = unsmob_grob (smob);
84
Grob *stem = unsmob_grob (me->get_object ("stem"));
86
(void) stem->get_property ("positioning-done");
88
return scm_from_int (0);
91
MAKE_SCHEME_CALLBACK (Note_head, print, 1);
93
Note_head::print (SCM smob)
95
Grob *me = unsmob_grob (smob);
98
return internal_print (me, &idx).smobbed_copy ();
286
102
Note_head::stem_attachment_coordinate (Grob *me, Axis a)
288
SCM brewer = me->get_property ("print-function");
289
Font_metric * fm = Font_interface::get_default_font (me);
291
if (brewer == Note_head::print_proc)
104
Offset off = robust_scm2offset (me->get_property ("stem-attachment"),
110
MAKE_SCHEME_CALLBACK(Note_head, calc_stem_attachment, 1);
112
Note_head::calc_stem_attachment (SCM smob)
114
Grob *me = unsmob_grob (smob);
115
Font_metric *fm = Font_interface::get_default_font (me);
117
internal_print (me, &key);
121
int k = fm->name_to_index (key);
293
SCM style = me->get_property ("style");
294
if (!gh_symbol_p (style))
299
SCM log = gh_int2scm (Note_head::get_balltype (me));
300
SCM proc = me->get_property ("glyph-name-procedure");
301
SCM scm_font_char = scm_call_2 (proc, log, style);
302
String font_char = "noteheads-" + ly_scm2string (scm_font_char);
304
int k = fm->name_to_index (font_char) ;
308
Box b = fm->get_indexed_char (k);
309
Offset wxwy = fm->get_indexed_wxwy (k);
124
Box b = fm->get_indexed_char (k);
125
Offset wxwy = fm->attachment_point (key);
126
for (int i = X_AXIS ; i < NO_AXES; i++)
310
130
Interval v = b[a];
311
131
if (!v.is_empty ())
312
return 2 * (wxwy[a] - v.center ()) / v.length ();
133
att[a] = (2 * (wxwy[a] - v.center ()) / v.length ());
319
SCM v = me->get_property ("stem-attachment-function");
320
if (!gh_procedure_p (v))
323
SCM result = scm_call_2 (v, me->self_scm (), gh_int2scm (a));
324
if (!gh_pair_p (result))
327
result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
329
return robust_scm2double (result,0);
138
return ly_offset2scm (att);
333
Note_head::get_balltype (Grob*me)
143
Note_head::get_balltype (Grob *me)
335
145
SCM s = me->get_property ("duration-log");
336
return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
146
return scm_is_number (s) ? min (int (scm_to_int (s)), 2) : 0;
339
ADD_INTERFACE (Note_head,"note-head-interface",
341
"note-names glyph-name-procedure accidental-grob style stem-attachment-function");
149
ADD_INTERFACE (Note_head, "note-head-interface",