a little baroque, but it might come in handy later on?
*/
-
class Spacing_spanner
{
public:
+ static void standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
+ Real * fixed, Real * space, Moment);
+
+
static Real default_bar_spacing (Grob*,Grob*,Grob*,Moment);
static Real note_spacing (Grob*,Grob*,Grob*,Moment, bool*);
static Real get_duration_space (Grob*,Moment dur, Rational shortest, bool*);
static Rational find_shortest (Link_array<Grob> const &);
- static void breakable_column_spacing (Item* l, Item *r);
+ static void breakable_column_spacing (Grob*, Item* l, Item *r, Moment);
static void find_loose_columns () {}
- static void prune_loose_colunms (Link_array<Grob> *cols);
+ static void prune_loose_colunms (Grob*,Link_array<Grob> *cols, Rational);
static void find_loose_columns (Link_array<Grob> cols);
static void set_explicit_neighbor_columns (Link_array<Grob> cols);
static void set_implicit_neighbor_columns (Link_array<Grob> cols);
static void do_measure (Rational, Grob*me,Link_array<Grob> *cols);
+ static void musical_column_spacing (Grob*,Item*,Item*, Real, Rational);
DECLARE_SCHEME_CALLBACK (set_springs, (SCM ));
};
the column containing the clef is really loose, and should be
attached right to the first column, but that is a lot of work for
- such a borderline case.
-
- )
+ such a borderline case.)
*/
if (!gh_pair_p (lns) || !gh_pair_p (rns))
some cases (two isolated, consecutive clef changes) won't be
nicely folded, but hey, then don't do that.
*/
- if( (Paper_column::musical_b (l_neighbor) || Item::breakable_b (l_neighbor))
+ if ((Paper_column::musical_b (l_neighbor) || Item::breakable_b (l_neighbor))
&& (Paper_column::musical_b (r_neighbor) || Item::breakable_b (r_neighbor)))
{
return true;
between.
*/
void
-Spacing_spanner::prune_loose_colunms (Link_array<Grob> *cols)
+Spacing_spanner::prune_loose_colunms (Grob*me,Link_array<Grob> *cols, Rational shortest)
{
Link_array<Grob> newcols;
-
+ Real increment = gh_scm2double (me->get_grob_property ("spacing-increment"));
for (int i=0; i < cols->size (); i++)
{
if (Item::breakable_b (cols->elem(i)) || Paper_column::musical_b (cols->elem (i)))
do
{
dists[d] = 0.0;
- Grob *lc = (d == LEFT) ? next_door[LEFT] : c;
- Grob *rc = d == LEFT ? c : next_door[RIGHT];
+ Item *lc = dynamic_cast<Item*> ((d == LEFT) ? next_door[LEFT] : c);
+ Item *rc = dynamic_cast<Item*> (d == LEFT ? c : next_door[RIGHT]);
for (SCM s = lc->get_grob_property ("spacing-wishes");
gh_pair_p (s); s = gh_cdr (s))
|| Note_spacing::right_column (sp) != rc)
continue;
- dists[d] = dists[d] >? Note_spacing::get_spacing (sp);
+ Real space, fixed;
+ fixed = 0.0;
+ bool dummy;
+
+ if (d == LEFT)
+ {
+ /*
+ The note spacing should be taken from the musical
+ columns.
+
+ */
+ Real base = note_spacing (me, lc, rc, shortest, &dummy);
+ Note_spacing::get_spacing (sp, rc, base, increment, &space, &fixed);
+
+ space -= increment;
+
+ dists[d] = dists[d] >? space;
+ }
+ else
+ {
+ Real space, fixed_space;
+ Staff_spacing::get_spacing_params (sp,
+ &space, &fixed_space);
+
+ dists[d] = dists[d] >? fixed_space;
+ }
+
}
}
while (flip (&d) != LEFT);
Link_array<Grob> all (me->pscore_l_->line_l_->column_l_arr ()) ;
set_explicit_neighbor_columns (all);
- prune_loose_colunms (&all);
- set_implicit_neighbor_columns (all);
Rational global_shortest = find_shortest (all);
+ prune_loose_colunms (me, &all, global_shortest);
+ set_implicit_neighbor_columns (all);
+
int j = 0;
for (int i = 1; i < all.size (); i++)
return d;
}
+/*
+ Generate spacing for a single measure. We used to have code that did
+ per-measure spacing. Now we have piecewise spacing. We should fix
+ this to support "spacing-regions": some regions have different notes
+ (different time sigs) than others, and should be spaced differently.
+ */
void
Spacing_spanner::do_measure (Rational shortest, Grob*me, Link_array<Grob> *cols)
{
if (!Paper_column::musical_b (l))
{
- breakable_column_spacing (l, r);
+ breakable_column_spacing (me, l, r, shortest);
/*
Item *rb = r->find_prebroken_piece (LEFT);
if (lb)
- breakable_column_spacing (lb,r);
+ breakable_column_spacing (me, lb,r, shortest);
if (rb)
- breakable_column_spacing (l, rb);
+ breakable_column_spacing (me, l, rb, shortest);
if (lb && rb)
- breakable_column_spacing (lb, rb);
+ breakable_column_spacing (me, lb, rb, shortest);
continue ;
}
- bool expand_only = false;
- Real note_space = note_spacing (me, lc, rc, shortest, &expand_only);
-
- Real hinterfleisch = note_space;
-
- SCM seq = lc->get_grob_property ("right-neighbors");
- /*
- hinterfleisch = hind-meat = amount of space following a note.
-
-
- We adjust the space following a note only if the next note
- happens after the current note (this is set in the grob
- property SPACING-SEQUENCE. */
+ musical_column_spacing (me, lc, rc, headwid, shortest);
+ if (Item *rb = r->find_prebroken_piece (LEFT))
+ musical_column_spacing (me, lc, rb, headwid, shortest);
+ }
+}
- Real stretch_distance = note_space;
- hinterfleisch = -1.0;
- Real max_factor = 0.0;
- for (SCM s = seq; gh_pair_p (s); s = ly_cdr (s))
- {
- Grob * wish = unsmob_grob (gh_car (s));
+/*
+ Generate the space between two musical columns LC and RC, given spacing parameters INCR and SHRTEST.
+ */
+void
+Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real increment, Rational shortest)
+{
+ bool expand_only = false;
+ Real base_note_space = note_spacing (me, lc, rc, shortest, &expand_only);
- if (Note_spacing::left_column (wish) != lc
- || Note_spacing::right_column (wish) != rc)
- continue;
+ Real max_note_space = -infinity_f;
+ Real max_fixed_note_space = -infinity_f;
- /*
- This is probably a waste of time in the case of polyphonic
- music. */
- if (Note_spacing::has_interface (wish))
- {
- hinterfleisch = hinterfleisch >?
- ( - headwid +
+ SCM seq = lc->get_grob_property ("right-neighbors");
- (note_space + Note_spacing::get_spacing (wish))
- *gh_scm2double (wish->get_grob_property ("space-factor"))
+ /*
+ We adjust the space following a note only if the next note
+ happens after the current note (this is set in the grob
+ property SPACING-SEQUENCE.
+ */
+ for (SCM s = seq; gh_pair_p (s); s = ly_cdr (s))
+ {
+ Grob * wish = unsmob_grob (gh_car (s));
- + Note_spacing::stem_dir_correction (wish));
- }
- }
+ Item *wish_rcol = Note_spacing::right_column (wish);
+ if (Note_spacing::left_column (wish) != lc
+ || (wish_rcol != rc && wish_rcol != rc->original_l_))
+ continue;
- if (hinterfleisch < 0)
+ /*
+ This is probably a waste of time in the case of polyphonic
+ music. */
+ if (Note_spacing::has_interface (wish))
{
- // maybe should issue a programming error.
- hinterfleisch = note_space;
+ Real space =0.0;
+ Real fixed =0.0;
+
+ Note_spacing::get_spacing (wish, rc, base_note_space, increment, &space, &fixed);
+ max_note_space = max_note_space >? space;
+ max_fixed_note_space = max_fixed_note_space >? fixed;
}
- else
- stretch_distance -= headwid; // why?
- if (max_factor == 0.0)
- max_factor = 1.0;
+ }
+
+ if (max_note_space < 0)
+ {
+ max_note_space = base_note_space;
+ max_fixed_note_space = increment;
+ }
+
+ Spaceable_grob::add_spring (lc, rc, max_note_space, 1 / (max_note_space -max_fixed_note_space), expand_only);
+}
+
+void
+Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
+ Real * fixed, Real * space,
+ Moment shortest)
+{
+ *fixed = l->extent (l, X_AXIS)[RIGHT] - r->extent (r, X_AXIS)[LEFT];
- Spaceable_grob::add_spring (l, r, max_factor * hinterfleisch, 1 / stretch_distance, expand_only);
+ if (l->breakable_b (l) && r->breakable_b(r))
+ {
+ Moment *dt = unsmob_moment (l->get_grob_property ("measure-length"));
+ Moment mlen (1);
+ if (dt)
+ mlen = *dt;
+
+ Real incr = gh_scm2double (me->get_grob_property ("spacing-increment"));
- /*
- TODO: we should have a separate routine determining this distance!
- */
- if (Item *rb = r->find_prebroken_piece (LEFT))
- {
- Spaceable_grob::add_spring (l, rb, max_factor * hinterfleisch, 1 / stretch_distance, expand_only);
- }
+ *space = *fixed + incr * double (mlen.main_part_ / shortest.main_part_) * 0.8;
}
+ else
+ {
+ Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
+ bool dummy;
+ *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
+ }
+
+
}
+
/*
- Read hints from L (todo: R) and generate springs.
+ Read hints from L and generate springs.
*/
void
-Spacing_spanner::breakable_column_spacing (Item* l, Item *r)
+Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shortest)
{
Real max_fixed = -infinity_f;
Real max_space = -infinity_f;
+
+ standard_breakable_column_spacing (me, l, r, &max_fixed, &max_space ,
+ shortest);
for (SCM s = l->get_grob_property ("spacing-wishes");
gh_pair_p (s); s = gh_cdr (s))
{
- Grob * spacing_grob = unsmob_grob (gh_car (s));
+ Item * spacing_grob = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
continue;
Real space;
Real fixed_space;
+ /*
+ column for the left one settings should be ok due automatic
+ pointer munging.
+
+ */
+ assert (spacing_grob-> column_l () == l);
+
Staff_spacing::get_spacing_params (spacing_grob,
&space, &fixed_space);
if (space > max_space)
}
}
+
+
+
if (isinf (max_space))
{
programming_error ("No pref spacing found");
max_fixed = 1.0;
}
+
+ if (l->break_status_dir() == RIGHT
+ && Paper_column::when_mom (l) == Paper_column::when_mom (r))
+ {
+ /* Start of line: this space is not stretchable */
+ max_fixed = max_space;
+ }
+
+ /*
+ Hmm. we do 1/0 in the next thing. Perhaps we should check if this
+ works on all architectures.
+ */
+
Spaceable_grob::add_spring (l, r, max_space, 1/(max_space - max_fixed), false);
}
programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).str ());
shortest_playing_len = 1;
}
-
- Moment delta_t = Paper_column::when_mom (rc) - Paper_column::when_mom (lc);
+
+ Moment lwhen = Paper_column::when_mom (lc);
+ Moment rwhen = Paper_column::when_mom (rc);
+
+ Moment delta_t = rwhen - lwhen;
Real dist = 0.0;
- if (delta_t.main_part_)
+ if (delta_t.main_part_ && !lwhen.grace_part_)
{
dist = get_duration_space (me, shortest_playing_len, shortest.main_part_, expand_only);
dist *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
return dist;
}
+
+
+ADD_INTERFACE (Spacing_spanner,"spacing-spanner-interface",
+ " SPACE = arithmetic_multiplier * ( C + log2 (TIME) ))
+The space taken by a note is determined by the formula
+
+
+
+where TIME is the amount of time a note occupies. The value of C is
+chosen such that the smallest space within a measure is
+arithmetic_basicspace:
+
+C = arithmetic_basicspace - log2 (mininum (SHORTEST, 1/8))
+
+The smallest space is the one following the shortest note in the
+measure, or the space following a hypothetical 1/8 note. Typically
+arithmetic_basicspace is set to a value so that the shortest note
+takes about two noteheads of space (ie, is followed by a notehead of
+space):
+
+@example
+2*quartwidth = arithmetic_multiplier * ( C + log2 (SHORTEST) ))
+
+@{ using: C = arithmetic_basicspace - log2 (mininum (SHORTEST, 1/8)) @}
+@{ assuming: SHORTEST <= 1/8 @}
+
+= arithmetic_multiplier *
+( arithmetic_basicspace - log2 (SHORTEST) + log2 (SHORTEST) )
+
+= arithmetic_multiplier * arithmetic_basicspace
+
+@{ choose: arithmetic_multiplier = 1.0*quartwidth (why?) @}
+
+= quartwidth * arithmetic_basicspace
+
+=>
+
+arithmetic_basicspace = 2/1 = 2
+
+
+If you want to space your music wider, use something like:
+
+arithmetic_basicspace = 4.;
+
+@end example",
+ "spacing-increment shortest-duration-space");
+