2 gregorian-ligature-engraver.cc -- implement Gregorian_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"
13 #include "staff-symbol-referencer.hh"
15 #include "paper-column.hh"
18 * TODO: This class shares some code with Mensural_ligature_engraver.
19 * Maybe we should create a common super class "Rod_ligature_engraver"
20 * and derive all shared code from it.
23 Gregorian_ligature_engraver::Gregorian_ligature_engraver ()
29 Gregorian_ligature_engraver::transform_heads (Spanner
*, Array
<Grob_info
>)
31 programming_error ("Gregorian_ligature_engraver::transform_heads (): "
32 "this is an abstract method that should not be called, "
33 "but overridden by a subclass");
37 Gregorian_ligature_engraver::try_music (Music
*m
)
39 if (m
->is_mus_type ("porrectus-event"))
45 return Ligature_engraver::try_music (m
);
49 * TODO: move this function to class Item?
52 Gregorian_ligature_engraver::get_set_column (Item
*item
, Paper_column
*column
)
54 Item
*parent
= dynamic_cast<Item
*> (item
->get_parent (X_AXIS
));
57 programming_error ("failed tweaking paper column in ligature");
61 String name
= parent
->name ();
62 if (!String::compare (name
, "PaperColumn"))
64 // Change column not only for targeted item (NoteColumn), but
65 // also for all associated grobs (NoteSpacing, SeparationItem).
66 Grob
*sl
= Staff_symbol_referencer::get_staff_symbol (item
);
67 for (SCM tail
= parent
->get_grob_property ("elements");
71 Item
*sibling
= unsmob_item (ly_car (tail
));
73 (Staff_symbol_referencer::get_staff_symbol (sibling
) == sl
))
75 sibling
->set_parent (column
, X_AXIS
);
81 get_set_column (parent
, column
);
85 void fix_prefix (char *name
, int mask
,
86 int *current_set
, int min_set
, int max_set
,
89 bool current
= *current_set
& mask
;
90 bool min
= min_set
& mask
;
91 bool max
= max_set
& mask
;
94 programming_error ("min_set > max_set");
99 primitive
->warning (_f ("\\%s ignored", name
));
100 *current_set
&= ~mask
;
104 primitive
->warning (_f ("implied \\%s added", name
));
105 *current_set
|= mask
;
109 void fix_prefix_set (int *current_set
, int min_set
, int max_set
, Grob
*primitive
)
111 fix_prefix ("virga", VIRGA
, current_set
, min_set
, max_set
, primitive
);
112 fix_prefix ("stropha", STROPHA
, current_set
, min_set
, max_set
, primitive
);
113 fix_prefix ("inclinatum", INCLINATUM
, current_set
, min_set
, max_set
, primitive
);
114 fix_prefix ("auctum", AUCTUM
, current_set
, min_set
, max_set
, primitive
);
115 fix_prefix ("descendens", DESCENDENS
, current_set
, min_set
, max_set
, primitive
);
116 fix_prefix ("ascendens", ASCENDENS
, current_set
, min_set
, max_set
, primitive
);
117 fix_prefix ("oriscus", ORISCUS
, current_set
, min_set
, max_set
, primitive
);
118 fix_prefix ("quilisma", QUILISMA
, current_set
, min_set
, max_set
, primitive
);
119 fix_prefix ("deminutus", DEMINUTUM
, current_set
, min_set
, max_set
, primitive
);
120 fix_prefix ("semivocalis", SEMIVOCALIS
, current_set
, min_set
, max_set
, primitive
);
121 fix_prefix ("cavum", CAVUM
, current_set
, min_set
, max_set
, primitive
);
122 fix_prefix ("linea", LINEA
, current_set
, min_set
, max_set
, primitive
);
123 fix_prefix ("pes_or_flexa", LINEA
, current_set
, min_set
, max_set
, primitive
);
126 void check_and_fix_all_prefixes (Array
<Grob_info
> primitives
)
128 /* Check for illegal head modifier combinations */
129 for (int i
= 0; i
< primitives
.size(); i
++)
131 Grob
*primitive
= primitives
[i
].grob_
;
133 /* compute head prefix set by inspecting primitive grob properties */
135 (VIRGA
* to_boolean (primitive
->get_grob_property ("virga"))) |
136 (STROPHA
* to_boolean (primitive
->get_grob_property ("stropha"))) |
137 (INCLINATUM
* to_boolean (primitive
->get_grob_property ("inclinatum"))) |
138 (AUCTUM
* to_boolean (primitive
->get_grob_property ("auctum"))) |
139 (DESCENDENS
* to_boolean (primitive
->get_grob_property ("descendens"))) |
140 (ASCENDENS
* to_boolean (primitive
->get_grob_property ("ascendens"))) |
141 (ORISCUS
* to_boolean (primitive
->get_grob_property ("oriscus"))) |
142 (QUILISMA
* to_boolean (primitive
->get_grob_property ("quilisma"))) |
143 (DEMINUTUM
* to_boolean (primitive
->get_grob_property ("deminutum"))) |
144 (SEMIVOCALIS
* to_boolean (primitive
->get_grob_property ("semivocalis"))) |
145 (CAVUM
* to_boolean (primitive
->get_grob_property ("cavum"))) |
146 (LINEA
* to_boolean (primitive
->get_grob_property ("linea"))) |
147 (PES_OR_FLEXA
* to_boolean (primitive
->get_grob_property ("pes-or-flexa")));
149 /* check: ascendens and descendens exclude each other; same with
150 auctum and diminutum */
151 if (prefix_set
& DESCENDENS
)
153 fix_prefix_set (&prefix_set
,
154 prefix_set
& ~ASCENDENS
,
155 prefix_set
& ~ASCENDENS
,
158 if (prefix_set
& AUCTUM
)
160 fix_prefix_set (&prefix_set
,
161 prefix_set
& ~DEMINUTUM
,
162 prefix_set
& ~DEMINUTUM
,
166 /* check: virga, quilisma and oriscus can not be combined with any
167 other prefix, but may be part of a pes or flexa */
168 if (prefix_set
& VIRGA
)
170 fix_prefix_set (&prefix_set
,
172 VIRGA
| PES_OR_FLEXA
,
175 if (prefix_set
& QUILISMA
)
177 fix_prefix_set (&prefix_set
,
179 QUILISMA
| PES_OR_FLEXA
,
182 if (prefix_set
& ORISCUS
)
184 fix_prefix_set (&prefix_set
,
186 ORISCUS
| PES_OR_FLEXA
,
190 /* check: auctum is the only valid optional prefix for stropha */
191 if (prefix_set
& STROPHA
)
193 fix_prefix_set (&prefix_set
,
199 /* check: semivocalis must occur in combination with and only with
201 if (prefix_set
& SEMIVOCALIS
)
203 fix_prefix_set (&prefix_set
,
204 SEMIVOCALIS
| PES_OR_FLEXA
,
205 SEMIVOCALIS
| PES_OR_FLEXA
,
209 /* check: inclinatum may be prefixed with auctum or diminutum only */
210 if (prefix_set
& INCLINATUM
)
212 fix_prefix_set (&prefix_set
,
214 INCLINATUM
| AUCTUM
| DEMINUTUM
,
218 /* check: cavum and linea (either or both) may be applied only
220 if (prefix_set
& (CAVUM
| LINEA
))
222 fix_prefix_set (&prefix_set
,
228 /* all other combinations should be valid (unless I made a
231 primitive
->set_grob_property ("prefix-set", gh_int2scm (prefix_set
));
236 * Marks those heads that participate in a pes or flexa.
239 provide_context_info (Array
<Grob_info
> primitives
)
241 Grob
*prev_primitive
= 0;
242 int prev_context_info
= 0;
244 for (int i
= 0; i
< primitives
.size(); i
++) {
245 Grob
*primitive
= primitives
[i
].grob_
;
246 Music
*music_cause
= primitives
[i
].music_cause ();
247 int context_info
= 0;
248 int pitch
= unsmob_pitch (music_cause
->get_mus_property ("pitch"))->steps ();
249 int prefix_set
= gh_scm2int (primitive
->get_grob_property ("prefix-set"));
251 if (prefix_set
& PES_OR_FLEXA
)
252 if (pitch
> prev_pitch
) // pes
254 prev_context_info
|= PES_LOWER
;
255 context_info
|= PES_UPPER
;
257 else if (pitch
< prev_pitch
) // flexa
259 prev_context_info
|= FLEXA_LEFT
;
260 context_info
|= FLEXA_RIGHT
;
262 else // (pitch == prev_pitch)
264 primitive
->warning ("may not apply `\\~' on heads with "
265 "identical pitch; ignoring `\\~'");
268 prev_primitive
->set_grob_property ("context-info",
269 gh_int2scm (prev_context_info
));
270 prev_primitive
= primitive
;
271 prev_context_info
= context_info
;
275 prev_primitive
->set_grob_property ("context-info",
276 gh_int2scm (prev_context_info
));
280 Gregorian_ligature_engraver::typeset_ligature (Spanner
*ligature
,
281 Array
<Grob_info
> primitives
)
283 // apply style-independent checking and transformation
284 check_and_fix_all_prefixes (primitives
);
285 provide_context_info (primitives
);
287 // apply style-specific transformation (including line-up)
288 transform_heads (ligature
, primitives
);
291 for (int i
= 0; i
< primitives
.size (); i
++)
293 typeset_grob (primitives
[i
].grob_
);
298 Gregorian_ligature_engraver::start_translation_timestep ()
300 Ligature_engraver::start_translation_timestep ();
304 ENTER_DESCRIPTION (Gregorian_ligature_engraver
,
305 /* descr */ "This is an abstract class. Subclasses such as Vaticana_ligature_engraver handle ligatures by glueing special ligature heads together.",
307 /* accepts */ "ligature-event abort-event",
308 /* acks */ "ligature-head-interface note-head-interface rest-interface",