2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2002--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 "ligature-engraver.hh"
23 #include "international.hh"
24 #include "note-head.hh"
27 #include "stream-event.hh"
28 #include "translator.icc"
31 * This abstract class provides the general framework for ligatures of
32 * any kind. It cares for handling start/stop ligatures events and
33 * collecting all noteheads inbetween, but delegates creation of a
34 * ligature spanner for each start/stop pair and typesetting of the
35 * ligature spanner to a concrete subclass.
37 * A concrete ligature engraver must subclass this class and provide
38 * functions create_ligature_spanner () and typeset_ligature
39 * (Spanner *, vector<Grob_info>). Subclasses of this class basically
40 * fall into two categories.
42 * The first category consists of engravers that engrave ligatures in
43 * a way that really deserves the name ligature. That is, they
44 * produce a single connected graphical object of fixed width,
45 * consisting of noteheads and other primitives. Space may be
46 * inserted only after each ligature, if necessary, but in no case
47 * between the primitives of the ligature. The same approach is
48 * used for Kievan notation ligatures, or, rather melismas.
49 * Though these are not single connected objects, they behave much
50 * in the same way and have a fixed, small amount of space between
51 * noteheads. Except in Kievan "ligatures", accidentals have to be put
52 * to the left of the ligature, and not to the left of individual
53 * noteheads. In Kievan ligatures, the B-flat may be part of the
54 * ligature itself. Class Coherent_ligature_engraver is the common
55 * superclass for all of these engravers.
57 * The second category is for engravers that are relaxed in the sense
58 * that they do not require to produce a single connected graphical
59 * object. For example, in contemporary editions, ligatures are often
60 * marked, but otherwise use contemporary notation and spacing. In
61 * this category, there is currently only a single class,
62 * Ligature_bracket_engraver, which marks each ligature with a
63 * horizontal sqare bracket, but otherwise leaves the appearance
68 * TODO: lyrics/melisma/syllables: there should be at most one
69 * syllable of lyrics per ligature (i.e. for the lyrics context, a
70 * ligature should count as a single note, regardless of how many
71 * heads the ligature consists of).
73 * TODO: currently, you have to add/remove the proper
74 * Ligature_engraver (Ligature_bracket_engraver,
75 * Mensural_ligature_engraver) to the proper translator
76 * (e.g. VoiceContext) to choose between various representations.
77 * Since adding/removing an engraver to a translator is a global
78 * action in the layout block, you cannot mix various representations
79 * _within_ the same score. Hence, for selecting a representation,
80 * one would rather like to have a property that can be set e.g. for
81 * several staves individually. However, it seems that this approach
82 * would require to have a single, complicated Ligature_engraver that
83 * consists of all the code... This needs further thoughts.
85 Ligature_engraver::Ligature_engraver (Context *c)
89 finished_ligature_ = 0;
90 events_drul_[LEFT] = events_drul_[RIGHT] = 0;
91 prev_start_event_ = 0;
93 brew_ligature_primitive_proc = SCM_EOL;
97 Ligature_engraver::listen_ligature (Stream_event *ev)
99 Direction d = to_dir (ev->get_property ("span-direction"));
100 ASSIGN_EVENT_ONCE (events_drul_[d], ev);
104 Ligature_engraver::process_music ()
106 if (events_drul_[STOP])
110 events_drul_[STOP]->origin ()->warning (_ ("cannot find start of ligature"));
115 events_drul_[STOP]->origin ()->warning (_ ("no right bound"));
117 ligature_->set_bound (RIGHT, last_bound_);
119 prev_start_event_ = 0;
120 finished_primitives_ = primitives_;
121 finished_ligature_ = ligature_;
122 primitives_.clear ();
125 last_bound_ = unsmob<Grob> (get_property ("currentMusicalColumn"));
129 // TODO: maybe forbid breaks only if not transcribing
130 context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T);
133 if (events_drul_[START])
137 events_drul_[START]->origin ()->warning (_ ("already have a ligature"));
141 prev_start_event_ = events_drul_[START];
142 ligature_ = create_ligature_spanner ();
144 Grob *bound = unsmob<Grob> (get_property ("currentMusicalColumn"));
146 events_drul_[START]->origin ()->warning (_ ("no left bound"));
148 ligature_->set_bound (LEFT, bound);
150 ligature_start_mom_ = now_mom ();
152 // TODO: dump cause into make_item/spanner.
153 // announce_grob (ligature_, events_drul_[START]->self_scm ());
158 Ligature_engraver::stop_translation_timestep ()
160 if (finished_ligature_)
162 if (!finished_primitives_.size ())
164 finished_ligature_->programming_error ("Ligature_engraver::stop_translation_timestep ():"
165 " junking empty ligature");
169 typeset_ligature (finished_ligature_, finished_primitives_);
170 finished_primitives_.clear ();
172 finished_ligature_ = 0;
175 events_drul_[START] = 0;
176 events_drul_[STOP] = 0;
180 Ligature_engraver::finalize ()
182 if (finished_ligature_)
184 typeset_ligature (finished_ligature_, finished_primitives_);
185 finished_primitives_.clear ();
186 finished_ligature_ = 0;
190 prev_start_event_->origin ()->warning (_ ("unterminated ligature"));
191 ligature_->suicide ();
196 Ligature_engraver::current_ligature ()
202 Ligature_engraver::acknowledge_ligature_head (Grob_info info)
206 primitives_.push_back (info);
207 if (info.grob () && !scm_is_null (brew_ligature_primitive_proc))
208 info.grob ()->set_property ("stencil", brew_ligature_primitive_proc);
213 Ligature_engraver::acknowledge_rest (Grob_info info)
217 info.event_cause ()->origin ()->warning (_ ("ignoring rest: ligature may not contain rest"));
218 prev_start_event_->origin ()->warning (_ ("ligature was started here"));
219 // TODO: maybe better should stop ligature here rather than
220 // ignoring the rest?
224 // no ADD_ACKNOWLEDGER / ADD_ACKNOWLEDGER / ADD_TRANSLATOR macro calls
225 // since this class is abstract