Grep for TODO and ugh/ugr/urg.
.* TODO before 1.2
-. * rename abc2ly mup2ly
. * rename 'staff_line_leading' (who is being lead where?) to
staff_space, interline; (or other meaningful name) and use throughout lily
. * rename files to class-name:
. * p-score
. * engraver-group
. * standardise(d) switches: -v, --version; -d, --debug,
-. * Auto_beam debugging output (waarom/wanneer heb jij die weggehaald?)
+. * Peter 1. Key signatures are no longer transposed with the rest
+ of
+ the music.
+
+ \notes\transpose bes {\key D; d1 }
+ should produce no key signature (key C)
+
+ 2. Crescendos and other dynamic markings that start inside a
+ \grace { } section are ignored.
+
+ \notes \relative c' { fis4 r4 \grace { [g16 ( \< a16] }
+ ) b4 \! a8. g16}
+
+ 3. Slurs that end within a grace section but start outside
+ are treated strangely.
+ a2 d,4 ( \grace { [e16 ) d16]} cis8 d
+
+
+ 4. Lyrics and grace sections don't go too well together.
+ The words are aligned with the main note, not the start of the
+ grace note. This is usually wrong, but is sometimes right.
+
+
. * Auto_beam debugging output (waarom/wanneer heb jij die weggehaald?)
. * Rename illegal to invalid
. * Mats:
- The paper11/13/26 files have to be updated.
. * Grace_slur_engraver.
+. * input/star-spangled-banner.ly: fold for lyrics?
. * Break_req handling is silly (break_forbid () + \break fucks up.)
. * hangOnClef with non-breakable clefs.
. * do scaled fonts generally
. * fix partial measures in meaningful way.
+. * Michael
+
+- The two spacing bugs in the choral-1.ly I sent you earlier, small
+GIFs attached for easy reference: #1: time meter and first note on the
+line are too close; #2: last note on the line and next bar are too
+close.
+
+- And I haven't got any feedback on this one, posted last week:
+
+Check out:
+
+\score {
+ \notes \relative c' {
+ \context Staff <
+ \context Voice = one { \stemdown c1 c4 }
+ \context Voice = two { \stemup d1 d4 }
+ >
+ }
+}
+
+Notes are shifted as expected. Now check out:
+
+\score {
+ \notes \relative c' {
+ \context Staff <
+ \context Voice = one { \stemdown c1 <a4 c4> }
+ \context Voice = two { \stemup d1 d4 }
+ >
+ }
+}
+
+i.e. do
+
+- \context Voice = one { \stemdown c1 c4 }
++ \context Voice = one { \stemdown c1 <a4 c4> }
+
+Now the chord collides with the note of the other voice!
+
. * relative mode for midi2ly
+. *
+Crescendi/diminuendi that cross a line break lose their vertical
+position and all end up above the top staff line, see the
+following example.
+
+----------------
+\score{
+ \context StaffGroup <
+ \context Staff=s1 \notes\relative c'{
+ c d e f |
+ g f e d | \break %% If this break is removed, it works fine
+ c d e f |}
+ \context Staff=s2 \notes\relative c'{
+ c \< d e f |
+ g f e d |
+ c d e \! f |}
+ >
+}
. * uniformise recent feta contributions.
. * bigger and fatter 4/4 C
. * sort out directory stuff.
[/home/fred/usr/src/lilypond/scm/lily.scm]
warning: can't find file: `init'
. * indent = 0.0 with linewidth=-1.0
+. * collisions & accidentals.
. * auto-beaming in input/test/spacing.ly.
huh, snap niks van: gewone beam gaat wel goed. hoe kan abe nu
invloed hebben op beam-creatie, stopt toch gewoon stokken in?
. * Beam
. * Stem
. * Rhythmic_column and interaction stem/rhythmic_column/note_head/dots.
-. * Slur
. * Duration
. * clef engraver
. * parser
(require 'allout)
(outline-init 't)
+
++ pl 56.jcn3
++ - slur de-hairification
++ * slurs always attached to noteheads, by default
++ * corrections for steep and high slurs
++ * snap to stem end when close
++ - bow/tie/slur dy/dx fix
++
++
source file of the GNU LilyPond music typesetter
- (c) 1996, 1997--1999, 1998 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ (c) 1996, 1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
Jan Nieuwenhuizen <janneke@gnu.org>
*/
/*
[TODO]
- * URG: share code with tie
- * begin and end should be treated as a Script.
- * damping
- * slur from notehead to stemend: c''()b''
+ * begin and end should be treated as a/acknowledge Scripts.
+ * broken slur should have uniform trend
*/
#include "slur.hh"
else
{
encompass_arr_.push (n);
- // n->stem_l_->slur_l_ = this;
add_dependency (n);
}
}
return Item::left_right_compare (n1, n2);
}
-bool
-Slur::broken_edge_b ( Direction dir) const
-{
- return extrema ()[dir] != spanned_drul_[dir];
-}
-
-bool
-Slur::normal_edge_b ( Direction dir) const
-{
- Note_column *n = extrema ()[dir];
- return !broken_edge_b ( dir)
- && n->stem_l_
- && n->stem_l_->get_elt_property (transparent_scm_sym) == SCM_BOOL_F
- && n->head_l_arr_.size ();
-}
-
-Drul_array<Note_column*>
-Slur::extrema ()const
-{
- Drul_array<Note_column*> extrema;
- extrema[LEFT] = encompass_arr_[0];
- extrema[RIGHT] = encompass_arr_.top ();
- return extrema;
-}
-
-/*
- TODO.
-
- Unhair this.
- */
void
Slur::do_post_processing ()
{
if (!dir_)
dir_ = get_default_dir ();
- Real interline_f = paper_l ()->get_realvar (interline_scm_sym);
- Real internote_f = interline_f / 2;
- // URG
- Real notewidth_f = paper_l ()->note_width () * 0.8;
-
/*
- [OSU]: slur and tie placement
+ Slur and tie placement [OSU]
- slurs:
- * x = center of head (upside-down: inner raakpunt stem) - d * gap
+ Slurs:
+ * x = centre of head - d * x_gap_f
- * y = length < 5ss : horizontal raakpunt + d * 0.25 ss
+ TODO:
+ * y = length < 5ss : horizontal tangent + d * 0.25 ss
y = length >= 5ss : y next interline - d * 0.25 ss
- --> height <= 5 length ?? we use <= 3 length, now...
*/
-
- Real gap_f = paper_l ()->get_var ("slur_x_gap");
+ Real interline_f = paper_l ()->get_realvar (interline_scm_sym);
+ Real internote_f = interline_f / 2;
+
+ Real x_gap_f = paper_l ()->get_var ("slur_x_gap");
+ Real y_gap_f = paper_l ()->get_var ("slur_y_gap");
+
+ Drul_array<Note_column*> note_column_drul;
+ note_column_drul[LEFT] = encompass_arr_[0];
+ note_column_drul[RIGHT] = encompass_arr_.top ();
- Direction d=LEFT;
-
+ bool fix_broken_b = false;
+ Direction d = LEFT;
do
{
- if (broken_edge_b (d))
+ dx_f_drul_[d] = dy_f_drul_[d] = 0;
+ if ((note_column_drul[d] == spanned_drul_[d])
+ && note_column_drul[d]->head_l_arr_.size ()
+ && (note_column_drul[d]->stem_l_))
{
- // ugh -- check if needed
- dx_f_drul_[d] = -d
- *(spanned_drul_[d]->extent (X_AXIS).length () - 0.5 * notewidth_f);
-
- // prebreak
- if (d == RIGHT)
+ Stem* stem_l = note_column_drul[d]->stem_l_;
+ /*
+ side directly attached to note head;
+ no beam getting in the way
+ */
+ if (((stem_l->get_elt_property (transparent_scm_sym) != SCM_BOOL_F)
+ || !((stem_l->dir_ == dir_) && (dir_ != d)))
+ && !((dir_ == stem_l->dir_)
+ && stem_l->beam_l_ && (stem_l->beams_i_drul_[-d] >= 1)))
{
- dx_f_drul_[LEFT] = spanned_drul_[LEFT]->extent (X_AXIS).length ();
-
- // urg -- check if needed
- if (encompass_arr_.size () > 1)
- dx_f_drul_[RIGHT] += notewidth_f;
+ dx_f_drul_[d] = spanned_drul_[d]->extent (X_AXIS).length () / 2;
+ dx_f_drul_[d] -= d * x_gap_f;
+
+ if (stem_l->dir_ != dir_)
+ {
+ dy_f_drul_[d] = note_column_drul[d]->extent (Y_AXIS)[dir_];
+ }
+ else
+ {
+ dy_f_drul_[d] = stem_l->chord_start_f ()
+ + dir_ * internote_f;
+ }
+ dy_f_drul_[d] += dir_ * y_gap_f;
}
- }
- /*
- normal slur
- */
- else if (normal_edge_b (d))
- {
- Real notewidth_f = extrema ()[d]->extent (X_AXIS).length ();
- dy_f_drul_[d] = (int)rint (extrema ()[d]->stem_l_-> extent (Y_AXIS)[dir_]);
- dx_f_drul_[d] += 0.5 * notewidth_f - d * gap_f;
- if (dir_ == extrema ()[d]->stem_l_->dir_)
+ /*
+ side attached to (visible) stem
+ */
+ else
{
- if (dir_ == d)
- dx_f_drul_[d] += 0.5 * dir_ * notewidth_f;
+ dx_f_drul_[d] = stem_l->hpos_f ()
+ - spanned_drul_[d]->absolute_coordinate (X_AXIS);
+ /*
+ side attached to beamed stem
+ */
+ if (stem_l->beam_l_ && (stem_l->beams_i_drul_[-d] >= 1))
+ {
+ dy_f_drul_[d] = stem_l->extent (Y_AXIS)[dir_];
+ dy_f_drul_[d] += dir_ * 2 * y_gap_f;
+ }
+ /*
+ side attached to notehead, with stem getting in the way
+ */
else
- dx_f_drul_[d] += 0.25 * dir_ * notewidth_f;
+ {
+ dx_f_drul_[d] -= d * x_gap_f;
+
+ dy_f_drul_[d] = stem_l->chord_start_f ()
+ + dir_ * internote_f;
+ dy_f_drul_[d] += dir_ * y_gap_f;
+ }
}
}
- else
- {
- Real notewidth_f = extrema ()[d]->extent (X_AXIS).length ();
- dy_f_drul_[d] = (int)rint (extrema ()[d]->head_positions_interval ()
- [dir_]) * internote_f;
- dx_f_drul_[d] += 0.5 * notewidth_f - d * gap_f;
+ /*
+ loose end
+ */
+ else
+ {
+ dx_f_drul_[d] -= d * x_gap_f;
+ /*
+ broken: should get y from other piece, so that slur
+ continues up/down trend
+
+ for now: be horizontal..
+ */
+ fix_broken_b = true;
}
- dy_f_drul_[d] += dir_ * interline_f;
- if (extrema ()[d]->stem_l_ && (dir_ == extrema ()[d]->stem_l_->dir_))
- dy_f_drul_[d] -= dir_ * internote_f;
- }
- while (flip(&d) != LEFT);
+ }
+ while (flip (&d) != LEFT);
- // now that both are set, do dependent
- do
- {
- if (broken_edge_b (d))
- {
- Direction u = d;
- flip(&u);
+ if (fix_broken_b)
+ do {
+ if (dy_f_drul_[d])
+ dy_f_drul_[-d] = dy_f_drul_[d];
+ }
+ while (flip (&d) != LEFT);
+
+
+ /*
+ Now we've got a fine slur
+ Catch and correct some ugly cases
+ */
- // postbreak
- if (d == LEFT)
- dy_f_drul_[u] += dir_ * internote_f;
+ Real dx_f = do_width ().length () + dx_f_drul_[RIGHT] - dx_f_drul_[LEFT];
+ Real dy_f = dy_f_drul_[RIGHT] - dy_f_drul_[LEFT];
+ Real height_f = do_height ().length ();
- dy_f_drul_[d] = dy_f_drul_[u];
- }
- }
- while (flip(&d) != LEFT);
+ Real height_damp_f = paper_l ()->get_var ("slur_height_damping");
+ Real slope_damp_f = paper_l ()->get_var ("slur_slope_damping");
+ Real ratio_f;
+
+
+ /*
+ Avoid too steep slurs.
+ */
+ ratio_f = abs (dy_f / dx_f);
+ if (ratio_f > slope_damp_f)
+ {
+ Direction d = (Direction)(- dir_ * (sign (dy_f)));
+ if (!d)
+ d = LEFT;
+ dy_f_drul_[d] += dir_ * (ratio_f - slope_damp_f) * dx_f;
+ }
/*
- Slur should follow line of music
+ Avoid too high slurs
*/
- if (normal_edge_b (LEFT)
- && normal_edge_b (RIGHT)
- && (extrema ()[LEFT]->stem_l_ != extrema ()[RIGHT]->stem_l_))
+ ratio_f = abs (height_f / dx_f);
+ if (ratio_f > height_damp_f)
{
- Real note_dy = extrema ()[RIGHT]->stem_l_->head_positions ()[dir_]
- - extrema ()[LEFT]->stem_l_->head_positions ()[dir_];
- Real dy = dy_f_drul_[RIGHT] - dy_f_drul_[LEFT];
+ Direction d = (Direction)(- dir_ * (sign (dy_f)));
+ if (!d)
+ d = LEFT;
+ dy_f_drul_[d] += dir_ * height_f * height_damp_f;
/*
- Should we always follow note-heads, (like a tie)?
- For now, only if the note_dy != slur_dy, we'll do
- slur_dy := note_dy * factor.
- */
- if (sign (dy) != sign (note_dy))
+ if y positions at same height, correct both ends
+ */
+ if (abs (dy_f / dx_f ) < slope_damp_f)
{
- Real damp_f = paper_l ()->get_var ("slur_slope_follow_music_factor");
- Real realdy = note_dy * damp_f;
- Direction adjust_dir = (Direction)(- dir_ * sign (realdy));
- if (!adjust_dir)
- adjust_dir = -dir_;
- /*
- adjust only if no beam gets in the way
- */
- if (!extrema ()[adjust_dir]->stem_l_->beam_l_
- || (adjust_dir == extrema ()[adjust_dir]->stem_l_->dir_)
- || (extrema ()[adjust_dir]->stem_l_->beams_i_drul_[-adjust_dir] < 1))
- {
- dy_f_drul_[adjust_dir] = dy_f_drul_[-adjust_dir]
- + 2 * adjust_dir * realdy;
- Real dx = notewidth_f / 2;
- if (adjust_dir != extrema ()[adjust_dir]->stem_l_->dir_)
- dx /= 2;
- dx_f_drul_[adjust_dir] -= adjust_dir * dx;
- }
+ dy_f_drul_[-d] += dir_ * height_f * height_damp_f;
}
}
/*
- Avoid too steep slurs.
- */
- Real damp_f = paper_l ()->get_var ("slur_slope_damping");
- Offset d_off = Offset (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT],
- dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]);
- d_off[X_AXIS] += extent (X_AXIS).length ();
-
- Real ratio_f = abs (d_off[Y_AXIS] / d_off[X_AXIS]);
- if (ratio_f > damp_f)
- dy_f_drul_[(Direction)(- dir_ * sign (d_off[Y_AXIS]))] +=
- dir_ * (ratio_f - damp_f) * d_off[X_AXIS];
+ If, after correcting, we're close to stem-end...
+ */
+ Real snap_f = paper_l ()->get_var ("slur_snap_to_stem");
+ do
+ {
+ if ((note_column_drul[d] == spanned_drul_[d])
+ && (note_column_drul[d]->stem_l_)
+ && (note_column_drul[d]->stem_l_->dir_ == dir_)
+ && (abs (note_column_drul[d]->stem_l_->extent (Y_AXIS)[dir_]
+ - dy_f_drul_[d]) <= snap_f))
+ {
+ /*
+ attach to stem-end
+ */
+ Stem* stem_l = note_column_drul[d]->stem_l_;
+ dx_f_drul_[d] = stem_l->hpos_f ()
+ - spanned_drul_[d]->absolute_coordinate (X_AXIS);
+ dy_f_drul_[d] = stem_l->extent (Y_AXIS)[dir_];
+ dy_f_drul_[d] += dir_ * 2 * y_gap_f;
+ }
+ }
+ while (flip (&d) != LEFT);
}
Array<Offset>
Slur::get_encompass_offset_arr () const
{
- Real notewidth = paper_l ()->note_width () * 0.8;
- Real gap = paper_l ()->get_var ("slur_x_gap");
-
- /*
- urg. Calcs done wrt the leftmost note. Fixme.
-
- Calcs ignore possibility of pre/postbreak.
-
-
- */
-
- Offset left = Offset (dx_f_drul_[LEFT], dy_f_drul_[LEFT]);
- left[X_AXIS] += encompass_arr_[0]->stem_l_->hpos_f ();
-
- Real internote = encompass_arr_[0]->stem_l_->staff_line_leading_f ()/2.0;
-
- /*
- <URG>
- i don't understand these two, but *must* for symmetry
- look at encompass array:
- lilypond -D input/test/slur-symmetry*.ly
- lilypond -D input/test/sleur.ly
-
- do_post_processing should have calculated these into
- dx_f_drul_[], no??
-
- */
-
- if (dir_ != encompass_arr_[0]->stem_l_->dir_)
- left[X_AXIS] += - 0.5 * notewidth * encompass_arr_[0]->stem_l_->dir_
- + gap;
- else if (encompass_arr_[0]->stem_l_->dir_ == UP)
- left[X_AXIS] -= notewidth;
-
- if ((dir_ == encompass_arr_[0]->stem_l_->dir_)
- && (encompass_arr_[0]->stem_l_->dir_ == DOWN))
- left[Y_AXIS] -= internote * encompass_arr_[0]->stem_l_->dir_;
- /* </URG> */
-
- Offset d = Offset (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT],
- dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]);
- d[X_AXIS] += extent (X_AXIS).length ();
+ Array<Offset> offset_arr;
+ Offset origin (absolute_coordinate (X_AXIS), 0);
int first = 1;
- int last = encompass_arr_.size () - 1;
+ int last = encompass_arr_.size () - 2;
-
- Array<Offset> notes;
- notes.push (Offset (0,0));
-
- // prebreak
- if (broken_edge_b (RIGHT))
- last++;
- else
- {
- Encompass_info info (encompass_arr_.top (), dir_, this);
- d[Y_AXIS] += info.interstaff_f_;
- }
-
- // postbreak
- if (broken_edge_b (LEFT))
+ /*
+ left is broken edge
+ */
+ if (encompass_arr_[0] != spanned_drul_[LEFT])
{
first--;
- /*
- interstaff postbreak: slur begins at height of last note
- */
- Encompass_info info (encompass_arr_[0], dir_, this);
- notes[0][Y_AXIS] += info.interstaff_f_;
}
- else
+ Encompass_info left_info (encompass_arr_[0], dir_, this);
+ offset_arr.push (Offset (0, left_info.interstaff_f_));
+
+ /*
+ right is broken edge
+ */
+ if (encompass_arr_.top () != spanned_drul_[RIGHT])
{
- Encompass_info info (encompass_arr_[0], dir_, this);
- notes[0][Y_AXIS] += info.interstaff_f_;
+ last++;
}
- for (int i = first; i < last; i++)
+ for (int i = first; i <= last; i++)
{
Encompass_info info (encompass_arr_[i], dir_, this);
- notes.push (info.o_ - left);
+ offset_arr.push (info.o_ - origin);
}
- /*
- interstaff prebreak: slur ends at height of last note
- */
- if (broken_edge_b (RIGHT))
- d[Y_AXIS] = notes.top ()[Y_AXIS];
+ offset_arr.push (Offset (do_width ().length (), 0));
- notes.push (d);
+#if 1
+ offset_arr[0] += Offset (dx_f_drul_[LEFT], dy_f_drul_[LEFT]);
+ offset_arr.top () += Offset (dx_f_drul_[RIGHT], dy_f_drul_[RIGHT]);
+#else
+ /*
+ check non-disturbed slur
+ FIXME: ends off by a tiny bit!!
+ */
+ offset_arr[0] += Offset (0, dy_f_drul_[LEFT]);
+ offset_arr.top () += Offset (0, dy_f_drul_[RIGHT]);
+#endif
- return notes;
+ return offset_arr;
}