#include <math.h>
#include <cstdio>
+
using namespace std;
+#include "spacing-options.hh"
#include "international.hh"
#include "main.hh"
#include "moment.hh"
#include "system.hh"
#include "warn.hh"
-
-/*
- TODO:
-
- use callback instead?
-
-*/
-Rational
-Spacing_spanner::effective_shortest_duration (Grob *me,
- Link_array<Grob> const &all)
+vector<Grob*>
+Spacing_spanner::get_columns (Spanner *me)
{
- SCM preset_shortest = me->get_property ("common-shortest-duration");
- Rational global_shortest;
- if (unsmob_moment (preset_shortest))
- global_shortest = unsmob_moment (preset_shortest)->main_part_;
- else
- {
- global_shortest = Spacing_spanner::find_shortest (me, all);
- if (be_verbose_global)
- message (_f ("Global shortest duration is %s", global_shortest.to_string ()) + "\n");
- }
-
- return global_shortest;
+ vector<Grob*> all (get_root_system (me)->columns ());
+ vsize start = binary_search (all, (Grob*)me->get_bound (LEFT),
+ &Paper_column::less_than);
+ vsize end = binary_search (all, (Grob*) me->get_bound (RIGHT),
+ &Paper_column::less_than);
+
+ all = vector<Grob*>::vector<Grob*> (all.begin () + start,
+ all.begin () + end + 1);
+ return all;
}
-
MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs, 1);
SCM
Spacing_spanner::set_springs (SCM smob)
{
- Grob *me = unsmob_grob (smob);
+ Spanner *me = unsmob_spanner (smob);
/*
can't use get_system() ? --hwn.
*/
- Link_array<Grob> all (get_root_system (me)->columns ());
-
+ vector<Grob*> all (get_columns (me));
set_explicit_neighbor_columns (all);
Spacing_options options;
options.init_from_grob (me);
- options.global_shortest_ = effective_shortest_duration (me, all);
prune_loose_columns (me, &all, &options);
set_implicit_neighbor_columns (all);
note has a different duration, but hey, don't write that kind of
stuff, then.
*/
-Rational
-Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
+
+MAKE_SCHEME_CALLBACK (Spacing_spanner, calc_common_shortest_duration, 1);
+SCM
+Spacing_spanner::calc_common_shortest_duration (SCM grob)
{
+ Spanner *me = unsmob_spanner (grob);
+
+ vector<Grob*> cols (get_columns (me));
+
/*
ascending in duration
*/
- std::vector<Rational> durations;
- std::vector<int> counts;
+ vector<Rational> durations;
+ vector<int> counts;
Rational shortest_in_measure;
shortest_in_measure.set_infinite (1);
shortest_in_measure = min (shortest_in_measure, this_shortest.main_part_);
}
else if (!shortest_in_measure.is_infinity ()
- && Item::is_breakable (cols[i]))
+ && Paper_column::is_breakable (cols[i]))
{
vsize j = 0;
for (; j < durations.size (); j++)
if (max_idx >= 0)
d = min (d, durations[max_idx]);
- return d;
+ return Moment (d).smobbed_copy ();
}
void
void
Spacing_spanner::generate_springs (Grob *me,
- Link_array<Grob> const &cols,
+ vector<Grob*> const &cols,
Spacing_options const *options)
{
- Paper_column *next = 0;
- Paper_column *next_next = 0;
- for (vsize i = cols.size (); i--;)
+ Paper_column *prev = 0;
+ for (vsize i = 0; i < cols.size (); i++)
{
Paper_column *col = dynamic_cast<Paper_column *> (cols[i]);
- if (next)
- generate_pair_spacing (me, col, next, next_next, options);
+ Paper_column *next = (i < cols.size()-1) ? dynamic_cast<Paper_column *> (cols[i+1]) : 0;
+
+ if (i > 0)
+ generate_pair_spacing (me, prev, col, next, options);
- next_next = next;
- next = col;
+ prev = col;
}
}
Real compound_fixed_note_space = 0.0;
if (options->stretch_uniformly_)
- compound_note_space = base_note_space;
+ {
+ compound_note_space = base_note_space;
+
+ if (!Paper_column::is_musical (right_col))
+ {
+ /*
+ Crude fix for notes that lead up to barlines and time sigs.
+ */
+ Interval lext = right_col->extent (right_col, X_AXIS);
+ if (!lext.is_empty ())
+ compound_note_space += -lext[LEFT];
+ }
+ }
else
{
int wish_count = 0;
-
+
extract_grob_set (left_col, "right-neighbors", neighbors);
/*
if (compound_note_space < 0 || wish_count == 0)
{
- compound_note_space = base_note_space;
- compound_fixed_note_space = options->increment_;
+
+ if (!Paper_column::is_musical (right_col))
+ {
+ Real left_col_stick_out = robust_relative_extent (left_col, left_col, X_AXIS)[RIGHT];
+ compound_fixed_note_space = max (left_col_stick_out, options->increment_);
+
+ compound_note_space = max (base_note_space,
+ base_note_space - options->increment_ + left_col_stick_out);
+ }
+ else
+ {
+ /*
+ Fixed should be 0.0. If there are no spacing wishes, we're
+ likely dealing with polyphonic spacing of hemiolas.
+
+ We used to have compound_fixed_note_space = options->increment_
+
+ but this can lead to numeric instability problems when we
+ do
+
+ inverse_strength = (compound_note_space - compound_fixed_note_space)
+
+ */
+
+ compound_note_space = base_note_space;
+ compound_fixed_note_space = 0.0;
+ }
}
else if (to_boolean (me->get_property ("average-spacing-wishes")))
{
Spaceable_grob::add_spring (l, r, distance, inverse_strength);
}
-ADD_INTERFACE (Spacing_spanner, "spacing-spanner-interface",
+ADD_INTERFACE (Spacing_spanner,
"The space taken by a note is dependent on its duration. Doubling a\n"
"duration adds spacing-increment to the space. The most common shortest\n"
"note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
"head width) A 16th note is followed by 0.5 note head width. The\n"
"quarter note is followed by 3 NHW, the half by 4 NHW, etc.\n",
+
"average-spacing-wishes "
- "grace-space-factor "
- "spacing-increment "
"base-shortest-duration "
- "strict-note-spacing "
- "shortest-duration-space "
"common-shortest-duration "
- "uniform-stretching "
"packed-spacing "
+ "shortest-duration-space "
+ "spacing-increment "
+ "strict-grace-spacing "
+ "strict-note-spacing "
+ "uniform-stretching "
+
);
-ADD_INTERFACE (Spacing_interface, "spacing-interface",
+ADD_INTERFACE (Spacing_interface,
"Something to do with line breaking and spacing. "
"Kill this one after determining line breaks.",
+
"");