From 94fd329b69d78ca44300c3ba75d7ba8159b18e6c Mon Sep 17 00:00:00 2001 From: Aleksandr Andreev Date: Fri, 22 Feb 2013 20:13:32 +0100 Subject: [PATCH] Creates support for melismas ("ligatures") in Kievan notation via the use of a ligature engraver. Author: Aleksandr Andreev --- lily/coherent-ligature-engraver.cc | 9 +- lily/include/kievan-ligature.hh | 32 ++++++ lily/kievan-ligature-engraver.cc | 154 +++++++++++++++++++++++++++++ lily/kievan-ligature.cc | 39 ++++++++ lily/ligature-engraver.cc | 9 +- ly/engraver-init.ly | 3 + scm/define-grobs.scm | 8 ++ 7 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 lily/include/kievan-ligature.hh create mode 100644 lily/kievan-ligature-engraver.cc create mode 100644 lily/kievan-ligature.cc diff --git a/lily/coherent-ligature-engraver.cc b/lily/coherent-ligature-engraver.cc index 843c5208c0..3e2915e719 100644 --- a/lily/coherent-ligature-engraver.cc +++ b/lily/coherent-ligature-engraver.cc @@ -40,9 +40,9 @@ * * - delegate actual creation of ligature to concrete subclass, * - * - collect all accidentals that occur within the ligature and put - * them at the left side of the ligature (TODO; see function - * collect_accidentals ()), + * - except in Kievan notation, collect all accidentals that occur + * within the ligature and put them at the left side of the ligature + * (TODO; see function collect_accidentals ()), * * - collapse superflous space after each ligature (TODO). * @@ -135,6 +135,9 @@ Coherent_ligature_engraver::collect_accidentals (Spanner *, vector const &) { /* TODO */ + /* NOTE: if implementing such a function, note that in Kievan notation, + * the B-flat accidental should not be "collected", but rather prints + * immediately before the note head as usual. */ } void diff --git a/lily/include/kievan-ligature.hh b/lily/include/kievan-ligature.hh new file mode 100644 index 0000000000..cb6494ca79 --- /dev/null +++ b/lily/include/kievan-ligature.hh @@ -0,0 +1,32 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2013 Aleksandr Andreev + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#ifndef KIEVAN_LIGATURE_HH +#define KIEVAN_LIGATURE_HH + +#include "lily-proto.hh" +#include "grob-interface.hh" + +struct Kievan_ligature +{ + DECLARE_SCHEME_CALLBACK (print, (SCM)); + DECLARE_GROB_INTERFACE (); +}; + +#endif /* KIEVAN_LIGATURE_HH */ diff --git a/lily/kievan-ligature-engraver.cc b/lily/kievan-ligature-engraver.cc new file mode 100644 index 0000000000..92b9848c5b --- /dev/null +++ b/lily/kievan-ligature-engraver.cc @@ -0,0 +1,154 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2013 Aleksandr Andreev + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#include "coherent-ligature-engraver.hh" +#include "font-interface.hh" +#include "international.hh" +#include "kievan-ligature.hh" +#include "paper-column.hh" +#include "rhythmic-head.hh" +#include "spanner.hh" +#include "stream-event.hh" +#include "warn.hh" + +#include "translator.icc" + +class Kievan_ligature_engraver : public Coherent_ligature_engraver +{ + +protected: + virtual Spanner *create_ligature_spanner (); + virtual void build_ligature (Spanner *ligature, + vector const &primitives); + DECLARE_TRANSLATOR_LISTENER (ligature); + +public: + TRANSLATOR_DECLARATIONS (Kievan_ligature_engraver); + +private: + void fold_up_primitives (vector const &primitives, Real padding, Real &min_length); +}; + +IMPLEMENT_TRANSLATOR_LISTENER (Kievan_ligature_engraver, ligature); +void +Kievan_ligature_engraver::listen_ligature (Stream_event *ev) +{ + Ligature_engraver::listen_ligature (ev); +} + +Kievan_ligature_engraver::Kievan_ligature_engraver () +{ + +} + +Spanner * +Kievan_ligature_engraver::create_ligature_spanner () +{ + return make_spanner ("KievanLigature", SCM_EOL); +} + +void +Kievan_ligature_engraver::fold_up_primitives (vector const &primitives, + Real padding, Real &min_length) +{ + Item *first = 0; + Real accumul_acc_space = 0.0; + // start us off with some padding on the left + min_length = padding; + + for (vsize i = 0; i < primitives.size (); i++) + { + Item *current = dynamic_cast (primitives[i].grob ()); + Interval my_ext = current->extent (current, X_AXIS); + Real head_width = my_ext.length (); + if (i == 0) + first = current; + + // must keep track of accidentals in spacing problem + Grob *acc_gr = unsmob_grob (current->get_object ("accidental-grob")); + if (acc_gr && i > 0) + { + Interval acc_ext = acc_gr->extent (acc_gr, X_AXIS); + accumul_acc_space += acc_ext.length(); + } + + move_related_items_to_column (current, first->get_column (), + min_length); + + // check if we have any dots + if (size_t const dot_count = Rhythmic_head::dot_count (current)) + { + Grob *dot_gr = Rhythmic_head::get_dots (current); + + head_width += Font_interface::get_default_font (current)-> + find_by_name ("dots.dotkievan").extent (X_AXIS).length() - + 0.5 * (padding - accumul_acc_space); + + dot_gr->translate_axis (0.5 * (padding - accumul_acc_space), X_AXIS); + } + + // add more padding if we have an accidental coming up + if (i < primitives.size () - 1) + { + Item *next = dynamic_cast (primitives[i + 1].grob ()); + Grob *acc_gr = unsmob_grob (next->get_object ("accidental-grob")); + if (acc_gr) + { + Interval acc_ext = acc_gr->extent (acc_gr, X_AXIS); + padding += acc_ext.length(); + } + } + + min_length += head_width + padding - accumul_acc_space; + + } + +} + +void +Kievan_ligature_engraver::build_ligature (Spanner *ligature, + vector const &primitives) +{ + Real min_length; + + Real padding = robust_scm2double (ligature->get_property ("padding"), 0.0); + fold_up_primitives (primitives, padding, 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 (Kievan_ligature_engraver, rest); +ADD_ACKNOWLEDGER (Kievan_ligature_engraver, ligature_head); + +ADD_TRANSLATOR (Kievan_ligature_engraver, + /* doc */ + "Handle @code{Kievan_ligature_events} by glueing Kievan" + " heads together.", + + /* create */ + "KievanLigature ", + + /* read */ + "", + + /* write */ + "" + ); diff --git a/lily/kievan-ligature.cc b/lily/kievan-ligature.cc new file mode 100644 index 0000000000..21ea23e16a --- /dev/null +++ b/lily/kievan-ligature.cc @@ -0,0 +1,39 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2013 Aleksandr Andreev + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#include "kievan-ligature.hh" + +#include "international.hh" +#include "item.hh" +#include "warn.hh" + +MAKE_SCHEME_CALLBACK (Kievan_ligature, print, 1); +SCM +Kievan_ligature::print (SCM) +{ + return SCM_EOL; +} + +ADD_INTERFACE (Kievan_ligature, + "A kievan ligature.", + + /* properties */ + "primitive " + "padding " + ); diff --git a/lily/ligature-engraver.cc b/lily/ligature-engraver.cc index fb6f54c706..297337a976 100644 --- a/lily/ligature-engraver.cc +++ b/lily/ligature-engraver.cc @@ -44,9 +44,14 @@ * 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 + * between the primitives of the ligature. The same approach is + * used for Kievan notation ligatures, or, rather melismas. + * Though these are not single connected objects, they behave much + * in the same way and have a fixed, small amount of space between + * noteheads. Except in Kievan "ligatures", 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 + * noteheads. In Kievan ligatures, the B-flat may be part of the + * ligature itself. 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 diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index a7754ef67c..58ee39a123 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -1139,6 +1139,9 @@ accommodated for typesetting a piece in Petrucci style." \description "Same as @code{Voice} context, except that it is accommodated for typesetting a piece in Kievan style." + \remove "Ligature_bracket_engraver" + \consists "Kievan_ligature_engraver" + %% Set glyph styles. \override NoteHead.style = #'kievan \override Stem.X-offset = #stem::kievan-offset-callback diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 915a51ca72..ad014bce44 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -1199,6 +1199,14 @@ pure-from-neighbor-interface staff-symbol-referencer-interface)))))) + (KievanLigature + . ( + (springs-and-rods . ,ly:spanner::set-spacing-rods) + (stencil . ,ly:kievan-ligature::print) + (padding . 0.5) + (meta . ((class . Spanner) + (interfaces . (font-interface + kievan-ligature-interface)))))) (LaissezVibrerTie . ( -- 2.39.2