2 vaticana-ligature-engraver.cc -- implement Vaticana_ligature_engraver
4 source file of the GNU LilyPond music typesetter
6 (C) 2003 Juergen Reuter <reuter@ipd.uka.de>
9 #include "gregorian-ligature-engraver.hh"
10 #include "gregorian-ligature.hh"
11 #include "vaticana-ligature.hh"
14 #include "staff-symbol-referencer.hh"
15 #include "font-interface.hh"
17 #include "paper-def.hh"
19 class Vaticana_ligature_engraver : public Gregorian_ligature_engraver
23 Real finish_primitive (Item *first_primitive,
33 TRANSLATOR_DECLARATIONS(Vaticana_ligature_engraver);
36 virtual Spanner *create_ligature_spanner ();
37 virtual void transform_heads (Spanner *ligature,
38 Array<Grob_info> primitives);
41 Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
46 Vaticana_ligature_engraver::create_ligature_spanner ()
48 return new Spanner (get_property ("VaticanaLigature"));
52 Vaticana_ligature_engraver::finish_primitive (Item *first_primitive,
63 // determine width of previous head and x-shift
67 is_stacked = context_info & PES_UPPER;
68 if (context_info & FLEXA_LEFT)
70 if (!String::compare (head, "vaticana_cephalicus") &&
71 !(context_info & PES_LOWER))
73 if (context_info & AUCTUM)
78 * This head is stacked upon another one; hence, it does not
79 * contribute to the total width of the ligature, hence its
80 * width is assumed to be 0.0. Moreover, it is shifted to
81 * the left by its width such that the right side of this
82 * and the other head are horizontally aligned.
85 x_shift = join_thickness -
86 Font_interface::get_default_font (primitive)->
87 find_by_name ("noteheads-" + head).extent (X_AXIS).length ();
89 else if (!String::compare (head, "porrectus") ||
90 !String::compare (head, ""))
93 * This head represents either half of a porrectus shape.
94 * Hence, it is assigned half the width of this shape.
96 head_width = 0.5 * flexa_width;
99 else // retrieve width from corresponding font
102 Font_interface::get_default_font (primitive)->
103 find_by_name ("noteheads-" + head).extent (X_AXIS).length ();
108 * Save the head's final shape and x-shift.
110 primitive->set_grob_property ("ligature-head",
111 ly_symbol2scm (head.to_str0 ()));
112 primitive->set_grob_property ("x-shift",
113 gh_double2scm (x_shift));
116 * If the head is the 2nd head of a pes or flexa (but not a
117 * porrectus), mark this head to be joined with the left-side
118 * neighbour head (i.e. the previous head) by a vertical beam.
120 if ((context_info & PES_UPPER) ||
121 ((context_info & FLEXA_RIGHT) &&
122 !(context_info & PES_LOWER)))
124 primitive->set_grob_property ("join-left",
125 gh_int2scm (pitch_delta));
128 * Create a small overlap of adjacent heads so that the join
129 * can be drawn perfectly between them.
131 distance -= join_thickness;
136 * Make a small space between adjacent notes of a ligature
137 * that are not directly joined.
139 distance += 2 * join_thickness;
143 * Horizontally line-up this head to form a ligature.
145 get_set_column (primitive, first_primitive->get_column ());
146 primitive->translate_axis (distance, X_AXIS);
147 distance += head_width;
153 Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
154 Array<Grob_info> primitives)
157 SCM flexa_width_scm = ligature->get_grob_property ("flexa-width");
158 if (flexa_width_scm != SCM_EOL)
160 flexa_width = gh_scm2double (flexa_width_scm);
164 programming_error ("Vaticana_ligature_engraver:"
165 "flexa-width undefined; assuming 2.0 staff space");
167 2.0 * Staff_symbol_referencer::staff_space (ligature);
171 SCM join_thickness_scm = ligature->get_grob_property ("thickness");
172 if (join_thickness_scm != SCM_EOL)
174 join_thickness = gh_scm2double (join_thickness_scm);
178 programming_error ("Vaticana_ligature_engraver:"
179 "thickness undefined; assuming 1.4 linethickness");
180 join_thickness = 1.4;
182 join_thickness *= ligature->get_paper ()->get_var ("linethickness");
184 Item *first_primitive = 0;
185 Item *prev_primitive = 0;
186 int prev_context_info = 0;
188 int prev_pitch_delta = 0;
189 String prev_head = "";
190 Real prev_distance = 0.0;
191 for (int i = 0; i < primitives.size(); i++) {
192 Item *primitive = dynamic_cast<Item*> (primitives[i].grob_);
193 Music *music_cause = primitives[i].music_cause ();
194 int context_info = gh_scm2int (primitive->get_grob_property ("context-info"));
195 int pitch = unsmob_pitch (music_cause->get_mus_property ("pitch"))->steps ();
197 if (!first_primitive)
198 first_primitive = primitive;
199 int prefix_set = gh_scm2int (primitive->get_grob_property ("prefix-set"));
202 * Now determine which head to typeset (this is context sensitive
203 * information, since it depends on neighbouring heads; therefore,
204 * this decision must be made here in the engraver rather than in
207 if (prefix_set & VIRGA)
208 head = "vaticana_virga";
209 else if (prefix_set & QUILISMA)
210 head = "vaticana_quilisma";
211 else if (prefix_set & ORISCUS)
212 head = "solesmes_oriscus";
213 else if (prefix_set & STROPHA)
214 if (prefix_set & AUCTUM)
215 head = "solesmes_stropha_aucta";
216 else head = "solesmes_stropha";
217 else if (prefix_set & SEMIVOCALIS)
218 if (pitch > prev_pitch)
219 head = "vaticana_epiphonus";
220 else head = "vaticana_cephalicus";
221 else if (prefix_set & INCLINATUM)
222 if (prefix_set & AUCTUM)
223 head = "solesmes_incl_auctum";
224 else if (prefix_set & DEMINUTUM)
225 head = "solesmes_incl_parvum";
227 head = "vaticana_inclinatum";
228 else if (prefix_set & (CAVUM | LINEA))
229 if ((prefix_set & CAVUM) && (prefix_set & LINEA))
230 head = "vaticana_linea_punctum_cavum";
231 else if (prefix_set & CAVUM)
232 head = "vaticana_punctum_cavum";
234 head = "vaticana_linea_punctum";
235 else if (prefix_set & AUCTUM)
236 if (prefix_set & ASCENDENS)
237 head = "solesmes_auct_asc";
239 head = "solesmes_auct_desc";
240 else if (prefix_set & DEMINUTUM)
241 head = "vaticana_plica";
242 else if ((prefix_set & PES_OR_FLEXA) &&
243 (context_info & PES_LOWER) &&
244 (context_info & FLEXA_RIGHT))
245 head = ""; // second head of porrectus
246 else if (context_info & PES_UPPER)
247 if (pitch - prev_pitch > 1)
248 head = "vaticana_upes";
250 head = "vaticana_vupes";
252 head = "vaticana_punctum";
255 * May need updating previous head, depending on the current head.
257 if (prefix_set & PES_OR_FLEXA)
258 if ((context_info & PES_LOWER) &&
259 (context_info & FLEXA_RIGHT)) // porrectus
261 prev_head = "porrectus";
262 prev_primitive->set_grob_property ("porrectus-height",
263 gh_int2scm (pitch - prev_pitch));
264 prev_primitive->set_grob_property ("porrectus-width",
265 gh_double2scm (flexa_width));
267 !(prev_context_info & PES_UPPER) &&
268 !(prev_context_info & FLEXA_RIGHT);
269 prev_primitive->set_grob_property ("add-stem",
270 gh_bool2scm (add_stem));
272 else if (context_info & PES_UPPER)
274 if (!String::compare (prev_head, "vaticana_punctum"))
275 prev_head = "vaticana_lpes";
279 if (!String::compare (prev_head, "vaticana_punctum"))
280 prev_head = "vaticana_rvirga";
284 * In the backend, porrectus and joins need to know about
285 * thickness. Hence, for simplicity, let's distribute the
286 * ligature grob's value for thickness to each ligature head (even
287 * if not all of them need to know).
289 primitive->set_grob_property ("thickness", gh_double2scm (join_thickness));
292 * The head of the current iteration still may change during the
293 * next iteration due to the context sensitiveness of the
294 * transformation. However, the head of the previous iteration is
295 * now fully attributed and can be prepared for the backend.
299 * Finish head of previous iteration for backend.
302 finish_primitive (first_primitive, prev_primitive,
303 prev_context_info, prev_head, prev_pitch_delta,
304 flexa_width, join_thickness, prev_distance);
306 prev_primitive = primitive;
307 prev_context_info = context_info;
308 prev_pitch_delta = pitch - prev_pitch;
314 * Finish head of last iteration for backend.
316 finish_primitive (first_primitive, prev_primitive,
317 prev_context_info, prev_head, prev_pitch_delta,
318 flexa_width, join_thickness, prev_distance);
322 ENTER_DESCRIPTION (Vaticana_ligature_engraver,
323 /* descr */ "Handles ligatures by glueing special ligature heads together.",
324 /* creats*/ "VaticanaLigature",
325 /* accepts */ "ligature-event abort-event",
326 /* acks */ "ligature-head-interface note-head-interface rest-interface",