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>
13 #include "note-head.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"
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
))
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
),
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
);
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
,
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.
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
);
201 SCM cause
= me
->get_grob_property ("cause");
202 SCM spitch
= unsmob_music (cause
)->get_mus_property ("pitch");
203 Pitch
* pit
= unsmob_pitch (spitch
);
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"),
216 Box
bx (Interval (0, 1.0), Interval (-0.5, 0.5));
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 ();
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
))
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
))
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",
262 "accidental-grob style stem-attachment-function");