+
+2003-01-07 Juergen Reuter <reuter@ipd.uka.de>
+
+ * lily/custos-engraver.cc: added TODO; editorial changes
+
+ * lily/ligature-bracket-engraver.cc: added typeset_ligature () for
+ consistency with other ligature engravers; removed access on (now)
+ private variable _ligature of Ligature_engraver
+
+ * lily/include/ligature-engraver.hh, lily/ligature-engraver.cc:
+ renamed last_bound -> last_bound_; issue programming_error on
+ abstract method calls; moved primitives code from
+ Mensural_bracket_engraver to here (because almost ligature
+ engravers will need it); renamed try_stop_ligature () ->
+ typeset_ligature (); bugfix: store primitives of finished ligature
+ in separate variable finished_primitives_ to avoid clash on input
+ like "\] \["; added current_ligature () to enable access on
+ private variable _ligature
+
+ * lily/mensural-ligature-engraver.cc: removed primitives_ code
+ (now in super class); renamed try_stop_ligature () ->
+ typeset_ligature ()
+
+ * lily/mensural-ligature.cc: issue programming_error on abstract
+ method calls
+
+ * lily/note-heads-engraver.cc: added TODO comment upon bool
+ in_ligature
+
+ * mf/parmesan-heads.mf: fixed some of set_char_box()
+
+ * scm/grob-description.scm: added VaticanaLigature
+
+ * scm/grob-property-description.scm: added neume prefix properties
+
+ * ly/gregorian-init.ly, lily/gregorian-ligature-engraver.cc,
+ lily/include/gregorian-ligature-engraver.hh,
+ lily/include/gregorian-ligature.hh: new files; framework for
+ gregorian ligature engravers such as vaticana
+
+ * lily/vaticana-ligature.cc, lily/vaticana-ligature-engraver.cc,
+ lily/include/vaticana-ligature.hh, input/test/vaticana.ly:
+ vaticana style ligature implementation (still somewhat uncomplete)
+
2003-01-07 Han-Wen Nienhuys <hanwen@cs.uu.nl>
* VERSION: release 1.7.11
--- /dev/null
+\version "1.7.10"
+\header {
+ title = "vaticana ligature test"
+ date = "2003"
+}
+
+\include "paper26.ly"
+\include "gregorian-init.ly"
+
+%
+% FIXME: custodes and clefs do not show on all staves
+% FIXME: some set_char_box() definitions seem to be bad
+%
+
+cantus = \notes \relative c {
+ \clef "vaticana_fa2"
+ \[ f \quilisma g \auctum \descendens a \]
+ \[ \virga a g \pes a \inclinatum f \inclinatum d
+ c \pes d \quilisma e \pes f \virga g
+ a \flexa f \pes g \inclinatum f \inclinatum e \]
+ \[ d \quilisma e f \flexa e \pes f \]
+ \[ e \flexa d \]
+}
+
+verba = \context Lyrics = verba \lyrics {
+ Al-4*3 le-4*15 lu-4*5 ia.4*2
+}
+
+\score {
+ \context VaticanaStaff <
+ \context VaticanaVoice <
+ \cantus
+ \verba
+ >
+ >
+ \paper {
+ stafflinethickness = \staffspace / 5.0
+ linewidth = 15.0 \cm
+%
+% FIXME: ragged-right alignment is currently broken
+% width = 15.0 \cm
+% raggedright = ##t
+%
+ \translator {
+ \VoiceContext
+ \name VaticanaVoice
+ \alias Voice
+ \remove Ligature_bracket_engraver
+ \consists Vaticana_ligature_engraver
+ NoteHead \set #'style = #'vaticana_punctum
+ Stem \set #'transparent = ##t
+ }
+ \translator {
+ \StaffContext
+ \name VaticanaStaff
+ \alias Staff
+ \accepts VaticanaVoice
+ \remove Bar_engraver
+ \consists Custos_engraver
+ StaffSymbol \set #'line-count = #4
+ TimeSignature \set #'transparent = ##t
+ KeySignature \set #'style = #'vaticana
+ Accidental \set #'style = #'vaticana
+ Custos \set #'style = #'vaticana
+ Custos \set #'neutral-position = #3
+ Custos \set #'neutral-direction = #-1
+ Custos \set #'adjust-if-on-staffline = ##t
+ }
+ \translator {
+ \HaraKiriStaffContext
+ \accepts VaticanaVoice
+ }
+ \translator {
+ \ScoreContext
+ \accepts VaticanaStaff
+ \remove Bar_number_engraver
+ }
+ }
+}
source file of the GNU LilyPond music typesetter
- (C) 2000 Juergen Reuter <reuterj@ira.uka.de>,
+ (C) 2000 Juergen Reuter <reuter@ipd.uka.de>,
Han-Wen Nienhuys <hanwen@cs.uu.nl>
#include "event.hh"
/*
- This class implements an engraver for custos symbols.
-*/
+ * This class implements an engraver for custos symbols.
+ *
+ * FIXME: note heads inside of ligatures (i.e. ligature heads) are
+ * sometimes not recognized by this engraver. --jr
+ */
class Custos_engraver : public Engraver
{
public:
--- /dev/null
+/*
+ gregorian-ligature-engraver.cc -- implement Gregorian_ligature_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (C) 2003 Juergen Reuter <reuter@ipd.uka.de>
+ */
+
+#include "gregorian-ligature-engraver.hh"
+#include "gregorian-ligature.hh"
+#include "item.hh"
+#include "warn.hh"
+#include "staff-symbol-referencer.hh"
+#include "spanner.hh"
+#include "paper-column.hh"
+
+/*
+ * TODO: This class shares some code with Mensural_ligature_engraver.
+ * Maybe we should create a common super class "Rod_ligature_engraver"
+ * and derive all shared code from it.
+ */
+
+Gregorian_ligature_engraver::Gregorian_ligature_engraver ()
+{
+ porrectus_req_ = 0;
+}
+
+void
+Gregorian_ligature_engraver::transform_heads (Spanner *, Array<Grob_info>)
+{
+ programming_error ("Gregorian_ligature_engraver::transform_heads (): "
+ "this is an abstract method that should not be called, "
+ "but overridden by a subclass");
+}
+
+bool
+Gregorian_ligature_engraver::try_music (Music *m)
+{
+ if (m->is_mus_type ("porrectus-event"))
+ {
+ porrectus_req_ = m;
+ return true;
+ }
+ else
+ return Ligature_engraver::try_music (m);
+}
+
+/*
+ * TODO: move this function to class Item?
+ */
+void
+Gregorian_ligature_engraver::get_set_column (Item *item, Paper_column *column)
+{
+ Item *parent = dynamic_cast<Item*> (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);
+ }
+}
+
+void fix_prefix (char *name, int mask,
+ int *current_set, int min_set, int max_set,
+ Grob *primitive)
+{
+ bool current = *current_set & mask;
+ bool min = min_set & mask;
+ bool max = max_set & mask;
+ if (max < min)
+ {
+ programming_error ("min_set > max_set");
+ return;
+ }
+ if (min && !current)
+ {
+ primitive->warning (_f ("\\%s ignored", name));
+ *current_set &= ~mask;
+ }
+ if (!max && current)
+ {
+ primitive->warning (_f ("implied \\%s added", name));
+ *current_set |= mask;
+ }
+}
+
+void fix_prefix_set (int *current_set, int min_set, int max_set, Grob *primitive)
+{
+ fix_prefix ("virga", VIRGA, current_set, min_set, max_set, primitive);
+ fix_prefix ("stropha", STROPHA, current_set, min_set, max_set, primitive);
+ fix_prefix ("inclinatum", INCLINATUM, current_set, min_set, max_set, primitive);
+ fix_prefix ("auctum", AUCTUM, current_set, min_set, max_set, primitive);
+ fix_prefix ("descendens", DESCENDENS, current_set, min_set, max_set, primitive);
+ fix_prefix ("ascendens", ASCENDENS, current_set, min_set, max_set, primitive);
+ fix_prefix ("oriscus", ORISCUS, current_set, min_set, max_set, primitive);
+ fix_prefix ("quilisma", QUILISMA, current_set, min_set, max_set, primitive);
+ fix_prefix ("deminutus", DEMINUTUM, current_set, min_set, max_set, primitive);
+ fix_prefix ("semivocalis", SEMIVOCALIS, current_set, min_set, max_set, primitive);
+ fix_prefix ("cavum", CAVUM, current_set, min_set, max_set, primitive);
+ fix_prefix ("linea", LINEA, current_set, min_set, max_set, primitive);
+ fix_prefix ("pes_or_flexa", LINEA, current_set, min_set, max_set, primitive);
+}
+
+void check_and_fix_all_prefixes (Array<Grob_info> primitives)
+{
+ /* Check for illegal head modifier combinations */
+ for (int i = 0; i < primitives.size(); i++) {
+ Grob *primitive = primitives[i].grob_;
+
+ /* compute head prefix set by inspecting primitive grob properties */
+ int prefix_set =
+ (VIRGA * to_boolean (primitive->get_grob_property ("virga"))) |
+ (STROPHA * to_boolean (primitive->get_grob_property ("stropha"))) |
+ (INCLINATUM * to_boolean (primitive->get_grob_property ("inclinatum"))) |
+ (AUCTUM * to_boolean (primitive->get_grob_property ("auctum"))) |
+ (DESCENDENS * to_boolean (primitive->get_grob_property ("descendens"))) |
+ (ASCENDENS * to_boolean (primitive->get_grob_property ("ascendens"))) |
+ (ORISCUS * to_boolean (primitive->get_grob_property ("oriscus"))) |
+ (QUILISMA * to_boolean (primitive->get_grob_property ("quilisma"))) |
+ (DEMINUTUM * to_boolean (primitive->get_grob_property ("deminutum"))) |
+ (SEMIVOCALIS * to_boolean (primitive->get_grob_property ("semivocalis"))) |
+ (CAVUM * to_boolean (primitive->get_grob_property ("cavum"))) |
+ (LINEA * to_boolean (primitive->get_grob_property ("linea"))) |
+ (PES_OR_FLEXA * to_boolean (primitive->get_grob_property ("pes-or-flexa")));
+
+ /* check: ascendens and descendens exclude each other; same with
+ auctum and diminutum */
+ if (prefix_set & DESCENDENS)
+ {
+ fix_prefix_set (&prefix_set,
+ prefix_set & ~ASCENDENS,
+ prefix_set & ~ASCENDENS,
+ primitive);
+ }
+ if (prefix_set & AUCTUM)
+ {
+ fix_prefix_set (&prefix_set,
+ prefix_set & ~DEMINUTUM,
+ prefix_set & ~DEMINUTUM,
+ primitive);
+ }
+
+ /* check: virga, quilisma and oriscus can not be combined with any
+ other prefix, but may be part of a pes or flexa */
+ if (prefix_set & VIRGA)
+ {
+ fix_prefix_set (&prefix_set,
+ VIRGA,
+ VIRGA | PES_OR_FLEXA,
+ primitive);
+ }
+ if (prefix_set & QUILISMA)
+ {
+ fix_prefix_set (&prefix_set,
+ QUILISMA,
+ QUILISMA | PES_OR_FLEXA,
+ primitive);
+ }
+ if (prefix_set & ORISCUS)
+ {
+ fix_prefix_set (&prefix_set,
+ ORISCUS,
+ ORISCUS | PES_OR_FLEXA,
+ primitive);
+ }
+
+ /* check: auctum is the only valid optional prefix for stropha */
+ if (prefix_set & STROPHA)
+ {
+ fix_prefix_set (&prefix_set,
+ STROPHA,
+ STROPHA | AUCTUM,
+ primitive);
+ }
+
+ /* check: semivocalis must occur in combination with and only with
+ pes or flexa */
+ if (prefix_set & SEMIVOCALIS)
+ {
+ fix_prefix_set (&prefix_set,
+ SEMIVOCALIS | PES_OR_FLEXA,
+ SEMIVOCALIS | PES_OR_FLEXA,
+ primitive);
+ }
+
+ /* check: inclinatum may be prefixed with auctum or diminutum only */
+ if (prefix_set & INCLINATUM)
+ {
+ fix_prefix_set (&prefix_set,
+ INCLINATUM,
+ INCLINATUM | AUCTUM | DEMINUTUM,
+ primitive);
+ }
+
+ /* check: cavum and linea (either or both) may be applied only
+ upon core punctum */
+ if (prefix_set & (CAVUM | LINEA))
+ {
+ fix_prefix_set (&prefix_set,
+ 0,
+ CAVUM | LINEA,
+ primitive);
+ }
+
+ /* all other combinations should be valid (unless I made a
+ mistake) */
+
+ primitive->set_grob_property ("prefix-set", gh_int2scm (prefix_set));
+ }
+}
+
+/*
+ * Marks those heads that participate in a pes or flexa.
+ */
+void
+provide_context_info (Array<Grob_info> primitives)
+{
+ Grob *prev_primitive = 0;
+ int prev_context_info = 0;
+ int prev_pitch = 0;
+ for (int i = 0; i < primitives.size(); i++) {
+ Grob *primitive = primitives[i].grob_;
+ Music *music_cause = primitives[i].music_cause ();
+ int context_info = 0;
+ int pitch = unsmob_pitch (music_cause->get_mus_property ("pitch"))->steps ();
+ int prefix_set = gh_scm2int (primitive->get_grob_property ("prefix-set"));
+
+ if (prefix_set & PES_OR_FLEXA)
+ if (pitch > prev_pitch) // pes
+ {
+ prev_context_info |= PES_LOWER;
+ context_info |= PES_UPPER;
+ }
+ else if (pitch < prev_pitch) // flexa
+ {
+ prev_context_info |= FLEXA_LEFT;
+ context_info |= FLEXA_RIGHT;
+ }
+ else // (pitch == prev_pitch)
+ {
+ primitive->warning ("may not apply `\\~' on heads with "
+ "identical pitch; ignoring `\\~'");
+ }
+ if (prev_primitive)
+ prev_primitive->set_grob_property ("context-info",
+ gh_int2scm (prev_context_info));
+ prev_primitive = primitive;
+ prev_context_info = context_info;
+ prev_pitch = pitch;
+ }
+ if (prev_primitive)
+ prev_primitive->set_grob_property ("context-info",
+ gh_int2scm (prev_context_info));
+}
+
+void
+Gregorian_ligature_engraver::typeset_ligature (Spanner *ligature,
+ Array<Grob_info> primitives)
+{
+ // apply style-independent checking and transformation
+ check_and_fix_all_prefixes (primitives);
+ provide_context_info (primitives);
+
+ // apply style-specific transformation (including line-up)
+ transform_heads (ligature, primitives);
+
+ // typeset
+ for (int i = 0; i < primitives.size (); i++)
+ {
+ typeset_grob (primitives[i].grob_);
+ }
+}
+
+void
+Gregorian_ligature_engraver::start_translation_timestep ()
+{
+ Ligature_engraver::start_translation_timestep ();
+ porrectus_req_ = 0;
+}
+
+ENTER_DESCRIPTION (Gregorian_ligature_engraver,
+/* descr */ "This is an abstract class. Subclasses such as Vaticana_ligature_engraver handle ligatures by glueing special ligature heads together.",
+/* creats*/ "",
+/* accepts */ "ligature-event abort-event",
+/* acks */ "ligature-head-interface note-head-interface rest-interface",
+/* reads */ "",
+/* write */ "");
--- /dev/null
+/*
+ gregorian-ligature-engraver.hh -- declare Gregorian_ligature_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2003 Juergen Reuter <reuter@ipd.uka.de>
+
+ */
+#ifndef GREGORIAN_LIGATURE_ENGRAVER_HH
+#define GREGORIAN_LIGATURE_ENGRAVER_HH
+
+#include "ligature-engraver.hh"
+
+class Gregorian_ligature_engraver : public Ligature_engraver
+{
+ Music *porrectus_req_;
+
+public:
+ TRANSLATOR_DECLARATIONS(Gregorian_ligature_engraver);
+
+protected:
+ virtual bool try_music (Music *);
+ virtual void typeset_ligature (Spanner *ligature,
+ Array<Grob_info> primitives);
+ virtual void transform_heads (Spanner *ligature,
+ Array<Grob_info> primitives); /* abstract method */
+ virtual void start_translation_timestep ();
+ void get_set_column (Item *, Paper_column *);
+};
+
+#endif // GREGORIAN_LIGATURE_ENGRAVER_HH
--- /dev/null
+/*
+ gregorian-ligature.hh -- part of GNU LilyPond
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2003 Juergen Reuter <reuter@ipd.uka.de>
+*/
+
+#ifndef GREGORIAN_LIGATURE_HH
+#define GREGORIAN_LIGATURE_HH
+
+/*
+ * Head prefixes: these bit-mask constants are used to represent
+ * attributes immediately derived from user input (e.g. by the user
+ * setting a gregorian ligature grob property or using the "\~"
+ * keyword). If the according bit of the head prefix value is set,
+ * the attribute applies for this head. The binary opereator "\~" is
+ * marked only upon the second head (i.e. the note that comes after
+ * the operator).
+ */
+#define VIRGA 0x0001 // attribute "\virga"
+#define STROPHA 0x0002 // attribute "\stropha"
+#define INCLINATUM 0x0004 // attribute "\inclinatum"
+#define AUCTUM 0x0008 // attribute "\auctum"
+#define DESCENDENS 0x0010 // attribute "\descendens"
+#define ASCENDENS 0x0020 // attribute "\ascendens"
+#define ORISCUS 0x0040 // attribute "\oriscus"
+#define QUILISMA 0x0080 // attribute "\quilisma"
+#define DEMINUTUM 0x0100 // attribute "\deminutum"
+#define SEMIVOCALIS 0x0100 // attribute "\semivocalis"
+#define CAVUM 0x0200 // attribute "\cavum"
+#define LINEA 0x0400 // attribute "\linea"
+#define PES_OR_FLEXA 0x0800 // operator "\~"
+
+/*
+ * Ligature context info: these attributes are derived from the head
+ * prefixes by considering the current and the following head.
+ */
+#define PES_LOWER 0x0001 // this is a head before "\~" in an ascending melody
+#define PES_UPPER 0x0002 // this is a head after "\~" in an ascending melody
+#define FLEXA_LEFT 0x0004 // this is a head before "\~" in a descending melody
+#define FLEXA_RIGHT 0x0008 // this is a head after "\~" in a descending melody
+
+#endif /* GREGORIAN_LIGATURE_HH */
(c) 2002 Juergen Reuter <reuter@ipd.uka.de>
*/
-#ifndef LIGATUREENGRAVER_HH
-#define LIGATUREEENGRAVER_HH
+#ifndef LIGATURE_ENGRAVER_HH
+#define LIGATURE_ENGRAVER_HH
#include "engraver.hh"
virtual void acknowledge_grob (Grob_info);
virtual bool try_music (Music*);
virtual void process_music ();
- virtual void try_stop_ligature ();
- virtual Spanner *create_ligature_spanner ();
-
- Spanner *finished_ligature_;
- Spanner *ligature_;
+ virtual Spanner *create_ligature_spanner (); /* abstract method */
+ virtual void typeset_ligature (Spanner *ligature,
+ Array<Grob_info> primitives); /* abstract method */
+ virtual Spanner *current_ligature ();
SCM brew_ligature_primitive_proc;
public:
private:
Drul_array<Music*> reqs_drul_;
+ Spanner *ligature_;
+ Array<Grob_info> primitives_;
+
+ Spanner *finished_ligature_;
+ Array<Grob_info> finished_primitives_;
+
Music *prev_start_req_;
// moment where ligature started.
Moment ligature_start_mom_;
- Grob *last_bound;
+ Grob *last_bound_;
};
-#endif // ENGRAVERGROUP_HH
+#endif // LIGATURE_ENGRAVER_HH
--- /dev/null
+/*
+ vaticana-ligature.hh
+
+ source file of the GNU LilyPond music typesetter
+
+ (C) 2003 Juergen Reuter <reuter@ipd.uka.de>
+*/
+
+#ifndef VATICANA_LIGATURE_HH
+#define VATICANA_LIGATURE_HH
+
+#include "lily-guile.hh"
+#include "molecule.hh"
+
+struct Vaticana_ligature
+{
+ DECLARE_SCHEME_CALLBACK (brew_ligature_primitive, (SCM ));
+ DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM ));
+ static bool has_interface (Grob *);
+};
+
+#endif // VATICANA_LIGATURE_HH
protected:
virtual Spanner *create_ligature_spanner ();
virtual void acknowledge_grob (Grob_info);
+ virtual void typeset_ligature (Spanner *ligature, Array<Grob_info>);
public:
TRANSLATOR_DECLARATIONS(Ligature_bracket_engraver);
return new Spanner (get_property ("LigatureBracket"));
}
+void
+Ligature_bracket_engraver::typeset_ligature (Spanner *ligature, Array<Grob_info>)
+{
+ typeset_grob (ligature);
+}
+
void
Ligature_bracket_engraver::acknowledge_grob (Grob_info info)
{
- if (ligature_)
+ if (current_ligature ())
{
if (Note_column::has_interface (info.grob_))
{
- Tuplet_bracket::add_column (ligature_, dynamic_cast<Item*> (info.grob_));
+ Tuplet_bracket::add_column (current_ligature (),
+ dynamic_cast<Item*> (info.grob_));
}
else Ligature_engraver::acknowledge_grob (info);
}
#include "ligature-head.hh"
#include "spanner.hh"
#include "score-engraver.hh"
+#include "note-head.hh"
#include "rest.hh"
#include "warn.hh"
finished_ligature_ = 0;
reqs_drul_[LEFT] = reqs_drul_[RIGHT] = 0;
prev_start_req_ = 0;
- last_bound = 0;
+ last_bound_ = 0;
brew_ligature_primitive_proc = SCM_EOL;
}
Spanner *
Ligature_engraver::create_ligature_spanner ()
{
+ programming_error ("Ligature_engraver::create_ligature_spanner (): "
+ "this is an abstract method that should not be called, "
+ "but overridden by a subclass");
return 0;
}
reqs_drul_[STOP]->origin ()->warning (_ ("can't find start of ligature"));
else
{
- if (!last_bound)
+ if (!last_bound_)
{
reqs_drul_[STOP]->origin ()->warning (_ ("no right bound"));
}
else
{
- ligature_->set_bound (RIGHT, last_bound);
+ ligature_->set_bound (RIGHT, last_bound_);
}
}
prev_start_req_ = 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_)
{
}
void
-Ligature_engraver::try_stop_ligature ()
+Ligature_engraver::typeset_ligature (Spanner *, Array<Grob_info>)
{
- if (finished_ligature_)
- {
- typeset_grob (finished_ligature_);
- finished_ligature_ = 0;
- }
+ programming_error ("Ligature_engraver::typeset_ligature (): "
+ "this is an abstract method that should not be called, "
+ "but overridden by a subclass");
}
void
Ligature_engraver::stop_translation_timestep ()
{
- try_stop_ligature ();
+ if (finished_ligature_)
+ {
+ typeset_ligature (finished_ligature_, finished_primitives_);
+ finished_primitives_.clear ();
+ finished_ligature_ = 0;
+ }
}
void
Ligature_engraver::finalize ()
{
- try_stop_ligature ();
+ if (finished_ligature_)
+ {
+ typeset_ligature (finished_ligature_, finished_primitives_);
+ finished_primitives_.clear ();
+ finished_ligature_ = 0;
+ }
if (ligature_)
{
prev_start_req_->origin ()->warning (_ ("unterminated ligature"));
}
}
+Spanner *
+Ligature_engraver::current_ligature ()
+{
+ return ligature_;
+}
+
void
Ligature_engraver::acknowledge_grob (Grob_info info)
{
if (ligature_)
{
+ if (Note_head::has_interface (info.grob_))
+ {
+ primitives_.push (info);
+ }
if (Ligature_head::has_interface (info.grob_))
{
info.grob_->set_grob_property ("ligature-primitive-callback",
*/
class Mensural_ligature_engraver : public Ligature_engraver
{
- Real distance_;
- Array<Grob_info> primitives_;
protected:
- virtual void acknowledge_grob (Grob_info);
- virtual void try_stop_ligature ();
virtual Spanner *create_ligature_spanner ();
+ virtual void typeset_ligature (Spanner *ligature,
+ Array<Grob_info> primitives);
public:
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 ();
+ int apply_transition (Array<Grob_info> primitives,
+ int state, int input, int i);
+ void transform_heads (Array<Grob_info> primitives);
+ void propagate_properties (Spanner *ligature, Array<Grob_info> primitives);
+ void fold_up_primitives (Array<Grob_info> primitives);
+ void join_primitives (Array<Grob_info> primitives);
void get_set_column (Item *item, Paper_column *new_col);
};
Mensural_ligature_engraver::Mensural_ligature_engraver ()
{
- distance_ = 0;
}
Spanner *
Mensural_ligature_engraver::create_ligature_spanner ()
{
- distance_ = 0;
return new Spanner (get_property ("MensuralLigature"));
}
};
int
-Mensural_ligature_engraver::apply_transition (int state, int input, int i)
+Mensural_ligature_engraver::apply_transition (Array<Grob_info> primitives,
+ int state, int input, int i)
{
int output = transition_output[state][input];
Item *last_last_primitive = (i > 1) ?
- dynamic_cast<Item*> (primitives_[i-2].grob_) : 0;
+ dynamic_cast<Item*> (primitives[i-2].grob_) : 0;
Item *last_primitive = (i > 0) ?
- dynamic_cast<Item*> (primitives_[i-1].grob_) : 0;
- Item *primitive = (i < primitives_.size ()) ?
- dynamic_cast<Item*> (primitives_[i].grob_) : 0;
+ dynamic_cast<Item*> (primitives[i-1].grob_) : 0;
+ Item *primitive = (i < primitives.size ()) ?
+ dynamic_cast<Item*> (primitives[i].grob_) : 0;
switch (output)
{
case MLP_NONE:
}
void
-Mensural_ligature_engraver::transform_heads ()
+Mensural_ligature_engraver::transform_heads (Array<Grob_info> primitives)
{
- if (primitives_.size () < 2)
+ if (primitives.size () < 2)
{
warning (_f ("ligature with less than 2 heads -> skipping"));
return;
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<Item*> (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"))
}
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) { ... }
}
/*
* A MensuralLigature grob consists of a bunch of LigatureHead grobs
- * that are glued together. It (a) does make sense to change
+ * 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
* propagate_properties() does.
*/
void
-Mensural_ligature_engraver::propagate_properties ()
+Mensural_ligature_engraver::propagate_properties (Spanner *ligature,
+ Array<Grob_info> primitives)
{
- SCM thickness_scm =
- finished_ligature_->get_grob_property ("thickness");
+ SCM thickness_scm = 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");
+ thickness *= ligature->get_paper ()->get_var ("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");
+ SCM flexa_width_scm = 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_);
+ 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<Item*> (primitives_[i].grob_);
+ Item *primitive = dynamic_cast<Item*> (primitives[i].grob_);
int output = gh_scm2int (primitive->get_grob_property ("primitive"));
primitive->set_grob_property ("thickness",
gh_double2scm (thickness));
primitive->set_grob_property ("flexa-width",
gh_double2scm (flexa_width));
set_delta_pitch (primitive,
- primitives_[i], primitives_[i+1]);
+ primitives[i], primitives[i+1]);
break;
default:
programming_error (_f ("unexpected case fall-through"));
}
void
-Mensural_ligature_engraver::fold_up_primitives ()
+Mensural_ligature_engraver::fold_up_primitives (Array<Grob_info> 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<Item*> (primitives_[i].grob_);
+ Item *current = dynamic_cast<Item*> (primitives[i].grob_);
if (i == 0)
{
first = current;
{
#if 0
Rod r;
- r.distance_ = distance_;
+ 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_ +=
+ distance +=
gh_scm2double (current->get_grob_property ("head-width")) -
gh_scm2double (current->get_grob_property ("thickness"));
}
}
void
-Mensural_ligature_engraver::join_primitives ()
+Mensural_ligature_engraver::join_primitives (Array<Grob_info> 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];
+ Grob_info info = primitives[i];
Pitch pitch = *unsmob_pitch (info.music_cause ()->get_mus_property ("pitch"));
if (i > 0)
{
}
void
-Mensural_ligature_engraver::try_stop_ligature ()
+Mensural_ligature_engraver::typeset_ligature (Spanner *ligature,
+ Array<Grob_info> primitives)
{
- if (finished_ligature_)
- {
- transform_heads ();
- propagate_properties ();
- fold_up_primitives ();
- join_primitives ();
+ transform_heads (primitives);
+ propagate_properties (ligature, primitives);
+ fold_up_primitives (primitives);
+ join_primitives (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)
-{
- Ligature_engraver::acknowledge_grob (info);
- if (ligature_)
+ for (int i = 0; i < primitives.size (); i++)
{
- if (Note_head::has_interface (info.grob_))
- {
- primitives_.push (info);
- }
+ typeset_grob (primitives[i].grob_);
}
}
SCM primitive_scm = me->get_grob_property ("primitive");
if (primitive_scm == SCM_EOL)
{
- programming_error ("Mensural_ligature: undefined primitive -> ignoring grob");
+ programming_error ("Mensural_ligature:"
+ "undefined primitive -> ignoring grob");
return Molecule ();
}
}
else
{
- programming_error (_f ("Mensural_ligature: thickness undefined on flexa %d; assuming 1.4", primitive));
+ programming_error (_f ("Mensural_ligature:"
+ "thickness undefined on flexa %d; assuming 1.4",
+ primitive));
thickness = 1.4 * me->get_paper ()->get_var ("linethickness");
}
}
}
else
{
- programming_error (_f ("Mensural_ligature: delta-pitch undefined on flexa %d; assuming 0", primitive));
+ programming_error (_f ("Mensural_ligature:"
+ "delta-pitch undefined on flexa %d; assuming 0",
+ primitive));
delta_pitch = 0;
}
}
else
{
- programming_error (_f ("Mensural_ligature: flexa-width undefined on flexa %d; assuming 2.0", primitive));
+ programming_error (_f ("Mensural_ligature:"
+ "flexa-width undefined on flexa %d; assuming 2.0",
+ primitive));
flexa_width = 2.0 * staff_space;
}
}
flexa_width, thickness, false, CENTER);
break;
default:
- programming_error (_f ("Mensural_ligature: unexpected case fall-through"));
+ programming_error (_f ("Mensural_ligature:"
+ "unexpected case fall-through"));
return Molecule ();
}
{
int join_left = gh_scm2int (join_left_scm);
if (!join_left)
- programming_error (_f ("Menusral_ligature: (join_left == 0)"));
+ programming_error (_f ("Mensural_ligature: (join_left == 0)"));
Real blotdiameter = (me->get_paper ()->get_var ("blotdiameter"));
Interval x_extent = Interval (0, thickness);
Interval y_extent = (join_left > 0) ?
Interval (0, -join_left * 0.5 * staff_space);
Box stem_box (x_extent, y_extent);
- Molecule stem =
- Lookup::roundfilledbox (stem_box, blotdiameter);
+ Molecule stem = Lookup::roundfilledbox (stem_box, blotdiameter);
out.add_molecule (stem);
}
/**
make balls and rests
*/
+
+/*
+ * TODO: junk bool in_ligature (and all the messy code around it).
+ * This can be done by also junking LigatureHead in
+ * scm/grob-description.scm. Instead, NoteHead should be used
+ * throughout typesetting of ligatures; ligature-(start/stop)-events
+ * should simply modify NoteHead properties values of
+ * molecule-callback ligature-primitive-callback. --jr
+ */
class Note_heads_engraver : public Engraver
{
Link_array<Item> notes_;
--- /dev/null
+/*
+ vaticana-ligature-engraver.cc -- implement Vaticana_ligature_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (C) 2003 Juergen Reuter <reuter@ipd.uka.de>
+ */
+
+#include "gregorian-ligature-engraver.hh"
+#include "gregorian-ligature.hh"
+#include "vaticana-ligature.hh"
+#include "item.hh"
+#include "spanner.hh"
+#include "staff-symbol-referencer.hh"
+#include "font-interface.hh"
+#include "warn.hh"
+#include "paper-def.hh"
+
+class Vaticana_ligature_engraver : public Gregorian_ligature_engraver
+{
+
+private:
+ Real finish_primitive (Item *first_primitive,
+ Item *primitive,
+ int context_info,
+ String head,
+ int pitch_delta,
+ Real flexa_width,
+ Real join_thickness,
+ Real distance);
+
+public:
+ TRANSLATOR_DECLARATIONS(Vaticana_ligature_engraver);
+
+protected:
+ virtual Spanner *create_ligature_spanner ();
+ virtual void transform_heads (Spanner *ligature,
+ Array<Grob_info> primitives);
+};
+
+Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
+{
+}
+
+Spanner *
+Vaticana_ligature_engraver::create_ligature_spanner ()
+{
+ return new Spanner (get_property ("VaticanaLigature"));
+}
+
+Real
+Vaticana_ligature_engraver::finish_primitive (Item *first_primitive,
+ Item *primitive,
+ int context_info,
+ String head,
+ int pitch_delta,
+ Real flexa_width,
+ Real join_thickness,
+ Real distance)
+{
+ if (primitive)
+ {
+ // determine width of previous head and x-shift
+ Real head_width;
+ Real x_shift;
+ bool is_stacked;
+ is_stacked = context_info & PES_UPPER;
+ if (context_info & FLEXA_LEFT)
+ is_stacked = false;
+ if (!String::compare (head, "vaticana_cephalicus") &&
+ !(context_info & PES_LOWER))
+ is_stacked = true;
+ if (context_info & AUCTUM)
+ is_stacked = false;
+ if (is_stacked)
+ {
+ /*
+ * This head is stacked upon another one; hence, it does not
+ * contribute to the total width of the ligature, hence its
+ * width is assumed to be 0.0. Moreover, it is shifted to
+ * the left by its width such that the right side of this
+ * and the other head are horizontally aligned.
+ */
+ head_width = 0.0;
+ x_shift = join_thickness -
+ Font_interface::get_default_font (primitive)->
+ find_by_name ("noteheads-" + head).extent (X_AXIS).length ();
+ }
+ else if (!String::compare (head, "porrectus") ||
+ !String::compare (head, ""))
+ {
+ /*
+ * This head represents either half of a porrectus shape.
+ * Hence, it is assigned half the width of this shape.
+ */
+ head_width = 0.5 * flexa_width;
+ x_shift = 0.0;
+ }
+ else // retrieve width from corresponding font
+ {
+ head_width =
+ Font_interface::get_default_font (primitive)->
+ find_by_name ("noteheads-" + head).extent (X_AXIS).length ();
+ x_shift = 0.0;
+ }
+
+ /*
+ * Save the head's final shape and x-shift.
+ */
+ primitive->set_grob_property ("ligature-head",
+ ly_symbol2scm (head.to_str0 ()));
+ primitive->set_grob_property ("x-shift",
+ gh_double2scm (x_shift));
+
+ /*
+ * If the head is the 2nd head of a pes or flexa (but not a
+ * porrectus), mark this head to be joined with the left-side
+ * neighbour head (i.e. the previous head) by a vertical beam.
+ */
+ if ((context_info & PES_UPPER) ||
+ ((context_info & FLEXA_RIGHT) &&
+ !(context_info & PES_LOWER)))
+ {
+ primitive->set_grob_property ("join-left",
+ gh_int2scm (pitch_delta));
+
+ /*
+ * Create a small overlap of adjacent heads so that the join
+ * can be drawn perfectly between them.
+ */
+ distance -= join_thickness;
+ }
+ else
+ {
+ /*
+ * Make a small space between adjacent notes of a ligature
+ * that are not directly joined.
+ */
+ distance += 2 * join_thickness;
+ }
+
+ /*
+ * Horizontally line-up this head to form a ligature.
+ */
+ get_set_column (primitive, first_primitive->get_column ());
+ primitive->translate_axis (distance, X_AXIS);
+ distance += head_width;
+ }
+ return distance;
+}
+
+void
+Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
+ Array<Grob_info> primitives)
+{
+ Real flexa_width;
+ SCM flexa_width_scm = ligature->get_grob_property ("flexa-width");
+ if (flexa_width_scm != SCM_EOL)
+ {
+ flexa_width = gh_scm2double (flexa_width_scm);
+ }
+ else
+ {
+ programming_error ("Vaticana_ligature_engraver:"
+ "flexa-width undefined; assuming 2.0 staff space");
+ flexa_width =
+ 2.0 * Staff_symbol_referencer::staff_space (ligature);
+ }
+
+ Real join_thickness;
+ SCM join_thickness_scm = ligature->get_grob_property ("thickness");
+ if (join_thickness_scm != SCM_EOL)
+ {
+ join_thickness = gh_scm2double (join_thickness_scm);
+ }
+ else
+ {
+ programming_error ("Vaticana_ligature_engraver:"
+ "thickness undefined; assuming 1.4 linethickness");
+ join_thickness = 1.4;
+ }
+ join_thickness *= ligature->get_paper ()->get_var ("linethickness");
+
+ Item *first_primitive = 0;
+ Item *prev_primitive = 0;
+ int prev_context_info = 0;
+ int prev_pitch = 0;
+ int prev_pitch_delta = 0;
+ String prev_head = "";
+ Real prev_distance = 0.0;
+ for (int i = 0; i < primitives.size(); i++) {
+ Item *primitive = dynamic_cast<Item*> (primitives[i].grob_);
+ Music *music_cause = primitives[i].music_cause ();
+ int context_info = gh_scm2int (primitive->get_grob_property ("context-info"));
+ int pitch = unsmob_pitch (music_cause->get_mus_property ("pitch"))->steps ();
+ String head;
+ if (!first_primitive)
+ first_primitive = primitive;
+ int prefix_set = gh_scm2int (primitive->get_grob_property ("prefix-set"));
+
+ /*
+ * Now determine which head to typeset (this is context sensitive
+ * information, since it depends on neighbouring heads; therefore,
+ * this decision must be made here in the engraver rather than in
+ * the backend).
+ */
+ if (prefix_set & VIRGA)
+ head = "vaticana_virga";
+ else if (prefix_set & QUILISMA)
+ head = "vaticana_quilisma";
+ else if (prefix_set & ORISCUS)
+ head = "solesmes_oriscus";
+ else if (prefix_set & STROPHA)
+ if (prefix_set & AUCTUM)
+ head = "solesmes_stropha_aucta";
+ else head = "solesmes_stropha";
+ else if (prefix_set & SEMIVOCALIS)
+ if (pitch > prev_pitch)
+ head = "vaticana_epiphonus";
+ else head = "vaticana_cephalicus";
+ else if (prefix_set & INCLINATUM)
+ if (prefix_set & AUCTUM)
+ head = "solesmes_incl_auctum";
+ else if (prefix_set & DEMINUTUM)
+ head = "solesmes_incl_parvum";
+ else
+ head = "vaticana_inclinatum";
+ else if (prefix_set & (CAVUM | LINEA))
+ if ((prefix_set & CAVUM) && (prefix_set & LINEA))
+ head = "vaticana_linea_punctum_cavum";
+ else if (prefix_set & CAVUM)
+ head = "vaticana_punctum_cavum";
+ else
+ head = "vaticana_linea_punctum";
+ else if (prefix_set & AUCTUM)
+ if (prefix_set & ASCENDENS)
+ head = "solesmes_auct_asc";
+ else
+ head = "solesmes_auct_desc";
+ else if (prefix_set & DEMINUTUM)
+ head = "vaticana_plica";
+ else if ((prefix_set & PES_OR_FLEXA) &&
+ (context_info & PES_LOWER) &&
+ (context_info & FLEXA_RIGHT))
+ head = ""; // second head of porrectus
+ else if (context_info & PES_UPPER)
+ if (pitch - prev_pitch > 1)
+ head = "vaticana_upes";
+ else
+ head = "vaticana_vupes";
+ else
+ head = "vaticana_punctum";
+
+ /*
+ * May need updating previous head, depending on the current head.
+ */
+ if (prefix_set & PES_OR_FLEXA)
+ if ((context_info & PES_LOWER) &&
+ (context_info & FLEXA_RIGHT)) // porrectus
+ {
+ prev_head = "porrectus";
+ prev_primitive->set_grob_property ("porrectus-height",
+ gh_int2scm (pitch - prev_pitch));
+ prev_primitive->set_grob_property ("porrectus-width",
+ gh_double2scm (flexa_width));
+ bool add_stem =
+ !(prev_context_info & PES_UPPER) &&
+ !(prev_context_info & FLEXA_RIGHT);
+ prev_primitive->set_grob_property ("add-stem",
+ gh_bool2scm (add_stem));
+ }
+ else if (context_info & PES_UPPER)
+ {
+ if (!String::compare (prev_head, "vaticana_punctum"))
+ prev_head = "vaticana_lpes";
+ }
+ else // flexa
+ {
+ if (!String::compare (prev_head, "vaticana_punctum"))
+ prev_head = "vaticana_rvirga";
+ }
+
+ /*
+ * In the backend, porrectus and joins need to know about
+ * thickness. Hence, for simplicity, let's distribute the
+ * ligature grob's value for thickness to each ligature head (even
+ * if not all of them need to know).
+ */
+ primitive->set_grob_property ("thickness", gh_double2scm (join_thickness));
+
+ /*
+ * The head of the current iteration still may change during the
+ * next iteration due to the context sensitiveness of the
+ * transformation. However, the head of the previous iteration is
+ * now fully attributed and can be prepared for the backend.
+ */
+
+ /*
+ * Finish head of previous iteration for backend.
+ */
+ prev_distance =
+ finish_primitive (first_primitive, prev_primitive,
+ prev_context_info, prev_head, prev_pitch_delta,
+ flexa_width, join_thickness, prev_distance);
+
+ prev_primitive = primitive;
+ prev_context_info = context_info;
+ prev_pitch_delta = pitch - prev_pitch;
+ prev_pitch = pitch;
+ prev_head = head;
+ }
+
+ /*
+ * Finish head of last iteration for backend.
+ */
+ finish_primitive (first_primitive, prev_primitive,
+ prev_context_info, prev_head, prev_pitch_delta,
+ flexa_width, join_thickness, prev_distance);
+}
+
+
+ENTER_DESCRIPTION (Vaticana_ligature_engraver,
+/* descr */ "Handles ligatures by glueing special ligature heads together.",
+/* creats*/ "VaticanaLigature",
+/* accepts */ "ligature-event abort-event",
+/* acks */ "ligature-head-interface note-head-interface rest-interface",
+/* reads */ "",
+/* write */ "");
--- /dev/null
+/*
+ vaticana-ligature.cc -- implement Vaticana_ligature
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2003 Juergen Reuter <reuter@ipd.uka.de>
+*/
+
+#include <math.h>
+#include "item.hh"
+#include "vaticana-ligature.hh"
+#include "font-interface.hh"
+#include "molecule.hh"
+#include "lookup.hh"
+#include "staff-symbol-referencer.hh"
+#include "note-head.hh"
+#include "paper-def.hh"
+#include "bezier.hh"
+#include "warn.hh"
+
+/*
+ * TODO: move this function to class Lookup?
+ */
+Molecule
+vaticana_brew_flexa (Grob *me,
+ Real interval,
+ bool solid,
+ Real width,
+ Real thickness,
+ bool add_stem,
+ Direction stem_direction)
+{
+ if (interval >= 0.0)
+ {
+ me->warning (_ ("ascending vaticana style flexa"));
+ }
+
+ Real space = Staff_symbol_referencer::staff_space (me);
+ Molecule molecule = Molecule ();
+ Real right_height = 0.6 * space;
+
+ // Compensate thickness that appears to be smaller in steep section
+ // of bend.
+ Real left_height = right_height + min (0.12 * abs(interval), 0.3) * space;
+
+ if (add_stem)
+ {
+ bool consider_interval =
+ stem_direction * interval > 0.0;
+
+ Interval stem_box_x (0, thickness);
+ Interval stem_box_y;
+
+ if (consider_interval)
+ {
+ Real y_length = max (abs(interval)/2.0*space +
+ (right_height-left_height),
+ 1.2*space);
+ stem_box_y = Interval (0, y_length);
+ }
+ else
+ stem_box_y = Interval (0, space);
+
+ Real y_correction =
+ (stem_direction == UP) ?
+ +0.5*left_height :
+ -0.5*left_height - stem_box_y.length();
+
+ Box stem_box (stem_box_x, stem_box_y);
+ Molecule stem = Lookup::filledbox (stem_box);
+ stem.translate_axis (y_correction, Y_AXIS);
+ molecule.add_molecule(stem);
+ }
+
+ // Compensate optical illusion regarding vertical position of left
+ // and right endings due to curved shape.
+ Real ypos_correction = -0.1*space * sign(interval);
+ Real interval_correction = 0.2*space * sign(interval);
+ Real corrected_interval = interval*space + interval_correction;
+
+ // middle curve of flexa
+ Bezier curve;
+ curve.control_[0] = Offset (0.00 * width, 0.0);
+ curve.control_[1] = Offset (0.33 * width, corrected_interval / 2.0);
+ curve.control_[2] = Offset (0.66 * width, corrected_interval / 2.0);
+ curve.control_[3] = Offset (1.00 * width, corrected_interval / 2.0);
+
+ Bezier top_curve = curve, bottom_curve = curve;
+ for (int i = 0; i < 4; i++)
+ {
+ Real thickness = 0.33 * ((3 - i)*left_height + i*right_height);
+ top_curve.control_[i] += Offset (0, +0.5*thickness);
+ bottom_curve.control_[i] += Offset (0, -0.5*thickness);
+ }
+
+ if (solid)
+ {
+ Molecule solid_head =
+ Lookup::bezier_sandwich (top_curve, bottom_curve);
+ molecule.add_molecule (solid_head);
+ }
+ else // outline
+ {
+ Bezier inner_top_curve = top_curve;
+ inner_top_curve.translate (Offset (0.0, -thickness));
+ Molecule top_edge =
+ Lookup::bezier_sandwich (top_curve, inner_top_curve);
+ molecule.add_molecule(top_edge);
+
+ Bezier inner_bottom_curve = bottom_curve;
+ inner_bottom_curve.translate (Offset (0.0, +thickness));
+ Molecule bottom_edge =
+ Lookup::bezier_sandwich (bottom_curve, inner_bottom_curve);
+ molecule.add_molecule(bottom_edge);
+
+ // TODO: Use horizontal slope with proper slope value rather
+ // than filled box for left edge, since the filled box stands
+ // out from the flexa shape if the interval is big and the line
+ // thickness small. The difficulty here is to compute a proper
+ // slope value, as it should roughly be equal with the slope of
+ // the left end of the bezier curve.
+ Box left_edge_box (Interval (0, thickness),
+ Interval (-0.5*left_height, +0.5*left_height));
+ Molecule left_edge = Lookup::filledbox (left_edge_box);
+ molecule.add_molecule(left_edge);
+
+ Box right_edge_box (Interval (-thickness, 0),
+ Interval (-0.5*right_height, +0.5*right_height));
+ Molecule right_edge = Lookup::filledbox (right_edge_box);
+ right_edge.translate_axis (width, X_AXIS);
+ right_edge.translate_axis (corrected_interval / 2.0, Y_AXIS);
+ molecule.add_molecule(right_edge);
+ }
+ molecule.translate_axis (ypos_correction, Y_AXIS);
+ return molecule;
+}
+
+void
+vaticana_add_ledger_lines (Grob *me, Molecule *out, int pos, Real offs,
+ bool ledger_take_space)
+{
+ int interspaces = Staff_symbol_referencer::line_count (me)-1;
+ if (abs (pos) - interspaces > 1)
+ {
+ Interval hd = out->extent (X_AXIS);
+ Real left_ledger_protusion = hd.length ()/4;
+ Real right_ledger_protusion = left_ledger_protusion;
+
+ Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
+ hd[RIGHT] + right_ledger_protusion);
+ Molecule ledger_lines =
+ Note_head::brew_ledger_lines (me, pos, interspaces,
+ l_extents,
+ ledger_take_space);
+ ledger_lines.translate_axis (offs, Y_AXIS);
+ out->add_molecule (ledger_lines);
+ }
+}
+
+Molecule
+vaticana_brew_primitive (Grob *me, bool ledger_take_space)
+{
+ SCM head_scm = me->get_grob_property ("ligature-head");
+ if (head_scm == SCM_EOL)
+ {
+ programming_error ("Vaticana_ligature:"
+ "undefined ligature-head -> ignoring grob");
+ return Molecule ();
+ }
+
+ String head = ly_symbol2string (head_scm);
+ if (!String::compare (head, ""))
+ {
+ // empty head (typically, this is the right side of porrectus
+ // shape, which is already typeset by the associated left side
+ // head); nothing left to do
+ return Molecule ();
+ }
+
+ Molecule out;
+ int porrectus_height = 0;
+ Real thickness = 0.0;
+ Real porrectus_width = 0.0;
+ Real staff_space = Staff_symbol_referencer::staff_space (me);
+
+ SCM thickness_scm = me->get_grob_property ("thickness");
+ if (thickness_scm != SCM_EOL)
+ {
+ thickness = gh_scm2double (thickness_scm);
+ }
+ else
+ {
+ programming_error (_f ("Vaticana_ligature:"
+ "thickness undefined; assuming 1.4",
+ me));
+ thickness = 1.4 * me->get_paper ()->get_var ("linethickness");
+ }
+
+ Real x_shift = 0.0;
+ SCM x_shift_scm = me->get_grob_property ("x-shift");
+ if (x_shift_scm != SCM_EOL)
+ {
+ x_shift = gh_scm2double (x_shift_scm);
+ }
+ else
+ {
+ programming_error (_f ("Vaticana_ligature:"
+ "x-shift undefined; assuming 0.0",
+ me));
+ }
+
+ if (!String::compare (head, "porrectus"))
+ {
+ SCM porrectus_height_scm = me->get_grob_property ("porrectus-height");
+ if (porrectus_height_scm != SCM_EOL)
+ {
+ porrectus_height = gh_scm2int (porrectus_height_scm);
+ }
+ else
+ {
+ me->warning ("Vaticana_ligature: "
+ "porrectus-height undefined; assuming 0");
+ }
+
+ SCM porrectus_width_scm = me->get_grob_property ("porrectus-width");
+ if (porrectus_width_scm != SCM_EOL)
+ {
+ porrectus_width = gh_scm2double (porrectus_width_scm);
+ }
+ else
+ {
+ me->warning ("Vaticana_ligature:"
+ "porrectus-width undefined; assuming 2.0");
+ porrectus_width = 2.0 * staff_space;
+ }
+
+ bool add_stem = to_boolean (me->get_grob_property ("add-stem"));
+ out = vaticana_brew_flexa (me, porrectus_height, true,
+ porrectus_width, thickness, add_stem, DOWN);
+ }
+ else
+ {
+ Molecule mol = Font_interface::get_default_font (me)->find_by_name ("noteheads-" + head);
+ mol.translate_axis (x_shift, X_AXIS);
+ out.add_molecule (mol);
+ }
+
+ SCM join_left_scm = me->get_grob_property ("join-left");
+ if (join_left_scm != SCM_EOL)
+ {
+ int join_left = gh_scm2int (join_left_scm);
+ if (!join_left)
+ programming_error (_f ("Vaticana_ligature: (join_left == 0)"));
+ Real blotdiameter = (me->get_paper ()->get_var ("blotdiameter"));
+ Interval x_extent =
+ Interval (-0.5 * thickness, +0.5 * thickness);
+ Interval y_extent = (join_left > 0) ?
+ Interval (-join_left * 0.5 * staff_space, 0) : // ascending join
+ Interval (0, -join_left * 0.5 * staff_space); // descending join
+ Box stem_box (x_extent, y_extent);
+
+ Molecule stem = Lookup::roundfilledbox (stem_box, blotdiameter);
+ out.add_molecule (stem);
+ }
+
+ int pos = (int)rint (Staff_symbol_referencer::get_position (me));
+ vaticana_add_ledger_lines(me, &out, pos, 0, ledger_take_space);
+ if (!String::compare (head, "porrectus"))
+ {
+ pos += porrectus_height;
+ vaticana_add_ledger_lines(me, &out, pos, 0.5*porrectus_height, ledger_take_space);
+ }
+
+ return out;
+}
+
+MAKE_SCHEME_CALLBACK (Vaticana_ligature, brew_ligature_primitive, 1);
+SCM
+Vaticana_ligature::brew_ligature_primitive (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ SCM primitive = vaticana_brew_primitive (me, false).smobbed_copy ();
+ return primitive;
+}
+
+MAKE_SCHEME_CALLBACK (Vaticana_ligature, brew_molecule, 1);
+SCM
+Vaticana_ligature::brew_molecule (SCM)
+{
+ return SCM_EOL;
+}
+
+ADD_INTERFACE (Vaticana_ligature, "vaticana-ligature-interface",
+ "A vaticana style gregorian ligature",
+ "ligature-head porrectus-height porrectus-width thickness join-left add-stem x-shift"
+ "ligature-primitive-callback");
--- /dev/null
+\version "1.7.10"
+
+%
+% declare shortcuts for gregorian chant notation
+%
+
+virga =
+ \once \property Voice.LigatureHead \override #'virga = ##t
+stropha =
+ \once \property Voice.LigatureHead \override #'stropha = ##t
+inclinatum =
+ \once \property Voice.LigatureHead \override #'inclinatum = ##t
+auctum =
+ \once \property Voice.LigatureHead \override #'auctum = ##t
+aucta =
+ \once \property Voice.LigatureHead \override #'auctum = ##t
+descendens =
+ \once \property Voice.LigatureHead \override #'descendens = ##t
+ascendens =
+ \once \property Voice.LigatureHead \override #'ascendens = ##t
+pes =
+ \once \property Voice.LigatureHead \override #'pes-or-flexa = ##t
+flexa =
+ \once \property Voice.LigatureHead \override #'pes-or-flexa = ##t
+semivocalis =
+ \once \property Voice.LigatureHead \override #'semivocalis = ##t
+oriscus =
+ \once \property Voice.LigatureHead \override #'oriscus = ##t
+quilisma =
+ \once \property Voice.LigatureHead \override #'quilisma = ##t
+deminutum =
+ \once \property Voice.LigatureHead \override #'deminutum = ##t
2beta# = ht# * b_h;
a# = beta# * a_b;
wd# = 2a# / a_w;
- set_char_box(0.3wd#, 0.3wd#, 0.5 ht#, 0.5 ht#);
+ set_char_box(0.2wd#, 0.2wd#, 0.5 ht#, 0.5 ht#);
black_notehead_width# := wd#;
save za, alpha, size;
2beta# = ht#*b_h;
a# = beta#*a_b;
wd# = 2a# / a_w;
- set_char_box(0.4wd#, 0.00wd#, 0.5 ht#, 0.5 ht#);
+ set_char_box(0.5stafflinethickness#, 0.40wd# + 0.5stafflinethickness#,
+ 0.31 ht#, 0.41 ht#);
black_notehead_width# := wd#;
define_pixels(ht, wd);
2beta# = ht# * b_h;
a# = beta# * a_b;
wd# = 2a# / a_w;
- set_char_box(0.5wd#, 0.0wd#, 0.5ht#, 0.5ht#);
+ set_char_box(0.0wd#, 0.5wd#, 0.5ht#, 0.5ht#);
black_notehead_width# := wd#;
save convexity;
(meta . ((interfaces . (piano-pedal-interface axis-group-interface side-position-interface spanner-interface))))
))
+ (VaticanaLigature
+ . (
+ (thickness . 1.0)
+ (flexa-width . 2.0)
+ (ligature-primitive-callback . ,Vaticana_ligature::brew_ligature_primitive)
+ (molecule-callback . ,Vaticana_ligature::brew_molecule)
+ (font-family . ancient)
+ (meta . ((interfaces . (mensural-ligature-interface font-interface))))
+ ))
+
(VoltaBracket
. (
(molecule-callback . ,Volta_bracket_interface::brew_molecule)
(grob-property-description 'arpeggio ly:grob? "pointer to arpeggio object.")
(grob-property-description 'arpeggio-direction ly:dir? "If set, put an
arrow on the arpeggio squiggly line.")
+(grob-property-description 'ascendens boolean? "is this neume of an ascending?.")
(grob-property-description 'attachment pair? "cons of symbols
indicating how a slur should be attached at the ends. The format is
'(LEFT-TYPE . RIGHT-TYPE), where both TYPEs are symbols. The values of
'(LEFT-offset . RIGHT-offset). This offset is added to the
attachments to prevent ugly slurs. [fixme: we need more documentation here].
.")
+(grob-property-description 'auctum boolean? "is this neume augmented?.")
(grob-property-description 'auto-properties boolean? "if true, as many properties of this grob as possible will be determined automatically from the musical context.")
(grob-property-description 'auto-knee-gap number? "If a gap is found between noteheads
where a horizontal beam fits that is larger than this number, make a kneed beam.")
(grob-property-description 'dash-length number? "the length of a dash.")
(grob-property-description 'dash-period number? "the length of one dash + white space.")
(grob-property-description 'dashed number? "[FIXME: use dash-period/dash length; see text-spanner] number representing the length of the dashes.")
+(grob-property-description 'descendens boolean? "is this neume of a descendent type?.")
(grob-property-description 'de-uglify-parameters list? "list of 3 real constants. They define the valid areas for the middle control points. Used in de_uglyfy. They are a bit empirical.")
(grob-property-description 'neutral-direction ly:dir? "Where to go if we're on the neutral position of the staff (by default, the middle of the staff; see also grob-property neutral-position). [Ross] has the following to say about this: Some engravers consider the middle line neutral, and take the option of using either up- or down-stems for notes that fall on it. However, more up-to-date engraving no longer permits an option; now a down-stem is always appropriate.")
(grob-property-description 'neutral-position number? "Position (in half staff spaces) where to flip the direction of stems: by default, custodes above this position get their stems downwards; custodes below this position get their stems upwards. A value of 0 designates the center of the staff. Use property neutral-direction to control the behaviour of stems on the neutral position itself. (Note: currently, neutral-position is supported only for custodes; for stems of note heads, neutral-position is currently fixed to 0, i.e. the middle of the staff.)")
+(grob-property-description 'deminutum boolean? "is this neume deminished?.")
(grob-property-description 'dependencies grob-list? "list of score-grob pointers that indicate who to compute first for certain global passes.")
(grob-property-description 'details list? "alist of parameters for detailed grob behavior.")
(grob-property-description 'dir-function procedure? "function of type (count total)->direction. Default value: beam-dir-majority, also available: beam-dir-mean, beam-dir-median.
")
(grob-property-description 'horizontal-shift integer? "integer that identifies ranking of note-column for horizontal shifting. This is used by @ref{note-collision-interface}.")
(grob-property-description 'ideal-distances list? "(OBJ . (DIST . STRENGTH)) pairs.")
+(grob-property-description 'inclinatum boolean? "is this neume an inclinatum?.")
(grob-property-description 'interfaces list? "list of symbols indicating the interfaces supported by this object. Is initialized from the @code{meta} field.")
(grob-property-description 'inversion list? " musical-pitch, optional.")
(grob-property-description 'items-worth-living grob-list? "list of interesting items. If empty in a particular system, clear that system.")
(grob-property-description 'note-head-style string? "name of the font character to be used as note heads in the ambitus grob.")
(grob-property-description 'note-heads grob-list? "List of note head grobs")
(grob-property-description 'old-accidentals list? "list of (pitch, accidental) pairs.")
+(grob-property-description 'oriscus boolean? "is this neume an oriscus?.")
(grob-property-description 'outer boolean? "whether a text spanner should extend to the outer edge of the spanned notes")
(grob-property-description 'padding number? "add this much extra space between objects that are next to each other.")
(grob-property-description 'pedal-type symbol? "Style of piano pedal: text, bracket or mixed.")
means force linebreak. Other values influence linebreaking decisions
as a real penalty.")
+(grob-property-description 'pes-or-flexa boolean? "shall this neume be joined with the previous head?.")
(grob-property-description 'pitch-max ly:pitch? "FIXME, JUNKME")
(grob-property-description 'pitch-min ly:pitch? "FIXME, JUNKME")
(grob-property-description 'pitches list? "list of musical-pitch.")
+(grob-property-description 'quilisma boolean? "is this neume a quilisma?.")
(grob-property-description 'positions pair? "cons of staff positions (LEFT . RIGHT")
(grob-property-description 'raise number? "height for text to be raised (a negative value lowers the text.")
(grob-property-description 'ratio number? "Slur parameter. See height-limit.")
TODO: revise typing.")
(grob-property-description 'self-alignment-Y number? "like self-alignment-X but for Y axis.")
(grob-property-description 'segments list? "DOCME. ")
+(grob-property-description 'semivocalis boolean? "is this neume a lisquescending one?.")
(grob-property-description 'shape symbol? "shape of cluster segments. Valid values include 'leftsided-stairs', 'rightsided-stairs', 'centered-stairs', and 'ramp'.")
(grob-property-description 'shorten number? "the amount of space that a stem should be shortened (DOCME!)")
(grob-property-description 'shorten-pair number-pair? "the length on each side to shorten a text-spanner, for example a pedal bracket")
")
(grob-property-description 'stem-spacing-correction number? "optical correction amount. [TODO: doco] ")
(grob-property-description 'stems grob-list? "list of stem objects, corresponding to the notes that the arpeggio has to be before.")
+(grob-property-description 'stropha boolean? "is this neume a stropha?.")
(grob-property-description 'style symbol? "a string determining what style of glyph is typeset. Valid choices depend on the function that is reading this property. .")
(grob-property-description 'support-head ly:grob? "the note head at
one end of the stem.")
no extent.
")
+(grob-property-description 'virga boolean? "is this neume a virga?.")
(grob-property-description 'when ly:moment? "when does this column happen?.")
(grob-property-description 'word-space number? "elongate left by this much (FIXME: cumbersome semantics).")
(grob-property-description 'alignment number? "alignment of lyrics on notehead, -1 is LEFT, 0 is CENTRE, 1 is RIGHT .")