source file of the GNU LilyPond music typesetter
- (c) 2002--2003 Juergen Reuter <reuter@ipd.uka.de>
+ (c) 2002--2004 Juergen Reuter <reuter@ipd.uka.de>
*/
#include "mensural-ligature.hh"
-#include "ligature-engraver.hh"
+#include "coherent-ligature-engraver.hh"
#include "event.hh"
#include "warn.hh"
#include "item.hh"
#include "rhythmic-head.hh"
#include "note-head.hh"
#include "staff-symbol-referencer.hh"
-#include "paper-def.hh"
+#include "output-def.hh"
#include "font-interface.hh"
/*
- * TODO: local accidentals: collect accidentals that occur within a
- * ligature and put them before the ligature. If an accidental
- * changes within a ligature, print a warning (user error) and ignore
- * any further accidental for that pitch within that ligature
- * (actually, in such a case, the user should split the ligature into
- * two separate ligatures). Similarly, any object that, in ordinary
- * notation, may be put to the left or to the right of a
- * note-head/ligature-head, should be collected and put before or
- * after the ligature.
- *
- * TODO: make spacing more robust: do not screw up spacing if user
- * erroneously puts rest in ligature.
- *
* TODO: My resources on Franco of Cologne's rules claim that his
* rules map ligature<->mensural timing in a non-ambigous way, but in
* fact, as presented in these resources, the rules become ambigous as
*
* TODO: prohibit multiple voices within a ligature.
*
- * TODO: for each ligature, add Rod that represents the total length
- * of the ligature (to preemptively avoid collision with adjacent
- * notes); or maybe just additionally create a mensural-ligature grob
- * (via Mensural_ligature::brew_molecule(SCM)) that just consists of a
- * bounding box around all primitives of the ligature.
- *
* TODO: enhance robustness: in case of an illegal ligature (e.g. the
* user events for a ligature that contains a minima or STATE_ERROR
* is reached), automatically break the ligature into smaller, valid
* pieces.
- *
- * TODO: In the future, there will be further ligature engravers
- * implemented, such as a Vaticana_ligature_engraver. There will be
- * redundant code between these engravers and the
- * Mensural_ligature_engraver. In particular these are functions
- * set_column_, fold_up_primitives, join_primitives, and
- * ackowledge_grob; further the code for handling accidentals. It is
- * not appropriate to put these things into Ligature_engraver, since,
- * for example, Ligature_bracket_engraver does not share any of this
- * code. Hence, we might to introduce a further subclass of
- * Ligature_engraver which serves as super class for
- * Mensural_ligature_engraver, Vaticana_ligature_engraver, among
- * others.
*/
-class Mensural_ligature_engraver : public Ligature_engraver
+class Mensural_ligature_engraver : public Coherent_ligature_engraver
{
protected:
virtual Spanner *create_ligature_spanner ();
- virtual void typeset_ligature (Spanner *ligature,
- Array<Grob_info> primitives);
+ virtual void build_ligature (Spanner *ligature, Array<Grob_info> primitives);
public:
- TRANSLATOR_DECLARATIONS(Mensural_ligature_engraver);
+ TRANSLATOR_DECLARATIONS (Mensural_ligature_engraver);
private:
int apply_transition (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);
};
Spanner *
Mensural_ligature_engraver::create_ligature_spanner ()
{
- return new Spanner (get_property ("MensuralLigature"));
-}
-
-/*
- * TODO: move this function to class Item?
- */
-void
-Mensural_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);
- }
+ return make_spanner ("MensuralLigature", SCM_EOL);
}
/*
programming_error ("last_primitive undefined");
break;
}
- last_primitive->set_grob_property ("primitive", gh_int2scm (output));
+ last_primitive->set_property ("primitive", scm_int2num (output));
break;
case MLP_BB:
case MLP_LB:
programming_error ("primitive undefined");
break;
}
- last_primitive->set_grob_property ("primitive", gh_int2scm (output));
- primitive->set_grob_property ("primitive", gh_int2scm (MLP_NONE));
+ last_primitive->set_property ("primitive", scm_int2num (output));
+ primitive->set_property ("primitive", scm_int2num (MLP_NONE));
break;
case MLP_SS:
// delayed primitive with two note heads
programming_error ("last_primitive undefined");
break;
}
- last_last_primitive->set_grob_property ("primitive", gh_int2scm (output));
- last_primitive->set_grob_property ("primitive", gh_int2scm (MLP_NONE));
+ last_last_primitive->set_property ("primitive", scm_int2num (output));
+ last_primitive->set_property ("primitive", scm_int2num (MLP_NONE));
break;
default:
programming_error (_f ("unexpected case fall-through"));
}
else
{
- pitch = *unsmob_pitch (nr->get_mus_property ("pitch"));
+ pitch = *unsmob_pitch (nr->get_property ("pitch"));
have_pitch = 1;
}
// TODO: if (state == STATE_ERROR) { ... }
}
-void set_delta_pitch (Item *primitive, Grob_info info1, Grob_info info2)
-{
- Pitch pitch1 = *unsmob_pitch (info1.music_cause ()->get_mus_property ("pitch"));
- Pitch pitch2 = *unsmob_pitch (info2.music_cause ()->get_mus_property ("pitch"));
- int delta_pitch = (pitch2.steps () - pitch1.steps ());
- primitive->set_grob_property ("delta-pitch", gh_int2scm (delta_pitch));
-}
-
/*
- * A MensuralLigature grob consists of a bunch of LigatureHead grobs
- * that are glued together. It (a) does not make sense to change
+ * A MensuralLigature grob consists of a bunch of NoteHead grobs 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
* e.g. the MensuralLigature (as in contrast to e.g. LigatureBracket),
- * and therefore should not be handled in the generic LigatureHead
- * (which is also used by LigatureBracket). Therefore, we let the
- * user control these properties via the concrete Ligature grob (like
+ * and therefore should not be handled in the NoteHead code (which is
+ * also used by LigatureBracket). Therefore, we let the user control
+ * these properties via the concrete Ligature grob (like
* MensuralLigature) and then copy these properties as necessary to
- * each of the LigatureHead grobs. This is what
- * propagate_properties() does.
+ * each of the NoteHead grobs. This is what
+ * propagate_properties () does.
*/
void
Mensural_ligature_engraver::propagate_properties (Spanner *ligature,
Array<Grob_info> primitives)
{
- SCM thickness_scm = ligature->get_grob_property ("thickness");
- Real thickness = (thickness_scm != SCM_EOL) ?
- gh_scm2double (thickness_scm) : 1.4;
- thickness *= ligature->get_paper ()->get_var ("linethickness");
+ Real thickness = robust_scm2double (ligature->get_property ("thickness"), 1.4);
+ thickness *= ligature->get_paper ()->get_dimension (ly_symbol2scm ("linethickness"));
Real head_width =
Font_interface::get_default_font (ligature)->
find_by_name ("noteheads--1mensural").extent (X_AXIS).length ();
- 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;
+ Real flexa_width = robust_scm2double (ligature->get_property ("flexa-width"), 2);
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++)
{
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));
+ int output = ly_scm2int (primitive->get_property ("primitive"));
+ primitive->set_property ("thickness",
+ scm_make_real (thickness));
switch (output) {
case MLP_NONE:
- primitive->set_grob_property ("head-width",
- gh_double2scm (half_flexa_width));
+ primitive->set_property ("head-width",
+ scm_make_real (half_flexa_width));
break;
case MLP_sc:
case MLP_ss:
case MLP_cs:
- primitive->set_grob_property ("head-width",
- gh_double2scm (head_width));
+ primitive->set_property ("head-width",
+ scm_make_real (head_width));
break;
case MLP_BB:
case MLP_LB:
case MLP_SS:
- primitive->set_grob_property ("head-width",
- gh_double2scm (half_flexa_width));
- primitive->set_grob_property ("flexa-width",
- gh_double2scm (flexa_width));
- set_delta_pitch (primitive,
- primitives[i], primitives[i+1]);
+ primitive->set_property ("head-width",
+ scm_make_real (half_flexa_width));
+ primitive->set_property ("flexa-width",
+ scm_make_real (flexa_width));
break;
default:
programming_error (_f ("unexpected case fall-through"));
if (i > 0)
{
-#if 0
- Rod r;
- 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);
}
distance +=
- gh_scm2double (current->get_grob_property ("head-width")) -
- gh_scm2double (current->get_grob_property ("thickness"));
+ ly_scm2double (current->get_property ("head-width")) -
+ ly_scm2double (current->get_property ("thickness"));
}
}
for (int i = 0; i < primitives.size (); i++)
{
Grob_info info = primitives[i];
- Pitch pitch = *unsmob_pitch (info.music_cause ()->get_mus_property ("pitch"));
+ Pitch pitch = *unsmob_pitch (info.music_cause ()->get_property ("pitch"));
if (i > 0)
{
Item *primitive = dynamic_cast<Item*> (info.grob_);
- int output = gh_scm2int (primitive->get_grob_property ("primitive"));
+ int output = ly_scm2int (primitive->get_property ("primitive"));
if (output & MLP_ANY)
{
int delta_pitch = (pitch.steps () - last_pitch.steps ());
- primitive->set_grob_property ("join-left",
- gh_int2scm (delta_pitch));
+ primitive->set_property ("join-left-amount",
+ scm_int2num (delta_pitch));
}
}
last_pitch = pitch;
}
void
-Mensural_ligature_engraver::typeset_ligature (Spanner *ligature,
- Array<Grob_info> primitives)
+Mensural_ligature_engraver::build_ligature (Spanner *ligature,
+ Array<Grob_info> 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_);
- }
}
ENTER_DESCRIPTION (Mensural_ligature_engraver,
/* descr */ "Handles Mensural_ligature_events by glueing special ligature heads together.",
/* creats*/ "MensuralLigature",
-/* accepts */ "ligature-event abort-event",
-/* acks */ "ligature-head-interface note-head-interface rest-interface",
+/* accepts */ "ligature-event",
+/* acks */ "note-head-interface rest-interface",
/* reads */ "",
/* write */ "");