]> git.donarmstrong.com Git - lilypond.git/commitdiff
Juergens patch.
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Tue, 7 Jan 2003 20:07:26 +0000 (20:07 +0000)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Tue, 7 Jan 2003 20:07:26 +0000 (20:07 +0000)
19 files changed:
ChangeLog
input/test/vaticana.ly [new file with mode: 0644]
lily/custos-engraver.cc
lily/gregorian-ligature-engraver.cc [new file with mode: 0644]
lily/include/gregorian-ligature-engraver.hh [new file with mode: 0644]
lily/include/gregorian-ligature.hh [new file with mode: 0644]
lily/include/ligature-engraver.hh
lily/include/vaticana-ligature.hh [new file with mode: 0644]
lily/ligature-bracket-engraver.cc
lily/ligature-engraver.cc
lily/mensural-ligature-engraver.cc
lily/mensural-ligature.cc
lily/note-heads-engraver.cc
lily/vaticana-ligature-engraver.cc [new file with mode: 0644]
lily/vaticana-ligature.cc [new file with mode: 0644]
ly/gregorian-init.ly [new file with mode: 0644]
mf/parmesan-heads.mf
scm/grob-description.scm
scm/grob-property-description.scm

index 9e67424fe9779980c8c9df32ebbc6a9c376c8f0c..556f19ed2d2ec3499b1eb8b5bb7df99034b79f79 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+
+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
diff --git a/input/test/vaticana.ly b/input/test/vaticana.ly
new file mode 100644 (file)
index 0000000..ae51e7f
--- /dev/null
@@ -0,0 +1,79 @@
+\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
+    }
+  }
+}
index d2b16c0afe49b64b7fe355fa68588bf69ed52377..fd7c315a2d09363f346e0f582ec6b53e748e0893 100644 (file)
@@ -3,7 +3,7 @@
 
   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:
diff --git a/lily/gregorian-ligature-engraver.cc b/lily/gregorian-ligature-engraver.cc
new file mode 100644 (file)
index 0000000..f3ba8b9
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+  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 */       "");
diff --git a/lily/include/gregorian-ligature-engraver.hh b/lily/include/gregorian-ligature-engraver.hh
new file mode 100644 (file)
index 0000000..6d8e9a1
--- /dev/null
@@ -0,0 +1,31 @@
+/*   
+  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
diff --git a/lily/include/gregorian-ligature.hh b/lily/include/gregorian-ligature.hh
new file mode 100644 (file)
index 0000000..1d95385
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  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 */
index bc5577a022e182fe6106a89bbfdc11c3fe6c6a9d..db4721c6bc4aa67bf36c8143639609ee70c2e008 100644 (file)
@@ -6,8 +6,8 @@
   (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"
 
@@ -21,11 +21,10 @@ protected:
   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:
@@ -34,13 +33,19 @@ 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
diff --git a/lily/include/vaticana-ligature.hh b/lily/include/vaticana-ligature.hh
new file mode 100644 (file)
index 0000000..feb965d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+  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
index 6f8d9e97cc0c84a675fe6daf268468950d75124d..9970886bed577b0ec2ecc0b8467f1e33a9354751 100644 (file)
@@ -17,6 +17,7 @@ class Ligature_bracket_engraver : public Ligature_engraver
 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);
@@ -36,14 +37,21 @@ Ligature_bracket_engraver::create_ligature_spanner ()
   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);
     }
index 3344e363a6b44f87bc05ea82d1787c31a0be3efc..53da233be8e5f76367ba425b27fb536ccc852861 100644 (file)
@@ -10,6 +10,7 @@
 #include "ligature-head.hh"
 #include "spanner.hh"
 #include "score-engraver.hh"
+#include "note-head.hh"
 #include "rest.hh"
 #include "warn.hh"
 
@@ -37,7 +38,7 @@ Ligature_engraver::Ligature_engraver ()
   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;
 }
 
@@ -64,6 +65,9 @@ Ligature_engraver::try_music (Music *m)
 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;
 }
 
@@ -76,20 +80,22 @@ Ligature_engraver::process_music ()
        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_)
     {
@@ -137,25 +143,33 @@ Ligature_engraver::start_translation_timestep ()
 }
 
 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"));
@@ -163,11 +177,21 @@ Ligature_engraver::finalize ()
     }
 }
 
+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",
index 436e49bf1760758d3b778f8fead7d147ff8927c7..4bedcaf4997d84532e6aebc3fa5b4f4a83ed8705 100644 (file)
  */
 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"));
 }
 
@@ -261,15 +258,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<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:
@@ -325,9 +323,9 @@ Mensural_ligature_engraver::apply_transition (int state, int input, int i)
 }
 
 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;
