]> git.donarmstrong.com Git - lilypond.git/blob - lily/vaticana-ligature-engraver.cc
(finish_primitive): compile fixes.
[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, "porrectus") ||
90                !String::compare (glyph_name, ""))
91         {
92           /*
93            * This head represents either half of a porrectus 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        * porrectus), 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
134         {
135           /*
136            * Make a small space between adjacent notes of a ligature
137            * that are not directly joined.
138            */
139           distance += 2 * join_thickness;
140         }
141
142       /*
143        * Horizontally line-up this head to form a ligature.
144        */
145       get_set_column (primitive, first_primitive->get_column ());
146       primitive->translate_axis (distance, X_AXIS);
147       distance += head_width;
148     }
149   return distance;
150 }
151
152 void
153 Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
154                                              Array<Grob_info> primitives)
155 {
156   Real flexa_width;
157   SCM flexa_width_scm = ligature->get_grob_property ("flexa-width");
158   if (flexa_width_scm != SCM_EOL)
159     {
160       flexa_width = gh_scm2double (flexa_width_scm);
161     }
162   else
163     {
164       programming_error ("Vaticana_ligature_engraver:"
165                          "flexa-width undefined; assuming 2.0 staff space");
166       flexa_width =
167         2.0 * Staff_symbol_referencer::staff_space (ligature);
168     }
169
170   Real join_thickness;
171   SCM join_thickness_scm = ligature->get_grob_property ("thickness");
172   if (join_thickness_scm != SCM_EOL)
173     {
174       join_thickness = gh_scm2double (join_thickness_scm);
175     }
176   else
177     {
178       programming_error ("Vaticana_ligature_engraver:"
179                          "thickness undefined; assuming 1.4 linethickness");
180       join_thickness = 1.4;
181     }
182   join_thickness *= ligature->get_paper ()->get_var ("linethickness");
183
184   Item *first_primitive = 0;
185   Item *prev_primitive = 0;
186   int prev_context_info = 0;
187   int prev_pitch = 0;
188   int prev_pitch_delta = 0;
189   String prev_glyph_name = "";
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 ();
196     String glyph_name;
197     if (!first_primitive)
198       first_primitive = primitive;
199     int prefix_set = gh_scm2int (primitive->get_grob_property ("prefix-set"));
200
201     /*
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
205      * the backend).
206      */
207     if (prefix_set & VIRGA)
208       glyph_name = "vaticana_virga";
209     else if (prefix_set & QUILISMA)
210       glyph_name = "vaticana_quilisma";
211     else if (prefix_set & ORISCUS)
212       glyph_name = "solesmes_oriscus";
213     else if (prefix_set & STROPHA)
214       if (prefix_set & AUCTUM)
215         glyph_name = "solesmes_stropha_aucta";
216       else glyph_name = "solesmes_stropha";
217     else if (prefix_set & SEMIVOCALIS)
218       if (pitch > prev_pitch)
219         glyph_name = "vaticana_epiphonus";
220       else glyph_name = "vaticana_cephalicus";
221     else if (prefix_set & INCLINATUM)
222       if (prefix_set & AUCTUM)
223         glyph_name = "solesmes_incl_auctum";
224       else if (prefix_set & DEMINUTUM)
225         glyph_name = "solesmes_incl_parvum";
226       else
227         glyph_name = "vaticana_inclinatum";
228     else if (prefix_set & (CAVUM | LINEA))
229       if ((prefix_set & CAVUM) && (prefix_set & LINEA))
230         glyph_name = "vaticana_linea_punctum_cavum";
231       else if (prefix_set & CAVUM)
232         glyph_name = "vaticana_punctum_cavum";
233       else
234         glyph_name = "vaticana_linea_punctum";
235     else if (prefix_set & AUCTUM)
236       if (prefix_set & ASCENDENS)
237         glyph_name = "solesmes_auct_asc";
238       else
239         glyph_name = "solesmes_auct_desc";
240     else if (prefix_set & DEMINUTUM)
241       glyph_name = "vaticana_plica";
242     else if ((prefix_set & PES_OR_FLEXA) &&
243              (context_info & PES_LOWER) &&
244              (context_info & FLEXA_RIGHT))
245       glyph_name = ""; // second head of porrectus
246     else if (context_info & PES_UPPER)
247       if (pitch - prev_pitch > 1)
248         glyph_name = "vaticana_upes";
249       else
250         glyph_name = "vaticana_vupes";
251     else
252       glyph_name = "vaticana_punctum";
253
254     /*
255      * May need updating previous head, depending on the current head.
256      */
257     if (prefix_set & PES_OR_FLEXA)
258       if ((context_info & PES_LOWER) &&
259           (context_info & FLEXA_RIGHT)) // porrectus
260         {
261           prev_glyph_name = "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));
266           bool add_stem =
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));
271         }
272       else if (context_info & PES_UPPER)
273         {
274           if (!String::compare (prev_glyph_name, "vaticana_punctum"))
275             prev_glyph_name = "vaticana_lpes";
276         }
277       else // flexa
278         {
279           if (!String::compare (prev_glyph_name, "vaticana_punctum"))
280             prev_glyph_name = "vaticana_rvirga";
281         }
282
283     /*
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).
288      */
289     primitive->set_grob_property ("thickness", gh_double2scm (join_thickness));
290
291     /*
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.
296      */
297
298     /*
299      * Finish head of previous iteration for backend.
300      */
301     prev_distance =
302       finish_primitive (first_primitive, prev_primitive,
303                         prev_context_info, prev_glyph_name, prev_pitch_delta,
304                         flexa_width, join_thickness, prev_distance);
305
306     prev_primitive = primitive;
307     prev_context_info = context_info;
308     prev_pitch_delta = pitch - prev_pitch;
309     prev_pitch = pitch;
310     prev_glyph_name = glyph_name;
311   }
312
313   /*
314    * Finish head of last iteration for backend.
315    */
316   finish_primitive (first_primitive, prev_primitive,
317                     prev_context_info, prev_glyph_name, prev_pitch_delta,
318                     flexa_width, join_thickness, prev_distance);
319 }
320
321
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",
327 /* reads */       "",
328 /* write */       "");