]> git.donarmstrong.com Git - lilypond.git/blob - lily/vaticana-ligature-engraver.cc
* Documentation/user/music-glossary.tely: bugfix: #'flag-style =
[lilypond.git] / lily / vaticana-ligature-engraver.cc
1 /*
2   vaticana-ligature-engraver.cc -- implement Vaticana_ligature_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c)  2003 Juergen Reuter <reuter@ipd.uka.de>
7  */
8
9 #include "gregorian-ligature-engraver.hh"
10 #include "gregorian-ligature.hh"
11 #include "vaticana-ligature.hh"
12 #include "item.hh"
13 #include "spanner.hh"
14 #include "staff-symbol-referencer.hh"
15 #include "font-interface.hh"
16 #include "warn.hh"
17 #include "paper-def.hh"
18
19 class Vaticana_ligature_engraver : public Gregorian_ligature_engraver
20 {
21
22 private:
23   Real finish_primitive (Item *first_primitive,
24                          Item *primitive,
25                          int context_info,
26                          String glyph_name,
27                          int pitch_delta,
28                          Real flexa_width,
29                          Real join_thickness,
30                          Real distance);
31
32 public:
33   TRANSLATOR_DECLARATIONS(Vaticana_ligature_engraver);
34
35 protected:
36   virtual Spanner *create_ligature_spanner ();
37   virtual void transform_heads (Spanner *ligature,
38                                 Array<Grob_info> primitives);
39 };
40
41 Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
42 {
43 }
44
45 Spanner *
46 Vaticana_ligature_engraver::create_ligature_spanner ()
47 {
48   return new Spanner (get_property ("VaticanaLigature"));
49 }
50
51 Real
52 Vaticana_ligature_engraver::finish_primitive (Item *first_primitive,
53                                               Item *primitive,
54                                               int context_info,
55                                               String glyph_name,
56                                               int pitch_delta,
57                                               Real flexa_width,
58                                               Real join_thickness,
59                                               Real distance)
60 {
61   if (primitive)
62     {
63       // determine width of previous head and x-offset
64       Real head_width;
65       Real x_offset;
66       bool is_stacked;
67       is_stacked = context_info & PES_UPPER;
68       if (context_info & FLEXA_LEFT)
69         is_stacked = false;
70       if (!String::compare (glyph_name, "vaticana_cephalicus") &&
71           !(context_info & PES_LOWER))
72         is_stacked = true;
73       if (context_info & AUCTUM)
74         is_stacked = false;
75       if (is_stacked)
76         {
77           /*
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.
83            */
84           head_width = 0.0;
85           x_offset = join_thickness -
86             Font_interface::get_default_font (primitive)->
87             find_by_name ("noteheads-" + glyph_name).extent (X_AXIS).length ();
88         }
89       else if (!String::compare (glyph_name, "flexa") ||
90                !String::compare (glyph_name, ""))
91         {
92           /*
93            * This head represents either half of a flexa shape.
94            * Hence, it is assigned half the width of this shape.
95            */
96           head_width = 0.5 * flexa_width;
97           x_offset = 0.0;
98         }
99       else // retrieve width from corresponding font
100         {
101           head_width =
102             Font_interface::get_default_font (primitive)->
103             find_by_name ("noteheads-" + glyph_name).extent (X_AXIS).length ();
104           x_offset = 0.0;
105         }
106
107       /*
108        * Save the head's final shape and x-offset.
109        */
110       primitive->set_grob_property ("glyph-name",
111                                     scm_makfrom0str (glyph_name.to_str0 ()));
112       primitive->set_grob_property ("x-offset",
113                                     gh_double2scm (x_offset));
114
115       /*
116        * If the head is the 2nd head of a pes or flexa (but not a
117        * flexa shape), mark this head to be joined with the left-side
118        * neighbour head (i.e. the previous head) by a vertical beam.
119        */
120       if ((context_info & PES_UPPER) ||
121           ((context_info & FLEXA_RIGHT) &&
122            !(context_info & PES_LOWER)))
123         {
124           primitive->set_grob_property ("join-left",
125                                         gh_int2scm (pitch_delta));
126
127           /*
128            * Create a small overlap of adjacent heads so that the join
129            * can be drawn perfectly between them.
130            */
131           distance -= join_thickness;
132         }
133       else if (!String::compare (glyph_name, ""))
134         {
135           /*
136            * 2nd (virtual) head of flexa shape: join tightly with 1st
137            * head, i.e. do *not* add additional space, such that next
138            * head will not be off from the flexa shape.
139            */
140         }
141       else if (context_info & AFTER_VIRGA)
142         {
143           /*
144            * Make a small space after a virga.
145            */
146           distance += 2 * join_thickness;
147         }
148
149       /*
150        * Horizontally line-up this head to form a ligature.
151        */
152       get_set_column (primitive, first_primitive->get_column ());
153       primitive->translate_axis (distance, X_AXIS);
154       distance += head_width;
155     }
156   return distance;
157 }
158
159 void
160 Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
161                                              Array<Grob_info> primitives)
162 {
163   Real flexa_width;
164   SCM flexa_width_scm = ligature->get_grob_property ("flexa-width");
165   if (flexa_width_scm != SCM_EOL)
166     {
167       flexa_width = gh_scm2double (flexa_width_scm);
168     }
169   else
170     {
171       programming_error ("Vaticana_ligature_engraver:"
172                          "flexa-width undefined; assuming 2.0 staff space");
173       flexa_width =
174         2.0 * Staff_symbol_referencer::staff_space (ligature);
175     }
176
177   Real join_thickness;
178   SCM join_thickness_scm = ligature->get_grob_property ("thickness");
179   if (join_thickness_scm != SCM_EOL)
180     {
181       join_thickness = gh_scm2double (join_thickness_scm);
182     }
183   else
184     {
185       programming_error ("Vaticana_ligature_engraver:"
186                          "thickness undefined; assuming 1.4 linethickness");
187       join_thickness = 1.4;
188     }
189   join_thickness *= ligature->get_paper ()->get_var ("linethickness");
190
191   Item *first_primitive = 0;
192   Item *prev_primitive = 0;
193   int prev_context_info = 0;
194   int prev_pitch = 0;
195   int prev_pitch_delta = 0;
196   String prev_glyph_name = "";
197   Real prev_distance = 0.0;
198   for (int i = 0; i < primitives.size(); i++) {
199     Item *primitive = dynamic_cast<Item*> (primitives[i].grob_);
200     Music *music_cause = primitives[i].music_cause ();
201     int context_info = gh_scm2int (primitive->get_grob_property ("context-info"));
202     int pitch = unsmob_pitch (music_cause->get_mus_property ("pitch"))->steps ();
203     String glyph_name;
204     if (!first_primitive)
205       first_primitive = primitive;
206     int prefix_set = gh_scm2int (primitive->get_grob_property ("prefix-set"));
207
208     /*
209      * Now determine which head to typeset (this is context sensitive
210      * information, since it depends on neighbouring heads; therefore,
211      * this decision must be made here in the engraver rather than in
212      * the backend).
213      */
214     if (prefix_set & VIRGA)
215       glyph_name = "vaticana_virga";
216     else if (prefix_set & QUILISMA)
217       glyph_name = "vaticana_quilisma";
218     else if (prefix_set & ORISCUS)
219       glyph_name = "solesmes_oriscus";
220     else if (prefix_set & STROPHA)
221       if (prefix_set & AUCTUM)
222         glyph_name = "solesmes_stropha_aucta";
223       else glyph_name = "solesmes_stropha";
224     else if (prefix_set & SEMIVOCALIS)
225       if (pitch > prev_pitch)
226         glyph_name = "vaticana_epiphonus";
227       else glyph_name = "vaticana_cephalicus";
228     else if (prefix_set & INCLINATUM)
229       if (prefix_set & AUCTUM)
230         glyph_name = "solesmes_incl_auctum";
231       else if (prefix_set & DEMINUTUM)
232         glyph_name = "solesmes_incl_parvum";
233       else
234         glyph_name = "vaticana_inclinatum";
235     else if (prefix_set & (CAVUM | LINEA))
236       if ((prefix_set & CAVUM) && (prefix_set & LINEA))
237         glyph_name = "vaticana_linea_punctum_cavum";
238       else if (prefix_set & CAVUM)
239         glyph_name = "vaticana_punctum_cavum";
240       else
241         glyph_name = "vaticana_linea_punctum";
242     else if (prefix_set & AUCTUM)
243       if (prefix_set & ASCENDENS)
244         glyph_name = "solesmes_auct_asc";
245       else
246         glyph_name = "solesmes_auct_desc";
247     else if (prefix_set & DEMINUTUM)
248       glyph_name = "vaticana_plica";
249     else if ((prefix_set & PES_OR_FLEXA) &&
250              (context_info & PES_LOWER) &&
251              (context_info & FLEXA_RIGHT))
252       glyph_name = ""; // second head of flexa shape
253     else if (context_info & PES_UPPER)
254       if (pitch - prev_pitch > 1)
255         glyph_name = "vaticana_upes";
256       else
257         glyph_name = "vaticana_vupes";
258     else
259       glyph_name = "vaticana_punctum";
260
261     /*
262      * May need updating previous head, depending on the current head.
263      */
264     if (prefix_set & PES_OR_FLEXA)
265       if ((context_info & PES_LOWER) &&
266           (context_info & FLEXA_RIGHT)) // flexa shape
267         {
268           prev_glyph_name = "flexa";
269           prev_primitive->set_grob_property ("flexa-height",
270                                              gh_int2scm (pitch - prev_pitch));
271           prev_primitive->set_grob_property ("flexa-width",
272                                              gh_double2scm (flexa_width));
273           bool add_stem =
274             !(prev_context_info & PES_UPPER) &&
275             !(prev_context_info & FLEXA_RIGHT);
276           prev_primitive->set_grob_property ("add-stem",
277                                              gh_bool2scm (add_stem));
278         }
279       else if (context_info & PES_UPPER)
280         {
281           if (!String::compare (prev_glyph_name, "vaticana_punctum"))
282             prev_glyph_name = "vaticana_lpes";
283         }
284       else // flexa
285         {
286           if (!String::compare (prev_glyph_name, "vaticana_punctum"))
287             prev_glyph_name = "vaticana_rvirga";
288         }
289
290     /*
291      * In the backend, flexa shapes and joins need to know about
292      * thickness.  Hence, for simplicity, let's distribute the
293      * ligature grob's value for thickness to each ligature head (even
294      * if not all of them need to know).
295      */
296     primitive->set_grob_property ("thickness", gh_double2scm (join_thickness));
297
298     /*
299      * The head of the current iteration still may change during the
300      * next iteration due to the context sensitiveness of the
301      * transformation.  However, the head of the previous iteration is
302      * now fully attributed and can be prepared for the backend.
303      */
304
305     /*
306      * Finish head of previous iteration for backend.
307      */
308     prev_distance =
309       finish_primitive (first_primitive, prev_primitive,
310                         prev_context_info, prev_glyph_name, prev_pitch_delta,
311                         flexa_width, join_thickness, prev_distance);
312
313     prev_primitive = primitive;
314     prev_context_info = context_info;
315     prev_pitch_delta = pitch - prev_pitch;
316     prev_pitch = pitch;
317     prev_glyph_name = glyph_name;
318   }
319
320   /*
321    * Finish head of last iteration for backend.
322    */
323   finish_primitive (first_primitive, prev_primitive,
324                     prev_context_info, prev_glyph_name, prev_pitch_delta,
325                     flexa_width, join_thickness, prev_distance);
326 }
327
328
329 ENTER_DESCRIPTION (Vaticana_ligature_engraver,
330 /* descr */       "Handles ligatures by glueing special ligature heads together.",
331 /* creats*/       "VaticanaLigature",
332 /* accepts */     "ligature-event abort-event",
333 /* acks  */      "ligature-head-interface note-head-interface rest-interface",
334 /* reads */       "",
335 /* write */       "");