Hi! Attached is a patch that introduces ligature brackets (anyone knows a better term for these beasts?). These brackets are used in modern notation when transcribing mensural music; they simply mark a series of notes that, in the original notation, formed a ligature.
Example: c d e \[ f g a g \] f e d c This puts square edges around the notes f g a g. This, of course, could have been implemented simplier, namely without using a spanner. However, for future extensions, I think a spanner fits best. I am planning to use this syntax to enclose ligatures in general (i.e. not only mensural or transcribed ones). Greetings, Juergen
diff -Naur lilypond-1.5.52/ChangeLog lilypond-1.5.52.NEW/ChangeLog --- lilypond-1.5.52/ChangeLog Fri Apr 12 19:44:59 2002 +++ lilypond-1.5.52.NEW/ChangeLog Tue Apr 16 01:16:13 2002 @@ -1,3 +1,15 @@ +2002-04-15 Juergen Reuter <[EMAIL PROTECTED]> + + * scm/grob-description.scm, lily/staff-symbol.cc: added properties + to control width of staff symbol in ragged-right mode (by request + of Han-Wen) + + * ly/engraver-init.ly, lily/include/my-lily-parser.hh, + lily/include/ligature-bracket.hh, lily/lexer.ll, lily/parser.yy, + lily/ligature-bracket.cc, lily/ligature-bracket-engraver.cc: + added support for ligature brackets (needed when transcribing + mensural music) + 2002-04-12 Han-Wen Nienhuys <[EMAIL PROTECTED]> * lily/*.cc: add some undocced properties. diff -Naur lilypond-1.5.52/lily/include/ligature-bracket.hh lilypond-1.5.52.NEW/lily/include/ligature-bracket.hh --- lilypond-1.5.52/lily/include/ligature-bracket.hh Thu Jan 1 01:00:00 1970 +++ lilypond-1.5.52.NEW/lily/include/ligature-bracket.hh Sun Apr 14 04:30:04 +2002 @@ -0,0 +1,25 @@ +/* + ligature-bracket.hh -- part of GNU LilyPond + + source file of the GNU LilyPond music typesetter + + (c) 2002 Juergen Reuter <[EMAIL PROTECTED]> +*/ + +#ifndef LIGATURE_BRACKET_HH +#define LIGATURE_BRACKET_HH + +#include "lily-proto.hh" +#include "lily-guile.hh" + +class Ligature_bracket +{ +public: + Ligature_bracket (SCM); + DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM )); + +private: +}; + +#endif /* LIGATURE_BRACKET_HH */ + diff -Naur lilypond-1.5.52/lily/include/my-lily-parser.hh lilypond-1.5.52.NEW/lily/include/my-lily-parser.hh --- lilypond-1.5.52/lily/include/my-lily-parser.hh Sat Mar 23 03:42:23 2002 +++ lilypond-1.5.52.NEW/lily/include/my-lily-parser.hh Sat Apr 13 20:10:47 2002 @@ -51,7 +51,9 @@ SCM last_beam_start_; void beam_check (SCM); - + + SCM last_ligature_start_; + Input here_input () const; void push_spot (); Input pop_spot (); diff -Naur lilypond-1.5.52/lily/lexer.ll lilypond-1.5.52.NEW/lily/lexer.ll --- lilypond-1.5.52/lily/lexer.ll Fri Mar 1 01:41:05 2002 +++ lilypond-1.5.52.NEW/lily/lexer.ll Sat Apr 13 20:00:54 2002 @@ -460,6 +460,10 @@ return E_OPEN; case ')': return E_CLOSE; + case '[': + return E_LEFTSQUARE; + case ']': + return E_RIGHTSQUARE; case '~': return E_TILDE; case '\\': diff -Naur lilypond-1.5.52/lily/ligature-bracket-engraver.cc lilypond-1.5.52.NEW/lily/ligature-bracket-engraver.cc --- lilypond-1.5.52/lily/ligature-bracket-engraver.cc Thu Jan 1 01:00:00 1970 +++ lilypond-1.5.52.NEW/lily/ligature-bracket-engraver.cc Mon Apr 15 03:27:25 +2002 @@ -0,0 +1,193 @@ +/* + ligature-bracket-engraver.cc -- implement Ligature__bracket_engraver + + source file of the GNU LilyPond music typesetter + + (c) 2002 Juergen Reuter <[EMAIL PROTECTED]> + + */ +#include "engraver.hh" +#include "musical-request.hh" +#include "warn.hh" +#include "drul-array.hh" +#include "item.hh" +#include "spanner.hh" +#include "score-engraver.hh" +#include "note-head.hh" +#include "stem.hh" +#include "rest.hh" + +class Ligature_bracket_engraver : public Engraver +{ + Drul_array<Span_req*> reqs_drul_; + + Spanner *finished_ligature_bracket_p_; + Spanner *ligature_bracket_p_; + Span_req *prev_start_req_; + + // moment where ligature started. + Moment ligature_start_mom_; + Grob *last_bound; + +protected: + virtual void stop_translation_timestep (); + virtual void start_translation_timestep (); + virtual void finalize (); + + virtual void acknowledge_grob (Grob_info); + virtual bool try_music (Music*); + virtual void process_music (); + +public: + TRANSLATOR_DECLARATIONS(Ligature_bracket_engraver); + +private: + void typeset_ligature_bracket (); +}; + + +Ligature_bracket_engraver::Ligature_bracket_engraver () +{ + ligature_bracket_p_ = 0; + finished_ligature_bracket_p_ = 0; + reqs_drul_[LEFT] = reqs_drul_[RIGHT] = 0; + prev_start_req_ = 0; + last_bound = 0; +} + +bool +Ligature_bracket_engraver::try_music (Music *m) +{ + if (Span_req *req_ = dynamic_cast<Span_req*> (m)) + { + if (scm_equal_p (req_->get_mus_property ("span-type"), + ly_str02scm ("abort")) == SCM_BOOL_T) + { + reqs_drul_[START] = 0; + reqs_drul_[STOP] = 0; + if (ligature_bracket_p_) + ligature_bracket_p_->suicide (); + ligature_bracket_p_ = 0; + } + else if (scm_equal_p (req_->get_mus_property ("span-type"), + ly_str02scm ("ligature-bracket")) == SCM_BOOL_T) + { + Direction d = req_->get_span_dir (); + reqs_drul_[d] = req_; + return true; + } + } + return false; +} + +void +Ligature_bracket_engraver::process_music () +{ + if (reqs_drul_[STOP]) + { + if (!ligature_bracket_p_) + reqs_drul_[STOP]->origin ()->warning (_ ("can't find start of ligature")); + else + { + if (!last_bound) + { + reqs_drul_[STOP]->origin ()->warning (_ ("no right bound")); + } + else + { + ligature_bracket_p_->set_bound (RIGHT, last_bound); + } + } + prev_start_req_ = 0; + finished_ligature_bracket_p_ = ligature_bracket_p_; + ligature_bracket_p_ = 0; + } + last_bound = unsmob_grob (get_property ("currentMusicalColumn")); + + if (ligature_bracket_p_) + { + // TODO: maybe forbid breaks only if not transcribing + top_engraver ()->forbid_breaks (); + } + if (reqs_drul_[START]) + { + if (ligature_bracket_p_) + { + reqs_drul_[START]->origin ()->warning (_ ("already have a ligature")); + return; + } + + prev_start_req_ = reqs_drul_[START]; + ligature_bracket_p_ = new Spanner (get_property ("LigatureBracket")); + + Grob *bound = unsmob_grob (get_property ("currentMusicalColumn")); + if (!bound) + { + reqs_drul_[START]->origin ()->warning (_ ("no left bound")); + } + else + { + ligature_bracket_p_->set_bound (LEFT, bound); + } + + ligature_start_mom_ = now_mom (); + + announce_grob(ligature_bracket_p_, reqs_drul_[START]->self_scm()); + } +} + +void +Ligature_bracket_engraver::start_translation_timestep () +{ + reqs_drul_[START] = 0; + reqs_drul_[STOP] = 0; +} + +void +Ligature_bracket_engraver::typeset_ligature_bracket () +{ + if (finished_ligature_bracket_p_) + { + typeset_grob (finished_ligature_bracket_p_); + finished_ligature_bracket_p_ = 0; + } +} + +void +Ligature_bracket_engraver::stop_translation_timestep () +{ + typeset_ligature_bracket (); +} + +void +Ligature_bracket_engraver::finalize () +{ + typeset_ligature_bracket (); + if (ligature_bracket_p_) + { + prev_start_req_->origin ()->warning (_ ("unterminated ligature")); + ligature_bracket_p_->suicide (); + } +} + +void +Ligature_bracket_engraver::acknowledge_grob (Grob_info info) +{ + if (ligature_bracket_p_) + { + if (Rest::has_interface (info.grob_l_)) + { + reqs_drul_[START]->origin ()->warning (_ ("ligature may not contain rest; +ignoring rest")); + prev_start_req_->origin ()->warning (_ ("ligature was started here")); + // TODO: maybe better should stop ligature here rather than + // ignoring the rest? + } + } +} + +ENTER_DESCRIPTION(Ligature_bracket_engraver, +/* descr */ "Handles Ligature_requests by engraving Ligature brackets.", +/* creats*/ "LigatureBracket", +/* acks */ "rest-interface", +/* reads */ "", +/* write */ ""); diff -Naur lilypond-1.5.52/lily/ligature-bracket.cc lilypond-1.5.52.NEW/lily/ligature-bracket.cc --- lilypond-1.5.52/lily/ligature-bracket.cc Thu Jan 1 01:00:00 1970 +++ lilypond-1.5.52.NEW/lily/ligature-bracket.cc Mon Apr 15 03:17:58 2002 @@ -0,0 +1,145 @@ +/* + ligature-bracket.cc -- implement Ligature_bracket + + source file of the GNU LilyPond music typesetter + + (c) 2002 Juergen Reuter <[EMAIL PROTECTED]> +*/ + +#include "ligature-bracket.hh" +#include "item.hh" +#include "paper-def.hh" +#include "spanner.hh" +#include "staff-symbol-referencer.hh" +#include "lookup.hh" +#include "box.hh" + +static Molecule +brew_edge (Direction dir, Real thickness, Real width, Real height, + Real blotdiameter) +{ + Molecule hline = Lookup::roundfilledbox (Box (Interval (0, width), + Interval (0, thickness)), + blotdiameter); + hline.translate_axis (height - thickness, Y_AXIS); + + Molecule vline = Lookup::roundfilledbox (Box (Interval (0, thickness), + Interval (0, height)), + blotdiameter); + if (dir == RIGHT) + { + vline.translate_axis (width - thickness, X_AXIS); + } + + Molecule edge = Molecule (); + edge.add_molecule (hline); + edge.add_molecule (vline); + return edge; +} + +MAKE_SCHEME_CALLBACK (Ligature_bracket, brew_molecule, 1); +SCM +Ligature_bracket::brew_molecule (SCM smob) +{ + Grob *me = unsmob_grob (smob); + Spanner *spanner = dynamic_cast<Spanner*> (me); + Real blotdiameter = me->paper_l ()->get_var ("blotdiameter"); + Real staff_space = Staff_symbol_referencer::staff_space (me); + + Real thickness = me->paper_l ()->get_var ("linethickness"); + SCM grob_thickness = me->get_grob_property ("thickness"); + if (gh_number_p (grob_thickness)) + thickness *= gh_scm2double (grob_thickness); + + SCM edge_width_scm = me->get_grob_property ("width"); + Real edge_width; + if (gh_number_p (edge_width_scm)) + { + edge_width = gh_scm2double (edge_width_scm); + } + else + { + edge_width = 0.75; + } + edge_width *= staff_space; + + SCM edge_height_scm = me->get_grob_property ("height"); + Real edge_height; + if (gh_number_p (edge_height_scm)) + { + edge_height = gh_scm2double (edge_height_scm); + } + else + { + edge_height = 0.5; + } + edge_height *= staff_space; + + Item* left_bound = spanner->get_bound (LEFT); + Item* right_bound = spanner->get_bound (RIGHT); + + Molecule bracket = Molecule (); + + Real y_min_offs = + 0.5 * Staff_symbol_referencer::line_count (me) * staff_space; + Real y_left_offs = y_min_offs; + Real y_right_offs = y_min_offs; + + Real left_bound_left_extent = 0; + + if (left_bound) + { + Molecule left_edge = + brew_edge (LEFT, thickness, edge_width, edge_height, blotdiameter); + Grob *left_common_x = me->common_refpoint (left_bound, X_AXIS); + left_bound_left_extent = + left_bound->extent (left_common_x, X_AXIS)[LEFT]; + left_edge.translate_axis (left_bound_left_extent, X_AXIS); + bracket.add_molecule (left_edge); + Grob *left_common_y = me->common_refpoint (left_bound, Y_AXIS); + y_left_offs = + max(y_left_offs, left_bound->extent (left_common_y, Y_AXIS)[UP]); + } + else + { + me->warning (_ ("no left bound")); + } + + if (right_bound) + { + Molecule right_edge = + brew_edge (RIGHT, thickness, edge_width, edge_height, blotdiameter); + Grob *staff_symbol = Staff_symbol_referencer::staff_symbol_l (me); + Grob *right_common_bound_x = + right_bound->common_refpoint (staff_symbol, X_AXIS); + + Real left_offs = 0; + if (left_bound) + { + Grob *left_common_bound_x = + left_bound->common_refpoint (staff_symbol, X_AXIS); + left_offs = left_bound->extent (left_common_bound_x, X_AXIS)[LEFT]; + } + + Real right_offs = + right_bound->extent (right_common_bound_x, X_AXIS)[RIGHT]; + + right_edge.translate_axis (+ right_offs + - left_offs + + left_bound_left_extent + - edge_width, + X_AXIS); + bracket.add_molecule (right_edge); + Grob *right_common_y = me->common_refpoint (right_bound, Y_AXIS); + y_right_offs = + max(y_right_offs, right_bound->extent (right_common_y, Y_AXIS)[UP]); + } + else + { + me->warning (_ ("no left bound")); + } + + bracket.translate_axis (max (y_left_offs, y_right_offs), Y_AXIS); + + return bracket.smobbed_copy (); +} diff -Naur lilypond-1.5.52/lily/parser.yy lilypond-1.5.52.NEW/lily/parser.yy --- lilypond-1.5.52/lily/parser.yy Sat Mar 23 03:42:23 2002 +++ lilypond-1.5.52.NEW/lily/parser.yy Mon Apr 15 01:42:48 2002 @@ -244,7 +244,8 @@ %token REST /* escaped */ -%token E_CHAR E_EXCLAMATION E_SMALLER E_BIGGER E_OPEN E_CLOSE E_TILDE +%token E_CHAR E_EXCLAMATION E_SMALLER E_BIGGER E_OPEN E_CLOSE +%token E_LEFTSQUARE E_RIGHTSQUARE E_TILDE %token E_BACKSLASH %token CHORD_BASS CHORD_COLON CHORD_MINUS CHORD_CARET %token FIGURE_SPACE @@ -1236,6 +1237,19 @@ Span_req*b= new Span_req; b->set_span_dir ( STOP); b->set_mus_property ("span-type", ly_str02scm ("beam")); + $$ = b; + } + | E_LEFTSQUARE { + Span_req *b = new Span_req; + b->set_span_dir (START); + b->set_mus_property ("span-type", ly_str02scm ("ligature-bracket")); + $$ = b; + THIS->last_ligature_start_ = b->self_scm (); + } + | E_RIGHTSQUARE { + Span_req *b = new Span_req; + b->set_span_dir (STOP); + b->set_mus_property ("span-type", ly_str02scm ("ligature-bracket")); $$ = b; } | BREATHE { diff -Naur lilypond-1.5.52/lily/staff-symbol.cc lilypond-1.5.52.NEW/lily/staff-symbol.cc --- lilypond-1.5.52/lily/staff-symbol.cc Wed Apr 10 19:11:39 2002 +++ lilypond-1.5.52.NEW/lily/staff-symbol.cc Sat Apr 13 19:55:43 2002 @@ -13,6 +13,7 @@ #include "debug.hh" #include "item.hh" #include "staff-symbol.hh" +#include "staff-symbol-referencer.hh" #include "spanner.hh" @@ -27,23 +28,38 @@ Grob * common = sp->get_bound (LEFT)->common_refpoint (sp->get_bound (RIGHT), X_AXIS); - bool ragged = to_boolean (me->paper_l ()->get_scmvar ("raggedright")); + bool paper_raggedright = to_boolean (me->paper_l ()->get_scmvar ("raggedright")); + bool grob_raggedright = to_boolean (me->get_grob_property ("ragged-right")); Real width; - if (ragged) + + SCM width_scm = me->get_grob_property ("width"); + if (gh_number_p (width_scm)) // user-defined width { - // *prevent* staff symbol from being ragged right width = - me->paper_l ()->get_var ("linewidth") - - sp->get_bound (LEFT)->relative_coordinate (common, X_AXIS) - ; + gh_scm2double (width_scm) * + Staff_symbol_referencer::staff_space (me); } - else + else // determine width automatically { - width = - // right_shift - left_shift - + sp->get_bound (RIGHT)->relative_coordinate (common , X_AXIS) - - sp->get_bound (LEFT)->relative_coordinate (common, X_AXIS) - ; + if (paper_raggedright && !grob_raggedright) + { + // *prevent* staff symbol from being ragged right; instead, use + // paper variable "linewidth" + width = me->paper_l ()->get_var ("linewidth"); + } + else // determine width from my own bounds + { + width = sp->get_bound (RIGHT)->relative_coordinate (common , X_AXIS); + } + } + + // respect indentation, if any + width -= sp->get_bound (LEFT)->relative_coordinate (common, X_AXIS); + + if (width < 0) + { + warning (_f ("staff symbol: indentation yields beyond end of line")); + width = 0; } Real t = me->paper_l ()->get_var ("linethickness"); diff -Naur lilypond-1.5.52/ly/engraver-init.ly lilypond-1.5.52.NEW/ly/engraver-init.ly --- lilypond-1.5.52/ly/engraver-init.ly Fri Apr 12 19:34:02 2002 +++ lilypond-1.5.52.NEW/ly/engraver-init.ly Sun Apr 14 22:10:26 2002 @@ -131,7 +131,8 @@ \consists "Arpeggio_engraver" \consists "Multi_measure_rest_engraver" \consists "Text_spanner_engraver" - + + \consists "Ligature_bracket_engraver" \consists "Breathing_sign_engraver" % \consists "Rest_engraver" \consists "Stem_engraver" diff -Naur lilypond-1.5.52/scm/grob-description.scm lilypond-1.5.52.NEW/scm/grob-description.scm --- lilypond-1.5.52/scm/grob-description.scm Fri Apr 12 19:39:16 2002 +++ lilypond-1.5.52.NEW/scm/grob-description.scm Sun Apr 14 22:02:06 2002 @@ -358,6 +358,13 @@ (meta . ((interfaces . (key-signature-interface font-interface break-aligned-interface)))) )) + (LigatureBracket + . ( + (width . 0.75) + (height . 0.5) + (molecule-callback . ,Ligature_bracket::brew_molecule) + (meta . ((interfaces . (ligature-bracket-interface)))) + )) (LyricHyphen . ( @@ -702,6 +709,7 @@ . ( (molecule-callback . ,Staff_symbol::brew_molecule) (line-count . 5) + (ragged-right . #f) (layer . 0) (meta . ((interfaces . (staff-symbol-interface)))) )) diff -Naur lilypond-1.5.52/scm/grob-property-description.scm lilypond-1.5.52.NEW/scm/grob-property-description.scm --- lilypond-1.5.52/scm/grob-property-description.scm Fri Apr 12 19:42:53 2002 +++ lilypond-1.5.52.NEW/scm/grob-property-description.scm Sat Apr 13 19:47:51 +2002 @@ -271,6 +271,7 @@ (grob-property-description 'pitches list? "list of musical-pitch.") (grob-property-description 'positions pair? "cons of staff positions (LEFT . RIGHT") +(grob-property-description 'ragged-right boolean? "In ragged alignment mode (i.e. if +paper variable @code{raggedright} is set), rag staff symbols only if this staff +symbol grob property is also set.") (grob-property-description 'raise number? "height for text to be raised (a negative value lowers the text.") (grob-property-description 'right-padding number? "space right of accs.") (grob-property-description 'right-trim-amount number? "shortening of the lyric extender on the right.")