Index: ChangeLog =================================================================== RCS file: /sources/lilypond/lilypond/ChangeLog,v retrieving revision 1.5109 diff -u -r1.5109 ChangeLog --- ChangeLog 9 Jun 2006 02:20:21 -0000 1.5109 +++ ChangeLog 9 Jun 2006 09:42:51 -0000 @@ -1,3 +1,24 @@ +2006-06-09 Joe Neeman + + * scm/page.scm (make-page): make it a bit friendlier to call + (make-page-stencil): don't crash if we annotate-layout when there is a + page with no systems + + * scm/layout-page-layout.scm (space-systems): make public and move + to toplevel so it can be called from C++ + (optimal-page-breaks): new interface to page-breaking + + * scm/define-context-properties.scm (all-user-translation-properties): + add revokePageTurns + + * lily/paper-column-engraver.cc (stop_translation_timestep): new + function to support breaking at special barlines preferably + (revoke_page_turns): new function to support revoking page turns if there + is an inconvenient volta repeat + (stop_translation_timestep): support the 2 new utility functions + + * lily/paper-book.cc (pages): new interface to page-breaking + 2006-06-08 Joe Neeman * scm/paper-system.scm (paper-system-annotate): also annotate the Index: lily/constrained-breaking.cc =================================================================== RCS file: /sources/lilypond/lilypond/lily/constrained-breaking.cc,v retrieving revision 1.7 diff -u -r1.7 constrained-breaking.cc --- lily/constrained-breaking.cc 9 Jun 2006 02:20:22 -0000 1.7 +++ lily/constrained-breaking.cc 9 Jun 2006 09:42:51 -0000 @@ -176,9 +176,14 @@ bool last = j == breaks_.size () - 1; bool ragged = ragged_right || (last && ragged_last); int k = i*lines_rank_ + j; - SCM pen = all_[breaks_[j]]->get_property ("line-break-penalty"); - if (scm_is_number (pen)) - lines_[k].break_penalty_ = scm_to_double (pen); + + Grob *c = all_[breaks_[j]]; + lines_[k].break_penalty_ = robust_scm2double (c->get_property ("line-break-penalty"), 0); + lines_[k].page_penalty_ = robust_scm2double (c->get_property ("page-break-penalty"), 0); + lines_[k].turn_penalty_ = robust_scm2double (c->get_property ("page-turn-penalty"), 0); + lines_[k].break_permission_ = c->get_property ("line-break-permission"); + lines_[k].page_permission_ = c->get_property ("page-break-permission"); + lines_[k].turn_permission_ = c->get_property ("page-turn-permission"); max_ext = max (max_ext, extent.length ()); lines_[k].force_ = forces[k]; @@ -276,6 +281,7 @@ ret.push_back (st[sys*rank + brk].details_); brk = st[sys*rank + brk].prev_; } + reverse (ret); return ret; } Index: lily/paper-book.cc =================================================================== RCS file: /sources/lilypond/lilypond/lily/paper-book.cc,v retrieving revision 1.132 diff -u -r1.132 paper-book.cc --- lily/paper-book.cc 15 Feb 2006 13:02:17 -0000 1.132 +++ lily/paper-book.cc 9 Jun 2006 09:42:51 -0000 @@ -381,7 +381,7 @@ pages_ = SCM_EOL; SCM proc = paper_->c_variable ("page-breaking"); - pages_ = scm_apply_0 (proc, scm_list_2 (systems (), self_scm ())); + pages_ = scm_apply_0 (proc, scm_list_1(self_scm ())); return pages_; } Index: lily/paper-column-engraver.cc =================================================================== RCS file: /sources/lilypond/lilypond/lily/paper-column-engraver.cc,v retrieving revision 1.17 diff -u -r1.17 paper-column-engraver.cc --- lily/paper-column-engraver.cc 10 May 2006 10:37:12 -0000 1.17 +++ lily/paper-column-engraver.cc 9 Jun 2006 09:42:52 -0000 @@ -8,6 +8,7 @@ #include "paper-column-engraver.hh" #include "system.hh" +#include "international.hh" #include "item.hh" #include "paper-column.hh" #include "staff-spacing.hh" @@ -27,9 +28,9 @@ musical_column_ = 0; breaks_ = 0; system_ = 0; - first_ = true; + last_special_barline_column_ = 0; last_breakable_column_ = 0; - last_breakable_moment_ = Moment (-1); + first_ = true; } void @@ -84,6 +85,7 @@ ly_symbol2scm ("spacing-wishes"), gi.grob ()); } + void Paper_column_engraver::acknowledge_note_spacing (Grob_info gi) { @@ -169,6 +171,53 @@ } } +/* 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) +{ + for (vsize i = page_turnable_columns_.size () - 1; i != VPOS; 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 () { @@ -190,25 +239,50 @@ { breaks_++; last_breakable_column_ = command_column_; - last_breakable_moment_ = now_mom (); + + 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_moment_ >= Rational (0)) + 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 && scm_is_number (pen) && *m <= last_breakable_moment_) + if (m) { - last_breakable_column_->set_property ("page-turn-permission", ly_symbol2scm ("allow")); - last_breakable_column_->set_property ("page-turn-penalty", pen); + 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 (); @@ -245,9 +319,13 @@ /* accept */ "break-event", /* read */ "forbidBreak " - "allowPageTurn", + "allowPageTurn " + "revokePageTurns " + , /* write */ "forbidBreak " "allowPageTurn " + "revokePageTurns " "currentCommandColumn " - "currentMusicalColumn"); + "currentMusicalColumn " + ); Index: lily/simple-spacer.cc =================================================================== RCS file: /sources/lilypond/lilypond/lily/simple-spacer.cc,v retrieving revision 1.100 diff -u -r1.100 simple-spacer.cc --- lily/simple-spacer.cc 6 Jun 2006 13:02:42 -0000 1.100 +++ lily/simple-spacer.cc 9 Jun 2006 09:42:52 -0000 @@ -442,7 +442,7 @@ if (!is_loose (icols[i])) cols.push_back (get_column_description (icols, i, false)); } - breaks.back () = cols.size () - 1; + breaks.back () = cols.size (); for (vsize b = 0; b < breaks.size () - 1; b++) { @@ -474,7 +474,14 @@ } } spacer.solve ((b == 0) ? line_len - indent : line_len, ragged); - force[b * breaks.size () + c] = spacer.force (); + + /* add a (convex) penalty for compression. We do this _only_ in get_line_forces, + not get_line_configuration. This is temporary, for backwards compatibility; + the old line/page-breaking stuff ignores page breaks when it calculates line + breaks, so compression penalties can result in scores (eg. wtk-fugue) blowing + up to too many pages. */ + Real f = spacer.force (); + force[b * breaks.size () + c] = f - (f < 0 ? f*f*6 : 0); if (cols[end].break_permission_ == force_break) break; Index: lily/include/paper-column-engraver.hh =================================================================== RCS file: /sources/lilypond/lilypond/lily/include/paper-column-engraver.hh,v retrieving revision 1.9 diff -u -r1.9 paper-column-engraver.hh --- lily/include/paper-column-engraver.hh 9 May 2006 02:15:56 -0000 1.9 +++ lily/include/paper-column-engraver.hh 9 Jun 2006 09:42:52 -0000 @@ -17,6 +17,9 @@ void set_columns (Paper_column *, Paper_column *); TRANSLATOR_DECLARATIONS (Paper_column_engraver); + Paper_column *find_turnable_column (Moment after_this); + void revoke_page_turns (Moment after_this, Real new_penalty); + protected: void stop_translation_timestep (); void start_translation_timestep (); @@ -38,8 +41,9 @@ bool first_; Moment last_moment_; - Moment last_breakable_moment_; + Paper_column *last_special_barline_column_; Paper_column *last_breakable_column_; + vector page_turnable_columns_; public: }; Index: ly/paper-defaults.ly =================================================================== RCS file: /sources/lilypond/lilypond/ly/paper-defaults.ly,v retrieving revision 1.24 diff -u -r1.24 paper-defaults.ly --- ly/paper-defaults.ly 16 Mar 2006 14:39:46 -0000 1.24 +++ ly/paper-defaults.ly 9 Jun 2006 09:42:53 -0000 @@ -76,6 +76,12 @@ %% ragged-last-bottom= ##t + %% + %% settings for the page breaker + %% + blank-last-page-force = 0 + blank-last-force = 10 + #(define font-defaults '((font-encoding . fetaMusic))) Index: scm/define-context-properties.scm =================================================================== RCS file: /sources/lilypond/lilypond/scm/define-context-properties.scm,v retrieving revision 1.76 diff -u -r1.76 define-context-properties.scm --- scm/define-context-properties.scm 16 May 2006 19:00:39 -0000 1.76 +++ scm/define-context-properties.scm 9 Jun 2006 09:42:53 -0000 @@ -338,6 +338,7 @@ (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.") (skipBars ,boolean? "If set to true, then Index: scm/define-grobs.scm =================================================================== RCS file: /sources/lilypond/lilypond/scm/define-grobs.scm,v retrieving revision 1.335 diff -u -r1.335 define-grobs.scm --- scm/define-grobs.scm 9 Jun 2006 02:20:22 -0000 1.335 +++ scm/define-grobs.scm 9 Jun 2006 09:42:53 -0000 @@ -1120,6 +1120,7 @@ (non-musical . #t) (line-break-permission . allow) + (page-break-permission . allow) ;; debugging stuff: print column number. ;; (font-size . -6) (font-name . "sans") (Y-extent . #f) Index: scm/layout-page-layout.scm =================================================================== RCS file: /sources/lilypond/lilypond/scm/layout-page-layout.scm,v retrieving revision 1.17 diff -u -r1.17 layout-page-layout.scm --- scm/layout-page-layout.scm 27 May 2006 01:07:55 -0000 1.17 +++ scm/layout-page-layout.scm 9 Jun 2006 09:42:53 -0000 @@ -143,6 +143,150 @@ (if (ly:output-def-lookup layout 'write-page-layout #f) (write-page-breaks pages))) +(define-public (space-systems paper-book page-height lines ragged?) + (define paper (ly:paper-book-paper paper-book)) + (let* ((global-inter-system-space + (ly:output-def-lookup paper 'between-system-space)) + (top-space + (ly:output-def-lookup paper 'page-top-space)) + (global-fixed-dist (ly:output-def-lookup paper 'between-system-padding)) + + (system-vector (list->vector + (append lines + (if (<= (length lines) 1) + '(#f) + '())))) + (staff-extents + (list->vector + (append (map paper-system-staff-extents lines) + (if (<= (length lines) 1) + '((0 . 0)) + '())))) + + (real-extents + (list->vector + (append + (map + (lambda (sys) (paper-system-extent sys Y)) lines) + (if (<= (length lines) 1) + '((0 . 0)) + '())))) + + (system-count (vector-length real-extents)) + (topskip (max + (+ + top-space + (interval-end (vector-ref staff-extents 0))) + (interval-end (vector-ref real-extents 0)) + )) + (last-system (vector-ref system-vector (1- system-count))) + (bottom-space (if (ly:prob? last-system) + (ly:prob-property last-system 'bottom-space 0.0) + 0.0)) + (space-left (- page-height + bottom-space + (apply + (map interval-length + (vector->list real-extents))))) + + (space (- page-height + topskip + bottom-space + (- (interval-start + (vector-ref real-extents (1- system-count)))))) + + (calc-spring + (lambda (idx) + (let* ( + (upper-system (vector-ref system-vector idx)) + (between-space (ly:prob-property upper-system 'next-space + global-inter-system-space)) + (fixed-dist (ly:prob-property upper-system 'next-padding + global-fixed-dist)) + + (this-system-ext (vector-ref staff-extents idx)) + (next-system-ext (vector-ref staff-extents (1+ idx))) + (fixed (max 0 (- (+ (interval-end next-system-ext) + fixed-dist) + (interval-start this-system-ext)))) + (title1? (and (vector-ref system-vector idx) + (paper-system-title? (vector-ref system-vector idx) + ))) + (title2? (and + (vector-ref system-vector (1+ idx)) + (paper-system-title? (vector-ref system-vector (1+ idx))))) + (ideal (+ + (cond + ((and title2? title1?) + (ly:output-def-lookup paper 'between-title-space)) + (title1? + (ly:output-def-lookup paper 'after-title-space)) + (title2? + (ly:output-def-lookup paper 'before-title-space)) + (else between-space)) + fixed)) + (hooke (/ 1 (- ideal fixed)))) + (list ideal hooke)))) + + (springs (map calc-spring (iota (1- system-count)))) + (calc-rod + (lambda (idx) + (let* ( + (upper-system (vector-ref system-vector idx)) + (fixed-dist (ly:prob-property upper-system 'next-padding + global-fixed-dist)) + (this-system-ext (vector-ref real-extents idx)) + (next-system-ext (vector-ref real-extents (1+ idx))) + + (distance (max (- (+ (interval-end next-system-ext) + fixed-dist) + (interval-start this-system-ext) + ) 0)) + (entry (list idx (1+ idx) distance))) + entry))) + (rods (map calc-rod (iota (1- system-count)))) + + ;; we don't set ragged based on amount space left. + ;; ragged-bottomlast = ##T is much more predictable + (result (ly:solve-spring-rod-problem + springs rods space + ragged?)) + + (force (car result)) + (positions + (map (lambda (y) + (+ y topskip)) + (cdr result)))) + + (if #f ;; debug. + (begin + (display (list "\n# systems: " system-count + "\nreal-ext" real-extents "\nstaff-ext" staff-extents + "\ninterscore" global-inter-system-space + "\nspace-left" space-left + "\nspring,rod" springs rods + "\ntopskip " topskip + " space " space + "\npage-height" page-height + "\nragged" ragged? + "\nforce" force + "\nres" (cdr result) + "\npositions" positions "\n")))) + + (cons force positions))) + +(define-public (make-page-from-systems p-book lines p-num prev ragged? last?) + (let* + ((page (make-page + p-book + 'lines lines + 'page-number p-num + 'prev prev + 'is-last last?)) + (height (page-printable-height page)) + (posns (cdr (space-systems p-book height lines ragged?)))) + (page-set-property! page 'configuration posns) + page)) + ;; Optimal distribution of ;; lines over pages; line breaks are a given. @@ -152,14 +296,14 @@ ;; - separate function for word-wrap style breaking? ;; - ragged-bottom? ragged-last-bottom? -(define-public (optimal-page-breaks lines paper-book) +(define-public (optimal-page-breaks paper-book) "Return pages as a list starting with 1st page. Each page is a 'page Prob." (define MAXPENALTY 1e9) (define paper (ly:paper-book-paper paper-book)) + (define lines (ly:paper-book-systems paper-book)) ;; ugh. - (define page-alist (layout->page-init (ly:paper-book-paper paper-book))) (define scopes (ly:paper-book-scopes paper-book)) (define force-equalization-factor #f) (define (get-path node done) @@ -188,136 +332,6 @@ inter-system-space)) user))) - (define (space-systems page-height lines ragged?) - (let* ((global-inter-system-space - (ly:output-def-lookup paper 'between-system-space)) - (top-space - (ly:output-def-lookup paper 'page-top-space)) - (global-fixed-dist (ly:output-def-lookup paper 'between-system-padding)) - - (system-vector (list->vector - (append lines - (if (= (length lines) 1) - '(#f) - '())))) - (staff-extents - (list->vector - (append (map paper-system-staff-extents lines) - (if (= (length lines) 1) - '((0 . 0)) - '())))) - - (real-extents - (list->vector - (append - (map - (lambda (sys) (paper-system-extent sys Y)) lines) - (if (= (length lines) 1) - '((0 . 0)) - '())))) - - (system-count (vector-length real-extents)) - (topskip (max - (+ - top-space - (interval-end (vector-ref staff-extents 0))) - (interval-end (vector-ref real-extents 0)) - )) - (last-system (vector-ref system-vector (1- system-count))) - (bottom-space (if (ly:prob? last-system) - (ly:prob-property last-system 'bottom-space 0.0) - 0.0)) - (space-left (- page-height - bottom-space - (apply + (map interval-length - (vector->list real-extents))))) - - (space (- page-height - topskip - bottom-space - (- (interval-start - (vector-ref real-extents (1- system-count)))))) - - (calc-spring - (lambda (idx) - (let* ( - (upper-system (vector-ref system-vector idx)) - (between-space (ly:prob-property upper-system 'next-space - global-inter-system-space)) - (fixed-dist (ly:prob-property upper-system 'next-padding - global-fixed-dist)) - - (this-system-ext (vector-ref staff-extents idx)) - (next-system-ext (vector-ref staff-extents (1+ idx))) - (fixed (max 0 (- (+ (interval-end next-system-ext) - fixed-dist) - (interval-start this-system-ext)))) - (title1? (and (vector-ref system-vector idx) - (paper-system-title? (vector-ref system-vector idx) - ))) - (title2? (and - (vector-ref system-vector (1+ idx)) - (paper-system-title? (vector-ref system-vector (1+ idx))))) - (ideal (+ - (cond - ((and title2? title1?) - (ly:output-def-lookup paper 'between-title-space)) - (title1? - (ly:output-def-lookup paper 'after-title-space)) - (title2? - (ly:output-def-lookup paper 'before-title-space)) - (else between-space)) - fixed)) - (hooke (/ 1 (- ideal fixed)))) - (list ideal hooke)))) - - (springs (map calc-spring (iota (1- system-count)))) - (calc-rod - (lambda (idx) - (let* ( - (upper-system (vector-ref system-vector idx)) - (fixed-dist (ly:prob-property upper-system 'next-padding - global-fixed-dist)) - (this-system-ext (vector-ref real-extents idx)) - (next-system-ext (vector-ref real-extents (1+ idx))) - - (distance (max (- (+ (interval-end next-system-ext) - fixed-dist) - (interval-start this-system-ext) - ) 0)) - (entry (list idx (1+ idx) distance))) - entry))) - (rods (map calc-rod (iota (1- system-count)))) - - ;; we don't set ragged based on amount space left. - ;; ragged-bottomlast = ##T is much more predictable - (result (ly:solve-spring-rod-problem - springs rods space - ragged?)) - - (force (car result)) - (positions - (map (lambda (y) - (+ y topskip)) - (cdr result)))) - - (if #f ;; debug. - (begin - (display (list "\n# systems: " system-count - "\nreal-ext" real-extents "\nstaff-ext" staff-extents - "\ninterscore" global-inter-system-space - "\nspace-left" space-left - "\nspring,rod" springs rods - "\ntopskip " topskip - " space " space - "\npage-height" page-height - "\nragged" ragged? - "\nforce" force - "\nres" (cdr result) - "\npositions" positions "\n")))) - - (cons force positions))) - (define (walk-paths done-lines best-paths current-lines last? current-best) "Return the best optimal-page-break-node that contains CURRENT-LINES. DONE-LINES.reversed ++ CURRENT-LINES is a consecutive @@ -331,8 +345,7 @@ (1+ (page-page-number (car best-paths))))) (this-page (make-page - page-alist - 'paper-book paper-book + paper-book 'is-last last? 'page-number this-page-num)) @@ -342,7 +355,7 @@ (and ragged-last? last?))) (height (page-printable-height this-page)) - (vertical-spacing (space-systems height current-lines ragged?)) + (vertical-spacing (space-systems paper-book height current-lines ragged?)) (satisfied-constraints (car vertical-spacing)) (force (if satisfied-constraints Index: scm/page.scm =================================================================== RCS file: /sources/lilypond/lilypond/scm/page.scm,v retrieving revision 1.11 diff -u -r1.11 page.scm --- scm/page.scm 3 Jun 2006 09:53:24 -0000 1.11 +++ scm/page.scm 9 Jun 2006 09:42:53 -0000 @@ -37,10 +37,11 @@ (define page-module (current-module)) -(define (make-page init . args) +(define (make-page p-book . args) (let* ((p (apply ly:make-prob (append - (list 'page init) + (list 'page (layout->page-init (ly:paper-book-paper p-book)) + 'paper-book p-book) args)))) (page-set-property! p 'head-stencil (page-header p)) @@ -196,7 +197,6 @@ ((p-book (page-property page 'paper-book)) (layout (ly:paper-book-paper p-book)) (scopes (ly:paper-book-scopes p-book)) - (lines (page-lines page)) (number (page-page-number page)) (last? (page-property page 'is-last)) ) @@ -314,8 +314,10 @@ (foot (prop 'foot-stencil)) ) - (if (or (annotate? layout) - (ly:output-def-lookup layout 'annotatesystems #f)) + (if (and + (or (annotate? layout) + (ly:output-def-lookup layout 'annotatesystems #f)) + (pair? lines)) (begin (for-each (lambda (sys next-sys) @@ -386,9 +388,6 @@ (let* ((p-book (page-property page 'paper-book)) (layout (ly:paper-book-paper p-book)) - (scopes (ly:paper-book-scopes p-book)) - (number (page-page-number page)) - (last? (page-property page 'is-last)) (h (- (ly:output-def-lookup layout 'paper-height) (ly:output-def-lookup layout 'top-margin) (ly:output-def-lookup layout 'bottom-margin)))