X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fligature-engraver.cc;h=c3830b4b02a2303ef78983f8f72b0cfe0fd1a64d;hb=7a6cc2409f4640656fb48c193f0b009be8016ec0;hp=f6e64da3e7197b6d8840ceb7a7931760f0fdd28c;hpb=21366dd8ddec170ae4af0d18f061be0f2eceb240;p=lilypond.git diff --git a/lily/ligature-engraver.cc b/lily/ligature-engraver.cc index f6e64da3e7..c3830b4b02 100644 --- a/lily/ligature-engraver.cc +++ b/lily/ligature-engraver.cc @@ -1,17 +1,52 @@ -/* +/* ligature-engraver.cc -- implement Ligature_engraver - + source file of the GNU LilyPond music typesetter - - (c) 2002 Juergen Reuter - - */ + + (c) 2002--2009 Juergen Reuter +*/ + #include "ligature-engraver.hh" -#include "ligature-head.hh" -#include "spanner.hh" -#include "score-engraver.hh" + +#include "context.hh" +#include "international.hh" +#include "note-head.hh" #include "rest.hh" -#include "warn.hh" +#include "spanner.hh" +#include "stream-event.hh" +#include "translator.icc" + +/* + * This abstract class provides the general framework for ligatures of + * any kind. It cares for handling start/stop ligatures events and + * collecting all noteheads inbetween, but delegates creation of a + * ligature spanner for each start/stop pair and typesetting of the + * ligature spanner to a concrete subclass. + * + * A concrete ligature engraver must subclass this class and provide + * functions create_ligature_spanner () and typeset_ligature + * (Spanner *, vector). Subclasses of this class basically + * fall into two categories. + * + * The first category consists of engravers that engrave ligatures in + * a way that really deserves the name ligature. That is, they + * produce a single connected graphical object of fixed width, + * consisting of noteheads and other primitives. Space may be + * inserted only after each ligature, if necessary, but in no case + * between the primitives of the ligature. Accidentals have to be put + * to the left of the ligature, and not to the left of individual + * noteheads. Class Coherent_ligature_engraver is the common + * superclass for all of these engravers. + * + * The second category is for engravers that are relaxed in the sense + * that they do not require to produce a single connected graphical + * object. For example, in contemporary editions, ligatures are often + * marked, but otherwise use contemporary notation and spacing. In + * this category, there is currently only a single class, + * Ligature_bracket_engraver, which marks each ligature with a + * horizontal sqare bracket, but otherwise leaves the appearance + * untouched. + */ /* * TODO: lyrics/melisma/syllables: there should be at most one @@ -24,7 +59,7 @@ * Mensural_ligature_engraver) to the proper translator * (e.g. VoiceContext) to choose between various representations. * Since adding/removing an engraver to a translator is a global - * action in the paper block, you can not mix various representations + * action in the layout block, you cannot mix various representations * _within_ the same score. Hence, for selecting a representation, * one would rather like to have a property that can be set e.g. for * several staves individually. However, it seems that this approach @@ -35,162 +70,141 @@ Ligature_engraver::Ligature_engraver () { ligature_ = 0; finished_ligature_ = 0; - reqs_drul_[LEFT] = reqs_drul_[RIGHT] = 0; - prev_start_req_ = 0; - last_bound = 0; + events_drul_[LEFT] = events_drul_[RIGHT] = 0; + prev_start_event_ = 0; + last_bound_ = 0; brew_ligature_primitive_proc = SCM_EOL; } -bool -Ligature_engraver::try_music (Music *m) -{ - if (Span_req *req_ = dynamic_cast (m)) - { - if (scm_equal_p (req_->get_mus_property ("span-type"), - scm_makfrom0str ("abort")) == SCM_BOOL_T) - { - reqs_drul_[START] = 0; - reqs_drul_[STOP] = 0; - if (ligature_) - ligature_->suicide (); - ligature_ = 0; - } - else if (scm_equal_p (req_->get_mus_property ("span-type"), - scm_makfrom0str ("ligature")) == SCM_BOOL_T) - { - Direction d = req_->get_span_dir (); - reqs_drul_[d] = req_; - return true; - } - } - return false; -} - -Spanner * -Ligature_engraver::create_ligature_spanner () +void +Ligature_engraver::listen_ligature (Stream_event *ev) { - return new Spanner (SCM_EOL); + Direction d = to_dir (ev->get_property ("span-direction")); + ASSIGN_EVENT_ONCE (events_drul_[d], ev); } void Ligature_engraver::process_music () { - if (reqs_drul_[STOP]) + if (events_drul_[STOP]) { if (!ligature_) - reqs_drul_[STOP]->origin ()->warning (_ ("can't find start of ligature")); - else { - if (!last_bound) - { - reqs_drul_[STOP]->origin ()->warning (_ ("no right bound")); - } - else - { - ligature_->set_bound (RIGHT, last_bound); - } + events_drul_[STOP]->origin ()->warning (_ ("cannot find start of ligature")); + return; } - prev_start_req_ = 0; + + if (!last_bound_) + events_drul_[STOP]->origin ()->warning (_ ("no right bound")); + else + ligature_->set_bound (RIGHT, last_bound_); + + prev_start_event_ = 0; + finished_primitives_ = primitives_; finished_ligature_ = ligature_; + primitives_.clear (); ligature_ = 0; } - last_bound = unsmob_grob (get_property ("currentMusicalColumn")); + last_bound_ = unsmob_grob (get_property ("currentMusicalColumn")); if (ligature_) { // TODO: maybe forbid breaks only if not transcribing - top_engraver ()->forbid_breaks (); + context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T); } - if (reqs_drul_[START]) + + if (events_drul_[START]) { if (ligature_) { - reqs_drul_[START]->origin ()->warning (_ ("already have a ligature")); + events_drul_[START]->origin ()->warning (_ ("already have a ligature")); return; } - prev_start_req_ = reqs_drul_[START]; + prev_start_event_ = events_drul_[START]; ligature_ = create_ligature_spanner (); - brew_ligature_primitive_proc = - ligature_->get_grob_property ("ligature-primitive-callback"); - if (brew_ligature_primitive_proc == SCM_EOL) - { - warning ("Ligature_engraver: ligature-primitive-callback undefined"); - } Grob *bound = unsmob_grob (get_property ("currentMusicalColumn")); if (!bound) - { - reqs_drul_[START]->origin ()->warning (_ ("no left bound")); - } + events_drul_[START]->origin ()->warning (_ ("no left bound")); else - { - ligature_->set_bound (LEFT, bound); - } + ligature_->set_bound (LEFT, bound); ligature_start_mom_ = now_mom (); - - announce_grob(ligature_, reqs_drul_[START]->self_scm()); + + // TODO: dump cause into make_item/spanner. + // announce_grob (ligature_, events_drul_[START]->self_scm ()); } } void -Ligature_engraver::start_translation_timestep () +Ligature_engraver::stop_translation_timestep () { - reqs_drul_[START] = 0; - reqs_drul_[STOP] = 0; + if (finished_ligature_) + { + if (!finished_primitives_.size ()) + { + finished_ligature_->programming_error ("Ligature_engraver::stop_translation_timestep (): " + "junking empty ligature"); + } + else + { + typeset_ligature (finished_ligature_, finished_primitives_); + finished_primitives_.clear (); + } + finished_ligature_ = 0; + } + + events_drul_[START] = 0; + events_drul_[STOP] = 0; } void -Ligature_engraver::try_stop_ligature () +Ligature_engraver::finalize () { if (finished_ligature_) { - typeset_grob (finished_ligature_); + typeset_ligature (finished_ligature_, finished_primitives_); + finished_primitives_.clear (); finished_ligature_ = 0; } + if (ligature_) + { + prev_start_event_->origin ()->warning (_ ("unterminated ligature")); + ligature_->suicide (); + } } -void -Ligature_engraver::stop_translation_timestep () +Spanner * +Ligature_engraver::current_ligature () { - try_stop_ligature (); + return ligature_; } void -Ligature_engraver::finalize () +Ligature_engraver::acknowledge_note_head (Grob_info info) { - try_stop_ligature (); if (ligature_) { - prev_start_req_->origin ()->warning (_ ("unterminated ligature")); - ligature_->suicide (); + primitives_.push_back (info); + if (info.grob () && brew_ligature_primitive_proc != SCM_EOL) + { + info.grob ()->set_property ("stencil", brew_ligature_primitive_proc); + } } } void -Ligature_engraver::acknowledge_grob (Grob_info info) +Ligature_engraver::acknowledge_rest (Grob_info info) { if (ligature_) { - if (Ligature_head::has_interface (info.grob_)) - { - info.grob_->set_grob_property ("ligature-primitive-callback", - brew_ligature_primitive_proc); - } - else if (Rest::has_interface (info.grob_)) - { - info.music_cause ()->origin ()->warning (_ ("ligature may not contain rest; ignoring rest")); - prev_start_req_->origin ()->warning (_ ("ligature was started here")); - // TODO: maybe better should stop ligature here rather than - // ignoring the rest? - } + info.event_cause ()->origin ()->warning (_ ("ignoring rest: ligature may not contain rest")); + prev_start_event_->origin ()->warning (_ ("ligature was started here")); + // TODO: maybe better should stop ligature here rather than + // ignoring the rest? } } -ENTER_DESCRIPTION (Ligature_engraver, -/* descr */ "Abstract class; a concrete subclass handles Ligature_requests by engraving Ligatures in a concrete style.", -/* creats*/ "Ligature", -/* acks */ "ligature-head-interface rest-interface", -/* reads */ "", -/* write */ ""); +// no ADD_ACKNOWLEDGER / ADD_ACKNOWLEDGER / ADD_TRANSLATOR macro calls +// since this class is abstract