2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2003--2010 Juergen Reuter <reuter@ipd.uka.de>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "gregorian-ligature-engraver.hh"
22 #include "font-interface.hh"
23 #include "gregorian-ligature.hh"
24 #include "international.hh"
25 #include "output-def.hh"
26 #include "paper-column.hh"
27 #include "separation-item.hh"
29 #include "staff-symbol-referencer.hh"
30 #include "stream-event.hh"
31 #include "vaticana-ligature.hh"
33 #include "dot-column.hh"
34 #include "rhythmic-head.hh"
36 #include "translator.icc"
39 * This class implements the notation specific aspects of Vaticana
40 * style ligatures for Gregorian chant notation.
44 * TODO: Maybe move handling of dots/mora to
45 * Gregorian_ligature_engraver? It's probably common for all types of
46 * Gregorian chant notation that have dotted notes.
48 * FIXME: The horizontal alignment of the mora column is bad (too far
49 * to the left), if the last dotted note is not the last primitive in
50 * the ligature. Fortunately, in practice this bug should have no
51 * negative impact, since dotted notes appear within a ligature
52 * usually always at the end of the ligature, such that the bug never
53 * should apply for valid ligatures.
55 * TODO: Graduale Triplex, tempus per annum, hebdomada septima,
56 * alleluia (page 280) shows a counter-example for collecting dots
57 * always in a single column behind the ligature. Maybe only the last
58 * two dots in a ligature should be collected and all other dots put
59 * behind or on top of the head?
61 class Vaticana_ligature_engraver
: public Gregorian_ligature_engraver
66 need_extra_horizontal_space (int prev_prefix_set
, int prefix_set
,
67 int context_info
, int delta_pitch
);
68 bool is_stacked_head (int prefix_set
,
70 Real
align_heads (vector
<Grob_info
> primitives
,
73 void check_for_prefix_loss (Item
*primitive
);
74 void check_for_ambiguous_dot_pitch (Grob_info primitive
);
75 void add_mora_column (Paper_column
*column
);
76 vector
<Grob_info
> augmented_primitives_
;
79 TRANSLATOR_DECLARATIONS (Vaticana_ligature_engraver
);
82 virtual Spanner
*create_ligature_spanner ();
83 virtual void transform_heads (Spanner
*ligature
,
84 vector
<Grob_info
> primitives
);
85 DECLARE_TRANSLATOR_LISTENER (pes_or_flexa
);
86 DECLARE_TRANSLATOR_LISTENER (ligature
);
89 IMPLEMENT_TRANSLATOR_LISTENER (Vaticana_ligature_engraver
, pes_or_flexa
);
91 Vaticana_ligature_engraver::listen_pes_or_flexa (Stream_event
*ev
)
93 Gregorian_ligature_engraver::listen_pes_or_flexa (ev
);
96 IMPLEMENT_TRANSLATOR_LISTENER (Vaticana_ligature_engraver
, ligature
);
98 Vaticana_ligature_engraver::listen_ligature (Stream_event
*ev
)
100 Ligature_engraver::listen_ligature (ev
);
103 Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
105 brew_ligature_primitive_proc
=
106 Vaticana_ligature::brew_ligature_primitive_proc
;
107 augmented_primitives_
.clear ();
111 Vaticana_ligature_engraver::create_ligature_spanner ()
113 return make_spanner ("VaticanaLigature", SCM_EOL
);
117 Vaticana_ligature_engraver::is_stacked_head (int prefix_set
,
122 // upper head of pes is stacked upon lower head of pes ...
123 is_stacked
= context_info
& PES_UPPER
;
125 // ... unless this note starts a flexa
126 if (context_info
& FLEXA_LEFT
)
129 // ... or another pes
130 if (context_info
& PES_LOWER
)
133 // ... or the previous note is a semivocalis or inclinatum
134 if (context_info
& AFTER_DEMINUTUM
)
137 // auctum head is never stacked upon preceding note
138 if (prefix_set
& AUCTUM
)
141 // virga is never stacked upon preceding note
142 if (prefix_set
& VIRGA
)
145 // oriscus is never stacked upon preceding note
146 if (prefix_set
& ORISCUS
)
149 if ((prefix_set
& DEMINUTUM
)
150 && ! (prefix_set
& INCLINATUM
)
151 && (context_info
& FLEXA_RIGHT
))
152 is_stacked
= true; // semivocalis head of deminutus form
158 * When aligning the heads, sometimes extra space is needed, e.g. to
159 * avoid clashing with the appendix of an adjacent notehead or with an
160 * adjacent notehead itself if it has the same pitch. Extra space is
161 * added at most once between to heads.
164 Vaticana_ligature_engraver::need_extra_horizontal_space (int prev_prefix_set
, int prefix_set
,
165 int context_info
, int delta_pitch
)
167 if (prev_prefix_set
& VIRGA
)
169 * After a virga, make a an additional small space such that the
170 * appendix on the right side of the head does not touch the
175 if ((prefix_set
& INCLINATUM
)
176 && ! (prev_prefix_set
& INCLINATUM
))
178 * Always start a series of inclinatum heads with an extra space.
182 if ((context_info
& FLEXA_LEFT
) && ! (context_info
& PES_UPPER
))
184 * Before a flexa (but not within a torculus), make a an
185 * additional small space such that the appendix on the left side
186 * of the flexa does not touch the this head.
190 if (delta_pitch
== 0)
192 * If there are two adjacent noteheads with the same pitch, add
193 * additional small space between them, such that they do not
202 Vaticana_ligature_engraver::align_heads (vector
<Grob_info
> primitives
,
206 if (!primitives
.size ())
208 programming_error ("Vaticana_ligature: "
209 "empty ligature [ignored]");
214 * The paper column where we put the whole ligature into.
217 = dynamic_cast<Item
*> (primitives
[0].grob ())->get_column ();
220 = thickness
* column
->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
223 * Amount of extra space two put between some particular
224 * configurations of adjacent heads.
226 * TODO: make this a property of primtive grobs.
228 Real extra_space
= 4.0 * join_thickness
;
231 * Keep track of the total width of the ligature.
233 Real ligature_width
= 0.0;
235 Item
*prev_primitive
= 0;
236 int prev_prefix_set
= 0;
237 for (vsize i
= 0; i
< primitives
.size (); i
++)
239 Item
*primitive
= dynamic_cast<Item
*> (primitives
[i
].grob ());
241 = scm_to_int (primitive
->get_property ("prefix-set"));
243 = scm_to_int (primitive
->get_property ("context-info"));
246 * Get glyph_name, delta_pitch and context_info for this head.
249 SCM glyph_name_scm
= primitive
->get_property ("glyph-name");
250 if (glyph_name_scm
== SCM_EOL
)
252 primitive
->programming_error ("Vaticana_ligature:"
253 " undefined glyph-name ->"
257 string glyph_name
= ly_scm2string (glyph_name_scm
);
260 if (prev_primitive
) /* urgh, need prev_primitive only here */
262 SCM delta_pitch_scm
= prev_primitive
->get_property ("delta-position");
263 if (delta_pitch_scm
!= SCM_EOL
)
264 delta_pitch
= scm_to_int (delta_pitch_scm
);
267 primitive
->programming_error ("Vaticana_ligature:"
268 " delta-position undefined ->"
275 * Now determine width and x-offset of head.
281 if (context_info
& STACKED_HEAD
)
284 * This head is stacked upon the previous one; hence, it
285 * does not contribute to the total width of the ligature,
286 * and its width is assumed to be 0.0. Moreover, it is
287 * shifted to the left by its width such that the right side
288 * of this and the other head are horizontally aligned.
291 x_offset
= join_thickness
292 - Font_interface::get_default_font (primitive
)->
293 find_by_name ("noteheads.s" + glyph_name
).extent (X_AXIS
).length ();
295 else if (glyph_name
== "flexa" || glyph_name
== "")
298 * This head represents either half of a flexa shape.
299 * Hence, it is assigned half the width of this shape.
301 head_width
= 0.5 * flexa_width
;
307 * This is a regular head, placed right to the previous one.
308 * Retrieve its width from corresponding font.
311 = Font_interface::get_default_font (primitive
)->
312 find_by_name ("noteheads.s" + glyph_name
).extent (X_AXIS
).length ();
317 * Save the head's final x-offset.
319 primitive
->set_property ("x-offset",
320 scm_from_double (x_offset
));
323 * If the head is the 2nd head of a pes or flexa (but not a
324 * flexa shape), mark this head to be joined with the left-side
325 * neighbour head (i.e. the previous head) by a vertical beam.
327 if ((context_info
& PES_UPPER
)
328 || ((context_info
& FLEXA_RIGHT
)
329 && ! (context_info
& PES_LOWER
)))
333 primitive
->programming_error ("vaticana ligature: add-join: "
334 "missing previous primitive");
338 prev_primitive
->set_property ("add-join",
342 * Create a small overlap of adjacent heads so that the join
343 * can be drawn perfectly between them.
345 ligature_width
-= join_thickness
;
348 else if (glyph_name
== "")
351 * This is the 2nd (virtual) head of flexa shape. Join it
352 * tightly with 1st head, i.e. do *not* add additional
353 * space, such that next head will not be off from the flexa
358 if (need_extra_horizontal_space (prev_prefix_set
, prefix_set
,
359 context_info
, delta_pitch
))
360 ligature_width
+= extra_space
;
363 * Horizontally line-up this head to form a ligature.
365 move_related_items_to_column (primitive
, column
, ligature_width
);
366 ligature_width
+= head_width
;
368 prev_primitive
= primitive
;
369 prev_prefix_set
= prefix_set
;
373 * Add extra horizontal padding space after ligature, such that
374 * neighbouring ligatures do not touch each other.
376 ligature_width
+= extra_space
;
378 return ligature_width
;
382 * Depending on the typographical features of a particular ligature
383 * style, some prefixes may be ignored. In particular, if a curved
384 * flexa shape is produced, any prefixes to either of the two
385 * contributing heads that would select a head other than punctum, is
386 * by definition ignored.
388 * This function prints a warning, if the given primitive is prefixed
389 * such that a head other than punctum would be chosen, if this
390 * primitive were engraved as a stand-alone head.
393 Vaticana_ligature_engraver::check_for_prefix_loss (Item
*primitive
)
396 = scm_to_int (primitive
->get_property ("prefix-set"));
397 if (prefix_set
& ~PES_OR_FLEXA
)
399 string prefs
= Gregorian_ligature::prefixes_to_str (primitive
);
400 primitive
->warning (_f ("ignored prefix (es) `%s' of this head according "
401 "to restrictions of the selected ligature style",
407 Vaticana_ligature_engraver::add_mora_column (Paper_column
*column
)
409 if (augmented_primitives_
.size () == 0) // no dot for column
411 if (!column
) // empty ligature???
413 augmented_primitives_
[0].grob ()->
414 programming_error ("no paper column to add dot");
417 Item
*dotcol
= make_item ("DotColumn", SCM_EOL
);
418 dotcol
->set_parent (column
, X_AXIS
);
419 for (vsize i
= 0; i
< augmented_primitives_
.size (); i
++)
422 dynamic_cast<Item
*> (augmented_primitives_
[i
].grob ());
423 Item
*dot
= make_item ("Dots", primitive
->self_scm ());
424 dot
->set_property ("dot-count", scm_from_int (1));
425 dot
->set_parent (primitive
, Y_AXIS
);
426 primitive
->set_object ("dot", dot
->self_scm ());
427 Dot_column::add_head (dotcol
, primitive
);
429 // FIXME: why isn't the dot picked up by Paper_column_engraver?
430 Separation_item::add_item (column
, dot
);
435 * This function prints a warning, if the given primitive has the same
436 * pitch as at least one of the primitives already stored in the
437 * augmented_primitives_ array.
439 * The rationale of this check is, that, if there are two dotted
440 * primitives with the same pitch, then collecting all dots in a dot
441 * column behind the ligature leads to a notational ambiguity of to
442 * which head the corresponding dot refers.
444 * Such a case should be treated as a badly specified ligature. The
445 * user should split the ligature to make the notation of dots
449 Vaticana_ligature_engraver::check_for_ambiguous_dot_pitch (Grob_info primitive
)
451 // TODO: Fix performance, which is currently O (n^2) (since this
452 // method is called O (n) times and takes O (n) steps in the for
453 // loop), but could be O (n) (by replacing the for loop by e.g. a
454 // bitmask based O (1) test); where n=<number of primitives in the
455 // ligature> (which is typically small (n<10), though).
456 Stream_event
*new_cause
= primitive
.event_cause ();
457 int new_pitch
= unsmob_pitch (new_cause
->get_property ("pitch"))->steps ();
458 for (vsize i
= 0; i
< augmented_primitives_
.size (); i
++)
460 Stream_event
*cause
= augmented_primitives_
[i
].event_cause ();
461 int pitch
= unsmob_pitch (cause
->get_property ("pitch"))->steps ();
462 if (pitch
== new_pitch
)
465 warning ("Ambiguous use of dots in ligature: there are "
466 "multiple dotted notes with the same pitch. "
467 "The ligature should be split.");
468 return; // supress multiple identical warnings
474 Vaticana_ligature_engraver::transform_heads (Spanner
*ligature
,
475 vector
<Grob_info
> primitives
)
477 Real flexa_width
= robust_scm2double (ligature
->get_property ("flexa-width"), 2);
479 Real thickness
= robust_scm2double (ligature
->get_property ("thickness"), 1);
481 Item
*prev_primitive
= 0;
482 int prev_prefix_set
= 0;
483 int prev_context_info
= 0;
484 int prev_delta_pitch
= 0;
485 string prev_glyph_name
= "";
486 augmented_primitives_
.clear ();
487 for (vsize i
= 0; i
< primitives
.size (); i
++)
489 Item
*primitive
= dynamic_cast<Item
*> (primitives
[i
].grob ());
492 SCM delta_pitch_scm
= primitive
->get_property ("delta-position");
493 if (delta_pitch_scm
!= SCM_EOL
)
494 delta_pitch
= scm_to_int (delta_pitch_scm
);
497 primitive
->programming_error ("Vaticana_ligature:"
498 " delta-position undefined ->"
503 /* retrieve & complete prefix_set and context_info */
505 = scm_to_int (primitive
->get_property ("prefix-set"));
507 = scm_to_int (primitive
->get_property ("context-info"));
509 if (Rhythmic_head::dot_count (primitive
) > 0)
510 // remove dots from primitive and add remember primitive for
511 // creating a dot column
513 Rhythmic_head::get_dots (primitive
)->set_property ("dot-count",
515 // TODO: Maybe completely remove grob "Dots" (dots->suicide
516 // () ?) rather than setting property "dot-count" to 0.
518 check_for_ambiguous_dot_pitch (primitives
[i
]);
519 augmented_primitives_
.push_back (primitives
[i
]);
521 else if (augmented_primitives_
.size () > 0)
523 primitive
->warning ("This ligature has a dotted head followed by "
524 "a non-dotted head. The ligature should be "
525 "split after the last dotted head before "
529 if (is_stacked_head (prefix_set
, context_info
))
531 context_info
|= STACKED_HEAD
;
532 primitive
->set_property ("context-info",
533 scm_from_int (context_info
));
537 * Now determine which head to typeset (this is context sensitive
538 * information, since it depends on neighbouring heads; therefore,
539 * this decision must be made here in the engraver rather than in
543 if (prefix_set
& VIRGA
)
545 glyph_name
= "vaticana.punctum";
546 primitive
->set_property ("add-stem", ly_bool2scm (true));
548 else if (prefix_set
& QUILISMA
)
549 glyph_name
= "vaticana.quilisma";
550 else if (prefix_set
& ORISCUS
)
551 glyph_name
= "solesmes.oriscus";
552 else if (prefix_set
& STROPHA
)
553 if (prefix_set
& AUCTUM
)
554 glyph_name
= "solesmes.stropha.aucta";
555 else glyph_name
= "solesmes.stropha";
556 else if (prefix_set
& INCLINATUM
)
557 if (prefix_set
& AUCTUM
)
558 glyph_name
= "solesmes.incl.auctum";
559 else if (prefix_set
& DEMINUTUM
)
560 glyph_name
= "solesmes.incl.parvum";
562 glyph_name
= "vaticana.inclinatum";
563 else if (prefix_set
& DEMINUTUM
)
568 glyph_name
= "vaticana.reverse.plica";
570 else if (prev_delta_pitch
> 0)
573 if (! (prev_context_info
& FLEXA_RIGHT
))
575 /* correct head of previous primitive */
576 if (prev_delta_pitch
> 1)
577 prev_glyph_name
= "vaticana.epiphonus";
579 prev_glyph_name
= "vaticana.vepiphonus";
581 if (prev_delta_pitch
> 1)
582 glyph_name
= "vaticana.plica";
584 glyph_name
= "vaticana.vplica";
586 else if (prev_delta_pitch
< 0)
589 if (! (prev_context_info
& FLEXA_RIGHT
))
590 /* correct head of previous primitive */
594 /* cephalicus head with fixed size cauda */
595 prev_glyph_name
= "vaticana.inner.cephalicus";
599 /* cephalicus head without cauda */
600 prev_glyph_name
= "vaticana.cephalicus";
604 * Flexa has no variable size cauda if its left head is
605 * stacked on the right head. This is true for
606 * cephalicus. Hence, remove the cauda.
608 * Urgh: for the current implementation, this rule only
609 * applies for cephalicus; but it is a fundamental rule.
610 * Therefore, the following line of code should be
611 * placed somewhere else.
613 prev_primitive
->set_property ("add-cauda",
614 ly_bool2scm (false));
616 if (prev_delta_pitch
< - 1)
617 glyph_name
= "vaticana.reverse.plica";
619 glyph_name
= "vaticana.reverse.vplica";
621 else // (prev_delta_pitch == 0)
623 primitive
->programming_error ("Vaticana_ligature:"
624 " deminutum head must have different"
625 " pitch -> ignoring grob");
628 else if (prefix_set
& (CAVUM
| LINEA
))
629 if ((prefix_set
& CAVUM
) && (prefix_set
& LINEA
))
630 glyph_name
= "vaticana.linea.punctum.cavum";
631 else if (prefix_set
& CAVUM
)
632 glyph_name
= "vaticana.punctum.cavum";
634 glyph_name
= "vaticana.linea.punctum";
635 else if (prefix_set
& AUCTUM
)
636 if (prefix_set
& ASCENDENS
)
637 glyph_name
= "solesmes.auct.asc";
639 glyph_name
= "solesmes.auct.desc";
640 else if ((context_info
& STACKED_HEAD
)
641 && (context_info
& PES_UPPER
))
642 if (prev_delta_pitch
> 1)
643 glyph_name
= "vaticana.upes";
645 glyph_name
= "vaticana.vupes";
647 glyph_name
= "vaticana.punctum";
650 * This head needs a cauda, if it starts a flexa, is not the upper
651 * head of a pes, and if it is a punctum.
653 if ((context_info
& FLEXA_LEFT
) && ! (context_info
& PES_UPPER
))
654 if (glyph_name
== "vaticana.punctum")
655 primitive
->set_property ("add-cauda", ly_bool2scm (true));
658 * Execptional rule for porrectus:
660 * If the current head is preceded by a \flexa and succeded by a
661 * \pes (e.g. "a \flexa g \pes a"), then join the current head and
662 * the previous head into a single curved flexa shape.
664 if ((context_info
& FLEXA_RIGHT
) && (context_info
& PES_LOWER
))
666 check_for_prefix_loss (prev_primitive
);
667 prev_glyph_name
= "flexa";
668 prev_primitive
->set_property ("flexa-height",
669 scm_from_int (prev_delta_pitch
));
670 prev_primitive
->set_property ("flexa-width",
671 scm_from_double (flexa_width
));
672 bool add_cauda
= !(prev_prefix_set
&& PES_OR_FLEXA
);
673 prev_primitive
->set_property ("add-cauda",
674 ly_bool2scm (add_cauda
));
675 check_for_prefix_loss (primitive
);
677 primitive
->set_property ("flexa-width",
678 scm_from_double (flexa_width
));
682 * Exceptional rule for pes:
684 * If this head is stacked on the previous one due to a \pes, then
685 * set the glyph of the previous head to that for this special
686 * case, thereby avoiding potential vertical collision with the
689 if (prefix_set
& PES_OR_FLEXA
)
691 if ((context_info
& PES_UPPER
) && (context_info
& STACKED_HEAD
))
693 if (prev_glyph_name
== "vaticana.punctum")
695 if (prev_delta_pitch
> 1)
696 prev_glyph_name
= "vaticana.lpes";
698 prev_glyph_name
= "vaticana.vlpes";
704 prev_primitive
->set_property ("glyph-name",
705 ly_string2scm (prev_glyph_name
));
708 * In the backend, flexa shapes and joins need to know about line
709 * thickness. Hence, for simplicity, let's distribute the
710 * ligature grob's value for thickness to each ligature head (even
711 * if not all of them need to know).
713 primitive
->set_property ("thickness", scm_from_double (thickness
));
715 prev_primitive
= primitive
;
716 prev_prefix_set
= prefix_set
;
717 prev_context_info
= context_info
;
718 prev_delta_pitch
= delta_pitch
;
719 prev_glyph_name
= glyph_name
;
722 prev_primitive
->set_property ("glyph-name",
723 ly_string2scm (prev_glyph_name
));
725 align_heads (primitives
, flexa_width
, thickness
);
727 // append all dots to paper column of ligature's last head
728 add_mora_column (prev_primitive
->get_column ());
730 #if 0 // experimental code to collapse spacing after ligature
731 /* TODO: set to max (old/new spacing-increment), since other
732 voices/staves also may want to set this property. */
733 Item
*first_primitive
= dynamic_cast<Item
*> (primitives
[0].grob ());
734 Paper_column
*paper_column
= first_primitive
->get_column ();
735 paper_column
->warning (_f ("Vaticana_ligature_engraver: "
736 "setting `spacing-increment = %f': ptr =%ul",
737 ligature_width
, paper_column
));
739 set_property ("forced-spacing", scm_from_double (ligature_width
));
743 ADD_ACKNOWLEDGER (Vaticana_ligature_engraver
, rest
);
744 ADD_ACKNOWLEDGER (Vaticana_ligature_engraver
, note_head
);
745 ADD_TRANSLATOR (Vaticana_ligature_engraver
,
747 "Handle ligatures by glueing special ligature heads together.",