@@ -335,18 +333,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<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"))
@@ -392,11 +388,11 @@ 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) { ... }
 }
 
@@ -410,7 +406,7 @@ void set_delta_pitch (Item *primitive, Grob_info info1, Grob_info info2)
 
 /*
  * 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
@@ -423,28 +419,27 @@ void set_delta_pitch (Item *primitive, Grob_info info1, Grob_info info2)
  * 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));
@@ -467,7 +462,7 @@ Mensural_ligature_engraver::propagate_properties ()
          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"));
@@ -477,12 +472,13 @@ Mensural_ligature_engraver::propagate_properties ()
 }
 
 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;
@@ -494,27 +490,27 @@ Mensural_ligature_engraver::fold_up_primitives ()
        {
 #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)
         {
@@ -532,35 +528,17 @@ Mensural_ligature_engraver::join_primitives ()
 }
 
 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_);
     }
 }
 
index ab39523488dae09c0d6ae903be3914bf59a42f1d..574a38ca2ace76ac359d16189dada1d9550b130b 100644 (file)
@@ -130,7 +130,8 @@ internal_brew_primitive (Grob *me, bool ledger_take_space)
   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 ();
     }
 
@@ -149,7 +150,9 @@ internal_brew_primitive (Grob *me, bool ledger_take_space)
        }
       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");
        }
     }
@@ -163,7 +166,9 @@ internal_brew_primitive (Grob *me, bool ledger_take_space)
        }
       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;
        }
 
@@ -174,7 +179,9 @@ internal_brew_primitive (Grob *me, bool ledger_take_space)
        }
       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;
        }
     }
@@ -205,7 +212,8 @@ internal_brew_primitive (Grob *me, bool ledger_take_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 ();
     }
 
@@ -214,7 +222,7 @@ internal_brew_primitive (Grob *me, bool ledger_take_space)
     {
       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) ?
@@ -222,8 +230,7 @@ internal_brew_primitive (Grob *me, bool ledger_take_space)
        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);
     }
 
index 9d19e641d52443343e62874ab0d98372dccad23b..3a388a9c4c13844c65b2ed69fc1ddba1eb44b827 100644 (file)
 /**
   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_;
diff --git a/lily/vaticana-ligature-engraver.cc b/lily/vaticana-ligature-engraver.cc
new file mode 100644 (file)
index 0000000..69bf875
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+  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 */       "");
diff --git a/lily/vaticana-ligature.cc b/lily/vaticana-ligature.cc
new file mode 100644 (file)
index 0000000..1fe4e19
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+  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");
diff --git a/ly/gregorian-init.ly b/ly/gregorian-init.ly
new file mode 100644 (file)
index 0000000..794c843
--- /dev/null
@@ -0,0 +1,32 @@
+\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
index d53c2e75efd5710963bad38ff86bf9d31fed8abb..3f15e6428b336d1a1fce937323c06d0242ab0401 100644 (file)
@@ -439,7 +439,7 @@ def inclinatum_char(expr verbose_name, internal_name, mudela_name,
                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;
@@ -572,7 +572,8 @@ fet_beginchar("Ed. Vat. quilisma", "vaticana_quilisma", "vatquilismahead")
        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);
@@ -633,7 +634,7 @@ fet_beginchar("Solesmes oriscus", "solesmes_oriscus",
        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;
index 3fad39566d5c674b4aced358f1732abfc2270c40..1beca51e0a83dc354ac90044af614836a7d015c6 100644 (file)
        (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)
index f7034298fdba078e61fed3750055b8d9d3403614..bb569b14eaa68b47f8dab76b6e7cb1586e8284f5 100644 (file)
@@ -76,6 +76,7 @@ This procedure is called (using dependency resolution) after line breaking. Retu
 (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
@@ -84,6 +85,7 @@ these symbols may be alongside-stem, stem, head or loose-end.")
 '(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.")
@@ -147,10 +149,12 @@ square of the inner notes involved.")
 (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.
@@ -262,6 +266,7 @@ name of character within font.")
 ")
 (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.")
@@ -354,6 +359,7 @@ provided in @code{input/regression/molecule-hacking.ly}.
 (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.")
@@ -363,11 +369,13 @@ this column. 10000 or more means forbid linebreak, -10000 or less
 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.")
@@ -385,6 +393,7 @@ reference point.
 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")
@@ -430,6 +439,7 @@ the Nth element of the list gives the amount stem shortening of a note with N fl
 ")
 (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.")
@@ -531,6 +541,7 @@ of booleans, signifying whether this grob should be transparent and have
 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 .")