X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fmensural-ligature-engraver.cc;h=da419df21f209392afc633fca93388dda10accff;hb=faaee71fb44c8e1040239797aad336f4e46c2c21;hp=436e49bf1760758d3b778f8fead7d147ff8927c7;hpb=a0a40c02de757661518577105dbb644a6ecdbc4d;p=lilypond.git diff --git a/lily/mensural-ligature-engraver.cc b/lily/mensural-ligature-engraver.cc index 436e49bf17..da419df21f 100644 --- a/lily/mensural-ligature-engraver.cc +++ b/lily/mensural-ligature-engraver.cc @@ -3,11 +3,11 @@ source file of the GNU LilyPond music typesetter - (C) 2002 Juergen Reuter + (c) 2002--2004 Juergen Reuter */ #include "mensural-ligature.hh" -#include "ligature-engraver.hh" +#include "coherent-ligature-engraver.hh" #include "event.hh" #include "warn.hh" #include "item.hh" @@ -18,23 +18,10 @@ #include "rhythmic-head.hh" #include "note-head.hh" #include "staff-symbol-referencer.hh" -#include "paper-def.hh" +#include "output-def.hh" #include "font-interface.hh" /* - * TODO: local accidentals: collect accidentals that occur within a - * ligature and put them before the ligature. If an accidental - * changes within a ligature, print a warning (user error) and ignore - * any further accidental for that pitch within that ligature - * (actually, in such a case, the user should split the ligature into - * two separate ligatures). Similarly, any object that, in ordinary - * notation, may be put to the left or to the right of a - * note-head/ligature-head, should be collected and put before or - * after the ligature. - * - * TODO: make spacing more robust: do not screw up spacing if user - * erroneously puts rest in ligature. - * * TODO: My resources on Franco of Cologne's rules claim that his * rules map ligature<->mensural timing in a non-ambigous way, but in * fact, as presented in these resources, the rules become ambigous as @@ -54,100 +41,39 @@ * * TODO: prohibit multiple voices within a ligature. * - * TODO: for each ligature, add Rod that represents the total length - * of the ligature (to preemptively avoid collision with adjacent - * notes); or maybe just additionally create a mensural-ligature grob - * (via Mensural_ligature::brew_molecule(SCM)) that just consists of a - * bounding box around all primitives of the ligature. - * * TODO: enhance robustness: in case of an illegal ligature (e.g. the * user events for a ligature that contains a minima or STATE_ERROR * is reached), automatically break the ligature into smaller, valid * pieces. - * - * TODO: In the future, there will be further ligature engravers - * implemented, such as a Vaticana_ligature_engraver. There will be - * redundant code between these engravers and the - * Mensural_ligature_engraver. In particular these are functions - * set_column_, fold_up_primitives, join_primitives, and - * ackowledge_grob; further the code for handling accidentals. It is - * not appropriate to put these things into Ligature_engraver, since, - * for example, Ligature_bracket_engraver does not share any of this - * code. Hence, we might to introduce a further subclass of - * Ligature_engraver which serves as super class for - * Mensural_ligature_engraver, Vaticana_ligature_engraver, among - * others. */ -class Mensural_ligature_engraver : public Ligature_engraver +class Mensural_ligature_engraver : public Coherent_ligature_engraver { - Real distance_; - Array primitives_; protected: - virtual void acknowledge_grob (Grob_info); - virtual void try_stop_ligature (); virtual Spanner *create_ligature_spanner (); + virtual void build_ligature (Spanner *ligature, Array primitives); public: - TRANSLATOR_DECLARATIONS(Mensural_ligature_engraver); + TRANSLATOR_DECLARATIONS (Mensural_ligature_engraver); private: - int apply_transition (int state, int input, int i); - void transform_heads (); - void propagate_properties (); - void fold_up_primitives (); - void join_primitives (); - void get_set_column (Item *item, Paper_column *new_col); + int apply_transition (Array primitives, + int state, int input, int i); + void transform_heads (Array primitives); + void propagate_properties (Spanner *ligature, Array primitives); + void fold_up_primitives (Array primitives); + void join_primitives (Array primitives); }; Mensural_ligature_engraver::Mensural_ligature_engraver () { - distance_ = 0; } Spanner * Mensural_ligature_engraver::create_ligature_spanner () { - distance_ = 0; - return new Spanner (get_property ("MensuralLigature")); -} - -/* - * TODO: move this function to class Item? - */ -void -Mensural_ligature_engraver::get_set_column (Item *item, Paper_column *column) -{ - Item *parent = dynamic_cast (item->get_parent (X_AXIS)); - if (!parent) - { - programming_error ("failed tweaking paper column in ligature"); - return; - } - - String name = parent->name (); - if (!String::compare (name, "PaperColumn")) - { - // Change column not only for targeted item (NoteColumn), but - // also for all associated grobs (NoteSpacing, SeparationItem). - Grob *sl = Staff_symbol_referencer::get_staff_symbol (item); - for (SCM tail = parent->get_grob_property ("elements"); - gh_pair_p (tail); - tail = ly_cdr (tail)) - { - Item *sibling = unsmob_item (ly_car (tail)); - if ((sibling) && - (Staff_symbol_referencer::get_staff_symbol (sibling) == sl)) - { - sibling->set_parent (column, X_AXIS); - } - } - } - else - { - get_set_column (parent, column); - } + return make_spanner ("MensuralLigature", SCM_EOL); } /* @@ -261,15 +187,16 @@ const int/*output*/ transition_output[/*old state*/][8/*input*/] = }; int -Mensural_ligature_engraver::apply_transition (int state, int input, int i) +Mensural_ligature_engraver::apply_transition (Array primitives, + int state, int input, int i) { int output = transition_output[state][input]; Item *last_last_primitive = (i > 1) ? - dynamic_cast (primitives_[i-2].grob_) : 0; + dynamic_cast (primitives[i-2].grob_) : 0; Item *last_primitive = (i > 0) ? - dynamic_cast (primitives_[i-1].grob_) : 0; - Item *primitive = (i < primitives_.size ()) ? - dynamic_cast (primitives_[i].grob_) : 0; + dynamic_cast (primitives[i-1].grob_) : 0; + Item *primitive = (i < primitives.size ()) ? + dynamic_cast (primitives[i].grob_) : 0; switch (output) { case MLP_NONE: @@ -284,7 +211,7 @@ Mensural_ligature_engraver::apply_transition (int state, int input, int i) programming_error ("last_primitive undefined"); break; } - last_primitive->set_grob_property ("primitive", gh_int2scm (output)); + last_primitive->set_property ("primitive", scm_int2num (output)); break; case MLP_BB: case MLP_LB: @@ -299,8 +226,8 @@ Mensural_ligature_engraver::apply_transition (int state, int input, int i) programming_error ("primitive undefined"); break; } - last_primitive->set_grob_property ("primitive", gh_int2scm (output)); - primitive->set_grob_property ("primitive", gh_int2scm (MLP_NONE)); + last_primitive->set_property ("primitive", scm_int2num (output)); + primitive->set_property ("primitive", scm_int2num (MLP_NONE)); break; case MLP_SS: // delayed primitive with two note heads @@ -314,8 +241,8 @@ Mensural_ligature_engraver::apply_transition (int state, int input, int i) programming_error ("last_primitive undefined"); break; } - last_last_primitive->set_grob_property ("primitive", gh_int2scm (output)); - last_primitive->set_grob_property ("primitive", gh_int2scm (MLP_NONE)); + last_last_primitive->set_property ("primitive", scm_int2num (output)); + last_primitive->set_property ("primitive", scm_int2num (MLP_NONE)); break; default: programming_error (_f ("unexpected case fall-through")); @@ -325,9 +252,9 @@ Mensural_ligature_engraver::apply_transition (int state, int input, int i) } void -Mensural_ligature_engraver::transform_heads () +Mensural_ligature_engraver::transform_heads (Array primitives) { - if (primitives_.size () < 2) + if (primitives.size () < 2) { warning (_f ("ligature with less than 2 heads -> skipping")); return; @@ -335,18 +262,16 @@ Mensural_ligature_engraver::transform_heads () int state = STATE_START; Pitch last_pitch, pitch; bool have_last_pitch = 0, have_pitch = 0; - for (int i = 0; i < primitives_.size (); i++) { + for (int i = 0; i < primitives.size (); i++) { last_pitch = pitch; have_last_pitch = have_pitch; - Grob_info info = primitives_[i]; + Grob_info info = primitives[i]; int duration_log = Note_head::get_balltype (dynamic_cast (info.grob_)); - Music * nr = info.music_cause (); + Music *nr = info.music_cause (); - /* - ugh. why not simply check for pitch? */ if (!nr->is_mus_type ("note-event")) @@ -359,7 +284,7 @@ Mensural_ligature_engraver::transform_heads () } else { - pitch = *unsmob_pitch (nr->get_mus_property ("pitch")); + pitch = *unsmob_pitch (nr->get_property ("pitch")); have_pitch = 1; } @@ -392,82 +317,67 @@ Mensural_ligature_engraver::transform_heads () } int input = (duration_log + 2) * 2 + ((delta_pitch < 0) ? 1 : 0); - state = apply_transition (state, input, i); + state = apply_transition (primitives, state, input, i); // TODO: if (state == STATE_ERROR) { ... } } - state = apply_transition (state, INPUT_AE, primitives_.size ()); + state = apply_transition (primitives, state, INPUT_AE, primitives.size ()); // TODO: if (state == STATE_ERROR) { ... } } -void set_delta_pitch (Item *primitive, Grob_info info1, Grob_info info2) -{ - Pitch pitch1 = *unsmob_pitch (info1.music_cause ()->get_mus_property ("pitch")); - Pitch pitch2 = *unsmob_pitch (info2.music_cause ()->get_mus_property ("pitch")); - int delta_pitch = (pitch2.steps () - pitch1.steps ()); - primitive->set_grob_property ("delta-pitch", gh_int2scm (delta_pitch)); -} - /* - * A MensuralLigature grob consists of a bunch of LigatureHead grobs - * that are glued together. It (a) does make sense to change + * A MensuralLigature grob consists of a bunch of NoteHead grobs that + * are glued together. It (a) does not make sense to change * properties like thickness or flexa-width from one head to the next * within a ligature (this would totally screw up alignment), and (b) * some of these properties (like flexa-width) are specific to * e.g. the MensuralLigature (as in contrast to e.g. LigatureBracket), - * and therefore should not be handled in the generic LigatureHead - * (which is also used by LigatureBracket). Therefore, we let the - * user control these properties via the concrete Ligature grob (like + * and therefore should not be handled in the NoteHead code (which is + * also used by LigatureBracket). Therefore, we let the user control + * these properties via the concrete Ligature grob (like * MensuralLigature) and then copy these properties as necessary to - * each of the LigatureHead grobs. This is what - * propagate_properties() does. + * each of the NoteHead grobs. This is what + * propagate_properties () does. */ void -Mensural_ligature_engraver::propagate_properties () +Mensural_ligature_engraver::propagate_properties (Spanner *ligature, + Array primitives) { - SCM thickness_scm = - finished_ligature_->get_grob_property ("thickness"); - Real thickness = (thickness_scm != SCM_EOL) ? - gh_scm2double (thickness_scm) : 1.4; - thickness *= finished_ligature_->get_paper ()->get_var ("linethickness"); + Real thickness = robust_scm2double (ligature->get_property ("thickness"), 1.4); + thickness *= ligature->get_paper ()->get_dimension (ly_symbol2scm ("linethickness")); Real head_width = - Font_interface::get_default_font (finished_ligature_)-> + Font_interface::get_default_font (ligature)-> find_by_name ("noteheads--1mensural").extent (X_AXIS).length (); - SCM flexa_width_scm = - finished_ligature_->get_grob_property ("flexa-width"); - Real flexa_width = (flexa_width_scm != SCM_EOL) ? - gh_scm2double (flexa_width_scm) : 2.0; - flexa_width *= Staff_symbol_referencer::staff_space (finished_ligature_); + Real flexa_width = robust_scm2double (ligature->get_property ("flexa-width"), 2); + flexa_width *= Staff_symbol_referencer::staff_space (ligature); Real half_flexa_width = 0.5 * (flexa_width + thickness); - for (int i = 0; i < primitives_.size (); i++) + for (int i = 0; i < primitives.size (); i++) { - Item *primitive = dynamic_cast (primitives_[i].grob_); - int output = gh_scm2int (primitive->get_grob_property ("primitive")); - primitive->set_grob_property ("thickness", - gh_double2scm (thickness)); + Item *primitive = dynamic_cast (primitives[i].grob_); + int output = scm_to_int (primitive->get_property ("primitive")); + primitive->set_property ("thickness", + scm_make_real (thickness)); switch (output) { case MLP_NONE: - primitive->set_grob_property ("head-width", - gh_double2scm (half_flexa_width)); + primitive->set_property ("head-width", + scm_make_real (half_flexa_width)); break; case MLP_sc: case MLP_ss: case MLP_cs: - primitive->set_grob_property ("head-width", - gh_double2scm (head_width)); + primitive->set_property ("head-width", + scm_make_real (head_width)); break; case MLP_BB: case MLP_LB: case MLP_SS: - primitive->set_grob_property ("head-width", - gh_double2scm (half_flexa_width)); - primitive->set_grob_property ("flexa-width", - gh_double2scm (flexa_width)); - set_delta_pitch (primitive, - primitives_[i], primitives_[i+1]); + primitive->set_property ("head-width", + scm_make_real (half_flexa_width)); + primitive->set_property ("flexa-width", + scm_make_real (flexa_width)); break; default: programming_error (_f ("unexpected case fall-through")); @@ -477,12 +387,13 @@ Mensural_ligature_engraver::propagate_properties () } void -Mensural_ligature_engraver::fold_up_primitives () +Mensural_ligature_engraver::fold_up_primitives (Array primitives) { Item *first = 0; - for (int i = 0; i < primitives_.size (); i++) + Real distance = 0; + for (int i = 0; i < primitives.size (); i++) { - Item *current = dynamic_cast (primitives_[i].grob_); + Item *current = dynamic_cast (primitives[i].grob_); if (i == 0) { first = current; @@ -492,39 +403,32 @@ Mensural_ligature_engraver::fold_up_primitives () if (i > 0) { -#if 0 - Rod r; - r.distance_ = distance_; - r.item_l_drul_[LEFT] = first; - r.item_l_drul_[RIGHT] = current; - r.add_to_cols (); -#endif - current->translate_axis (distance_, X_AXIS); + current->translate_axis (distance, X_AXIS); } - distance_ += - gh_scm2double (current->get_grob_property ("head-width")) - - gh_scm2double (current->get_grob_property ("thickness")); + distance += + scm_to_double (current->get_property ("head-width")) - + scm_to_double (current->get_property ("thickness")); } } void -Mensural_ligature_engraver::join_primitives () +Mensural_ligature_engraver::join_primitives (Array primitives) { Pitch last_pitch; - for (int i = 0; i < primitives_.size (); i++) + for (int i = 0; i < primitives.size (); i++) { - Grob_info info = primitives_[i]; - Pitch pitch = *unsmob_pitch (info.music_cause ()->get_mus_property ("pitch")); + Grob_info info = primitives[i]; + Pitch pitch = *unsmob_pitch (info.music_cause ()->get_property ("pitch")); if (i > 0) { Item *primitive = dynamic_cast (info.grob_); - int output = gh_scm2int (primitive->get_grob_property ("primitive")); + int output = scm_to_int (primitive->get_property ("primitive")); if (output & MLP_ANY) { int delta_pitch = (pitch.steps () - last_pitch.steps ()); - primitive->set_grob_property ("join-left", - gh_int2scm (delta_pitch)); + primitive->set_property ("join-left-amount", + scm_int2num (delta_pitch)); } } last_pitch = pitch; @@ -532,42 +436,19 @@ Mensural_ligature_engraver::join_primitives () } void -Mensural_ligature_engraver::try_stop_ligature () -{ - if (finished_ligature_) - { - transform_heads (); - propagate_properties (); - fold_up_primitives (); - join_primitives (); - - for (int i = 0; i < primitives_.size (); i++) - { - typeset_grob (primitives_[i].grob_); - } - - primitives_.clear (); - finished_ligature_ = 0; - } -} - -void -Mensural_ligature_engraver::acknowledge_grob (Grob_info info) +Mensural_ligature_engraver::build_ligature (Spanner *ligature, + Array primitives) { - Ligature_engraver::acknowledge_grob (info); - if (ligature_) - { - if (Note_head::has_interface (info.grob_)) - { - primitives_.push (info); - } - } + transform_heads (primitives); + propagate_properties (ligature, primitives); + fold_up_primitives (primitives); + join_primitives (primitives); } ENTER_DESCRIPTION (Mensural_ligature_engraver, /* descr */ "Handles Mensural_ligature_events by glueing special ligature heads together.", /* creats*/ "MensuralLigature", -/* accepts */ "ligature-event abort-event", -/* acks */ "ligature-head-interface note-head-interface rest-interface", +/* accepts */ "ligature-event", +/* acks */ "note-head-interface rest-interface", /* reads */ "", /* write */ "");