2002-04-01 Han-Wen <hanwen@cs.uu.nl>
+ * lily/multi-measure-rest.cc (set_spacing_rods): tune rods to the
+ extent of the mm rest.
+
+ * lily/spacing-spanner.cc (get_duration_space): better spacing for
+ really short notes.
+
* lily/tuplet-bracket.cc (make_bracket): new function
(get_x_offset): new function; make tuplet brackets align on stems
if stem has same direction.
@lilypondfile[printfilename]{spacing-rest.ly}
+@lilypondfile[printfilename]{spacing-short-notes.ly}
+
@lilypondfile[printfilename]{lyrics-bar.ly}
@lilypondfile[printfilename]{spacing-knee.ly}
--- /dev/null
+\header {
+
+texidoc = "Notes that are shorter than the common shortest note, Get a
+space (i.e. without the space needed for the note) proportional to
+their duration. So 16th notes get 1/2 of the space of an eigth note.
+The total distance for a 16th is (including note head) is 3/4 of the
+eighth note. "
+
+}
+
+\score { \notes \relative c''
+{
+ \time 2/4
+ c16 c c c c4 c4
+ c8 c8 c8 c8
+ c8 c8 c4
+ c8 c8 c4
+
+}
+
+ \paper { linewidth = -1. }
+}
\score{
\notes \context Voice \relative c'' {
\times 2/3 { \times 2/3 { a8 b c} c }
- \times 3/4 { c4 c4 c4 c4 }
+ \times 2/3 { r8 [b f] }
+ \times 2/3 { r8 b r8 }
+ c4 |
+
+ \times 3/4 { c4 c4 c4 c4 } c4 |
+
\time 6/8
\times 6/9 { c8 c c c c c c c c }
count ++;
}
+
Real outer_padding_factor = 1.5; // make outer padding this much bigger.
Real inner_padding = (space - symbols_width) / (2 * outer_padding_factor + (count-1));
-
+ if (inner_padding < 0)
+ {
+ inner_padding = 1.0;
+ }
+
Molecule mol;
for (SCM s = mols; gh_pair_p (s); s = gh_cdr(s))
{
Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
+ Real sym_width = symbol_molecule (me, 0.0).extent (X_AXIS).length ();
+
for (int i=0; i < 4; i++)
{
Item * l = combinations[i][0];
Rod rod;
rod.item_l_drul_[LEFT] = l;
rod.item_l_drul_[RIGHT] = r;
+
+
rod.distance_f_ = l->extent (l, X_AXIS)[BIGGER] - r->extent (r, X_AXIS)[SMALLER]
- + 5.0; // magic!
+ + sym_width + 2.0; // 2.0 = magic!
rod.add_to_cols ();
}
max_count = counts[i];
}
- // printf ("Den %d/%d, c %d\n", durations[i].num (), durations[i].den (), counts[i]);
+ printf ("duration %d/%d, count %d\n", durations[i].num (), durations[i].den (), counts[i]);
}
/*
max_note_space = max_note_space >? space;
max_fixed_note_space = max_fixed_note_space >? fixed;
}
-
}
if (max_note_space < 0)
Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool * expand_only)
{
Real k = gh_scm2double (me->get_grob_property ("shortest-duration-space"));
-
+ Real incr = gh_scm2double (me->get_grob_property ("spacing-increment"));
+
if (d < shortest)
{
+ /*
+ We don't space really short notes using the log of the
+ duration, since it would disproportionally stretches the long
+ notes in a piece. In stead, we use geometric spacing with constant 0.5
+ (i.e. linear.)
+
+ This should probably be tunable, to use other base numbers.
+
+ In Mozart hrn3 by EB., we have 8th note = 3.9 mm (total), 16th note =
+ 3.6 mm (total). head-width = 2.4, so we 1.2mm for 16th, 1.5
+ mm for 8th. (white space), suggesting that we use
+
+ (1.2 / 1.5)^{-log2(duration ratio)}
+
+
+ */
Rational ratio = d.main_part_ / shortest;
*expand_only = true;
- return (0.5 + 0.5 * double (ratio)) * k ;
+ return ((k-1) + double (ratio)) * incr;
}
else
{
/*
- @see
- John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
- OSU-CISRC-10/87-TR35, Department of Computer and Information Science,
- The Ohio State University, 1987.
+ John S. Gourlay. ``Spacing a Line of Music,'' Technical
+ Report OSU-CISRC-10/87-TR35, Department of Computer and
+ Information Science, The Ohio State University, 1987.
*/
Real log = log_2 (shortest);
k -= log;
Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
*expand_only = false;
- return (log_2 (compdur) + k) * gh_scm2double (me->get_grob_property ("spacing-increment"));
+ return (log_2 (compdur) + k) * incr;
}
}
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",
+ "
+The space taken by a note is dependent on its duration. Doubling a
+duration adds spacing-increment to the space. The most common shortest
+note gets shortest-duration-space. Notes that are even shorter are
+spaced proportonial to their duration.
+
+Typically, the increment is the width of a black note head. In a
+piece with lots of 8th notes, and some 16th notes, the eighth note
+gets 2 note heads width (i.e. the space following a note is 1 note
+head width) A 16th note is followed by 0.5 note head width. The
+quarter note is followed by 3 NHW, the half by 4 NHW, etc.
+",
"spacing-increment shortest-duration-space");
#include "lookup.hh"
-static Real
-get_x_offset (Grob *g, Grob *common, Direction my_dir)
+static Grob*
+get_x_bound_grob (Grob *g, Direction my_dir)
{
if (Note_column::stem_l (g)
&& Note_column::dir (g) == my_dir)
{
g = Note_column::stem_l (g);
}
- return g->relative_coordinate (common, X_AXIS);
+ return g;
}
Grob * commonx = column_arr[0]->common_refpoint (column_arr.top (),X_AXIS);
Direction dir = Directional_element_interface::get (me);
-
- Real x0 = get_x_offset (column_arr[0], commonx, dir);
- Real x1 = get_x_offset (column_arr.top(), commonx, dir);
+
+ Grob * lgr = get_x_bound_grob (column_arr[0], dir);
+ Grob * rgr = get_x_bound_grob (column_arr.top(), dir);
+ Real x0 = lgr->extent (commonx,X_AXIS)[LEFT];
+ Real x1 = rgr->extent (commonx,X_AXIS)[RIGHT];
+
Real w = x1 -x0;
Real ly = gh_scm2double (me->get_grob_property ("left-position"));
Grob * commony = me->common_refpoint (me->get_grob_property ("note-columns"), Y_AXIS);
Grob * commonx = me->common_refpoint (me->get_grob_property ("note-columns"), X_AXIS);
- Direction d = Directional_element_interface::get (me);
+ Direction dir = Directional_element_interface::get (me);
/*
Use outer non-rest columns to determine slope
if (l < r)
{
- *dy = column_arr[r]->extent (commony, Y_AXIS) [d]
- - column_arr[l]->extent (commony, Y_AXIS) [d] ;
+ *dy = column_arr[r]->extent (commony, Y_AXIS) [dir]
+ - column_arr[l]->extent (commony, Y_AXIS) [dir] ;
}
else
* dy = 0;
- *offset = - d * infinity_f;
+ *offset = - dir * infinity_f;
if (!column_arr.size ())
return;
- Real x0 = get_x_offset (column_arr[0], commonx, d);
- Real x1 = get_x_offset (column_arr.top(), commonx, d);
+ Grob * lgr = get_x_bound_grob (column_arr[0], dir);
+ Grob * rgr = get_x_bound_grob (column_arr.top(), dir);
+ Real x0 = lgr->extent (commonx,X_AXIS)[LEFT];
+ Real x1 = rgr->extent (commonx,X_AXIS)[RIGHT];
+
/*
Slope.
for (int i = 0; i < column_arr.size (); i++)
{
- Real notey = column_arr[i]->extent (commony, Y_AXIS)[d]
+ Real notey = column_arr[i]->extent (commony, Y_AXIS)[dir]
- me->relative_coordinate (commony, Y_AXIS);
Real x = column_arr[i]->relative_coordinate (commonx, X_AXIS) - x0;
Real tuplety = *dy * x * factor;
- if (notey * d > (*offset + tuplety) * d)
+ if (notey * dir > (*offset + tuplety) * dir)
*offset = notey - tuplety;
}
// padding
- *offset += gh_scm2double (me->get_grob_property ("padding")) *d;
+ *offset += gh_scm2double (me->get_grob_property ("padding")) *dir;
/*
*offset = rint (*offset);
if (Staff_symbol_referencer::on_staffline (me, (int) rint (*offset)))
- *offset += d;
+ *offset += dir;
*offset *= 0.5 * ss;
}
(SpacingSpanner
. (
(spacing-procedure . ,Spacing_spanner::set_springs)
- (grace-space-factor . 0.5)
-
+ (grace-space-factor . 0.6)
(shortest-duration-space . 2.0)
(spacing-increment . 1.2)
-
-
(meta . ((interfaces . (spacing-spanner-interface))))
))
(grob-property-description 'neutral-direction dir? "Where to go if we're on the neutral position of the staff (by default, the middle of the staff; see also grob-property neutral-position). [Ross] has the following to say about this: Some engravers consider the middle line neutral, and take the option of using either up- or down-stems for notes that fall on it. However, more up-to-date engraving no longer permits an option; now a down-stem is always appropriate.")
(grob-property-description 'neutral-position number? "Position (in half staff spaces) where to flip the direction of stems: by default, custodes above this position get their stems downwards; custodes below this position get their stems upwards. A value of 0 designates the center of the staff. Use property neutral-direction to control the behaviour of stems on the neutral position itself. (Note: currently, neutral-position is supported only for custodes; for stems of note heads, neutral-position is currently fixed to 0, i.e. the middle of the staff.)")
-
-(grob-property-description 'delta-y number? "amount of ascension.")
(grob-property-description 'dependencies list? "list of score-grob pointers that indicate who to compute first for certain global passes.")
(grob-property-description 'details list? "alist of parameters for detailed grob behavior.")
(grob-property-description 'dir-forced boolean? "set if direction has been forced; read by Beam.")