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 ()
88 finished_ligature_ = 0;
89 events_drul_[LEFT] = events_drul_[RIGHT] = 0;
90 prev_start_event_ = 0;
92 brew_ligature_primitive_proc = SCM_EOL;
96 Ligature_engraver::listen_ligature (Stream_event *ev)
98 Direction d = to_dir (ev->get_property ("span-direction"));
99 ASSIGN_EVENT_ONCE (events_drul_[d], ev);
103 Ligature_engraver::process_music ()
105 if (events_drul_[STOP])
109 events_drul_[STOP]->origin ()->warning (_ ("cannot find start of ligature"));
114 events_drul_[STOP]->origin ()->warning (_ ("no right bound"));
116 ligature_->set_bound (RIGHT, last_bound_);
118 prev_start_event_ = 0;
119 finished_primitives_ = primitives_;
120 finished_ligature_ = ligature_;
121 primitives_.clear ();
124 last_bound_ = Grob::unsmob (get_property ("currentMusicalColumn"));
128 // TODO: maybe forbid breaks only if not transcribing
129 context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T);
132 if (events_drul_[START])
136 events_drul_[START]->origin ()->warning (_ ("already have a ligature"));
140 prev_start_event_ = events_drul_[START];
141 ligature_ = create_ligature_spanner ();
143 Grob *bound = Grob::unsmob (get_property ("currentMusicalColumn"));
145 events_drul_[START]->origin ()->warning (_ ("no left bound"));
147 ligature_->set_bound (LEFT, bound);
149 ligature_start_mom_ = now_mom ();
151 // TODO: dump cause into make_item/spanner.
152 // announce_grob (ligature_, events_drul_[START]->self_scm ());
157 Ligature_engraver::stop_translation_timestep ()
159 if (finished_ligature_)
161 if (!finished_primitives_.size ())
163 finished_ligature_->programming_error ("Ligature_engraver::stop_translation_timestep ():"
164 " junking empty ligature");
168 typeset_ligature (finished_ligature_, finished_primitives_);
169 finished_primitives_.clear ();
171 finished_ligature_ = 0;
174 events_drul_[START] = 0;
175 events_drul_[STOP] = 0;
179 Ligature_engraver::finalize ()
181 if (finished_ligature_)
183 typeset_ligature (finished_ligature_, finished_primitives_);
184 finished_primitives_.clear ();
185 finished_ligature_ = 0;
189 prev_start_event_->origin ()->warning (_ ("unterminated ligature"));
190 ligature_->suicide ();
195 Ligature_engraver::current_ligature ()
201 Ligature_engraver::acknowledge_ligature_head (Grob_info info)
205 primitives_.push_back (info);
206 if (info.grob () && !scm_is_null (brew_ligature_primitive_proc))
207 info.grob ()->set_property ("stencil", brew_ligature_primitive_proc);
212 Ligature_engraver::acknowledge_rest (Grob_info info)
216 info.event_cause ()->origin ()->warning (_ ("ignoring rest: ligature may not contain rest"));
217 prev_start_event_->origin ()->warning (_ ("ligature was started here"));
218 // TODO: maybe better should stop ligature here rather than
219 // ignoring the rest?
223 // no ADD_ACKNOWLEDGER / ADD_ACKNOWLEDGER / ADD_TRANSLATOR macro calls
224 // since this class is abstract