2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2003--2015 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"
42 * This class implements the notation specific aspects of Vaticana
43 * style ligatures for Gregorian chant notation.
47 * TODO: Maybe move handling of dots/mora to
48 * Gregorian_ligature_engraver? It's probably common for all types of
49 * Gregorian chant notation that have dotted notes.
51 * FIXME: The horizontal alignment of the mora column is bad (too far
52 * to the left), if the last dotted note is not the last primitive in
53 * the ligature. Fortunately, in practice this bug should have no
54 * negative impact, since dotted notes appear within a ligature
55 * usually always at the end of the ligature, such that the bug never
56 * should apply for valid ligatures.
58 * TODO: Graduale Triplex, tempus per annum, hebdomada septima,
59 * alleluia (page 280) shows a counter-example for collecting dots
60 * always in a single column behind the ligature. Maybe only the last
61 * two dots in a ligature should be collected and all other dots put
62 * behind or on top of the head?
64 class Vaticana_ligature_engraver : public Gregorian_ligature_engraver
69 need_extra_horizontal_space (int prev_prefix_set, int prefix_set,
70 int context_info, int delta_pitch);
71 bool is_stacked_head (int prefix_set,
73 Real align_heads (vector<Grob_info> const &primitives,
76 void check_for_prefix_loss (Item *primitive);
77 void check_for_ambiguous_dot_pitch (Grob_info primitive);
78 void add_mora_column (Paper_column *column);
79 vector<Grob_info> augmented_primitives_;
82 TRANSLATOR_DECLARATIONS (Vaticana_ligature_engraver);
85 virtual Spanner *create_ligature_spanner ();
86 virtual void transform_heads (Spanner *ligature,
87 vector<Grob_info> const &primitives);
88 DECLARE_TRANSLATOR_LISTENER (pes_or_flexa);
89 DECLARE_TRANSLATOR_LISTENER (ligature);
92 IMPLEMENT_TRANSLATOR_LISTENER (Vaticana_ligature_engraver, pes_or_flexa);
94 Vaticana_ligature_engraver::listen_pes_or_flexa (Stream_event *ev)
96 Gregorian_ligature_engraver::listen_pes_or_flexa (ev);
99 IMPLEMENT_TRANSLATOR_LISTENER (Vaticana_ligature_engraver, ligature);
101 Vaticana_ligature_engraver::listen_ligature (Stream_event *ev)
103 Ligature_engraver::listen_ligature (ev);
106 Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
108 brew_ligature_primitive_proc
109 = Vaticana_ligature::brew_ligature_primitive_proc;
110 augmented_primitives_.clear ();
114 Vaticana_ligature_engraver::create_ligature_spanner ()
116 return make_spanner ("VaticanaLigature", SCM_EOL);
120 Vaticana_ligature_engraver::is_stacked_head (int prefix_set,
125 // upper head of pes is stacked upon lower head of pes ...
126 is_stacked = context_info & PES_UPPER;
128 // ... unless this note starts a flexa
129 if (context_info & FLEXA_LEFT)
132 // ... or another pes
133 if (context_info & PES_LOWER)
136 // ... or the previous note is a semivocalis or inclinatum
137 if (context_info & AFTER_DEMINUTUM)
140 // auctum head is never stacked upon preceding note
141 if (prefix_set & AUCTUM)
144 // virga is never stacked upon preceding note
145 if (prefix_set & VIRGA)
148 // oriscus is never stacked upon preceding note
149 if (prefix_set & ORISCUS)
152 if ((prefix_set & DEMINUTUM)
153 && ! (prefix_set & INCLINATUM)
154 && (context_info & FLEXA_RIGHT))
155 is_stacked = true; // semivocalis head of deminutus form
161 * When aligning the heads, sometimes extra space is needed, e.g. to
162 * avoid clashing with the appendix of an adjacent notehead or with an
163 * adjacent notehead itself if it has the same pitch. Extra space is
164 * added at most once between to heads.
167 Vaticana_ligature_engraver::need_extra_horizontal_space (int prev_prefix_set, int prefix_set,
168 int context_info, int delta_pitch)
170 if (prev_prefix_set & VIRGA)
172 * After a virga, make an additional small space such that the
173 * appendix on the right side of the head does not touch the
178 if ((prefix_set & INCLINATUM)
179 && ! (prev_prefix_set & INCLINATUM))
181 * Always start a series of inclinatum heads with an extra space.
185 if ((context_info & FLEXA_LEFT) && ! (context_info & PES_UPPER))
187 * Before a flexa (but not within a torculus), make an
188 * additional small space such that the appendix on the left side
189 * of the flexa does not touch the this head.
193 if (delta_pitch == 0)
195 * If there are two adjacent noteheads with the same pitch, add
196 * additional small space between them, such that they do not
205 Vaticana_ligature_engraver::align_heads (vector<Grob_info> const &primitives,
209 if (!primitives.size ())
211 programming_error ("Vaticana_ligature:"
212 " empty ligature [ignored]");
217 * The paper column where we put the whole ligature into.
220 = dynamic_cast<Item *> (primitives[0].grob ())->get_column ();
223 = thickness * column->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
226 * Amount of extra space two put between some particular
227 * configurations of adjacent heads.
229 * TODO: make this a property of primtive grobs.
231 Real extra_space = 4.0 * join_thickness;
234 * Keep track of the total width of the ligature.
236 Real ligature_width = 0.0;
238 Item *prev_primitive = 0;
239 int prev_prefix_set = 0;
240 for (vsize i = 0; i < primitives.size (); i++)
242 Item *primitive = dynamic_cast<Item *> (primitives[i].grob ());
244 = scm_to_int (primitive->get_property ("prefix-set"));
246 = scm_to_int (primitive->get_property ("context-info"));
249 * Get glyph_name, delta_pitch and context_info for this head.
252 SCM glyph_name_scm = primitive->get_property ("glyph-name");
253 if (scm_is_null (glyph_name_scm))
255 primitive->programming_error ("Vaticana_ligature:"
256 " undefined glyph-name ->"
260 string glyph_name = ly_scm2string (glyph_name_scm);
263 if (prev_primitive) /* urgh, need prev_primitive only here */
265 SCM delta_pitch_scm = prev_primitive->get_property ("delta-position");
266 if (!scm_is_null (delta_pitch_scm))
267 delta_pitch = scm_to_int (delta_pitch_scm);
270 primitive->programming_error ("Vaticana_ligature:"
271 " delta-position undefined ->"
278 * Now determine width and x-offset of head.
284 if (context_info & STACKED_HEAD)
287 * This head is stacked upon the previous one; hence, it
288 * does not contribute to the total width of the ligature,
289 * and its width is assumed to be 0.0. Moreover, it is
290 * shifted to the left by its width such that the right side
291 * of this and the other head are horizontally aligned.
294 x_offset = join_thickness
295 - Font_interface::get_default_font (primitive)->
296 find_by_name ("noteheads.s" + glyph_name).extent (X_AXIS).length ();
298 else if (glyph_name == "flexa" || glyph_name == "")
301 * This head represents either half of a flexa shape.
302 * Hence, it is assigned half the width of this shape.
304 head_width = 0.5 * flexa_width;
310 * This is a regular head, placed right to the previous one.
311 * Retrieve its width from corresponding font.
314 = Font_interface::get_default_font (primitive)->
315 find_by_name ("noteheads.s" + glyph_name).extent (X_AXIS).length ();
320 * Save the head's final x-offset.
322 primitive->set_property ("x-offset",
323 scm_from_double (x_offset));
326 * If the head is the 2nd head of a pes or flexa (but not a
327 * flexa shape), mark this head to be joined with the left-side
328 * neighbour head (i.e. the previous head) by a vertical beam.
330 if ((context_info & PES_UPPER)
331 || ((context_info & FLEXA_RIGHT)
332 && ! (context_info & PES_LOWER)))
336 primitive->programming_error ("Vaticana ligature: add-join:"
337 " missing previous primitive");
341 prev_primitive->set_property ("add-join",
345 * Create a small overlap of adjacent heads so that the join
346 * can be drawn perfectly between them.
348 ligature_width -= join_thickness;
351 else if (glyph_name == "")
354 * This is the 2nd (virtual) head of flexa shape. Join it
355 * tightly with 1st head, i.e. do *not* add additional
356 * space, such that next head will not be off from the flexa
361 if (need_extra_horizontal_space (prev_prefix_set, prefix_set,
362 context_info, delta_pitch))
363 ligature_width += extra_space;
366 * Horizontally line-up this head to form a ligature.
368 move_related_items_to_column (primitive, column, ligature_width);
369 ligature_width += head_width;
371 prev_primitive = primitive;
372 prev_prefix_set = prefix_set;
376 * Add extra horizontal padding space after ligature, such that
377 * neighbouring ligatures do not touch each other.
379 ligature_width += extra_space;
381 return ligature_width;
385 * Depending on the typographical features of a particular ligature
386 * style, some prefixes may be ignored. In particular, if a curved
387 * flexa shape is produced, any prefixes to either of the two
388 * contributing heads that would select a head other than punctum, is
389 * by definition ignored.
391 * This function prints a warning, if the given primitive is prefixed
392 * such that a head other than punctum would be chosen, if this
393 * primitive were engraved as a stand-alone head.
396 Vaticana_ligature_engraver::check_for_prefix_loss (Item *primitive)
399 = scm_to_int (primitive->get_property ("prefix-set"));
400 if (prefix_set & ~PES_OR_FLEXA)
402 string prefs = Gregorian_ligature::prefixes_to_str (primitive);
403 primitive->warning (_f ("ignored prefix(es) `%s' of this head"
404 " according to restrictions of the selected"
411 Vaticana_ligature_engraver::add_mora_column (Paper_column *column)
413 if (augmented_primitives_.size () == 0) // no dot for column
415 if (!column) // empty ligature???
417 augmented_primitives_[0].grob ()->
418 programming_error ("no paper column to add dot");
421 Item *dotcol = make_item ("DotColumn", SCM_EOL);
422 dotcol->set_parent (column, X_AXIS);
423 for (vsize i = 0; i < augmented_primitives_.size (); i++)
426 = dynamic_cast<Item *> (augmented_primitives_[i].grob ());
427 Item *dot = make_item ("Dots", primitive->self_scm ());
428 dot->set_property ("dot-count", scm_from_int (1));
429 dot->set_parent (primitive, Y_AXIS);
430 primitive->set_object ("dot", dot->self_scm ());
431 Dot_column::add_head (dotcol, primitive);
433 // FIXME: why isn't the dot picked up by Paper_column_engraver?
434 Separation_item::add_item (column, dot);
439 * This function prints a warning, if the given primitive has the same
440 * pitch as at least one of the primitives already stored in the
441 * augmented_primitives_ array.
443 * The rationale of this check is, that, if there are two dotted
444 * primitives with the same pitch, then collecting all dots in a dot
445 * column behind the ligature leads to a notational ambiguity of to
446 * which head the corresponding dot refers.
448 * Such a case should be treated as a badly specified ligature. The
449 * user should split the ligature to make the notation of dots
453 Vaticana_ligature_engraver::check_for_ambiguous_dot_pitch (Grob_info primitive)
455 // TODO: Fix performance, which is currently O (n^2) (since this
456 // method is called O (n) times and takes O (n) steps in the for
457 // loop), but could be O (n) (by replacing the for loop by e.g. a
458 // bitmask based O (1) test); where n=<number of primitives in the
459 // ligature> (which is typically small (n<10), though).
460 Stream_event *new_cause = primitive.event_cause ();
461 int new_pitch = unsmob<Pitch> (new_cause->get_property ("pitch"))->steps ();
462 for (vsize i = 0; i < augmented_primitives_.size (); i++)
464 Stream_event *cause = augmented_primitives_[i].event_cause ();
465 int pitch = unsmob<Pitch> (cause->get_property ("pitch"))->steps ();
466 if (pitch == new_pitch)
469 warning (_ ("Ambiguous use of dots in ligature: there are"
470 " multiple dotted notes with the same pitch."
471 " The ligature should be split."));
472 return; // supress multiple identical warnings
478 Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
479 vector<Grob_info> const &primitives)
481 Real flexa_width = robust_scm2double (ligature->get_property ("flexa-width"), 2);
483 Real thickness = robust_scm2double (ligature->get_property ("thickness"), 1);
485 Item *prev_primitive = 0;
486 int prev_prefix_set = 0;
487 int prev_context_info = 0;
488 int prev_delta_pitch = 0;
489 string prev_glyph_name = "";
490 augmented_primitives_.clear ();
491 for (vsize i = 0; i < primitives.size (); i++)
493 Item *primitive = dynamic_cast<Item *> (primitives[i].grob ());
496 SCM delta_pitch_scm = primitive->get_property ("delta-position");
497 if (!scm_is_null (delta_pitch_scm))
498 delta_pitch = scm_to_int (delta_pitch_scm);
501 primitive->programming_error ("Vaticana_ligature:"
502 " delta-position undefined ->"
507 /* retrieve & complete prefix_set and context_info */
509 = scm_to_int (primitive->get_property ("prefix-set"));
511 = scm_to_int (primitive->get_property ("context-info"));
513 if (Rhythmic_head::dot_count (primitive) > 0)
514 // remove dots from primitive and add remember primitive for
515 // creating a dot column
517 Rhythmic_head::get_dots (primitive)->set_property ("dot-count",
519 // TODO: Maybe completely remove grob "Dots" (dots->suicide
520 // () ?) rather than setting property "dot-count" to 0.
522 check_for_ambiguous_dot_pitch (primitives[i]);
523 augmented_primitives_.push_back (primitives[i]);
525 else if (augmented_primitives_.size () > 0)
527 primitive->warning (_ ("This ligature has a dotted head followed by"
528 " a non-dotted head. The ligature should be"
529 " split after the last dotted head before"
533 if (is_stacked_head (prefix_set, context_info))
535 context_info |= STACKED_HEAD;
536 primitive->set_property ("context-info",
537 scm_from_int (context_info));
541 * Now determine which head to typeset (this is context sensitive
542 * information, since it depends on neighbouring heads; therefore,
543 * this decision must be made here in the engraver rather than in
547 if (prefix_set & VIRGA)
549 glyph_name = "vaticana.punctum";
550 primitive->set_property ("add-stem", ly_bool2scm (true));
552 else if (prefix_set & QUILISMA)
553 glyph_name = "vaticana.quilisma";
554 else if (prefix_set & ORISCUS)
555 glyph_name = "solesmes.oriscus";
556 else if (prefix_set & STROPHA)
557 if (prefix_set & AUCTUM)
558 glyph_name = "solesmes.stropha.aucta";
559 else glyph_name = "solesmes.stropha";
560 else if (prefix_set & INCLINATUM)
561 if (prefix_set & AUCTUM)
562 glyph_name = "solesmes.incl.auctum";
563 else if (prefix_set & DEMINUTUM)
564 glyph_name = "solesmes.incl.parvum";
566 glyph_name = "vaticana.inclinatum";
567 else if (prefix_set & DEMINUTUM)
572 glyph_name = "vaticana.reverse.plica";
574 else if (prev_delta_pitch > 0)
577 if (! (prev_context_info & FLEXA_RIGHT))
579 /* correct head of previous primitive */
580 if (prev_delta_pitch > 1)
581 prev_glyph_name = "vaticana.epiphonus";
583 prev_glyph_name = "vaticana.vepiphonus";
585 if (prev_delta_pitch > 1)
586 glyph_name = "vaticana.plica";
588 glyph_name = "vaticana.vplica";
590 else if (prev_delta_pitch < 0)
593 if (! (prev_context_info & FLEXA_RIGHT))
594 /* correct head of previous primitive */
598 /* cephalicus head with fixed size cauda */
599 prev_glyph_name = "vaticana.inner.cephalicus";
603 /* cephalicus head without cauda */
604 prev_glyph_name = "vaticana.cephalicus";
608 * Flexa has no variable size cauda if its left head is
609 * stacked on the right head. This is true for
610 * cephalicus. Hence, remove the cauda.
612 * Urgh: for the current implementation, this rule only
613 * applies for cephalicus; but it is a fundamental rule.
614 * Therefore, the following line of code should be
615 * placed somewhere else.
617 prev_primitive->set_property ("add-cauda",
618 ly_bool2scm (false));
620 if (prev_delta_pitch < - 1)
621 glyph_name = "vaticana.reverse.plica";
623 glyph_name = "vaticana.reverse.vplica";
625 else // (prev_delta_pitch == 0)
627 primitive->programming_error ("Vaticana_ligature:"
628 " deminutum head must have different"
629 " pitch -> ignoring grob");
632 else if (prefix_set & (CAVUM | LINEA))
633 if ((prefix_set & CAVUM) && (prefix_set & LINEA))
634 glyph_name = "vaticana.linea.punctum.cavum";
635 else if (prefix_set & CAVUM)
636 glyph_name = "vaticana.punctum.cavum";
638 glyph_name = "vaticana.linea.punctum";
639 else if (prefix_set & AUCTUM)
640 if (prefix_set & ASCENDENS)
641 glyph_name = "solesmes.auct.asc";
643 glyph_name = "solesmes.auct.desc";
644 else if ((context_info & STACKED_HEAD)
645 && (context_info & PES_UPPER))
646 if (prev_delta_pitch > 1)
647 glyph_name = "vaticana.upes";
649 glyph_name = "vaticana.vupes";
651 glyph_name = "vaticana.punctum";
654 * This head needs a cauda, if it starts a flexa, is not the upper
655 * head of a pes, and if it is a punctum.
657 if ((context_info & FLEXA_LEFT) && ! (context_info & PES_UPPER))
658 if (glyph_name == "vaticana.punctum")
659 primitive->set_property ("add-cauda", ly_bool2scm (true));
662 * Execptional rule for porrectus:
664 * If the current head is preceded by a \flexa and succeded by a
665 * \pes (e.g. "a \flexa g \pes a"), then join the current head and
666 * the previous head into a single curved flexa shape.
668 if ((context_info & FLEXA_RIGHT) && (context_info & PES_LOWER))
670 check_for_prefix_loss (prev_primitive);
671 prev_glyph_name = "flexa";
672 prev_primitive->set_property ("flexa-height",
673 scm_from_int (prev_delta_pitch));
674 prev_primitive->set_property ("flexa-width",
675 scm_from_double (flexa_width));
676 bool add_cauda = !(prev_prefix_set && PES_OR_FLEXA);
677 prev_primitive->set_property ("add-cauda",
678 ly_bool2scm (add_cauda));
679 check_for_prefix_loss (primitive);
681 primitive->set_property ("flexa-width",
682 scm_from_double (flexa_width));
686 * Exceptional rule for pes:
688 * If this head is stacked on the previous one due to a \pes, then
689 * set the glyph of the previous head to that for this special
690 * case, thereby avoiding potential vertical collision with the
693 if (prefix_set & PES_OR_FLEXA)
695 if ((context_info & PES_UPPER) && (context_info & STACKED_HEAD))
697 if (prev_glyph_name == "vaticana.punctum")
699 if (prev_delta_pitch > 1)
700 prev_glyph_name = "vaticana.lpes";
702 prev_glyph_name = "vaticana.vlpes";
708 prev_primitive->set_property ("glyph-name",
709 ly_string2scm (prev_glyph_name));
712 * In the backend, flexa shapes and joins need to know about line
713 * thickness. Hence, for simplicity, let's distribute the
714 * ligature grob's value for thickness to each ligature head (even
715 * if not all of them need to know).
717 primitive->set_property ("thickness", scm_from_double (thickness));
719 prev_primitive = primitive;
720 prev_prefix_set = prefix_set;
721 prev_context_info = context_info;
722 prev_delta_pitch = delta_pitch;
723 prev_glyph_name = glyph_name;
726 prev_primitive->set_property ("glyph-name",
727 ly_string2scm (prev_glyph_name));
729 align_heads (primitives, flexa_width, thickness);
731 // append all dots to paper column of ligature's last head
732 add_mora_column (prev_primitive->get_column ());
734 #if 0 // experimental code to collapse spacing after ligature
735 /* TODO: set to std::max (old/new spacing-increment), since other
736 voices/staves also may want to set this property. */
737 Item *first_primitive = dynamic_cast<Item *> (primitives[0].grob ());
738 Paper_column *paper_column = first_primitive->get_column ();
739 paper_column->warning (_f ("Vaticana_ligature_engraver:"
740 " setting `spacing-increment = %f': ptr =%ul",
741 ligature_width, paper_column));
743 set_property ("forced-spacing", scm_from_double (ligature_width));
747 ADD_ACKNOWLEDGER (Vaticana_ligature_engraver, rest);
748 ADD_ACKNOWLEDGER (Vaticana_ligature_engraver, ligature_head);
749 ADD_TRANSLATOR (Vaticana_ligature_engraver,
751 "Handle ligatures by glueing special ligature heads"