From a68f287dcc2277fb7943923426c459dde0426598 Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Sun, 17 Sep 2006 11:02:28 +0000 Subject: [PATCH] * scm/define-music-types.scm (music-descriptions): remove BreakEvent and fix {Page,Line}{Break,Turn}Event so Music::to_event doesn't complain. * lily/accidental-placement.cc (ape_compare): * lily/semi-tie.cc (compare): * lily/note-column.cc (shift_compare): replace by XXX_less * lily/tie-formatting-problem.cc (set_chord_outline): * lily/tie-column.cc (calc_positioning_done): * lily/system.cc (post_processing) (get_paper_system): * lily/stem.cc (note_head_positions) (calc_positioning_done): * lily/spanner.cc (do_break_processing) (find_broken_piece): * lily/span-bar.cc (print): * lily/semi-tie-column.cc (calc_positioning_done): * lily/rest-collision.cc (calc_positioning_done): * lily/program-option.cc (get_help_string): * lily/note-collision.cc (get_clash_groups): * lily/new-fingering-engraver.cc (position_scripts): * lily/keyword.cc (Keyword_table): * lily/hara-kiri-group-spanner.cc (request_suicide): * lily/grob-pq-engraver.cc (stop_translation_timestep): * lily/accidental-placement.cc (calc_positioning_done): (stagger_apes): * lily/beam.cc (get_beam_segments): * lily/grob-array.cc (remove_duplicates): use new vector_sort * input/mutopia/W.A.Mozart/mozart-hrn3-defs.ily: ragged-last-bottom = ##f (test the new page breaker) * flower/include/std-vector.hh (vector_sort): use STL sort stuff * scm/define-context-properties.scm (all-internal-translation-properties): remove properties that were used to communicate page-turn stuff to the paper-column engraver. * lily/lily-guile.cc (robust_scm2string): new function * lily/paper-column-engraver.cc: Clean up page turn stuff * lily/page-turn-engraver.cc: Re-write the page turn logic here instead of cluttering up paper-column-engraver.cc --- ChangeLog | 50 ++++ flower/include/interval.hh | 4 +- flower/include/std-vector.hh | 43 +-- input/mutopia/W.A.Mozart/mozart-hrn3-defs.ily | 1 + lily/accidental-placement.cc | 10 +- lily/beam.cc | 2 +- lily/dot-column.cc | 2 +- lily/grob-array.cc | 2 +- lily/grob-pq-engraver.cc | 13 +- lily/hara-kiri-group-spanner.cc | 2 +- lily/include/lily-guile.hh | 1 + lily/include/note-column.hh | 2 +- lily/include/paper-column-engraver.hh | 3 - lily/include/semi-tie.hh | 4 +- lily/include/spanner.hh | 2 +- lily/include/staff-symbol-referencer.hh | 3 +- lily/include/tie.hh | 4 +- lily/keyword.cc | 7 +- lily/lily-guile.cc | 8 + lily/new-fingering-engraver.cc | 12 +- lily/note-collision.cc | 2 +- lily/note-column.cc | 6 +- lily/page-turn-engraver.cc | 245 ++++++++++++++++-- lily/paper-column-engraver.cc | 95 ------- lily/program-option.cc | 2 +- lily/rest-collision.cc | 2 +- lily/semi-tie-column.cc | 2 +- lily/semi-tie.cc | 8 +- lily/span-bar.cc | 2 +- lily/spanner.cc | 6 +- lily/staff-symbol-referencer.cc | 7 + lily/stem.cc | 10 +- lily/system.cc | 4 +- lily/tie-column.cc | 2 +- lily/tie-formatting-problem.cc | 2 +- lily/tie.cc | 8 +- scm/define-context-properties.scm | 6 +- scm/define-music-types.scm | 11 +- 38 files changed, 371 insertions(+), 224 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8460604166..6919772b25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,53 @@ +2006-09-17 Joe Neeman + + * scm/define-music-types.scm (music-descriptions): remove + BreakEvent and fix {Page,Line}{Break,Turn}Event so + Music::to_event doesn't complain. + + * lily/accidental-placement.cc (ape_compare): + * lily/semi-tie.cc (compare): + * lily/note-column.cc (shift_compare): replace by XXX_less + + * lily/tie-formatting-problem.cc (set_chord_outline): + * lily/tie-column.cc (calc_positioning_done): + * lily/system.cc (post_processing) + (get_paper_system): + * lily/stem.cc (note_head_positions) + (calc_positioning_done): + * lily/spanner.cc (do_break_processing) + (find_broken_piece): + * lily/span-bar.cc (print): + * lily/semi-tie-column.cc (calc_positioning_done): + * lily/rest-collision.cc (calc_positioning_done): + * lily/program-option.cc (get_help_string): + * lily/note-collision.cc (get_clash_groups): + * lily/new-fingering-engraver.cc (position_scripts): + * lily/keyword.cc (Keyword_table): + * lily/hara-kiri-group-spanner.cc (request_suicide): + * lily/grob-pq-engraver.cc (stop_translation_timestep): + * lily/accidental-placement.cc (calc_positioning_done): + (stagger_apes): + * lily/beam.cc (get_beam_segments): + * lily/grob-array.cc (remove_duplicates): + use new vector_sort + + * input/mutopia/W.A.Mozart/mozart-hrn3-defs.ily: + ragged-last-bottom = ##f (test the new page breaker) + + * flower/include/std-vector.hh (vector_sort): use STL sort stuff + + * scm/define-context-properties.scm + (all-internal-translation-properties): remove properties that + were used to communicate page-turn stuff to the paper-column + engraver. + + * lily/lily-guile.cc (robust_scm2string): new function + + * lily/paper-column-engraver.cc: Clean up page turn stuff + + * lily/page-turn-engraver.cc: Re-write the page turn logic here + instead of cluttering up paper-column-engraver.cc + 2006-09-17 Nicolas Sceaux * scm/layout-page-dump.scm (scm): export utility function names, diff --git a/flower/include/interval.hh b/flower/include/interval.hh index 1b095dedc3..7b7d4f54e5 100644 --- a/flower/include/interval.hh +++ b/flower/include/interval.hh @@ -128,9 +128,9 @@ struct Interval_t : public Drul_array at (RIGHT) = t; } - static int left_comparison (Interval_t const &a, Interval_t const &b) + static bool left_less (Interval_t const &a, Interval_t const &b) { - return sign (a[LEFT] - b[RIGHT]); + return a[LEFT] < b[RIGHT]; } }; diff --git a/flower/include/std-vector.hh b/flower/include/std-vector.hh index da3686a07c..10641dc5a0 100644 --- a/flower/include/std-vector.hh +++ b/flower/include/std-vector.hh @@ -191,46 +191,17 @@ binary_search (vector const &v, return lb; } -#if 0 -/* FIXME: the COMPARE functionality is broken? */ -template +template void -vector_sort (vector &v, int (*compare) (T const &, T const &), - vsize lower=VPOS, vsize upper=VPOS) +vector_sort (vector &v, + Compare less, + vsize b=0, vsize e=VPOS) { - typename vector::iterator b = v.begin (); - typename vector::iterator e = v.begin (); - if (lower == VPOS) - { - lower = 0; - upper = v.size (); - } - sort (b + lower, e + upper, compare); -} -#else + if (e == VPOS) + e = v.size (); -// ugh, c&p -template void -vector_sort (vector &v, int (*compare) (T const &, T const &), - vsize lower=VPOS, vsize upper=VPOS) -{ - if (lower == VPOS) - { - lower = 0; - upper = v.size () - 1; - } - if (upper == VPOS || lower >= upper) - return; - swap (v[lower], v[(lower + upper) / 2]); - vsize last = lower; - for (vsize i = lower +1; i <= upper; i++) - if (compare (v[i], v[lower]) < 0) - swap (v[++last], v[i]); - swap (v[lower], v[last]); - vector_sort (v, compare, lower, last - 1); - vector_sort (v, compare, last + 1, upper); + sort (v.begin () + b, v.begin () + e, less); } -#endif template void diff --git a/input/mutopia/W.A.Mozart/mozart-hrn3-defs.ily b/input/mutopia/W.A.Mozart/mozart-hrn3-defs.ily index c383c429de..3a10112524 100644 --- a/input/mutopia/W.A.Mozart/mozart-hrn3-defs.ily +++ b/input/mutopia/W.A.Mozart/mozart-hrn3-defs.ily @@ -45,6 +45,7 @@ cresc = { indent = 10. \mm line-width = 189. \mm + ragged-last-bottom = ##f } diff --git a/lily/accidental-placement.cc b/lily/accidental-placement.cc index f05a5e67f5..2a97f7f382 100644 --- a/lily/accidental-placement.cc +++ b/lily/accidental-placement.cc @@ -135,6 +135,12 @@ int ape_compare (Accidental_placement_entry *const &a, return sign (ape_priority (a) - ape_priority (b)); } +bool ape_less (Accidental_placement_entry *const &a, + Accidental_placement_entry *const &b) +{ + return ape_priority (a) < ape_priority (b); +} + int ape_rcompare (Accidental_placement_entry *const &a, Accidental_placement_entry *const &b) { @@ -154,7 +160,7 @@ stagger_apes (vector *apes) { vector asc = *apes; - vector_sort (asc, &ape_compare); + vector_sort (asc, &ape_less); apes->clear (); @@ -293,7 +299,7 @@ Accidental_placement::calc_positioning_done (SCM smob) for (vsize i = note_cols.size (); i--;) concat (heads, extract_grob_array (note_cols[i], "note-heads")); - vector_sort (heads, default_compare); + vector_sort (heads, less ()); uniq (heads); common[Y_AXIS] = common_refpoint_of_array (heads, common[Y_AXIS], Y_AXIS); diff --git a/lily/beam.cc b/lily/beam.cc index 9dd66cef9a..c52b6f14f9 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -368,7 +368,7 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) i != stem_segments.end (); i++) { vector segs = (*i).second; - vector_sort (segs, default_compare); + vector_sort (segs, less ()); Beam_segment current; diff --git a/lily/dot-column.cc b/lily/dot-column.cc index 3ebddc69a0..ac76bd4a16 100644 --- a/lily/dot-column.cc +++ b/lily/dot-column.cc @@ -233,7 +233,7 @@ Dot_column::calc_positioning_done (SCM smob) } } - vector_sort (dots, &compare_position); + vector_sort (dots, position_less); for (vsize i = dots.size (); i--;) if (!dots[i]->is_live ()) dots.erase (dots.begin () + i); diff --git a/lily/grob-array.cc b/lily/grob-array.cc index dff5102a83..bf85be414c 100644 --- a/lily/grob-array.cc +++ b/lily/grob-array.cc @@ -87,7 +87,7 @@ Grob_array::remove_duplicates () { assert (!ordered_); - vector_sort (grobs_, default_compare); + vector_sort (grobs_, less ()); ::uniq (grobs_); } diff --git a/lily/grob-pq-engraver.cc b/lily/grob-pq-engraver.cc index e4e8b944f9..80d072b404 100644 --- a/lily/grob-pq-engraver.cc +++ b/lily/grob-pq-engraver.cc @@ -15,13 +15,14 @@ struct Grob_pq_entry { Grob *grob_; Moment end_; - static int compare (Grob_pq_entry const &a, - Grob_pq_entry const &b) - { - return Moment::compare (a.end_, b.end_); - } }; +bool +operator< (Grob_pq_entry const &a, Grob_pq_entry const &b) +{ + return a.end_ < b.end_; +} + class Grob_pq_engraver : public Engraver { public: @@ -95,7 +96,7 @@ Grob_pq_engraver::stop_translation_timestep () while (scm_is_pair (busy) && *unsmob_moment (scm_caar (busy)) == now) busy = scm_cdr (busy); - vector_sort (started_now_, Grob_pq_entry::compare); + vector_sort (started_now_, less ()); SCM lst = SCM_EOL; SCM *tail = &lst; for (vsize i = 0; i < started_now_.size (); i++) diff --git a/lily/hara-kiri-group-spanner.cc b/lily/hara-kiri-group-spanner.cc index bc59b12ae7..1515e8fea2 100644 --- a/lily/hara-kiri-group-spanner.cc +++ b/lily/hara-kiri-group-spanner.cc @@ -82,7 +82,7 @@ Hara_kiri_group_spanner::request_suicide (Grob *me, int start, int end) for (int j = iv[LEFT]; j <= iv[RIGHT]; j++) ranks.push_back (j); } - vector_sort (ranks, default_compare); + vector_sort (ranks, less ()); uniq (ranks); SCM scm_vec = scm_c_make_vector (ranks.size (), SCM_EOL); diff --git a/lily/include/lily-guile.hh b/lily/include/lily-guile.hh index 23b3c64785..07abff74ef 100644 --- a/lily/include/lily-guile.hh +++ b/lily/include/lily-guile.hh @@ -64,6 +64,7 @@ Drul_array robust_scm2drul (SCM, Drul_array); Drul_array robust_scm2booldrul (SCM, Drul_array); Interval robust_scm2interval (SCM, Drul_array); Offset robust_scm2offset (SCM, Offset); +string robust_scm2string (SCM, string); SCM ly_quote_scm (SCM s); bool type_check_assignment (SCM val, SCM sym, SCM type_symbol); diff --git a/lily/include/note-column.hh b/lily/include/note-column.hh index 5085ee52eb..ec12414539 100644 --- a/lily/include/note-column.hh +++ b/lily/include/note-column.hh @@ -19,7 +19,7 @@ class Note_column { public: - static int shift_compare (Grob *const &, Grob *const &); + static bool shift_less (Grob *const &, Grob *const &); static Direction dir (Grob *me); static Grob *accidentals (Grob *me); static Grob *arpeggio (Grob *me); diff --git a/lily/include/paper-column-engraver.hh b/lily/include/paper-column-engraver.hh index e5db58c7a3..5f3131ccb0 100644 --- a/lily/include/paper-column-engraver.hh +++ b/lily/include/paper-column-engraver.hh @@ -44,9 +44,6 @@ protected: bool first_; Moment last_moment_; - Paper_column *last_special_barline_column_; - Paper_column *last_breakable_column_; - vector page_turnable_columns_; public: }; diff --git a/lily/include/semi-tie.hh b/lily/include/semi-tie.hh index d0a0baf5b7..ec63c627ef 100644 --- a/lily/include/semi-tie.hh +++ b/lily/include/semi-tie.hh @@ -20,8 +20,8 @@ struct Semi_tie DECLARE_SCHEME_CALLBACK (calc_direction, (SCM)); DECLARE_SCHEME_CALLBACK (calc_control_points, (SCM)); - static int compare (Grob *const &s1, - Grob *const &s2); + static bool less (Grob *const &s1, + Grob *const &s2); static int get_position (Grob *); }; diff --git a/lily/include/spanner.hh b/lily/include/spanner.hh index 2e8906ab96..91153b79b8 100644 --- a/lily/include/spanner.hh +++ b/lily/include/spanner.hh @@ -56,7 +56,7 @@ public: Real spanner_length () const; static int compare (Spanner *const &, Spanner *const &); - static bool less_than (Spanner *const &, Spanner *const &); + static bool less (Spanner *const &, Spanner *const &); virtual Grob *find_broken_piece (System *) const; virtual void derived_mark () const; static bool has_interface (Grob *); diff --git a/lily/include/staff-symbol-referencer.hh b/lily/include/staff-symbol-referencer.hh index 5e1fd878fd..1b4c096b8e 100644 --- a/lily/include/staff-symbol-referencer.hh +++ b/lily/include/staff-symbol-referencer.hh @@ -40,6 +40,7 @@ public: static int get_rounded_position (Grob *); }; -int compare_position (Grob *const &, Grob *const &); +int compare_position (Grob *const &, Grob *const &);\ +bool position_less (Grob *const &, Grob *const &); #endif /* STAFF_SYMBOL_REFERENCER_HH */ diff --git a/lily/include/tie.hh b/lily/include/tie.hh index 5b3706dafd..7f96b826cf 100644 --- a/lily/include/tie.hh +++ b/lily/include/tie.hh @@ -33,8 +33,8 @@ public: DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM)); DECLARE_SCHEME_CALLBACK (calc_direction, (SCM)); DECLARE_SCHEME_CALLBACK (calc_control_points, (SCM)); - static int compare (Grob *const &s1, - Grob *const &s2); + static bool less (Grob *const &s1, + Grob *const &s2); }; diff --git a/lily/keyword.cc b/lily/keyword.cc index 8f969e6ce8..b5f7947ada 100644 --- a/lily/keyword.cc +++ b/lily/keyword.cc @@ -14,17 +14,12 @@ bool tab_less (Keyword_ent const &p1, Keyword_ent const &p2) return strcmp (p1.name_, p2.name_) < 0; } -int tabcmp (Keyword_ent const &p1, Keyword_ent const &p2) -{ - return strcmp (p1.name_, p2.name_); -} - Keyword_table::Keyword_table (Keyword_ent *tab) { while (tab->name_) table_.push_back (*tab++); - vector_sort (table_, tabcmp); + vector_sort (table_, tab_less); } vsize diff --git a/lily/lily-guile.cc b/lily/lily-guile.cc index 971063e54e..e1a0e9bffd 100644 --- a/lily/lily-guile.cc +++ b/lily/lily-guile.cc @@ -653,6 +653,14 @@ robust_scm2offset (SCM k, Offset o) return o; } +string +robust_scm2string (SCM k, string s) +{ + if (scm_is_string (k)) + s = ly_scm2string (k); + return s; +} + int robust_scm2int (SCM k, int o) { diff --git a/lily/new-fingering-engraver.cc b/lily/new-fingering-engraver.cc index cb2a1bd202..75e893c351 100644 --- a/lily/new-fingering-engraver.cc +++ b/lily/new-fingering-engraver.cc @@ -35,12 +35,14 @@ struct Finger_tuple note_event_ = finger_event_ = 0; follow_into_staff_ = false; } - static int compare (Finger_tuple const &c1, Finger_tuple const &c2) - { - return c1.position_- c2.position_; - } }; +bool +operator< (Finger_tuple const &a, Finger_tuple const &b) +{ + return a.position_ < b.position_; +} + class New_fingering_engraver : public Engraver { vector fingerings_; @@ -220,7 +222,7 @@ New_fingering_engraver::position_scripts (SCM orientations, } } - vector_sort (*scripts, Finger_tuple::compare); + vector_sort (*scripts, less ()); bool up_p = scm_c_memq (ly_symbol2scm ("up"), orientations) != SCM_BOOL_F; bool down_p = scm_c_memq (ly_symbol2scm ("down"), orientations) != SCM_BOOL_F; diff --git a/lily/note-collision.cc b/lily/note-collision.cc index e84e5263c6..d9a08dcdc8 100644 --- a/lily/note-collision.cc +++ b/lily/note-collision.cc @@ -371,7 +371,7 @@ Note_collision_interface::get_clash_groups (Grob *me) do { vector &clashes (clash_groups[d]); - vector_sort (clashes, Note_column::shift_compare); + vector_sort (clashes, Note_column::shift_less); } while ((flip (&d)) != UP); diff --git a/lily/note-column.cc b/lily/note-column.cc index c77aa351f5..146b3b0654 100644 --- a/lily/note-column.cc +++ b/lily/note-column.cc @@ -34,15 +34,15 @@ Note_column::has_rests (Grob *me) return unsmob_grob (me->get_object ("rest")); } -int -Note_column::shift_compare (Grob *const &p1, Grob *const &p2) +bool +Note_column::shift_less (Grob *const &p1, Grob *const &p2) { SCM s1 = p1->get_property ("horizontal-shift"); SCM s2 = p2->get_property ("horizontal-shift"); int h1 = (scm_is_number (s1)) ? scm_to_int (s1) : 0; int h2 = (scm_is_number (s2)) ? scm_to_int (s2) : 0; - return h1 - h2; + return h1 < h2; } Item * diff --git a/lily/page-turn-engraver.cc b/lily/page-turn-engraver.cc index 1a2bf5f5b4..56abfb256c 100644 --- a/lily/page-turn-engraver.cc +++ b/lily/page-turn-engraver.cc @@ -13,8 +13,58 @@ #include "grob.hh" #include "international.hh" #include "moment.hh" +#include "paper-column.hh" +#include "stream-event.hh" #include "warn.hh" +#include "translator.icc" + +class Page_turn_event { +public: + SCM permission_; + Real penalty_; + Interval_t duration_; + + Page_turn_event (Rational start, Rational end, SCM perm, Real pen) + { + duration_[LEFT] = start; + duration_[RIGHT] = end; + permission_ = perm; + penalty_ = pen; + } + + /* Suppose we have decided on a possible page turn, only to change + out mind later (for example, if there is a volta repeat and it + would be difficult to turn the page back). Then we need to + re-penalize a region of the piece. Depending on how the events + intersect, we may have to split it into as many as 3 pieces. + */ + vector penalize (Page_turn_event const &penalty) + { + Interval_t intersect = intersection (duration_, penalty.duration_); + vector ret; + + if (intersect.is_empty ()) + { + ret.push_back (*this); + return ret; + } + + Real new_pen = max (penalty_, penalty.penalty_); + + if (duration_[LEFT] < penalty.duration_[LEFT]) + ret.push_back (Page_turn_event (duration_[LEFT], penalty.duration_[LEFT], permission_, penalty_)); + + if (penalty.permission_ != SCM_EOL) + ret.push_back (Page_turn_event (intersect[LEFT], intersect[RIGHT], permission_, new_pen)); + + if (penalty.duration_[RIGHT] < duration_[RIGHT]) + ret.push_back (Page_turn_event (penalty.duration_[RIGHT], duration_[LEFT], permission_, penalty_)); + + return ret; + } +}; + class Page_turn_engraver : public Engraver { Moment rest_begin_; @@ -22,14 +72,28 @@ class Page_turn_engraver : public Engraver Moment note_end_; Rational repeat_begin_rest_length_; + vector forced_breaks_; + vector automatic_breaks_; + vector repeat_penalties_; + + /* the next 3 are in sync (ie. same number of elements, etc.) */ + vector breakable_moments_; + vector breakable_columns_; + vector special_barlines_; + + SCM max_permission (SCM perm1, SCM perm2); Real penalty (Rational rest_len); + Grob *breakable_column (Page_turn_event const &); protected: + DECLARE_TRANSLATOR_LISTENER (break); DECLARE_ACKNOWLEDGER (note_head); public: TRANSLATOR_DECLARATIONS (Page_turn_engraver); void stop_translation_timestep (); + void start_translation_timestep (); + void finalize (); }; Page_turn_engraver::Page_turn_engraver () @@ -40,10 +104,32 @@ Page_turn_engraver::Page_turn_engraver () note_end_ = 0; } +Grob* +Page_turn_engraver::breakable_column (Page_turn_event const &brk) +{ + vsize start = lower_bound (breakable_moments_, brk.duration_[LEFT], less ()); + vsize end = upper_bound (breakable_moments_, brk.duration_[RIGHT], less ()); + + if (start == breakable_moments_.size ()) + return NULL; + if (end == breakable_moments_.size () || breakable_moments_[end] > brk.duration_[RIGHT]) + { + if (end == 0) + return NULL; + end--; + } + + for (vsize i = end + 1; i-- > start;) + if (special_barlines_[i]) + return breakable_columns_[i]; + + return breakable_columns_[end]; +} + Real Page_turn_engraver::penalty (Rational rest_len) { - Rational min_turn = robust_scm2moment (get_property ("minPageTurnLength"), Moment (1)).main_part_; + Rational min_turn = robust_scm2moment (get_property ("minimumPageTurnLength"), Moment (1)).main_part_; return (rest_len < min_turn) ? infinity_f : 0; } @@ -62,10 +148,9 @@ Page_turn_engraver::acknowledge_note_head (Grob_info gi) { Real pen = penalty ((now_mom () - rest_begin_).main_part_); if (!isinf (pen)) - { - SCM val = scm_cons (rest_begin_.smobbed_copy (), scm_from_double (pen)); - context ()->get_score_context ()->set_property ("allowPageTurn", val); - } + automatic_breaks_.push_back (Page_turn_event (rest_begin_.main_part_, + now_mom ().main_part_, + ly_symbol2scm ("allow"), 0)); } if (rest_begin_ <= repeat_begin_) @@ -73,9 +158,59 @@ Page_turn_engraver::acknowledge_note_head (Grob_info gi) note_end_ = now_mom () + Moment (Duration (dur_log, dot_count).get_length ()); } +IMPLEMENT_TRANSLATOR_LISTENER (Page_turn_engraver, break); +void +Page_turn_engraver::listen_break (Stream_event *ev) +{ + string name = ly_scm2string (scm_symbol_to_string (ev->get_property ("class"))); + + if (name == "page-turn-event") + { + SCM permission = ev->get_property ("break-permission"); + Real penalty = robust_scm2double (ev->get_property ("break-penalty"), 0); + Rational now = now_mom ().main_part_; + + forced_breaks_.push_back (Page_turn_event (now, now, permission, penalty)); + } +} + +void +Page_turn_engraver::start_translation_timestep () +{ + /* What we want to do is to build a list of all the + breakable paper columns. In general, paper-columns won't be marked as + such until the Paper_column_engraver has done stop_translation_timestep. + + Therefore, we just grab /all/ paper columns (in the + stop_translation_timestep, since they're not created here yet) + and remove the non-breakable ones at the beginning of the following + timestep. + */ + + if (breakable_columns_.size () && !Paper_column::is_breakable (breakable_columns_.back ())) + { + breakable_columns_.pop_back (); + breakable_moments_.pop_back (); + special_barlines_.pop_back (); + } +} + void Page_turn_engraver::stop_translation_timestep () { + Grob *pc = unsmob_grob (get_property ("currentCommandColumn")); + + if (pc) + { + breakable_columns_.push_back (pc); + breakable_moments_.push_back (now_mom ().main_part_); + + SCM bar_scm = get_property ("whichBar"); + string bar = robust_scm2string (bar_scm, ""); + + special_barlines_.push_back (bar != "" && bar != "|"); + } + /* C&P from Repeat_acknowledge_engraver */ SCM cs = get_property ("repeatCommands"); bool start = false; @@ -92,17 +227,20 @@ Page_turn_engraver::stop_translation_timestep () if (end && repeat_begin_.main_part_ >= Moment (0)) { + Rational now = now_mom ().main_part_; Real pen = penalty ((now_mom () - rest_begin_).main_part_ + repeat_begin_rest_length_); Moment *m = unsmob_moment (get_property ("minimumRepeatLengthForPageTurn")); if (m && *m > (now_mom () - repeat_begin_)) pen = infinity_f; - if (pen > 0) - { - SCM val = scm_cons (repeat_begin_.smobbed_copy (), scm_from_double (pen)); - context ()->get_score_context ()->set_property ("revokePageTurns", val); - } + + if (pen == infinity_f) + repeat_penalties_.push_back (Page_turn_event (repeat_begin_.main_part_, now, SCM_EOL, -infinity_f)); + else + repeat_penalties_.push_back (Page_turn_event (repeat_begin_.main_part_, now, ly_symbol2scm ("allow"), pen)); + repeat_begin_ = Moment (-1); } + if (start) { repeat_begin_ = now_mom (); @@ -111,15 +249,92 @@ Page_turn_engraver::stop_translation_timestep () rest_begin_ = note_end_; } -#include "translator.icc" +/* return the most permissive symbol (where force is the most permissive and + forbid is the least +*/ +SCM +Page_turn_engraver::max_permission (SCM perm1, SCM perm2) +{ + if (perm1 == SCM_EOL) + return perm2; + if (perm1 == ly_symbol2scm ("allow") && perm2 == ly_symbol2scm ("force")) + return perm2; + return perm1; +} + +void +Page_turn_engraver::finalize () +{ + vsize rep_index = 0; + vector auto_breaks; + + /* filter the automatic breaks through the repeat penalties */ + for (vsize i = 0; i < automatic_breaks_.size (); i++) + { + Page_turn_event &brk = automatic_breaks_[i]; + + /* find the next applicable repeat penalty */ + for (; + rep_index < repeat_penalties_.size () + && repeat_penalties_[rep_index].duration_[RIGHT] <= brk.duration_[LEFT]; + rep_index++) + ; + + if (rep_index >= repeat_penalties_.size () + || brk.duration_[RIGHT] <= repeat_penalties_[rep_index].duration_[LEFT]) + auto_breaks.push_back (brk); + else + { + vector split = brk.penalize (repeat_penalties_[rep_index]); + + /* it's possible that the last of my newly-split events overlaps the next repeat_penalty, + in which case we need to refilter that event */ + if (rep_index < repeat_penalties_.size () - 1 + && split.size () + && split.back ().duration_[RIGHT] > repeat_penalties_[rep_index+1].duration_[LEFT]) + { + automatic_breaks_[i] = split.back (); + split.pop_back (); + i--; + } + auto_breaks.insert (auto_breaks.end (), split.begin (), split.end ()); + } + } + + /* apply the automatic breaks */ + for (vsize i = 0; i < auto_breaks.size (); i++) + { + Page_turn_event const &brk = auto_breaks[i]; + Grob *pc = breakable_column (auto_breaks[i]); + if (pc) + { + SCM perm = max_permission (pc->get_property ("page-turn-permission"), brk.permission_); + Real pen = min (robust_scm2double (pc->get_property ("page-turn-penalty"), infinity_f), brk.penalty_); + pc->set_property ("page-turn-permission", perm); + pc->set_property ("page-turn-penalty", scm_from_double (pen)); + } + } + + /* apply the manual breaks */ + for (vsize i = 0; i < forced_breaks_.size (); i++) + { + Page_turn_event const &brk = forced_breaks_[i]; + Grob *pc = breakable_column (forced_breaks_[i]); + if (pc) + { + pc->set_property ("page-turn-permission", brk.permission_); + pc->set_property ("page-turn-penalty", scm_from_double (brk.penalty_)); + } + } +} ADD_ACKNOWLEDGER (Page_turn_engraver, note_head); ADD_TRANSLATOR (Page_turn_engraver, /* doc */ "Decide where page turns are allowed to go", /* create */ "", /* accept */ "", - /* read */ "", - /* write */ - "allowPageTurn " - "revokePageTurns " + /* read */ + "minimumPageTurnLength " + "minimumRepeatLengthForPageTurn ", + /* write */ "" ); diff --git a/lily/paper-column-engraver.cc b/lily/paper-column-engraver.cc index 2768349511..af67b67fe2 100644 --- a/lily/paper-column-engraver.cc +++ b/lily/paper-column-engraver.cc @@ -28,8 +28,6 @@ Paper_column_engraver::Paper_column_engraver () musical_column_ = 0; breaks_ = 0; system_ = 0; - last_special_barline_column_ = 0; - last_breakable_column_ = 0; first_ = true; } @@ -171,56 +169,6 @@ Paper_column_engraver::process_music () } } -/* return either - - the last column with a special (ie. not "|" or "") barline - - the last column - after the given moment -*/ -Paper_column* -Paper_column_engraver::find_turnable_column (Moment after_this) -{ - if (last_special_barline_column_) - { - Moment m = *unsmob_moment (last_special_barline_column_->get_property ("when")); - if (m >= after_this) - return last_special_barline_column_; - } - if (last_breakable_column_) - { - Moment m = *unsmob_moment (last_breakable_column_->get_property ("when")); - if (m >= after_this) - return last_breakable_column_; - } - return 0; -} - -void -Paper_column_engraver::revoke_page_turns (Moment after_this, Real new_penalty) -{ - if (!page_turnable_columns_.size ()) - return; - - for (vsize i = page_turnable_columns_.size () - 1; i--;) - { - Paper_column *col = page_turnable_columns_[i]; - Moment mom = *unsmob_moment (col->get_property ("when")); - if (mom >= after_this) - { - if (isinf (new_penalty)) - { - col->del_property ( ly_symbol2scm ("page-turn-permission")); - page_turnable_columns_.erase (page_turnable_columns_.begin () + i); - } - else - { - Real prev_pen = robust_scm2double (col->get_property ("page-turn-penalty"), 0); - if (new_penalty > prev_pen) - col->set_property ("page-turn-penalty", scm_from_double (new_penalty)); - } - } - } -} - void Paper_column_engraver::stop_translation_timestep () { @@ -245,51 +193,12 @@ Paper_column_engraver::stop_translation_timestep () else if (Paper_column::is_breakable (command_column_)) { breaks_++; - last_breakable_column_ = command_column_; - - SCM which_bar = get_property ("whichBar"); - if (scm_is_string (which_bar)) - { - string bar = ly_scm2string (which_bar); - if (bar != "" && bar != "|") - last_special_barline_column_ = command_column_; - } if (! (breaks_%8)) progress_indication ("[" + to_string (breaks_) + "]"); } - SCM page_br = get_property ("allowPageTurn"); - if (scm_is_pair (page_br) && last_breakable_column_) - { - SCM pen = scm_cdr (page_br); - Moment *m = unsmob_moment (scm_car (page_br)); - if (m) - { - Paper_column *turn = find_turnable_column (*m); - if (turn) - { - turn->set_property ("page-turn-permission", ly_symbol2scm ("allow")); - turn->set_property ("page-turn-penalty", pen); - page_turnable_columns_.push_back (turn); - } - } - } - - /* The page-turn-engraver is allowed to change its mind and revoke previously-allowed - page turns (for example if there is a volta repeat where a turn is inconvenient) */ - SCM revokes = get_property ("revokePageTurns"); - if (scm_is_pair (revokes)) - { - Moment *start = unsmob_moment (scm_car (revokes)); - Real pen = robust_scm2double (scm_cdr (revokes), infinity_f); - if (start) - revoke_page_turns (*start, pen); - } - context ()->get_score_context ()->unset_property (ly_symbol2scm ("forbidBreak")); - context ()->get_score_context ()->unset_property (ly_symbol2scm ("allowPageTurn")); - context ()->get_score_context ()->unset_property (ly_symbol2scm ("revokePageTurns")); first_ = false; break_events_.clear (); @@ -326,13 +235,9 @@ ADD_TRANSLATOR (Paper_column_engraver, /* accept */ "break-event", /* read */ "forbidBreak " - "allowPageTurn " - "revokePageTurns " , /* write */ "forbidBreak " - "allowPageTurn " - "revokePageTurns " "currentCommandColumn " "currentMusicalColumn " ); diff --git a/lily/program-option.cc b/lily/program-option.cc index 279cb37686..9ec4901c85 100644 --- a/lily/program-option.cc +++ b/lily/program-option.cc @@ -133,7 +133,7 @@ get_help_string () } string help ("Options supported by ly:set-option\n\n"); - vector_sort (opts, string_compare); + vector_sort (opts, less ()); for (vsize i = 0; i < opts.size (); i++) help += opts[i]; diff --git a/lily/rest-collision.cc b/lily/rest-collision.cc index e10a7f0cc4..a2c9fa63c0 100644 --- a/lily/rest-collision.cc +++ b/lily/rest-collision.cc @@ -151,7 +151,7 @@ Rest_collision::calc_positioning_done (SCM smob) Direction d = LEFT; do - vector_sort (ordered_rests[d], Note_column::shift_compare); + vector_sort (ordered_rests[d], Note_column::shift_less); while (flip (&d) != LEFT) ; diff --git a/lily/semi-tie-column.cc b/lily/semi-tie-column.cc index a7542249b1..055b377c72 100644 --- a/lily/semi-tie-column.cc +++ b/lily/semi-tie-column.cc @@ -45,7 +45,7 @@ Semi_tie_column::calc_positioning_done (SCM smob) extract_grob_set (me, "ties", lv_ro_ties); vector lv_ties (lv_ro_ties); - vector_sort (lv_ties, &Semi_tie::compare); + vector_sort (lv_ties, Semi_tie::less); Ties_configuration ties_config; diff --git a/lily/semi-tie.cc b/lily/semi-tie.cc index bddae0e2b2..fbc98f20aa 100644 --- a/lily/semi-tie.cc +++ b/lily/semi-tie.cc @@ -70,10 +70,10 @@ Semi_tie::get_position (Grob *me) return (int) rint (Staff_symbol_referencer::get_position (h)); } -int -Semi_tie::compare (Grob *const &s1, - Grob *const &s2) +bool +Semi_tie::less (Grob *const &s1, + Grob *const &s2) { - return sign (get_position (s1) - get_position (s2)); + return get_position (s1) < get_position (s2); } diff --git a/lily/span-bar.cc b/lily/span-bar.cc index 84fe893a0c..5c1c76e855 100644 --- a/lily/span-bar.cc +++ b/lily/span-bar.cc @@ -72,7 +72,7 @@ Span_bar::print (SCM smobbed_me) if (!model_bar) model_bar = me; - vector_sort (extents, Interval::left_comparison); + vector_sort (extents, Interval::left_less); Stencil span_bar; for (vsize i = 1; i < extents.size (); i++) diff --git a/lily/spanner.cc b/lily/spanner.cc index f8726a8647..77285e8ed1 100644 --- a/lily/spanner.cc +++ b/lily/spanner.cc @@ -124,7 +124,7 @@ Spanner::do_break_processing () } } } - vector_sort (broken_intos_, Spanner::compare); + vector_sort (broken_intos_, Spanner::less); for (vsize i = broken_intos_.size (); i--;) broken_intos_[i]->break_index_ = i; } @@ -238,7 +238,7 @@ Spanner::get_system () const Grob * Spanner::find_broken_piece (System *l) const { - vsize idx = binary_search (broken_intos_, (Spanner *)l, Spanner::less_than); + vsize idx = binary_search (broken_intos_, (Spanner *)l, Spanner::less); if (idx != VPOS) return broken_intos_ [idx]; return 0; @@ -251,7 +251,7 @@ Spanner::compare (Spanner *const &p1, Spanner *const &p2) } bool -Spanner::less_than (Spanner *const &a, Spanner *const &b) +Spanner::less (Spanner *const &a, Spanner *const &b) { return a->get_system ()->get_rank () < b->get_system ()->get_rank (); } diff --git a/lily/staff-symbol-referencer.cc b/lily/staff-symbol-referencer.cc index 87e83fadad..aa45e55e7a 100644 --- a/lily/staff-symbol-referencer.cc +++ b/lily/staff-symbol-referencer.cc @@ -156,6 +156,13 @@ compare_position (Grob *const &a, Grob *const &b) - Staff_symbol_referencer::get_position ((Grob *) b)); } +bool +position_less (Grob *const &a, Grob *const &b) +{ + return Staff_symbol_referencer::get_position (a) + < Staff_symbol_referencer::get_position (b); +} + ADD_INTERFACE (Staff_symbol_referencer, "staff-symbol-referencer-interface", "An object whose Y position is meant relative to a staff " "symbol. " diff --git a/lily/stem.cc b/lily/stem.cc index d95ff4be39..6a0fb43485 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -180,12 +180,6 @@ Stem::extremal_heads (Grob *me) return exthead; } -static int -integer_compare (int const &a, int const &b) -{ - return a - b; -} - /* The positions, in ascending order. */ vector Stem::note_head_positions (Grob *me) @@ -201,7 +195,7 @@ Stem::note_head_positions (Grob *me) ps.push_back (p); } - vector_sort (ps, integer_compare); + vector_sort (ps, less ()); return ps; } @@ -410,7 +404,7 @@ Stem::calc_positioning_done (SCM smob) extract_grob_set (me, "note-heads", ro_heads); vector heads (ro_heads); - vector_sort (heads, compare_position); + vector_sort (heads, position_less); Direction dir = get_grob_direction (me); if (dir < 0) diff --git a/lily/system.cc b/lily/system.cc index 54562cdc04..07c705ffe6 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -317,7 +317,7 @@ System::post_processing () anyway. */ vector all_elts_sorted (all_elements_->array ()); - vector_sort (all_elts_sorted, default_compare); + vector_sort (all_elts_sorted, std::less ()); uniq (all_elts_sorted); this->get_stencil (); for (vsize i = all_elts_sorted.size (); i--;) @@ -357,7 +357,7 @@ System::get_paper_system () entries.push_back (e); } - vector_sort (entries, default_compare); + vector_sort (entries, std::less ()); for (vsize j = 0; j < entries.size (); j++) { Grob *g = entries[j].grob_; diff --git a/lily/tie-column.cc b/lily/tie-column.cc index e8384f1855..13d5fb0177 100644 --- a/lily/tie-column.cc +++ b/lily/tie-column.cc @@ -83,7 +83,7 @@ Tie_column::calc_positioning_done (SCM smob) return SCM_BOOL_T; } - vector_sort (ties, &Tie::compare); + vector_sort (ties, Tie::less); Tie_formatting_problem problem; problem.from_ties (ties); diff --git a/lily/tie-formatting-problem.cc b/lily/tie-formatting-problem.cc index dada24694c..d5bd961887 100644 --- a/lily/tie-formatting-problem.cc +++ b/lily/tie-formatting-problem.cc @@ -219,7 +219,7 @@ Tie_formatting_problem::set_chord_outline (vector bounds, for (vsize i = 0; i < bounds.size (); i++) ranks.push_back (bounds[i]->get_column ()->get_rank ()); - vector_sort (ranks, default_compare); + vector_sort (ranks, less ()); uniq (ranks); for (vsize i = 0; i < ranks.size (); i++) diff --git a/lily/tie.cc b/lily/tie.cc index 3f282071e7..f6561fa576 100644 --- a/lily/tie.cc +++ b/lily/tie.cc @@ -28,11 +28,11 @@ #include "warn.hh" -int -Tie::compare (Grob *const &s1, - Grob *const &s2) +bool +Tie::less (Grob *const &s1, + Grob *const &s2) { - return sign (Tie::get_position (s1) - Tie::get_position (s2)); + return Tie::get_position (s1) < Tie::get_position (s2); } void diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 2eee74626a..7e2aca836c 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -39,8 +39,6 @@ "If true, then the accidentals are aligned in bass figure context.") (allowBeamBreak ,boolean? "If true allow line breaks for beams over bar lines.") - (allowPageTurn ,pair? "In the form (moment-start . penalty). Allow a page turn -at the most recent breakpoint if it was after moment-start.") (associatedVoice ,string? "Name of the @code{Voice} that has the melody for this @code{Lyrics} line.") (autoBeamSettings ,list? "Specifies @@ -313,6 +311,9 @@ markup. Called with 2 arguments, event and context.") (midiMaximumVolume ,number? "Analogous to @code{midiMinimumVolume}.") (minimumFret ,number? "The tablature auto string-selecting mechanism selects the highest string with a fret at least @code{minimumFret}") + (minimumPageTurnLength ,ly:moment? "Minimum length of a rest for a page turn to be allowed") + (minimumRepeatLengthForPageTurn ,ly:moment? "Minimum length of a repeated section for a page +turn to be allowed within that section") (minimumVerticalExtent ,number-pair? "minimum vertical extent, same format as @var{verticalExtent}") (output ,ly:music-output? "The output produced by a score-level translator during music interpretation") @@ -346,7 +347,6 @@ whether they are processed in this context.") (restNumberThreshold ,number? "If a multimeasure rest has more measures than this, a number is printed. ") - (revokePageTurns ,pair? "Signals to the paper-column-engraver to revoke (or increase the penalties for) all the page turns within a time interval. Used to disable page turns that occur within an unturnable volta repeat.") (shapeNoteStyles ,vector? "Vector of symbols, listing style for each note head relative to the tonic (qv.) of the scale.") (shortInstrumentName ,markup? "See @code{instrument}") diff --git a/scm/define-music-types.scm b/scm/define-music-types.scm index 41ded2f871..bfed38e04d 100644 --- a/scm/define-music-types.scm +++ b/scm/define-music-types.scm @@ -104,17 +104,10 @@ Syntax for manual control: c8-[ c c-] c8") (types . (general-music event beam-event span-event)) )) - (BendAfterEvent . ((description . "A drop/fall/doit jazz articulation") (types . (general-music bend-after-event event)))) - (BreakEvent - . ( - (description . "Create a line break, Syntax: \\break or page break, Syntax: \\pagebreak.") - - (types . (general-music break-event event)) - )) (BreathingEvent . ( (description . "Creates a `breath mark' or `comma'. @@ -343,12 +336,12 @@ SYNTAX (PageBreakEvent . ( (description . "Allow, forbid or force a page break.") - (types . (general-music break-event event)) + (types . (general-music break-event page-break-event event)) )) (PageTurnEvent . ( (description . "Allow, forbid or force a page turn.") - (types . (general-music break-event event)) + (types . (general-music break-event page-turn-event event)) )) (PartCombineMusic . ( -- 2.39.2