]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/vaticana-ligature-engraver.cc
* lily/score.cc (default_rendering): clean protection.
[lilypond.git] / lily / vaticana-ligature-engraver.cc
index 9e655406c4a2499e91ca3ab780d5427a64b57f65..8fd1a60d903b8270c68aced28b5a5fd4f497f3d7 100644 (file)
@@ -3,7 +3,7 @@
   
   source file of the GNU LilyPond music typesetter
   
-  (c)  2003 Juergen Reuter <reuter@ipd.uka.de>
+  (c) 2003 Juergen Reuter <reuter@ipd.uka.de>
  */
 
 #include "gregorian-ligature-engraver.hh"
@@ -33,7 +33,7 @@ private:
                    Real thickness);
 
 public:
-  TRANSLATOR_DECLARATIONS(Vaticana_ligature_engraver);
+  TRANSLATOR_DECLARATIONS (Vaticana_ligature_engraver);
 
 protected:
   virtual Spanner *create_ligature_spanner ();
@@ -48,7 +48,7 @@ Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
 Spanner *
 Vaticana_ligature_engraver::create_ligature_spanner ()
 {
-  return new Spanner (get_property ("VaticanaLigature"));
+  return make_spanner ("VaticanaLigature");
 }
 
 bool
@@ -92,20 +92,48 @@ Vaticana_ligature_engraver::is_stacked_head (int prefix_set,
       return is_stacked_b;
 }
 
-inline int get_context_info (Item *primitive)
+/*
+ * When aligning the heads, sometimes extra space is needed, e.g. to
+ * avoid clashing with the appendix of an adjacent notehead or with an
+ * adjacent notehead itself if it has the same pitch.  Extra space is
+ * added at most once between to heads.
+ */
+bool
+need_extra_space (int prev_prefix_set, int prefix_set,
+                 int context_info, int delta_pitch)
 {
-  SCM context_info_scm = primitive->get_grob_property ("context-info");
-  if (context_info_scm != SCM_EOL)
-    {
-      return gh_scm2int (context_info_scm);
-    }
-  else
-    {
-      primitive->programming_error ("Vaticana_ligature:"
-                                   "context-info undefined -> "
-                                   "aborting ligature");
-      return -1;
-    }
+  if (prev_prefix_set & VIRGA)
+    /*
+     * After a virga, make a an additional small space such that the
+     * appendix on the right side of the head does not touch the
+     * following head.
+     */
+    return true;
+
+  if ((prefix_set & INCLINATUM) &&
+          !(prev_prefix_set & INCLINATUM))
+    /*
+     * Always start a series of inclinatum heads with an extra space.
+     */
+    return true;
+
+  if ((context_info & FLEXA_LEFT) && !(context_info & PES_UPPER))
+    /*
+     * Before a flexa (but not within a torculus), make a an
+     * additional small space such that the appendix on the left side
+     * of the flexa does not touch the this head.
+     */
+    return true;
+
+  if (delta_pitch == 0)
+    /*
+     * If there are two adjacent noteheads with the same pitch, add
+     * additional small space between them, such that they do not
+     * touch each other.
+     */
+    return true;
+
+  return false;
 }
 
 Real
