2 ambitus.cc -- implement Ambitus
4 source file of the GNU LilyPond music typesetter
6 (c) 2002--2003 Juergen Reuter <reuter@ipd.uka.de>
9 #include "staff-symbol-referencer.hh"
12 #include "molecule.hh"
13 #include "note-head.hh"
15 #include "font-interface.hh"
16 #include "paper-def.hh"
20 * TODO: note-head collision handling
22 * TODO: accidentals collision handling
24 * TODO: alternative representation: adding the ambitus as text script
25 * to the instrument name (e.g. "Soprano (c^1 - f^2)").
27 * FIXME: Accidentals are too close at the note heads (it seems that
28 * the extent of the ledger lines is ignored).
30 * TODO: If (depending on breakAlignOrder) ambitus is put behind
31 * key-signature, then do not repeat accidentals that already appear
32 * in the key signature.
34 * FIXME: A staff containing more than a single context will result in
35 * multiple ambitus grobs per staff. This is basically ok, but there is
36 * currently no proper collision handling for this case.
38 * TODO: make ignore_octave and force_accidental of function
39 * number_accidentals accessible via grob properties.
43 Given a pitch and a key_signature, decide what accidentals to show.
45 Possible return values:
47 0: do not show any accidental
48 1: show pitch->alteration_ only
49 2: show pitch->get_alteration, preceded by a natural sign
51 UGH: code duplication! See accidental-engraver.
55 number_accidentals (SCM key_signature
, Pitch
*pitch
,
56 bool ignore_octave_b
, bool force_accidental
)
58 int notename
= pitch
->get_notename ();
59 int octave
= pitch
->get_octave();
60 int alteration
= pitch
->get_alteration();
62 if (force_accidental
) // ignore key signature
67 scm_display (key_signature
, scm_current_output_port ());
72 prev
= ly_assoc_cdr (scm_int2num (notename
), key_signature
);
74 prev
= gh_assoc (gh_cons (scm_int2num (octave
), scm_int2num (notename
)),
77 /* should really be true unless prev == SCM_BOOL_F */
78 if (gh_pair_p (prev
) && gh_pair_p (ly_cdr (prev
)))
80 prev
= gh_cons (ly_car (prev
), ly_cadr (prev
));
83 /* If an accidental was not found */
84 if (prev
== SCM_BOOL_F
)
85 prev
= gh_assoc (scm_int2num (notename
), key_signature
);
87 SCM prev_acc
= (prev
== SCM_BOOL_F
) ? scm_int2num (0) : ly_cdr (prev
);
88 int sig_alteration
= gh_number_p (prev_acc
) ? gh_scm2int (prev_acc
) : 0;
90 if (alteration
== sig_alteration
) // no accidental at all needed
93 if ((alteration
== 0) && (sig_alteration
!= 0)) // need ordinary natural
96 if (sig_alteration
== 0) // use pitch's alteration
103 add_accidentals (Item
*me
, Molecule
*head
, int num_acc
,
104 Pitch
*pitch
, String accidentals_style
, Real yoffs
)
108 if (pitch
->get_alteration())
110 Molecule
accidental (Font_interface::get_default_font (me
)->
111 find_by_name (String ("accidentals-") +
113 to_string (pitch
->get_alteration())));
114 accidental
.translate_axis (yoffs
, Y_AXIS
);
115 head
->add_at_edge (X_AXIS
, LEFT
, accidental
, 0.1, 0);
119 Molecule
natural (Font_interface::get_default_font (me
)->
120 find_by_name (String ("accidentals-") +
123 natural
.translate_axis (yoffs
, Y_AXIS
);
124 head
->add_at_edge (X_AXIS
, LEFT
, natural
, 0.1, 0);
128 MAKE_SCHEME_CALLBACK (Ambitus
,brew_molecule
,1);
130 Ambitus::brew_molecule (SCM smob
)
132 Item
*me
= (Item
*)unsmob_grob (smob
);
133 Molecule molecule
= Molecule ();
135 SCM scm_note_head_style
= me
->get_grob_property ("note-head-style");
136 String note_head_style
;
137 if (gh_symbol_p (scm_note_head_style
))
139 String note_head_style
=
140 ly_symbol2string (scm_note_head_style
);
144 note_head_style
= String ("noteheads-2");
146 if (Font_interface::get_default_font (me
)->find_by_name (note_head_style
).empty_b ())
148 String message
= "Ambitus: no such note head: `" + note_head_style
+ "'";
149 me
->warning (_ (message
.to_str0 ()));
154 FIXME: Use positions.
157 Pitch
*pitch_min
= unsmob_pitch (me
->get_grob_property ("pitch-min"));
160 me
->programming_error("Ambitus: pitch_min undefined; assuming 0");
165 p_min
= pitch_min
->steps ();
167 Pitch
*pitch_max
= unsmob_pitch (me
->get_grob_property ("pitch-max"));
170 me
->programming_error("Ambitus: pitch_max undefined; assuming 0");
175 p_max
= pitch_max
->steps ();
179 me
->programming_error ("Ambitus: reverse range");
182 SCM c0
= me
->get_grob_property ("c0-position");
183 if (gh_number_p (c0
))
185 p_min
+= gh_scm2int (c0
);
186 p_max
+= gh_scm2int (c0
);
191 Font_interface::get_default_font (me
)->find_by_name (note_head_style
);
192 head_min
.translate_axis (0.5*p_min
, Y_AXIS
);
194 Font_interface::get_default_font (me
)->find_by_name (note_head_style
);
195 head_max
.translate_axis (0.5*p_max
, Y_AXIS
);
198 if (to_boolean (me
->get_grob_property ("join-heads")) &&
199 ((p_max
- p_min
) >= 3))
201 Real linethickness
= me
->get_paper ()->get_var ("linethickness");
202 Real blotdiameter
= me
->get_paper ()->get_var ("blotdiameter");
203 Interval x_extent
= 0.5 * Interval (-linethickness
, +linethickness
);
204 Interval y_extent
= 0.5 * Interval (p_min
+ 1.35, p_max
- 1.35);
205 Box
line_box (x_extent
, y_extent
);
206 Molecule line
= Lookup::roundfilledbox (line_box
, blotdiameter
);
207 line
.translate_axis (0.5 * head_min
.extent (X_AXIS
).length (), X_AXIS
);
208 molecule
.add_molecule (line
);
212 Interval hd
= head_min
.extent (X_AXIS
);
213 Real left_ledger_protusion
= hd
.length () / 4;
214 Real right_ledger_protusion
= left_ledger_protusion
;
215 Interval l_extents
= Interval (hd
[LEFT
] - left_ledger_protusion
,
216 hd
[RIGHT
] + right_ledger_protusion
);
217 Molecule ledger_lines
;
218 int interspaces
= Staff_symbol_referencer::line_count (me
) - 1;
220 Note_head::brew_ledger_lines (me
, p_min
, interspaces
, l_extents
, true);
221 ledger_lines
.translate_axis (0.5 * p_min
, Y_AXIS
);
222 molecule
.add_molecule (ledger_lines
);
224 Note_head::brew_ledger_lines (me
, p_max
, interspaces
, l_extents
, true);
225 ledger_lines
.translate_axis (0.5 * p_max
, Y_AXIS
);
226 molecule
.add_molecule (ledger_lines
);
229 SCM key_signature
= me
->get_grob_property ("key-signature");
230 SCM scm_accidentals_style
= me
->get_grob_property ("accidentals-style");
231 String accidentals_style
;
232 if (gh_symbol_p (scm_accidentals_style
))
235 ly_symbol2string (scm_accidentals_style
);
239 accidentals_style
= String ("");
242 num_acc
= number_accidentals (key_signature
, pitch_min
, true, false);
243 add_accidentals (me
, &head_min
, num_acc
, pitch_min
,
244 accidentals_style
, 0.5 * p_min
);
245 num_acc
= number_accidentals (key_signature
, pitch_max
, true, false);
246 add_accidentals (me
, &head_max
, num_acc
, pitch_max
,
247 accidentals_style
, 0.5 * p_max
);
250 molecule
.add_molecule (head_min
);
251 molecule
.add_molecule (head_max
);
253 return molecule
.smobbed_copy ();
256 ADD_INTERFACE (Ambitus
, "ambitus-interface",
257 "An ambitus represents the pitch range of a voice.",
258 "c0-position pitch-min pitch-max accidentals note-head-style join-heads");