From 0d2366b609aab8894c3dc9d82cf7d2565c923234 Mon Sep 17 00:00:00 2001 From: hanwen Date: Sun, 20 Feb 2005 20:03:28 +0000 Subject: [PATCH] * scm/define-grobs.scm (all-grob-descriptions): put ledger lines in layer 0 too. * scm/define-context-properties.scm (all-user-translation-properties): add tieWaitForNote * scm/define-grobs.scm (all-grob-descriptions): add Tie_column::before_line_breaking * lily/tie.cc (get_column_rank): new function * lily/tie-column.cc (before_line_breaking): new function. (werner_directions): take into account ties that start on different columns. * lily/score-engraver.cc (set_columns): move add_column() so we have column rank available. * lily/tie.cc (get_column_rank): new function. --- ChangeLog | 20 +++ .../topdocs/{NEWS.texi => NEWS.tely} | 30 +++- Documentation/user/notation.itely | 20 ++- input/regression/tie-arpeggio.ly | 24 +++ lily/include/tie-column.hh | 2 +- lily/include/tie.hh | 5 +- lily/score-engraver.cc | 8 +- lily/tie-column.cc | 141 ++++++++---------- lily/tie-engraver.cc | 72 ++++++--- lily/tie.cc | 12 ++ python/lilylib.py | 4 +- scm/define-context-properties.scm | 2 + scm/define-grobs.scm | 2 + 13 files changed, 226 insertions(+), 116 deletions(-) rename Documentation/topdocs/{NEWS.texi => NEWS.tely} (97%) create mode 100644 input/regression/tie-arpeggio.ly diff --git a/ChangeLog b/ChangeLog index ddfed302aa..c9de4da868 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,25 @@ 2005-02-20 Han-Wen Nienhuys + * scm/define-grobs.scm (all-grob-descriptions): put ledger lines + in layer 0 too. + + * scm/define-context-properties.scm + (all-user-translation-properties): add tieWaitForNote + + * scm/define-grobs.scm (all-grob-descriptions): add + Tie_column::before_line_breaking + + * lily/tie.cc (get_column_rank): new function + + * lily/tie-column.cc (before_line_breaking): new function. + (werner_directions): take into account ties that start on + different columns. + + * lily/score-engraver.cc (set_columns): move add_column() so we + have column rank available. + + * lily/tie.cc (get_column_rank): new function. + * input/regression/utf8.ly (japanese): add japanese lyrics. * lily/pfb.cc (LY_DEFINE): ly:ttf->pfa, new function. diff --git a/Documentation/topdocs/NEWS.texi b/Documentation/topdocs/NEWS.tely similarity index 97% rename from Documentation/topdocs/NEWS.texi rename to Documentation/topdocs/NEWS.tely index 873644620e..253ceb93bf 100644 --- a/Documentation/topdocs/NEWS.texi +++ b/Documentation/topdocs/NEWS.tely @@ -8,6 +8,26 @@ @itemize @bullet +@item +With the new @code{tieWaitForNote} property, arpeggios may be written +out using ties, for example, + +@lilypond[fragment,verbatim,relative=1,raggedright] +\set tieWaitForNote = ##t +\grace { c16[~ e~ g]~ } 4 +@end lilypond + +Thanks to Steve Doonan for funding development of this feature. + +@item +Individual objects may be assigned colors, for example, + +@lilypond[fragment,relative=1,verbatim,raggedright] + \override Beam #'color = #cyan + \override NoteHead #'color = #darkyellow + c4 +@end lilypond + @item The PostScript backend is now used by default. This backend requires less machinery to run, and gives more consistent results. @@ -16,8 +36,11 @@ Due bugs in GhostScript's PDF handling, it is recommended to upgrade to GhostScript 8.x. @item -Separator slashes may be inserted between systems in a score. See -@file{input/regression/system-separator.ly} for an example. +Separator slashes may be inserted between systems in a score. For an +example, see +@file{input/regression/system-separator.ly}: + +@lilypondfile{system-separator.ly} @item Locations of errors in the input are now calculated more precisely. @@ -40,6 +63,9 @@ or using the classic font selection mechanism \override TextScript #'font-series = #'bold @end example +Any Type1 and TrueType font recognized by FontConfig is available in +LilyPond as well. + @noindent Input strings encoded in UTF-8 are then rendered through Pango. diff --git a/Documentation/user/notation.itely b/Documentation/user/notation.itely index 564169a733..5dfe97beb5 100644 --- a/Documentation/user/notation.itely +++ b/Documentation/user/notation.itely @@ -474,6 +474,16 @@ automatic note splitting (see @ref{Automatic note splitting}). This mechanism automatically splits long notes, and ties them across bar lines. +Ties are sometimes used to write out arpeggios. In this case, two tied +notes need not be consecutive. This can be achieved by setting the +@code{tieWaitForNote} property to true. For example, + +@lilypond[fragment,verbatim,relative=1,raggedright] +\set tieWaitForNote = ##t +\grace { c16[~ e~ g]~ } 4 +@end lilypond + + @refcommands @@ -3633,11 +3643,11 @@ c\sostenutoDown d e c, f g a\sostenutoUp @subsection Arpeggio @cindex Arpeggio -@cindex broken arpeggio +@cindex broken chord @cindex @code{\arpeggio} -You can specify an arpeggio sign on a chord by attaching an -@code{\arpeggio} to a chord +You can specify an arpeggio sign (also known as broken chord) on a +chord by attaching an @code{\arpeggio} to a chord @lilypond[quote,raggedright,fragment,relative=1,verbatim] @@ -3693,9 +3703,13 @@ arpeggiate the chord @seealso +Notation manual: @ref{Ties}, for writing out arpeggios. + Program reference: @internalsref{ArpeggioEvent}, @internalsref{Arpeggio}. + + @refbugs It is not possible to mix connected arpeggios and unconnected diff --git a/input/regression/tie-arpeggio.ly b/input/regression/tie-arpeggio.ly new file mode 100644 index 0000000000..0f05b53585 --- /dev/null +++ b/input/regression/tie-arpeggio.ly @@ -0,0 +1,24 @@ +\header +{ + + texidoc = "when @code{tieWaitForNote} is set, the right-tied note + does not have to follow the lef-tied note directly. When + @code{tieWaitForNote} is set to false, any tie will erase all pending + ties." + +} + +\version "2.5.12" + +\paper { raggedright = ##t } +\relative { + c~ e~ g~ + \set tieWaitForNote = ##t + c~ e~ g~ + + ~ + + \set tieWaitForNote = ##f + ~ + +} diff --git a/lily/include/tie-column.hh b/lily/include/tie-column.hh index 530c845fb9..9bce382846 100644 --- a/lily/include/tie-column.hh +++ b/lily/include/tie-column.hh @@ -20,8 +20,8 @@ public: static bool has_interface (Grob*); static void add_tie (Grob*me, Grob*); DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM)); + DECLARE_SCHEME_CALLBACK (before_line_breaking, (SCM)); static void set_directions (Grob*me); - static void old_directions (Grob*me); static void werner_directions (Grob*me); }; diff --git a/lily/include/tie.hh b/lily/include/tie.hh index 21a8100703..06fba20065 100644 --- a/lily/include/tie.hh +++ b/lily/include/tie.hh @@ -21,11 +21,12 @@ public: static void set_interface (Grob*); static bool has_interface (Grob*); static void set_direction (Grob*); - static Grob * head (Grob*, Direction) ; + static Grob *head (Grob*, Direction) ; + static int get_column_rank (Grob*, Direction); static Real get_position (Grob*) ; - DECLARE_SCHEME_CALLBACK (print, (SCM )); static Direction get_default_dir (Grob*) ; static SCM get_control_points (SCM); + DECLARE_SCHEME_CALLBACK (print, (SCM )); DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM )); }; diff --git a/lily/score-engraver.cc b/lily/score-engraver.cc index 37c60dd94f..d7d699f449 100644 --- a/lily/score-engraver.cc +++ b/lily/score-engraver.cc @@ -129,8 +129,8 @@ Score_engraver::initialize () Object_key const *sys_key = context()->get_grob_key ("System"); pscore_->typeset_line (new System (props, sys_key)); - make_columns (); system_ = pscore_->system_; + make_columns (); system_->set_bound (LEFT, command_column_); command_column_->set_property ("breakable", SCM_BOOL_T); @@ -215,9 +215,6 @@ Score_engraver::stop_translation_timestep () progress_indication ("[" + to_string (breaks_) + "]"); } - - system_->add_column (command_column_); - system_->add_column (musical_column_); command_column_ = 0; musical_column_ = 0; @@ -240,6 +237,9 @@ Score_engraver::set_columns (Paper_column *new_command, { context ()->set_property ("currentMusicalColumn", new_musical->self_scm ()); } + + system_->add_column (command_column_); + system_->add_column (musical_column_); } Music_output* diff --git a/lily/tie-column.cc b/lily/tie-column.cc index 187536553c..b4c541595f 100644 --- a/lily/tie-column.cc +++ b/lily/tie-column.cc @@ -8,7 +8,7 @@ */ #include "tie-column.hh" - +#include "paper-column.hh" #include "spanner.hh" #include "group-interface.hh" #include "tie.hh" @@ -22,23 +22,25 @@ TODO: this doesn't follow standard pattern. Regularize. */ void -Tie_column::add_tie (Grob*me, Grob *s) +Tie_column::add_tie (Grob*me, Grob *tie) { - if (s->get_parent (Y_AXIS) - && Tie_column::has_interface (s->get_parent (Y_AXIS))) + if (tie->get_parent (Y_AXIS) + && Tie_column::has_interface (tie->get_parent (Y_AXIS))) return ; - + + if (!Pointer_group_interface::count (me, ly_symbol2scm ("ties"))) { - dynamic_cast (me)->set_bound (LEFT, Tie::head (s, LEFT)); - dynamic_cast (me)->set_bound (RIGHT, Tie::head (s, RIGHT)); + dynamic_cast (me)->set_bound (LEFT, Tie::head (tie, LEFT)); + dynamic_cast (me)->set_bound (RIGHT, Tie::head (tie, RIGHT)); } - s->set_parent (me, Y_AXIS); - Pointer_group_interface::add_grob (me, ly_symbol2scm ("ties"), s); - s->add_dependency (me); + + + tie->set_parent (me, Y_AXIS); + Pointer_group_interface::add_grob (me, ly_symbol2scm ("ties"), tie); + tie->add_dependency (me); } - void Tie_column::set_directions (Grob*me) { @@ -53,77 +55,21 @@ tie_compare (Grob* const & s1, } /* - See [Ross p. 138]. - +Werner: - In normal chord cases, the outer ties point outwards, and the - direction of the rest is determined by their staff position. + . The algorithm to choose the direction of the ties doesn't work + properly. I suggest the following for applying ties sequentially + from top to bottom: - Ross forgets about the tie that is *on* the middle staff line. We - assume it goes UP. (TODO: make me settable) */ -void -Tie_column::old_directions (Grob*me) -{ - Link_array ties = - Pointer_group_interface__extract_grobs (me, (Grob*)0, "ties"); - - for (int i = ties.size (); i--;) - if (get_grob_direction (ties[i])) - ties.del (i); - - if (!ties.size ()) - return ; + + The topmost tie is always `up'. - Direction d = get_grob_direction (me); - if (d) - { - for (int i = ties.size (); i--;) - { - Grob * t = ties[i]; - set_grob_direction (t, d); - } - return; - } - - if (ties.size () == 1) - { - Grob * t = ties[0]; - set_grob_direction (t, Tie::get_default_dir (t)); - return; - } - - ties.sort (tie_compare); - set_grob_direction (ties[0], DOWN); - ties.del (0); - - set_grob_direction (ties.pop (), UP); - for (int i = ties.size (); i--;) - { - Grob * t = ties[i]; - Real p = Tie::get_position (t); - Direction d = (Direction) sign (p); - if (!d) - d = UP; - set_grob_direction (t, d); - } - -} + + If there is a vertical gap to the last note above larger than + or equal to a fifth (or sixth?), the tie is `up', otherwise it + is `down'. -/* - -% . The algorithm to choose the direction of the ties doesn't work -% properly. I suggest the following for applying ties sequentially -% from top to bottom: -% -% + The topmost tie is always `up'. -% -% + If there is a vertical gap to the last note above larger than -% or equal to a fifth (or sixth?), the tie is `up', otherwise it -% is `down'. -% -% + The bottommost tie is always `down'. + + The bottommost tie is always `down'. - */ +*/ void Tie_column::werner_directions (Grob *me) { @@ -159,7 +105,11 @@ Tie_column::werner_directions (Grob *me) Real last_down_pos = 10000; if (!get_grob_direction (ties[0])) set_grob_direction (ties[0], DOWN); - + + /* + Go downward. + */ + Grob *last_tie = 0; for (int i = ties.size (); i--;) { Grob *t = ties[i]; @@ -168,7 +118,13 @@ Tie_column::werner_directions (Grob *me) Real p = Tie::get_position (t); if (!d) { - if (last_down_pos - p > 5) + if (last_tie + && Tie::get_column_rank (t, LEFT) + < Tie::get_column_rank (last_tie, LEFT)) + { + d = DOWN; + } + else if (last_down_pos - p > 5) { d = UP; } @@ -182,6 +138,8 @@ Tie_column::werner_directions (Grob *me) if (d == DOWN) last_down_pos = p; + + last_tie = t; } return ; @@ -196,7 +154,30 @@ Tie_column::after_line_breaking (SCM smob) return SCM_UNSPECIFIED; } - +/* + Extend the spanner over its Tie constituents. + */ +MAKE_SCHEME_CALLBACK (Tie_column, before_line_breaking, 1); +SCM +Tie_column::before_line_breaking (SCM smob) +{ + Spanner *me = dynamic_cast (unsmob_grob (smob)); + for (SCM s = me->get_property ("ties"); scm_is_pair (s); s = scm_cdr (s)) + { + Spanner *tie = dynamic_cast (unsmob_grob (scm_car (s))); + Direction dir = LEFT; + do + { + if (dir * Paper_column::get_rank (tie->get_bound (dir)->get_column ()) + > dir * Paper_column::get_rank (me->get_bound (dir)->get_column ())) + { + me->set_bound (dir, Tie::head (tie, dir)); + } + } + while (flip (&dir) != LEFT); + } + return SCM_UNSPECIFIED; +} ADD_INTERFACE (Tie_column, "tie-column-interface", "Object that sets directions of multiple ties in a tied chord", diff --git a/lily/tie-engraver.cc b/lily/tie-engraver.cc index e0649feb2d..f8b998f59c 100644 --- a/lily/tie-engraver.cc +++ b/lily/tie-engraver.cc @@ -27,14 +27,29 @@ TODO: Remove the dependency on musical info. We should tie on the basis of position and duration-log of the heads (not of the events). */ + +struct Head_event_tuple +{ + Grob *head_; + SCM tie_definition_; + Music *event_; + Head_event_tuple() + { + } + Head_event_tuple(Grob *h, Music *m, SCM def) + { + head_ = h; + event_ = m; + tie_definition_ = def; + } +}; + class Tie_engraver : public Engraver { Music *event_; - Music *last_event_; Link_array now_heads_; - Link_array heads_to_tie_; + Array heads_to_tie_; Link_array ties_; - SCM tie_start_definition_; Spanner * tie_column_; @@ -51,19 +66,18 @@ public: }; +void +Tie_engraver::derived_mark () const +{ + Engraver::derived_mark (); + for (int i = 0; i < heads_to_tie_.size(); i++) + scm_gc_mark (heads_to_tie_[i].tie_definition_); +} Tie_engraver::Tie_engraver () { event_ = 0; - last_event_ = 0; tie_column_ = 0; - tie_start_definition_ = SCM_EOL; -} - -void -Tie_engraver::derived_mark () const -{ - scm_gc_mark (tie_start_definition_); } @@ -96,7 +110,7 @@ Tie_engraver::acknowledge_grob (Grob_info i) now_heads_.push (h); for (int i = heads_to_tie_.size (); i--;) { - Grob *th = heads_to_tie_[i]; + Grob *th = heads_to_tie_[i].head_; Music * right_mus = unsmob_music (h->get_property ("cause")); Music * left_mus = unsmob_music (th->get_property ("cause")); @@ -107,21 +121,22 @@ Tie_engraver::acknowledge_grob (Grob_info i) && ly_c_equal_p (right_mus->get_property ("pitch"), left_mus->get_property ("pitch"))) { - Grob * p = new Spanner (tie_start_definition_, context()->get_grob_key ("Tie")); - announce_grob (p, last_event_->self_scm ()); + Grob * p = new Spanner (heads_to_tie_[i].tie_definition_, + context()->get_grob_key ("Tie")); + announce_grob (p, heads_to_tie_[i].event_->self_scm ()); Tie::set_interface (p); // cannot remove yet! Tie::set_head (p, LEFT, th); Tie::set_head (p, RIGHT, h); ties_.push (p); + heads_to_tie_.del (i); } } if (ties_.size () && ! tie_column_) { - tie_column_ = make_spanner ("TieColumn", SCM_EOL); - + tie_column_ = make_spanner ("TieColumn", ties[0]->self_scm ()); } if (tie_column_) @@ -134,7 +149,7 @@ void Tie_engraver::start_translation_timestep () { context ()->set_property ("tieMelismaBusy", - ly_bool2scm (heads_to_tie_.size ())); + ly_bool2scm (heads_to_tie_.size ())); } @@ -143,23 +158,36 @@ Tie_engraver::stop_translation_timestep () { if (ties_.size ()) { - heads_to_tie_.clear (); + if (!to_boolean (get_property ("tieWaitForNote"))) + { + heads_to_tie_.clear (); + } + for (int i = 0; i< ties_.size (); i++) { typeset_tie (ties_[i]); } ties_.clear (); - last_event_ = 0; tie_column_ = 0; } if (event_) { - tie_start_definition_ = updated_grob_properties (context (), ly_symbol2scm ("Tie")); - heads_to_tie_ = now_heads_; - last_event_ = event_; + SCM start_definition + = updated_grob_properties (context (), ly_symbol2scm ("Tie")); + + if (!to_boolean (get_property ("tieWaitForNote"))) + heads_to_tie_.clear(); + + for (int i = 0; i < now_heads_.size(); i++) + { + heads_to_tie_.push (Head_event_tuple (now_heads_[i], event_, + start_definition + )); + } } + event_ = 0; now_heads_.clear (); } diff --git a/lily/tie.cc b/lily/tie.cc index c2610d6f6f..569aa220ad 100644 --- a/lily/tie.cc +++ b/lily/tie.cc @@ -65,6 +65,18 @@ Tie::head (Grob*me, Direction d) return 0; } +int +Tie::get_column_rank (Grob *me, Direction d) +{ + Spanner *span = dynamic_cast (me); + Grob * h = head (me, d); + if (!h) + h = span->get_bound (d); + + Grob *col = dynamic_cast (h)->get_column (); + return Paper_column::get_rank (col); +} + Real Tie::get_position (Grob*me) { diff --git a/python/lilylib.py b/python/lilylib.py index 42a21f74b0..8e38dc23e1 100644 --- a/python/lilylib.py +++ b/python/lilylib.py @@ -504,7 +504,7 @@ def make_ps_images (ps_name, resolution = 90): if y == 0: y = 1 - cmd = r'''gs -g%dx%d -sDEVICE=pnggray -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=%s -r%d -dNOPAUSE %s %s -c showpage -c quit ''' % \ + cmd = r'''gs -g%dx%d -sDEVICE=png16m -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=%s -r%d -dNOPAUSE %s %s -c showpage -c quit ''' % \ (x, y, output_file, resolution, trans_ps, ps_name) rms = glob.glob (base + '-page*.png') @@ -516,7 +516,7 @@ def make_ps_images (ps_name, resolution = 90): if os.path.isfile (rmfile): os.unlink (rmfile) - cmd = r'''gs -s -sDEVICE=pnggray -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=%s -dNOPAUSE -r%d %s -c quit''' % (output_file, + cmd = r'''gs -s -sDEVICE=png16m -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=%s -dNOPAUSE -r%d %s -c quit''' % (output_file, resolution, ps_name) status = system (cmd) diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 3bf7c51fc0..d8ac756c8b 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -351,6 +351,8 @@ the system/staff? Set to @code{SystemStartBrace}, takes a string number, a list of string tunings and Pitch object. It returns the text as a string.") + (tieWaitForNote ,boolean? "If true, tied notes do not have to follow each other directly. +This can be used for writing out arpeggios") (timeSignatureFraction ,number-pair? "pair of numbers, signifying the time signature. For example @code{#'(4 . 4)} is a 4/4 time signature.") diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index c7680bd388..fece9d0b2e 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -570,6 +570,7 @@ (X-extent-callback . #f) (Y-extent-callback . #f) (print-function . ,Ledger_line_spanner::print) + (layer . 0) (meta . ((interfaces . (spanner-interface ledger-line-interface)))) )) @@ -1242,6 +1243,7 @@ (TieColumn . ( (after-line-breaking-callback . ,Tie_column::after_line_breaking) + (before-line-breaking-callback . ,Tie_column::before_line_breaking) (X-extent-callback . #f) (Y-extent-callback . #f) (meta . ((interfaces . (tie-column-interface spanner-interface)))) -- 2.39.5