@@ -143,19 +171,20 @@ Vaticana_ligature_engraver::align_heads (Array<Grob_info> primitives,
   Real ligature_width = 0.0;
 
   Item *prev_primitive = 0;
+  int prev_prefix_set = 0;
   for (int i = 0; i < primitives.size (); i++)
     {
       Item *primitive = dynamic_cast<Item*> (primitives[i].grob_);
-      int context_info;
-
-      if ((context_info = get_context_info (primitive)) < 0)
-       break; // programming error
+      int prefix_set =
+       gh_scm2int (primitive->get_property ("prefix-set"));
+      int context_info =
+       gh_scm2int (primitive->get_property ("context-info"));
 
       /*
        * Get glyph_name, delta_pitch and context_info for this head.
        */
 
-      SCM glyph_name_scm = primitive->get_grob_property ("glyph-name");
+      SCM glyph_name_scm = primitive->get_property ("glyph-name");
       if (glyph_name_scm == SCM_EOL)
        {
          primitive->programming_error ("Vaticana_ligature:"
@@ -168,7 +197,7 @@ Vaticana_ligature_engraver::align_heads (Array<Grob_info> primitives,
       int delta_pitch = 0;
       if (prev_primitive) /* urgh, need prev_primitive only here */
        {
-         SCM delta_pitch_scm = prev_primitive->get_grob_property ("delta-pitch");
+         SCM delta_pitch_scm = prev_primitive->get_property ("delta-pitch");
          if (delta_pitch_scm != SCM_EOL)
            {
              delta_pitch = gh_scm2int (delta_pitch_scm);
@@ -228,7 +257,7 @@ Vaticana_ligature_engraver::align_heads (Array<Grob_info> primitives,
       /*
        * Save the head's final x-offset.
        */
-      primitive->set_grob_property ("x-offset",
+      primitive->set_property ("x-offset",
                                    gh_double2scm (x_offset));
 
       /*
@@ -247,8 +276,8 @@ Vaticana_ligature_engraver::align_heads (Array<Grob_info> primitives,
            }
          else
            {
-             prev_primitive->set_grob_property ("add-join",
-                                                gh_bool2scm(true));
+             prev_primitive->set_property ("add-join",
+                                                gh_bool2scm (true));
 
              /*
               * Create a small overlap of adjacent heads so that the join
@@ -267,37 +296,9 @@ Vaticana_ligature_engraver::align_heads (Array<Grob_info> primitives,
           */
        }
 
-      /* Sometimes, extra space is needed, e.g. to avoid clashing with
-        the appendix of an adjacent notehead or with an adjacent
-        notehead itself if it has the same pitch. */
-
-      if (context_info & AFTER_VIRGA)
-       {
-         /*
-          * After a virga, make a an additional small space such that
-          * the appendix on the right side of the head does not touch
-          * the following head.
-          */
-         ligature_width += extra_space;
-       }
-      else if ((context_info & FLEXA_LEFT) && !(context_info & PES_UPPER))
-       {
-         /*
-          * Before a flexa (but not within a torculus), make a an
-          * additional small space such that the appendix on the left
-          * side of the flexa does not touch the this head.
-          */
-         ligature_width += extra_space;
-       }
-      else if (delta_pitch == 0)
-       {
-         /*
-          * If there are two adjacent noteheads with the same pitch,
-          * add additional small space between them, such that they
-          * do not touch each other.
-          */
-         ligature_width += extra_space;
-       }
+      if (need_extra_space (prev_prefix_set, prefix_set,
+                           context_info, delta_pitch))
+       ligature_width += extra_space;
 
       /*
        * Horizontally line-up this head to form a ligature.
@@ -307,6 +308,7 @@ Vaticana_ligature_engraver::align_heads (Array<Grob_info> primitives,
       ligature_width += head_width;
 
       prev_primitive = primitive;
+      prev_prefix_set = prefix_set;
     }
 
   /*
@@ -318,48 +320,49 @@ Vaticana_ligature_engraver::align_heads (Array<Grob_info> primitives,
   return ligature_width;
 }
 
+/*
+ * Depending on the typographical features of a particular ligature
+ * style, some prefixes may be ignored.  In particular, if a curved
+ * flexa shape is produced, any prefixes to either of the two
+ * contributing heads that would select a head other than punctum, is
+ * by definition ignored.
+ *
+ * This function prints a warning, if the given primitive is prefixed
+ * such that a head other than punctum would be chosen, if this
+ * primitive were engraved as a stand-alone head.
+ */
 void
-Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
-                                            Array<Grob_info> primitives)
+check_for_prefix_loss (Item *primitive)
 {
-  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
+  int prefix_set =
+    gh_scm2int (primitive->get_property ("prefix-set"));
+  if (prefix_set & ~PES_OR_FLEXA)
     {
-      ligature->programming_error ("Vaticana_ligature_engraver:"
-                                  "flexa-width undefined; "
-                                  "assuming 2.0 staff space");
-      flexa_width =
-       2.0 * Staff_symbol_referencer::staff_space (ligature);
+      String prefs = Gregorian_ligature::prefixes_to_str (primitive);
+      primitive->warning (_f ("ignored prefix (es) `%s' of this head according "
+                             "to restrictions of the selected ligature style",
+                             prefs.to_str0 ()));
     }
+}
 
-  Real thickness;
-  SCM thickness_scm = ligature->get_grob_property ("thickness");
-  if (thickness_scm != SCM_EOL)
-    {
-      thickness = gh_scm2double (thickness_scm);
-    }
-  else
-    {
-      ligature->programming_error ("Vaticana_ligature_engraver:"
-                                  "thickness undefined; assuming 1.0");
-      thickness = 1.0;
-    }
+void
+Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
+                                            Array<Grob_info> primitives)
+{
+  Real flexa_width= robust_scm2double ( ligature->get_property ("flexa-width"), 2);
+
+  Real thickness= robust_scm2double ( ligature->get_property ("thickness"), 1);
 
   Item *prev_primitive = 0;
   int prev_prefix_set = 0;
   int prev_context_info = 0;
   int prev_delta_pitch = 0;
   String prev_glyph_name = "";
-  for (int i = 0; i < primitives.size(); i++) {
+  for (int i = 0; i < primitives.size (); i++) {
     Item *primitive = dynamic_cast<Item*> (primitives[i].grob_);
 
     int delta_pitch;
-    SCM delta_pitch_scm = primitive->get_grob_property ("delta-pitch");
+    SCM delta_pitch_scm = primitive->get_property ("delta-pitch");
     if (delta_pitch_scm != SCM_EOL)
       {
        delta_pitch = gh_scm2int (delta_pitch_scm);
@@ -374,13 +377,13 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
 
     /* retrieve & complete prefix_set and context_info */
     int prefix_set =
-      gh_scm2int (primitive->get_grob_property ("prefix-set"));
+      gh_scm2int (primitive->get_property ("prefix-set"));
     int context_info =
-      gh_scm2int (primitive->get_grob_property ("context-info"));
+      gh_scm2int (primitive->get_property ("context-info"));
     if (is_stacked_head (prefix_set, context_info))
       {
        context_info |= STACKED_HEAD;
-       primitive->set_grob_property ("context-info",
+       primitive->set_property ("context-info",
                                      gh_int2scm (context_info));
       }
 
@@ -394,7 +397,7 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
     if (prefix_set & VIRGA)
       {
        glyph_name = "vaticana_punctum";
-       primitive->set_grob_property ("add-stem", gh_bool2scm(true));
+       primitive->set_property ("add-stem", gh_bool2scm (true));
       }
     else if (prefix_set & QUILISMA)
       glyph_name = "vaticana_quilisma";
@@ -455,8 +458,8 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
               * Therefore, the following line of code should be
               * placed somewhere else.
               */
-             prev_primitive->set_grob_property ("add-cauda",
-                                                gh_bool2scm(false));
+             prev_primitive->set_property ("add-cauda",
+                                                gh_bool2scm (false));
            }
          glyph_name = "vaticana_reverse_plica";
        }
@@ -487,7 +490,7 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
      */
     if ((context_info & FLEXA_LEFT) && !(context_info & PES_UPPER))
       if (!String::compare (glyph_name, "vaticana_punctum"))
-       primitive->set_grob_property ("add-cauda", gh_bool2scm(true));
+       primitive->set_property ("add-cauda", gh_bool2scm (true));
 
     /*
      * Execptional rule for porrectus:
@@ -498,15 +501,19 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
      */
     if ((context_info & FLEXA_RIGHT) && (context_info & PES_LOWER))
       {
-       glyph_name = "";
+       check_for_prefix_loss (prev_primitive);
        prev_glyph_name = "flexa";
-       prev_primitive->set_grob_property ("flexa-height",
+       prev_primitive->set_property ("flexa-height",
                                           gh_int2scm (prev_delta_pitch));
-       prev_primitive->set_grob_property ("flexa-width",
+       prev_primitive->set_property ("flexa-width",
                                           gh_double2scm (flexa_width));
        bool add_cauda = !(prev_prefix_set && PES_OR_FLEXA);
-       prev_primitive->set_grob_property ("add-cauda",
+       prev_primitive->set_property ("add-cauda",
                                           gh_bool2scm (add_cauda));
+       check_for_prefix_loss (primitive);
+       glyph_name = "";
+       primitive->set_property ("flexa-width",
+                                     gh_double2scm (flexa_width));
       }
 
     /*
@@ -530,7 +537,7 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
       }
 
     if (prev_primitive)
-      prev_primitive->set_grob_property ("glyph-name",
+      prev_primitive->set_property ("glyph-name",
                                         scm_makfrom0str (prev_glyph_name.to_str0 ()));
 
     /*
@@ -539,7 +546,7 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
      * 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 (thickness));
+    primitive->set_property ("thickness", gh_double2scm (thickness));
 
     prev_primitive = primitive;
     prev_prefix_set = prefix_set;
@@ -548,7 +555,7 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
     prev_glyph_name = glyph_name;
   }
 
-  prev_primitive->set_grob_property ("glyph-name",
+  prev_primitive->set_property ("glyph-name",
                                     scm_makfrom0str (prev_glyph_name.to_str0 ()));
 
 #if 0
@@ -558,15 +565,15 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
   align_heads (primitives, flexa_width, thickness);
 
 #if 0 // experimental code to collapse spacing after ligature
-  /* TODO: set to max(old/new spacing-increment), since other
+  /* TODO: set to max (old/new spacing-increment), since other
      voices/staves also may want to set this property. */
   Item *first_primitive = dynamic_cast<Item*> (primitives[0].grob_);
-  Paper_column *paper_column = first_primitive->get_column();
+  Paper_column *paper_column = first_primitive->get_column ();
   paper_column->warning (_f ("Vaticana_ligature_engraver: "
                             "setting `spacing-increment = %f': ptr=%ul",
                             ligature_width, paper_column));
   paper_column->
-    set_grob_property("forced-spacing", gh_double2scm (ligature_width));
+    set_property ("forced-spacing", gh_double2scm (ligature_width));
 #endif
 }
 
@@ -574,7 +581,7 @@ Vaticana_ligature_engraver::transform_heads (Spanner *ligature,
 ENTER_DESCRIPTION (Vaticana_ligature_engraver,
 /* descr */       "Handles ligatures by glueing special ligature heads together.",
 /* creats*/       "VaticanaLigature",
-/* accepts */     "ligature-event abort-event",
+/* accepts */     "ligature-event",
 /* acks  */      "note-head-interface rest-interface",
 /* reads */       "",
 /* write */       "");