X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fmensural-ligature-engraver.cc;h=482538c720588537f16291fc2b243b46514fe7ad;hb=97a0169312a260933246ab224e4f8b0969871dd5;hp=d6e8eed3ca3ffc700ba27a4d80905732496dff8a;hpb=1528c75809ebc59d93018dbf59559436f75f082b;p=lilypond.git diff --git a/lily/mensural-ligature-engraver.cc b/lily/mensural-ligature-engraver.cc index d6e8eed3ca..482538c720 100644 --- a/lily/mensural-ligature-engraver.cc +++ b/lily/mensural-ligature-engraver.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 2002--2011 Juergen Reuter , + Copyright (C) 2002--2015 Juergen Reuter , Pal Benko LilyPond is free software: you can redistribute it and/or modify @@ -57,29 +57,27 @@ class Mensural_ligature_engraver : public Coherent_ligature_engraver protected: virtual Spanner *create_ligature_spanner (); - virtual void build_ligature (Spanner *ligature, vector primitives); - DECLARE_TRANSLATOR_LISTENER (ligature); - + virtual void build_ligature (Spanner *ligature, + vector const &primitives); + public: TRANSLATOR_DECLARATIONS (Mensural_ligature_engraver); + TRANSLATOR_INHERIT (Coherent_ligature_engraver); private: - void transform_heads (vector primitives); - void propagate_properties (Spanner *ligature, vector primitives); - void fold_up_primitives (vector primitives); + void transform_heads (vector const &primitives); + void propagate_properties (Spanner *ligature, + vector const &primitives, + Real &min_length); + void fold_up_primitives (vector const &primitives, + Real &min_length); }; -IMPLEMENT_TRANSLATOR_LISTENER (Mensural_ligature_engraver, ligature); -void -Mensural_ligature_engraver::listen_ligature (Stream_event *ev) -{ - Ligature_engraver::listen_ligature (ev); -} - -Mensural_ligature_engraver::Mensural_ligature_engraver () +Mensural_ligature_engraver::Mensural_ligature_engraver (Context *c) + : Coherent_ligature_engraver (c) { - brew_ligature_primitive_proc = - Mensural_ligature::brew_ligature_primitive_proc; + brew_ligature_primitive_proc + = Mensural_ligature::brew_ligature_primitive_proc; } Spanner * @@ -89,7 +87,7 @@ Mensural_ligature_engraver::create_ligature_spanner () } void -Mensural_ligature_engraver::transform_heads (vector primitives) +Mensural_ligature_engraver::transform_heads (vector const &primitives) { if (primitives.size () < 2) { @@ -115,52 +113,52 @@ Mensural_ligature_engraver::transform_heads (vector primitives) Stream_event *nr = info.event_cause (); /* - ugh. why not simply check for pitch? + ugh. why not simply check for pitch? */ if (!nr->in_event_class ("note-event")) - { - nr->origin ()->warning - (_ ("cannot determine pitch of ligature primitive -> skipping")); - at_beginning = true; - continue; - } - - int pitch = unsmob_pitch (nr->get_property ("pitch"))->steps (); + { + nr->origin ()->warning + (_ ("cannot determine pitch of ligature primitive -> skipping")); + at_beginning = true; + continue; + } + + int pitch = unsmob (nr->get_property ("pitch"))->steps (); int prim = 0; if (at_beginning) - { - if (i == s - 1) - { - // we can get here after invalid input - nr->origin ()->warning - (_ ("single note ligature - skipping")); - break; - } - prev_semibrevis = prev_brevis_shape = false; - prev_primitive = NULL; - } + { + if (i == s - 1) + { + // we can get here after invalid input + nr->origin ()->warning + (_ ("single note ligature - skipping")); + break; + } + prev_semibrevis = prev_brevis_shape = false; + prev_primitive = NULL; + } else - { - if (pitch == prev_pitch) - { - nr->origin ()->warning - (_ ("prime interval within ligature -> skipping")); - at_beginning = true; + { + if (pitch == prev_pitch) + { + nr->origin ()->warning + (_ ("prime interval within ligature -> skipping")); + at_beginning = true; prim = MLP_NONE; - continue; - } - } + continue; + } + } if (duration_log < -3 // is this possible at all??? - || duration_log > 0) - { - nr->origin ()->warning - (_ ("mensural ligature: duration none of Mx, L, B, S -> skipping")); + || duration_log > 0) + { + nr->origin ()->warning + (_ ("mensural ligature: duration none of Mx, L, B, S -> skipping")); prim = MLP_NONE; - at_beginning = true; - continue; - } + at_beginning = true; + continue; + } bool general_case = true; bool make_flexa = false; @@ -169,82 +167,82 @@ Mensural_ligature_engraver::transform_heads (vector primitives) // first check special cases // 1. beginning if (at_beginning) - { - // a. semibreves - if (duration_log == 0) - { + { + // a. semibreves + if (duration_log == 0) + { prim = MLP_UP | MLP_BREVIS; - general_case = false; - } - // b. descendens longa or brevis - else if (i < s - 1 - && (unsmob_pitch (primitives[i + 1].event_cause () - ->get_property ("pitch"))->steps () < pitch) - && duration_log > -3) - { - int left_stem = duration_log == -1 ? MLP_DOWN : 0; + general_case = false; + } + // b. descendens longa or brevis + else if (i < s - 1 + && (unsmob (primitives[i + 1].event_cause () + ->get_property ("pitch"))->steps () < pitch) + && duration_log > -3) + { + int left_stem = duration_log == -1 ? MLP_DOWN : 0; prim = left_stem | MLP_BREVIS; - general_case = false; - } - } + general_case = false; + } + } // 2. initial semibrevis must be followed by another one else if (prev_semibrevis) - { - prev_semibrevis = false; - if (duration_log == 0) - { - prim = MLP_BREVIS; - general_case = false; - } - else - { - nr->origin ()->warning - (_ ("semibrevis must be followed by another one -> skipping")); + { + prev_semibrevis = false; + if (duration_log == 0) + { + prim = MLP_BREVIS; + general_case = false; + } + else + { + nr->origin ()->warning + (_ ("semibrevis must be followed by another one -> skipping")); prim = MLP_NONE; - at_beginning = true; - continue; - } - } + at_beginning = true; + continue; + } + } // 3. semibreves are otherwise not allowed else if (duration_log == 0) - { - nr->origin ()->warning - (_ ("semibreves can only appear at the beginning of a ligature,\n" - "and there may be only zero or two of them")); + { + nr->origin ()->warning + (_ ("semibreves can only appear at the beginning of a ligature,\n" + "and there may be only zero or two of them")); prim = MLP_NONE; - at_beginning = true; - continue; - } + at_beginning = true; + continue; + } // 4. end, descendens else if (i == s - 1 && pitch < prev_pitch) - { - // brevis; previous note must be turned into flexa - if (duration_log == -1) - { - if (prev_brevis_shape) - { + { + // brevis; previous note must be turned into flexa + if (duration_log == -1) + { + if (prev_brevis_shape) + { make_flexa = true; general_case = false; - } - else - { - nr->origin ()->warning - (_ ("invalid ligatura ending:\n" - "when the last note is a descending brevis,\n" - "the penultimate note must be another one,\n" - "or the ligatura must be LB or SSB")); - prim = MLP_NONE; - break; - } - } - // longa - else if (duration_log == -2) - { - prim = MLP_BREVIS; - general_case = allow_flexa = false; - } - // else maxima; fall through to regular case below - } + } + else + { + nr->origin ()->warning + (_ ("invalid ligatura ending:\n" + "when the last note is a descending brevis,\n" + "the penultimate note must be another one,\n" + "or the ligatura must be LB or SSB")); + prim = MLP_NONE; + break; + } + } + // longa + else if (duration_log == -2) + { + prim = MLP_BREVIS; + general_case = allow_flexa = false; + } + // else maxima; fall through to regular case below + } if (allow_flexa && to_boolean (primitive->get_property ("ligature-flexa"))) @@ -271,23 +269,23 @@ Mensural_ligature_engraver::transform_heads (vector primitives) /* breve: check whether descending */ - int const next_pitch = unsmob_pitch - (next_info.event_cause ()->get_property ("pitch"))->steps (); + int const next_pitch = unsmob + (next_info.event_cause ()->get_property ("pitch"))->steps (); if (next_pitch < pitch) - /* - sorry, forbidden - */ - make_flexa = false; + /* + sorry, forbidden + */ + make_flexa = false; } } } if (general_case) - { + { static int const shape[3] = {MLP_MAXIMA, MLP_LONGA, MLP_BREVIS}; prim = shape[duration_log + 3]; - } + } if (make_flexa) { @@ -295,21 +293,21 @@ Mensural_ligature_engraver::transform_heads (vector primitives) turn the note with the previous one into a flexa */ prev_primitive->set_property - ("primitive", - scm_from_int - (MLP_FLEXA_BEGIN - | (scm_to_int (prev_primitive->get_property ("primitive")) - & MLP_STEM))); + ("primitive", + scm_from_int + (MLP_FLEXA_BEGIN + | (scm_to_int (prev_primitive->get_property ("primitive")) + & MLP_STEM))); prev_primitive->set_property - ("flexa-interval", scm_from_int (pitch - prev_pitch)); + ("flexa-interval", scm_from_int (pitch - prev_pitch)); prim = MLP_FLEXA_END; primitive->set_property - ("flexa-interval", scm_from_int (pitch - prev_pitch)); + ("flexa-interval", scm_from_int (pitch - prev_pitch)); } // join_primitives replacement if (!(at_beginning || make_flexa)) - prev_primitive->set_property ("add-join", ly_bool2scm (true)); + prev_primitive->set_property ("add-join", ly_bool2scm (true)); at_beginning = false; prev_primitive = primitive; @@ -336,63 +334,70 @@ Mensural_ligature_engraver::transform_heads (vector primitives) */ void Mensural_ligature_engraver::propagate_properties (Spanner *ligature, - vector primitives) + vector const &primitives, + Real &min_length) { Real thickness - = robust_scm2double (ligature->get_property ("thickness"), 1.4); + = robust_scm2double (ligature->get_property ("thickness"), 1.3); thickness - *= ligature->layout ()->get_dimension (ly_symbol2scm ("line-thickness")); + *= ligature->layout ()->get_dimension (ly_symbol2scm ("line-thickness")); Real head_width = Font_interface::get_default_font (ligature)-> - find_by_name ("noteheads.sM1mensural").extent (X_AXIS).length (); + find_by_name ("noteheads.sM1mensural").extent (X_AXIS).length (); Real maxima_head_width = Font_interface::get_default_font (ligature)-> - find_by_name ("noteheads.sM3ligmensural").extent (X_AXIS).length (); + find_by_name ("noteheads.sM3ligmensural").extent (X_AXIS).length (); + min_length = 0.0; Item *prev_primitive = NULL; for (vsize i = 0; i < primitives.size (); i++) { Item *primitive = dynamic_cast (primitives[i].grob ()); int output = scm_to_int (primitive->get_property ("primitive")); primitive->set_property ("thickness", - scm_from_double (thickness)); - - switch (output & MLP_ANY) { - case MLP_BREVIS: - case MLP_LONGA: - primitive->set_property ("head-width", scm_from_double (head_width)); - break; - case MLP_MAXIMA: - primitive->set_property ("head-width", - scm_from_double (maxima_head_width)); - break; - case MLP_FLEXA_BEGIN: - /* - the next note (should be MLP_FLEXA_END) will handle this one - */ - break; - case MLP_FLEXA_END: + scm_from_double (thickness)); + + switch (output & MLP_ANY) { - SCM flexa_scm = primitive->get_property ("flexa-width"); - Real const flexa_width = robust_scm2double (flexa_scm, 2.0); - SCM head_width = scm_from_double (0.5 * (flexa_width + thickness)); - primitive->set_property ("head-width", head_width); - prev_primitive->set_property ("head-width", head_width); - prev_primitive->set_property ("flexa-width", flexa_scm); + case MLP_BREVIS: + case MLP_LONGA: + min_length += head_width; + primitive->set_property ("head-width", scm_from_double (head_width)); + break; + case MLP_MAXIMA: + min_length += maxima_head_width; + primitive->set_property ("head-width", + scm_from_double (maxima_head_width)); + break; + case MLP_FLEXA_BEGIN: + /* + the next note (should be MLP_FLEXA_END) will handle this one + */ + break; + case MLP_FLEXA_END: + { + SCM flexa_scm = primitive->get_property ("flexa-width"); + Real const flexa_width = robust_scm2double (flexa_scm, 2.0); + min_length += flexa_width + thickness; + SCM head_width = scm_from_double (0.5 * (flexa_width + thickness)); + primitive->set_property ("head-width", head_width); + prev_primitive->set_property ("head-width", head_width); + prev_primitive->set_property ("flexa-width", flexa_scm); + } + break; + default: + programming_error (_ ("unexpected case fall-through")); + break; } - break; - default: - programming_error (_ ("unexpected case fall-through")); - break; - } prev_primitive = primitive; } } void -Mensural_ligature_engraver::fold_up_primitives (vector primitives) +Mensural_ligature_engraver::fold_up_primitives (vector const &primitives, + Real &min_length) { Item *first = 0; Real distance = 0.0; @@ -403,89 +408,107 @@ Mensural_ligature_engraver::fold_up_primitives (vector primitives) { Item *current = dynamic_cast (primitives[i].grob ()); if (i == 0) - { - first = current; - staff_space = Staff_symbol_referencer::staff_space (first); - thickness = scm_to_double (current->get_property ("thickness")); - } + { + first = current; + staff_space = Staff_symbol_referencer::staff_space (first); + thickness = scm_to_double (current->get_property ("thickness")); + } move_related_items_to_column (current, first->get_column (), - distance); + distance); Real head_width = scm_to_double (current->get_property ("head-width")); distance += head_width - thickness; - if (Rhythmic_head::dot_count (current) > 0) - /* - Move dots above/behind the ligature. - dots should also avoid staff lines. - */ - { - Grob *dot_gr = Rhythmic_head::get_dots (current); - - bool const on_line = Staff_symbol_referencer::on_line - (current, - robust_scm2int (current->get_property ("staff-position"), 0)); - Real vert_shift = on_line ? staff_space * 0.5 : 0.0; - bool const flexa_begin = - scm_to_int (current->get_property ("primitive")) - & MLP_FLEXA_BEGIN; - - if (i + 1 < primitives.size ()) - /* - dot in the midst => avoid next note; - what to avoid and where depends on - being on a line or between lines - */ - { - int const delta = - scm_to_int (current->get_property ("delta-position")); - if (flexa_begin) - vert_shift += delta < 0 - ? staff_space : (on_line ? -2.0 : -1.0) * staff_space; - else if (on_line) - { - if (0 < delta && delta < 3) - vert_shift -= staff_space; - } - else if (delta == 1 || delta == -1) - vert_shift -= delta * staff_space; - } - - dot_gr->translate_axis (vert_shift, Y_AXIS); - - /* - move all dots behind head - */ - dot_gr->translate_axis - ((flexa_begin ? staff_space * 0.6 : head_width) - 2.0*thickness, X_AXIS); - } + if (size_t const dot_count = Rhythmic_head::dot_count (current)) + /* + Move dots above/behind the ligature. + dots should also avoid staff lines. + */ + { + Grob *dot_gr = Rhythmic_head::get_dots (current); + + bool const on_line = Staff_symbol_referencer::on_line + (current, + robust_scm2int (current->get_property ("staff-position"), 0)); + Real vert_shift = on_line ? staff_space * 0.5 : 0.0; + bool const flexa_begin + = scm_to_int (current->get_property ("primitive")) + & MLP_FLEXA_BEGIN; + + if (i + 1 < primitives.size ()) + /* + dot in the midst => avoid next note; + what to avoid and where depends on + being on a line or between lines + */ + { + int const delta + = scm_to_int (current->get_property ("delta-position")); + if (flexa_begin) + vert_shift += delta < 0 + ? staff_space : (on_line ? -2.0 : -1.0) * staff_space; + else if (on_line) + { + if (0 < delta && delta < 3) + vert_shift -= staff_space; + } + else if (delta == 1 || delta == -1) + vert_shift -= delta * staff_space; + } + else + min_length += head_width * dot_count; + + dot_gr->translate_axis (vert_shift, Y_AXIS); + + /* + move all dots behind head + */ + dot_gr->translate_axis + ((flexa_begin ? staff_space * 0.6 : head_width) - 2.0 * thickness, X_AXIS); + } } } void Mensural_ligature_engraver::build_ligature (Spanner *ligature, - vector primitives) + vector const &primitives) { + /* + the X extent of the actual graphics representing the ligature; + less space than that means collision + */ + Real min_length; + transform_heads (primitives); - propagate_properties (ligature, primitives); - fold_up_primitives (primitives); + propagate_properties (ligature, primitives, min_length); + fold_up_primitives (primitives, min_length); + + if (robust_scm2double (ligature->get_property ("minimum-length"), 0.0) + < min_length) + ligature->set_property ("minimum-length", scm_from_double (min_length)); } -ADD_ACKNOWLEDGER (Mensural_ligature_engraver, rest); -ADD_ACKNOWLEDGER (Mensural_ligature_engraver, note_head); + +void +Mensural_ligature_engraver::boot () +{ + ADD_LISTENER (Mensural_ligature_engraver, ligature); + ADD_ACKNOWLEDGER (Mensural_ligature_engraver, rest); + ADD_ACKNOWLEDGER (Mensural_ligature_engraver, ligature_head); +} ADD_TRANSLATOR (Mensural_ligature_engraver, - /* doc */ - "Handle @code{Mensural_ligature_events} by glueing special" - " ligature heads together.", + /* doc */ + "Handle @code{Mensural_ligature_events} by glueing special" + " ligature heads together.", - /* create */ - "MensuralLigature ", + /* create */ + "MensuralLigature ", - /* read */ - "", + /* read */ + "", - /* write */ - "" - ); + /* write */ + "" + );