X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fspacing-spanner.cc;h=5a889c74b480154d3e452a64e75c7ddc9f278d77;hb=23cd484ee45d2e5807540265a6fe6b70e9eb2020;hp=5e48941547d3a43869b5e65c23a090d85ceb0905;hpb=bfb10684605084baf1a898be8f42c0e463c5764a;p=lilypond.git diff --git a/lily/spacing-spanner.cc b/lily/spacing-spanner.cc index 5e48941547..5a889c74b4 100644 --- a/lily/spacing-spanner.cc +++ b/lily/spacing-spanner.cc @@ -3,14 +3,16 @@ source file of the GNU LilyPond music typesetter - (c) 1999--2002 Han-Wen Nienhuys + (c) 1999--2003 Han-Wen Nienhuys */ #include #include +#include "main.hh" #include "system.hh" +#include "warn.hh" #include "paper-def.hh" #include "paper-score.hh" #include "paper-column.hh" @@ -23,15 +25,9 @@ #include "spring.hh" #include "paper-column.hh" #include "spaceable-grob.hh" +#include "break-align-interface.hh" +#include "spacing-interface.hh" -/* - paper-column: - - Don't be confused by right-items: each spacing wish can also contain - a number of items, with which a spacing constraint may be kept. It's - a little baroque, but it might come in handy later on? - - */ class Spacing_spanner { public: @@ -42,10 +38,10 @@ public: 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 const &); + static Rational find_shortest (Grob *, Link_array const &); static void breakable_column_spacing (Grob*, Item* l, Item *r, Moment); static void find_loose_columns () {} - static void prune_loose_colunms (Grob*,Link_array *cols, Rational); + static void prune_loose_columns (Grob*,Link_array *cols, Rational); static void find_loose_columns (Link_array cols); static void set_explicit_neighbor_columns (Link_array cols); static void set_implicit_neighbor_columns (Link_array cols); @@ -58,6 +54,13 @@ public: /* Return whether COL is fixed to its neighbors by some kind of spacing constraint. + + + If in doubt, then we're not loose; the spacing engine should space + for it, risking suboptimal spacing. + + (Otherwise, we might risk core dumps, and other weird stuff.) + */ static bool loose_column (Grob *l, Grob *c, Grob *r) @@ -95,7 +98,7 @@ loose_column (Grob *l, Grob *c, Grob *r) if (!l_neighbor || !r_neighbor) return false; - l_neighbor = l_neighbor->column_l(); + l_neighbor = l_neighbor->get_column (); r_neighbor = dynamic_cast (Note_spacing::right_column (r_neighbor)); if (l == l_neighbor && r == r_neighbor) @@ -104,26 +107,45 @@ loose_column (Grob *l, Grob *c, Grob *r) if (!l_neighbor || !r_neighbor) return false; + + /* Only declare loose if the bounds make a little sense. This means 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)) - && (Paper_column::musical_b (r_neighbor) || Item::breakable_b (r_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; + return false; } /* - If in doubt: we're not loose; the spacing engine should space for - it, risking suboptimal spacing. + A rather hairy check, but we really only want to move around clefs. (anything else?) - (Otherwise, we might risk core dumps, and other weird stuff.) + in any case, we don't want to move bar lines. + */ + for (SCM e = c->get_grob_property ("elements"); gh_pair_p (e); e = gh_cdr (e)) + { + Grob * g = unsmob_grob (gh_car (e)); + if (g && Break_align_interface::has_interface (g)) + { + for (SCM s = g->get_grob_property ("elements"); gh_pair_p (s); + s = gh_cdr (s)) + { + Grob *h = unsmob_grob (gh_car (s)); - */ - return false; + /* + ugh. -- fix staff-bar name? + */ + if (h && h->get_grob_property ("break-align-symbol") == ly_symbol2scm ("staff-bar")) + return false; + } + } + } + + return true; } /* @@ -132,7 +154,7 @@ loose_column (Grob *l, Grob *c, Grob *r) between. */ void -Spacing_spanner::prune_loose_colunms (Grob*me,Link_array *cols, Rational shortest) +Spacing_spanner::prune_loose_columns (Grob*me,Link_array *cols, Rational shortest) { Link_array newcols; Real increment = gh_scm2double (me->get_grob_property ("spacing-increment")); @@ -216,7 +238,7 @@ Spacing_spanner::prune_loose_colunms (Grob*me,Link_array *cols, Rational s while (flip (&d) != LEFT); Rod r; - r.distance_f_ = dists[LEFT] + dists[RIGHT]; + r.distance_ = dists[LEFT] + dists[RIGHT]; r.item_l_drul_[LEFT] = dynamic_cast (cols->elem(i-1)); r.item_l_drul_[RIGHT] = dynamic_cast (cols->elem (i+1)); @@ -248,7 +270,7 @@ Spacing_spanner::set_explicit_neighbor_columns (Link_array cols) { Item * wish = dynamic_cast (unsmob_grob (gh_car (s))); - Item * lc = wish->column_l (); + Item * lc = wish->get_column (); Grob * right = Note_spacing::right_column (wish); if (!right) @@ -256,8 +278,8 @@ Spacing_spanner::set_explicit_neighbor_columns (Link_array cols) Item * rc = dynamic_cast (right); - int right_rank = Paper_column::rank_i (rc); - int left_rank = Paper_column::rank_i (lc); + int right_rank = Paper_column::get_rank (rc); + int left_rank = Paper_column::get_rank (lc); /* update the left column. @@ -280,7 +302,7 @@ Spacing_spanner::set_explicit_neighbor_columns (Link_array cols) && unsmob_grob (gh_car (left_neighs))) { Item * it = dynamic_cast (unsmob_grob (gh_car (left_neighs))); - maxrank = Paper_column::rank_i (it->column_l()); + maxrank = Paper_column::get_rank (it->get_column ()); } if (left_rank >= maxrank) @@ -339,12 +361,25 @@ Spacing_spanner::set_springs (SCM smob) { Grob *me = unsmob_grob (smob); - Link_array all (me->pscore_l_->line_l_->column_l_arr ()) ; + Link_array all (me->pscore_->system_->columns ()) ; set_explicit_neighbor_columns (all); - Rational global_shortest = find_shortest (all); - prune_loose_colunms (me, &all, global_shortest); + SCM preset_shortest = me->get_grob_property ("common-shortest-duration"); + Rational global_shortest; + if (unsmob_moment (preset_shortest)) + { + global_shortest = unsmob_moment (preset_shortest)->main_part_; + } + else + { + global_shortest = find_shortest (me, all); + if (verbose_global_b) + { + progress_indication (_f("Global shortest duration is %s\n", global_shortest.to_string ())); + } + } + prune_loose_columns (me, &all, global_shortest); set_implicit_neighbor_columns (all); @@ -375,7 +410,7 @@ Spacing_spanner::set_springs (SCM smob) */ Rational -Spacing_spanner::find_shortest (Link_array const &cols) +Spacing_spanner::find_shortest (Grob *me, Link_array const &cols) { /* ascending in duration @@ -445,10 +480,11 @@ Spacing_spanner::find_shortest (Link_array const &cols) // printf ("duration %d/%d, count %d\n", durations[i].num (), durations[i].den (), counts[i]); } - /* - TODO: 1/8 should be adjustable? - */ + SCM bsd = me->get_grob_property ("base-shortest-duration"); Rational d = Rational (1,8); + if (Moment *m = unsmob_moment (bsd)) + d = m->main_part_; + if (max_idx >= 0) d = d *cols) /* - Generate the space between two musical columns LC and RC, given spacing parameters INCR and SHRTEST. + Generate the space between two musical columns LC and RC, given + spacing parameters INCR and SHORTEST. */ void Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real increment, Rational shortest) @@ -532,7 +569,7 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc Item *wish_rcol = Note_spacing::right_column (wish); if (Note_spacing::left_column (wish) != lc - || (wish_rcol != rc && wish_rcol != rc->original_l_)) + || (wish_rcol != rc && wish_rcol != rc->original_)) continue; /* @@ -549,25 +586,90 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc } } + if (Paper_column::when_mom (rc).grace_part_ && + !Paper_column::when_mom (lc).grace_part_) + { + /* + Ugh. 0.8 is arbitrary. + */ + max_note_space *= 0.8; + } + if (max_note_space < 0) { max_note_space = base_note_space; - max_fixed_note_space = increment; + max_fixed_note_space = increment; + } + + /* + Whatever we do, the fixed space is smaller than the real + space. + + TODO: this criterion is discontinuous in the derivative. + Maybe it should be continuous? + */ + max_fixed_note_space = max_fixed_note_space get_paper ()->get_scmvar ("packed")); + Real strength, distance; + + /* + TODO: make sure that the space doesn't exceed the right margin. + */ + if (packed) + { + /* + In packed mode, pack notes as tight as possible. This makes + sense mostly in combination with raggedright mode: the notes + are then printed at minimum distance. This is mostly useful + for ancient notation, but may also be useful for some flavours + of contemporary music. If not in raggedright mode, lily will + pack as much bars of music as possible into a line, but the + line will then be stretched to fill the whole linewidth. + */ + strength = 1.0; + distance = max_fixed_note_space; + } + else + { + strength = 1 / (max_note_space - max_fixed_note_space); + distance = max_note_space; } - bool ragged = to_boolean (me->paper_l ()->get_scmvar ("raggedright")); - Real strength = (ragged) ? 1.0 : 1 / (max_note_space - max_fixed_note_space); - Real distance = (ragged) ? max_fixed_note_space : max_note_space; - Spaceable_grob::add_spring (lc, rc, distance, strength, expand_only); + // Spaceable_grob::add_spring (lc, rc, distance, strength, expand_only); + + Spaceable_grob::add_spring (lc, rc, distance, strength, false); } + +/* + The one-size-fits all spacing. It doesn't take into account + different spacing wishes from one to the next column. + */ 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]; - + + *fixed = 0.0; + Direction d = LEFT; + Drul_array cols(l,r); + + do + { + if (!Paper_column::musical_b (cols[d])) + { + /* + Tied accidentals over barlines cause problems, so lets see + what happens if we do this for non musical columns only. + */ + Interval lext = cols[d]->extent (cols [d], X_AXIS); + *fixed += -d * lext[-d]; + } + } + while (flip (&d) != LEFT); + if (l->breakable_b (l) && r->breakable_b(r)) { Moment *dt = unsmob_moment (l->get_grob_property ("measure-length")); @@ -586,8 +688,6 @@ Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r, *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy); } - - } @@ -619,10 +719,20 @@ Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shor pointer munging. */ - assert (spacing_grob-> column_l () == l); + assert (spacing_grob-> get_column () == l); Staff_spacing::get_spacing_params (spacing_grob, - &space, &fixed_space); + &space, &fixed_space); + + if (Paper_column::when_mom (r).grace_part_) + { + /* + Correct for grace notes. + + Ugh. The 0.8 is arbitrary. + */ + space *= 0.8; + } if (space > max_space) { max_space = space; @@ -632,10 +742,21 @@ Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shor - + if (isinf (max_space)) { - programming_error ("No pref spacing found"); + /* + One situation where this can happen is when there is a column + that only serves as a spanning point for a short staff-symbol. + + ===============X=== + + |=======Y + + + (here no StaffSpacing from Y to X is found.) + */ + warning ("No spacing wishes found. Does your score have a staff?"); max_space = 2.0; max_fixed = 1.0; } @@ -652,10 +773,16 @@ Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shor Hmm. we do 1/0 in the next thing. Perhaps we should check if this works on all architectures. */ - - bool ragged = to_boolean (me->paper_l ()->get_scmvar ("raggedright")); - Real strength = (ragged) ? 1.0 : 1 / (max_space - max_fixed); - Real distance = (ragged) ? max_fixed : max_space; + + /* + There used to be code that changed spacing depending on + raggedright setting. Ugh. + + Do it more cleanly, or rename the property. + + */ + Real strength = 1 / (max_space - max_fixed); + Real distance = max_space; Spaceable_grob::add_spring (l, r, distance, strength, false); } @@ -688,8 +815,10 @@ Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool */ Rational ratio = d.main_part_ / shortest; - + +#if 0 *expand_only = true; +#endif return ((k-1) + double (ratio)) * incr; } else @@ -720,7 +849,7 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc, if (! shortest_playing_len.to_bool ()) { - programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).str ()); + programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ()); shortest_playing_len = 1; } @@ -730,6 +859,14 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc, Moment delta_t = rwhen - lwhen; Real dist = 0.0; + /* + In normal situations, the next column is at most + SHORTEST_PLAYING_LEN away. However chord-tremolos do funky faking stuff + with durations, invalidating this assumption. Here we kludge + around to get chord tremolos to behave properly. + + */ + shortest_playing_len = shortest_playing_len >? delta_t; if (delta_t.main_part_ && !lwhen.grace_part_) { dist = get_duration_space (me, shortest_playing_len, shortest.main_part_, expand_only); @@ -757,17 +894,21 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc, ADD_INTERFACE (Spacing_spanner,"spacing-spanner-interface", - " -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. -", - "grace-space-factor spacing-increment shortest-duration-space"); +"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 shortest-duration-space. Notes that are even shorter are\n" +"spaced proportonial to their duration.\n" +"\n" +"Typically, the increment is the width of a black note head. In a\n" +"piece with lots of 8th notes, and some 16th notes, the eighth note\n" +"gets 2 note heads width (i.e. the space following a note is 1 note\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", + "grace-space-factor spacing-increment base-shortest-duration shortest-duration-space common-shortest-duration"); + + + +ADD_INTERFACE (Spacing_interface,"spacing-interface", + "Something to do with line breaking and spacing. Kill this one after determining line breaks.", + "");