2 ambitus.cc -- implement Ambitus
4 source file of the GNU LilyPond music typesetter
6 (c) 2002--2004 Juergen Reuter <reuter@ipd.uka.de>
9 #include "staff-symbol-referencer.hh"
13 #include "note-head.hh"
15 #include "font-interface.hh"
16 #include "paper-def.hh"
22 This does 3 things at one:
28 It confuses interpretation & formatting.
35 * TODO: note-head collision handling
37 * TODO: accidentals collision handling
39 * TODO: alternative representation: adding the ambitus as text script
40 * to the instrument name (e.g. "Soprano (c^1 - f^2)").
42 * FIXME: Accidentals are too close at the note heads (it seems that
43 * the extent of the ledger lines is ignored).
45 * TODO: If (depending on breakAlignOrder) ambitus is put behind
46 * key-signature, then do not repeat accidentals that already appear
47 * in the key signature.
49 * FIXME: A staff containing more than a single context will result in
50 * multiple ambitus grobs per staff. This is basically ok, but there is
51 * currently no proper collision handling for this case.
53 * TODO: make ignore_octave and force_accidental of function
54 * number_accidentals accessible via grob properties.
58 Given a pitch and a key_signature, decide what accidentals to show.
60 Possible return values:
62 0: do not show any accidental
63 1: show pitch->alteration_ only
64 2: show pitch->get_alteration, preceded by a natural sign
66 UGH: code duplication! See accidental-engraver.
70 number_accidentals (SCM key_signature
, Pitch
*pitch
,
71 bool ignore_octave_b
, bool force_accidental
)
73 int notename
= pitch
->get_notename ();
74 int octave
= pitch
->get_octave ();
75 int alteration
= pitch
->get_alteration ();
77 if (force_accidental
) // ignore key signature
82 scm_display (key_signature
, scm_current_output_port ());
87 prev
= ly_assoc_cdr (scm_int2num (notename
), key_signature
);
89 prev
= scm_assoc (scm_cons (scm_int2num (octave
), scm_int2num (notename
)),
92 /* should really be true unless prev == SCM_BOOL_F */
93 if (ly_pair_p (prev
) && ly_pair_p (ly_cdr (prev
)))
95 prev
= scm_cons (ly_car (prev
), ly_cadr (prev
));
98 /* If an accidental was not found */
99 if (prev
== SCM_BOOL_F
)
100 prev
= scm_assoc (scm_int2num (notename
), key_signature
);
102 SCM prev_acc
= (prev
== SCM_BOOL_F
) ? scm_int2num (0) : ly_cdr (prev
);
103 int sig_alteration
= ly_number_p (prev_acc
) ? ly_scm2int (prev_acc
) : 0;
105 if (alteration
== sig_alteration
) // no accidental at all needed
108 if ((alteration
== 0) && (sig_alteration
!= 0)) // need ordinary natural
111 if (sig_alteration
== 0) // use pitch's alteration
118 add_accidentals (Item
*me
, Stencil
*head
, int num_acc
,
119 Pitch
*pitch
, String accidentals_style
, Real yoffs
)
123 if (pitch
->get_alteration ())
125 Stencil
accidental (Font_interface::get_default_font (me
)->
126 find_by_name (String ("accidentals-") +
128 to_string (pitch
->get_alteration ())));
129 accidental
.translate_axis (yoffs
, Y_AXIS
);
130 head
->add_at_edge (X_AXIS
, LEFT
, accidental
, 0.1, 0);
134 Stencil
natural (Font_interface::get_default_font (me
)->
135 find_by_name (String ("accidentals-") +
138 natural
.translate_axis (yoffs
, Y_AXIS
);
139 head
->add_at_edge (X_AXIS
, LEFT
, natural
, 0.1, 0);
143 MAKE_SCHEME_CALLBACK (Ambitus
,print
,1);
145 Ambitus::print (SCM smob
)
147 Item
*me
= (Item
*)unsmob_grob (smob
);
148 Stencil stencil
= Stencil ();
150 SCM scm_note_head_style
= me
->get_property ("note-head-style");
151 String note_head_style
;
152 if (ly_symbol_p (scm_note_head_style
))
154 String note_head_style
=
155 ly_symbol2string (scm_note_head_style
);
159 note_head_style
= String ("noteheads-2");
161 if (Font_interface::get_default_font (me
)->find_by_name (note_head_style
).is_empty ())
163 String message
= "Ambitus: no such note head: `" + note_head_style
+ "'";
164 me
->warning (_ (message
.to_str0 ()));
169 FIXME: Use positions.
172 Pitch
*pitch_min
= unsmob_pitch (me
->get_property ("pitch-min"));
175 me
->programming_error ("Ambitus: pitch_min undefined; assuming 0");
180 p_min
= pitch_min
->steps ();
182 Pitch
*pitch_max
= unsmob_pitch (me
->get_property ("pitch-max"));
185 me
->programming_error ("Ambitus: pitch_max undefined; assuming 0");
190 p_max
= pitch_max
->steps ();
194 me
->programming_error ("Ambitus: reverse range");
197 SCM c0
= me
->get_property ("c0-position");
198 if (ly_number_p (c0
))
200 p_min
+= ly_scm2int (c0
);
201 p_max
+= ly_scm2int (c0
);
206 Font_interface::get_default_font (me
)->find_by_name (note_head_style
);
207 head_min
.translate_axis (0.5*p_min
, Y_AXIS
);
209 Font_interface::get_default_font (me
)->find_by_name (note_head_style
);
210 head_max
.translate_axis (0.5*p_max
, Y_AXIS
);
213 if (to_boolean (me
->get_property ("join-heads")) &&
214 ((p_max
- p_min
) >= 3))
216 Real linethickness
= me
->get_paper ()->get_dimension (ly_symbol2scm ("linethickness"));
217 Real blotdiameter
= me
->get_paper ()->get_dimension (ly_symbol2scm ("blotdiameter"));
218 Interval x_extent
= 0.5 * Interval (-linethickness
, +linethickness
);
219 Interval y_extent
= 0.5 * Interval (p_min
+ 1.35, p_max
- 1.35);
220 Box
line_box (x_extent
, y_extent
);
221 Stencil line
= Lookup::round_filled_box (line_box
, blotdiameter
);
222 line
.translate_axis (0.5 * head_min
.extent (X_AXIS
).length (), X_AXIS
);
223 stencil
.add_stencil (line
);
227 Interval hd
= head_min
.extent (X_AXIS
);
228 Real left_ledger_protusion
= hd
.length () / 4;
229 Real right_ledger_protusion
= left_ledger_protusion
;
230 Interval l_extents
= Interval (hd
[LEFT
] - left_ledger_protusion
,
231 hd
[RIGHT
] + right_ledger_protusion
);
232 Stencil ledger_lines
;
233 int interspaces
= Staff_symbol_referencer::line_count (me
) - 1;
235 Note_head::brew_ledger_lines (me
, p_min
, interspaces
, l_extents
, 0,true);
236 ledger_lines
.translate_axis (0.5 * p_min
, Y_AXIS
);
237 stencil
.add_stencil (ledger_lines
);
239 Note_head::brew_ledger_lines (me
, p_max
, interspaces
, l_extents
, 0, true);
240 ledger_lines
.translate_axis (0.5 * p_max
, Y_AXIS
);
241 stencil
.add_stencil (ledger_lines
);
244 SCM key_signature
= me
->get_property ("key-signature");
245 SCM scm_accidentals_style
= me
->get_property ("accidentals-style");
246 String accidentals_style
;
247 if (ly_symbol_p (scm_accidentals_style
))
250 ly_symbol2string (scm_accidentals_style
);
254 accidentals_style
= String ("");
258 num_acc
= number_accidentals (key_signature
, pitch_min
, true, false);
259 add_accidentals (me
, &head_min
, num_acc
, pitch_min
,
260 accidentals_style
, 0.5 * p_min
);
261 num_acc
= number_accidentals (key_signature
, pitch_max
, true, false);
262 add_accidentals (me
, &head_max
, num_acc
, pitch_max
,
263 accidentals_style
, 0.5 * p_max
);
266 stencil
.add_stencil (head_min
);
267 stencil
.add_stencil (head_max
);
269 return stencil
.smobbed_copy ();
272 ADD_INTERFACE (Ambitus
, "ambitus-interface",
273 "An object that represents the pitch range of a voice.",
274 "c0-position pitch-min pitch-max accidentals note-head-style accidentals-style join-heads");