2005-12-23 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ * lily/beam.cc (calc_direction): use default-direction
+ iso. get_default_direction()
+
+ * scm/define-grob-properties.scm (all-user-grob-properties): add
+ default-direction property.
+
+ * scm/define-grobs.scm (all-grob-descriptions): add MelodyItem.
+
+ * lily/stem.cc (calc_default_direction): remove
+ Stem::get_default_direction, use default-direction with callback
+ instead.
+
+ * lily/melody-spanner.cc (calc_neutral_stem_direction):
+
+ * lily/melody-engraver.cc: new file. Acknowledge stems for
+ interpolated stem directions.
+
+ * lily/melody-spanner.cc: new file. Interpolate stem directions.
+
+ * scm/define-grobs.scm (all-grob-descriptions): add MelodyItem
+
* lily/slur-configuration.cc (fit_factor): more robust check for
point in curve X-extent.
}
else
{
- /*
- ugh.
-
- can happen in stem-tremolo case.
- TODO: fixme.
- */
- d = Stem::get_default_dir (stems[0]);
+ d = to_dir (stems[0]->get_property ("default-direction"));
}
}
if (is_direction (stem_dir_scm))
stem_dir = to_dir (stem_dir_scm);
else
- stem_dir = Stem::get_default_dir (s);
+ stem_dir = to_dir (s->get_property ("default-direction"));
+
+ if (!stem_dir)
+ stem_dir = to_dir (s->get_property ("neutral-direction"));
if (stem_dir)
{
/* I can imagine counting those boundaries as a half forced stem,
but let's count them full for now. */
+ Direction defdir = to_dir (s->get_property ("default-direction"));
+
if (abs (Stem::chord_start_y (s)) > 0.1
- && (get_grob_direction (s) != Stem::get_default_dir (s)))
+ && defdir
+ && get_grob_direction (s) != defdir)
f++;
}
return f;
--- /dev/null
+/*
+ melody-spanner.hh -- declare Melody_spanner
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#ifndef MELODY_SPANNER_HH
+#define MELODY_SPANNER_HH
+
+#include "lily-guile.hh"
+#include "lily-proto.hh"
+
+class Melody_spanner
+{
+public:
+ static bool has_interface (Grob*);
+ static void add_stem (Grob*, Grob*);
+ DECLARE_SCHEME_CALLBACK(calc_neutral_stem_direction, (SCM));
+};
+
+#endif /* MELODY_SPANNER_HH */
+
static void set_spacing_hints (Grob *);
DECLARE_SCHEME_CALLBACK (print, (SCM));
+ DECLARE_SCHEME_CALLBACK (calc_default_direction, (SCM));
DECLARE_SCHEME_CALLBACK (offset_callback, (SCM element));
DECLARE_SCHEME_CALLBACK (calc_direction, (SCM));
DECLARE_SCHEME_CALLBACK (calc_beaming, (SCM));
--- /dev/null
+/*
+ melody-engraver.cc -- implement Melody_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 1997--2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+*/
+
+
+#include "engraver.hh"
+
+#include "item.hh"
+#include "melody-spanner.hh"
+
+/**
+ Make stems upon receiving noteheads.
+*/
+class Melody_engraver : public Engraver
+{
+ Grob *melody_item_;
+protected:
+
+ DECLARE_ACKNOWLEDGER (stem);
+ TRANSLATOR_DECLARATIONS (Melody_engraver);
+};
+
+
+Melody_engraver::Melody_engraver ()
+{
+ melody_item_ = 0;
+}
+
+void
+Melody_engraver::acknowledge_stem (Grob_info info)
+{
+ if (!melody_item_)
+ melody_item_ = make_item ("MelodyItem", info.grob ()->self_scm ());
+
+ Melody_spanner::add_stem (melody_item_, info.grob ());
+}
+
+
+#include "translator.icc"
+ADD_ACKNOWLEDGER (Melody_engraver, stem);
+ADD_TRANSLATOR (Melody_engraver,
+ "Create information for context dependent typesetting decisions. ",
+ "MelodyItem",
+ "",
+ "",
+ "");
+
--- /dev/null
+/*
+ melody-spanner.cc -- implement Melody_spanner
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "melody-spanner.hh"
+#include "grob.hh"
+#include "pointer-group-interface.hh"
+
+/*
+ TODO: this could be either item or spanner. For efficiency reasons,
+ let's take item for now.
+*/
+
+
+/*
+ Interpolate stem directions for neutral stems.
+ */
+MAKE_SCHEME_CALLBACK(Melody_spanner,calc_neutral_stem_direction, 1);
+SCM
+Melody_spanner::calc_neutral_stem_direction (SCM smob)
+{
+ Grob *stem = unsmob_grob (smob);
+ Grob *me = unsmob_grob (stem->get_object ("melody-spanner"));
+
+ extract_grob_set (me, "stems", stems);
+
+ Array<Direction> dirs;
+ for (int i = 0; i < stems.size (); i++)
+ {
+ dirs.push (to_dir (stems[i]->get_property ("default-direction")));
+ }
+
+ int last_nonneutral = -1;
+ int next_nonneutral = 0;
+ while (next_nonneutral < dirs.size() && !dirs[next_nonneutral])
+ next_nonneutral ++;
+
+ while (last_nonneutral < dirs.size () - 1)
+ {
+ Direction d1 = CENTER;
+ Direction d2 = CENTER;
+ if (last_nonneutral >= 0)
+ d1 = dirs[last_nonneutral];
+ if (next_nonneutral < dirs.size ())
+ d2 = dirs[next_nonneutral];
+
+ Direction total = CENTER;
+ if (d1 && d1 == d2)
+ total = d1;
+ else if (d1 && !d2)
+ total = d1;
+ else if (d2 && !d1)
+ total = d2;
+ else
+ total = to_dir (me->get_property ("neutral-direction"));
+
+ for (int i = last_nonneutral + 1; i < next_nonneutral; i++)
+ stems[i]->set_property ("neutral-direction", scm_from_int (total));
+
+
+ last_nonneutral = next_nonneutral;
+ while (last_nonneutral < dirs.size ()
+ && dirs[last_nonneutral])
+ last_nonneutral ++;
+ next_nonneutral = last_nonneutral;
+ last_nonneutral --;
+
+ while (next_nonneutral < dirs.size ()
+ && !dirs[next_nonneutral])
+ next_nonneutral ++;
+ }
+
+ me->suicide ();
+ return SCM_UNSPECIFIED;
+}
+
+void
+Melody_spanner::add_stem (Grob *me, Grob *stem)
+{
+ Pointer_group_interface::add_grob (me, ly_symbol2scm ("stems"), stem);
+ stem->set_object ("melody-spanner", me->self_scm ());
+ stem->set_property ("neutral-direction", Melody_spanner::calc_neutral_stem_direction_proc);
+}
+
+ADD_INTERFACE (Melody_spanner, "melody-spanner-interface",
+ "Context dependent typesetting decisions.",
+
+ "stems "
+ "neutral-direction ");
+
+
}
#include "translator.icc"
+
ADD_ACKNOWLEDGER (Stem_engraver, rhythmic_head);
+
ADD_TRANSLATOR (Stem_engraver,
/* doc */ "Create stems and single-stem tremolos. It also works together with "
"the beam engraver for overriding beaming.",
dir = get_grob_direction (me);
}
else
- dir = get_default_dir (me);
+ {
+ SCM dd = me->get_property ("default-direction");
+ dir = to_dir (dd);
+ if (!dir)
+ return me->get_property ("neutral-direction");
+ }
return scm_from_int (dir);
}
-/* A separate function, since this is used elsewhere too. */
-Direction
-Stem::get_default_dir (Grob *me)
+MAKE_SCHEME_CALLBACK(Stem, calc_default_direction, 1);
+SCM
+Stem::calc_default_direction (SCM smob)
{
+ Grob *me = unsmob_grob (smob);
+
Direction dir = CENTER;
int staff_center = 0;
Interval hp = head_positions (me);
if (!hp.is_empty ())
{
- int udistance = (int) (UP *hp[UP] - staff_center);
- int ddistance = (int) (DOWN *hp[DOWN] - staff_center);
+ int udistance = (int) (UP * hp[UP] - staff_center);
+ int ddistance = (int) (DOWN * hp[DOWN] - staff_center);
- if (sign (ddistance - udistance))
- dir = Direction (sign (ddistance - udistance));
- else
- dir = to_dir (me->get_property ("neutral-direction"));
+ dir = Direction (sign (ddistance - udistance));
}
- return dir;
+
+ return scm_from_int (dir);
}
-
MAKE_SCHEME_CALLBACK (Stem, height, 1);
SCM
Stem::height (SCM smob)
"avoid-note-head "
"beam "
"beaming "
+ "default-direction "
"details "
"direction "
"duration-log "
dash-period. Should be between 0.0 (no line) and 1.0 (continuous
line).")
+ (default-direction ,ly:dir? "Direction determined by note head positions.")
(direction ,ly:dir? "Up or down, left or right?")
(dot-color ,symbol? "Color of dots. Options include
@code{black} and @code{white}.")
text-interface
font-interface))))))
+
+ (MeasureGrouping
+ . (
+ (Y-offset . ,Side_position_interface::y_aligned_side)
+ (side-axis . ,Y)
+
+ (stencil . ,Measure_grouping::print)
+
+ (padding . 2)
+ (direction . 1)
+ (thickness . 1)
+ (height . 2.0)
+ (staff-padding . 3)
+ (meta . ((class . Spanner)
+ (interfaces . (side-position-interface
+ measure-grouping-interface))))))
+
+ (MelodyItem
+ . (
+ (neutral-direction . ,DOWN)
+ (meta . ((class . Item)
+ (interfaces . (melody-spanner-interface spacing-interface))))))
(MensuralLigature
. (
(thickness . 1.4)
font-interface
metronome-mark-interface))))))
- (MeasureGrouping
- . (
- (Y-offset . ,Side_position_interface::y_aligned_side)
- (side-axis . ,Y)
-
- (stencil . ,Measure_grouping::print)
-
- (padding . 2)
- (direction . 1)
- (thickness . 1)
- (height . 2.0)
- (staff-padding . 3)
- (meta . ((class . Spanner)
- (interfaces . (side-position-interface
- measure-grouping-interface))))))
(MultiMeasureRest
. (
(Stem
. (
(direction . ,Stem::calc_direction)
+ (default-direction . ,Stem::calc_default_direction)
(stem-end-position . ,Stem::calc_stem_end_position)
(stem-info . ,Stem::calc_stem_info)
(positioning-done . ,Stem::calc_positioning_done)