X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fslur.cc;h=425a3b8809f411a9dc2c78fb1e0931f906efe2ab;hb=f07f18bef861d6afa48b941b7579079d5d40df80;hp=ef773b2cc6e5baf54f18d50bccd710572fa5a83f;hpb=8a3305b98a3adf067745aed6ee4960c7bf9b8bfe;p=lilypond.git diff --git a/lily/slur.cc b/lily/slur.cc index ef773b2cc6..dac80152cf 100644 --- a/lily/slur.cc +++ b/lily/slur.cc @@ -1,302 +1,239 @@ /* - slur.cc -- implement Slur + slur.cc -- implement external interface for Slur source file of the GNU LilyPond music typesetter - (c) 1996, 1997--1998, 1998 Han-Wen Nienhuys - Jan Nieuwenhuizen + (c) 1996--2005 Han-Wen Nienhuys + Jan Nieuwenhuizen */ -/* - [TODO] - * URG: share code with tie - * begin and end should be treated as a Script. - * damping - * slur from notehead to stemend: c''()b'' - */ - #include "slur.hh" -#include "scalar.hh" + +#include + +#include "beam.hh" +#include "bezier.hh" +#include "directional-element-interface.hh" +#include "font-interface.hh" +#include "group-interface.hh" #include "lookup.hh" -#include "paper-def.hh" +#include "main.hh" // DEBUG_SLUR_SCORING #include "note-column.hh" +#include "output-def.hh" +#include "spanner.hh" +#include "staff-symbol-referencer.hh" +#include "staff-symbol.hh" #include "stem.hh" -#include "p-col.hh" -#include "molecule.hh" -#include "debug.hh" -#include "box.hh" -#include "bezier.hh" -#include "encompass-info.hh" -#include "main.hh" +#include "text-interface.hh" +#include "warn.hh" +#include "slur-scoring.hh" - -Slur::Slur () +MAKE_SCHEME_CALLBACK (Slur, height, 2); +SCM +Slur::height (SCM smob, SCM ax) { + Axis a = (Axis)scm_to_int (ax); + Grob *me = unsmob_grob (smob); + assert (a == Y_AXIS); + + SCM mol = me->get_uncached_stencil (); + Interval ext; + if (Stencil *m = unsmob_stencil (mol)) + ext = m->extent (a); + return ly_interval2scm (ext); } -void -Slur::add_column (Note_column*n) +/* + Ugh should have dash-length + dash-period +*/ +MAKE_SCHEME_CALLBACK (Slur, print, 1); +SCM +Slur::print (SCM smob) { - if (!n->head_l_arr_.size ()) - warning (_ ("Putting slur over rest.")); - encompass_arr_.push (n); - n->stem_l_->slur_l_ = this; - add_dependency (n); -} + Grob *me = unsmob_grob (smob); + if (!scm_ilength (me->get_property ("note-columns"))) + { + me->suicide (); + return SCM_EOL; + } -void -Slur::set_default_dir () -{ - dir_ = DOWN; - for (int i=0; i < encompass_arr_.size (); i ++) + Real staff_thick = Staff_symbol_referencer::line_thickness (me); + Real base_thick = robust_scm2double (me->get_property ("thickness"), 1); + Real thick = base_thick * staff_thick; + Bezier one = get_curve (me); + Stencil a; + + /* + TODO: replace dashed with generic property. + */ + SCM p = me->get_property ("dash-period"); + SCM f = me->get_property ("dash-fraction"); + if (scm_is_number (p) && scm_is_number (f)) + a = Lookup::dashed_slur (one, thick, robust_scm2double (p, 1.0), + robust_scm2double (f, 0)); + else + a = Lookup::slur (one, + get_grob_direction (me) * staff_thick * 1.0, + thick); + +#if DEBUG_SLUR_SCORING + SCM quant_score = me->get_property ("quant-score"); + + if (to_boolean (me->get_layout () + ->lookup_variable (ly_symbol2scm ("debug-slur-scoring"))) + && scm_is_string (quant_score)) { - if (encompass_arr_[i]->dir_ < 0) - { - dir_ = UP; - break; - } + String str; + SCM properties = Font_interface::text_font_alist_chain (me); + + Stencil tm = *unsmob_stencil (Text_interface::interpret_markup + (me->get_layout ()->self_scm (), properties, + quant_score)); + a.add_at_edge (Y_AXIS, get_grob_direction (me), tm, 1.0, 0); } -} +#endif -void -Slur::do_add_processing () -{ - set_bounds (LEFT, encompass_arr_[0]); - if (encompass_arr_.size () > 1) - set_bounds (RIGHT, encompass_arr_.top ()); + return a.smobbed_copy (); } -void -Slur::do_pre_processing () +Bezier +Slur::get_curve (Grob *me) { - // don't set directions -} + Bezier b; + int i = 0; + for (SCM s = me->get_property ("control-points"); s != SCM_EOL; + s = scm_cdr (s)) + b.control_[i++] = ly_scm2offset (scm_car (s)); -void -Slur::do_substitute_dependency (Score_element*o, Score_element*n) -{ - int i; - while ((i = encompass_arr_.find_i (dynamic_cast (o))) >=0) - { - if (n) - encompass_arr_[i] = dynamic_cast (n); - else - encompass_arr_.del (i); - } + return b; } -static int -Note_column_compare (Note_column *const&n1 , Note_column* const&n2) +void +Slur::add_column (Grob *me, Grob *n) { - return Item::left_right_compare (n1, n2); + Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-columns"), n); + add_bound_item (dynamic_cast (me), dynamic_cast (n)); } void -Slur::do_post_processing () +Slur::add_extra_encompass (Grob *me, Grob *n) { - encompass_arr_.sort (Note_column_compare); - if (!dir_) - set_default_dir (); - - Real interline_f = paper ()->interline_f (); - Real internote_f = interline_f / 2; - // URG - Real notewidth_f = paper ()->note_width () * 0.8; - - /* - [OSU]: slur and tie placement - - slurs: - * x = centre of head (upside-down: inner raakpunt stem) - d * gap - - * y = length < 5ss : horizontal raakpunt + d * 0.25 ss - y = length >= 5ss : y next interline - d * 0.25 ss - --> height <= 5 length ?? we use <= 3 length, now... - */ - - Real gap_f = paper ()->get_var ("slur_x_gap"); - - Drul_array extrema; - extrema[LEFT] = encompass_arr_[0]; - extrema[RIGHT] = encompass_arr_.top (); - - Direction d=LEFT; - - do - { - /* - broken slur - */ - if (extrema[d] != spanned_drul_[d]) - { - // ugh -- check if needed - dx_f_drul_[d] = -d - *(spanned_drul_[d]->extent (X_AXIS).length () - 0.5 * notewidth_f); - - // prebreak - if (d == RIGHT) - { - dx_f_drul_[LEFT] = spanned_drul_[LEFT]->extent (X_AXIS).length (); - - // urg -- check if needed - if (encompass_arr_.size () > 1) - dx_f_drul_[RIGHT] += notewidth_f; - } - } - /* - normal slur - */ - else if (extrema[d]->stem_l_ && !extrema[d]->stem_l_->transparent_b_ - && extrema[d]->head_l_arr_.size ()) - { - Real notewidth_f = extrema[d]->extent (X_AXIS).length (); - dy_f_drul_[d] = (int)rint (extrema[d]->stem_l_-> extent (Y_AXIS)[dir_]); - dx_f_drul_[d] += 0.5 * notewidth_f - d * gap_f; - if (dir_ == extrema[d]->stem_l_->dir_) - { - if (dir_ == d) - dx_f_drul_[d] += 0.5 * (dir_ * d) * d * notewidth_f; - else - dx_f_drul_[d] += 0.25 * (dir_ * d) * d * notewidth_f; - } - } - else - { - Real notewidth_f = extrema[d]->extent (X_AXIS).length (); - dy_f_drul_[d] = (int)rint (extrema[d]->head_positions_interval () - [dir_]) * internote_f; - dx_f_drul_[d] += 0.5 * notewidth_f - d * gap_f; - } - dy_f_drul_[d] += dir_ * interline_f; - if (extrema[d]->stem_l_ && (dir_ == extrema[d]->stem_l_->dir_)) - dy_f_drul_[d] -= dir_ * internote_f; - } - while (flip(&d) != LEFT); - - // now that both are set, do dependent - do - { - /* - broken slur - */ - if (extrema[d] != spanned_drul_[d]) - { - Direction u = d; - flip(&u); - - // postbreak - if (d == LEFT) - dy_f_drul_[u] += dir_ * internote_f; - - dy_f_drul_[d] = dy_f_drul_[(Direction)-d]; - } - } - while (flip(&d) != LEFT); - - /* - Avoid too steep slurs. - * slur from notehead to stemend: c''()b'' - */ - Real damp_f = paper ()->get_var ("slur_slope_damping"); - Offset d_off = Offset (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT], - dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]); - d_off.x () += extent (X_AXIS).length (); - - Real ratio_f = abs (d_off.y () / d_off.x ()); - if (ratio_f > damp_f) - dy_f_drul_[(Direction)(- dir_ * sign (d_off.y ()))] += - dir_ * (ratio_f - damp_f) * d_off.x (); + Pointer_group_interface::add_grob (me, ly_symbol2scm ("encompass-objects"), n); + me->add_dependency (n); } -Array -Slur::get_encompass_offset_arr () const +MAKE_SCHEME_CALLBACK (Slur, outside_slur_callback, 2); +SCM +Slur::outside_slur_callback (SCM grob, SCM axis) { - Real notewidth = paper ()->note_width () * 0.8; - Real gap = paper ()->get_var ("slur_x_gap"); - Real internote = paper ()->internote_f (); - - Offset left = Offset (dx_f_drul_[LEFT], dy_f_drul_[LEFT]); - left.x () += encompass_arr_[0]->stem_l_->hpos_f (); - - /* - - i don't understand these two, but *must* for symmetry - look at encompass array: - lilypond -D input/test/slur-symmetry*.ly - lilypond -D input/test/sleur.ly + Grob *script = unsmob_grob (grob); + Axis a = Axis (scm_to_int (axis)); + (void) a; + assert (a == Y_AXIS); - do_post_processing should have calculated these into - dx_f_drul_[], no?? + Grob *slur = unsmob_grob (script->get_property ("slur")); - */ + if (!slur) + return scm_from_int (0); - if (dir_ != encompass_arr_[0]->stem_l_->dir_) - left.x () += - 0.5 * notewidth * encompass_arr_[0]->stem_l_->dir_ - + gap; - else if (encompass_arr_[0]->stem_l_->dir_ == UP) - left.x () -= notewidth; + Grob *cx = script->common_refpoint (slur, X_AXIS); + Grob *cy = script->common_refpoint (slur, Y_AXIS); - if ((dir_ == encompass_arr_[0]->stem_l_->dir_) - && (encompass_arr_[0]->stem_l_->dir_ == DOWN)) - left.y () -= internote * encompass_arr_[0]->stem_l_->dir_; - /* */ + Bezier curve = Slur::get_curve (slur); - Offset d = Offset (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT], - dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]); - d.x () += extent (X_AXIS).length (); + curve.translate (Offset (slur->relative_coordinate (cx, X_AXIS), + slur->relative_coordinate (cy, Y_AXIS))); - int first = 1; - int last = encompass_arr_.size () - 1; + Interval yext = robust_relative_extent (script, cy, Y_AXIS); + Interval xext = robust_relative_extent (script, cx, X_AXIS); - // prebreak - if (encompass_arr_.top () != spanned_drul_[RIGHT]) - last++; + Real slur_padding = robust_scm2double (script->get_property ("slur-padding"), + 0.0); // todo: slur property, script property? + yext.widen (slur_padding); + Real EPS = 1e-3; - // postbreak - if (encompass_arr_[0] != spanned_drul_[LEFT]) - first--; + Interval bezext (curve.control_[0][X_AXIS], + curve.control_[3][X_AXIS]); - Array notes; - notes.push (Offset (0,0)); + bool consider[] = { false, false, false }; + Real ys[] = {0, 0, 0}; + int k = 0; + bool do_shift = false; - for (int i = first; i < last; i++) + for (int d = LEFT; d <= RIGHT; d++) { - Encompass_info info (encompass_arr_[i], dir_); - notes.push (info.o_ - left); + Real x = xext.linear_combination ((Direction) d); + consider[k] = bezext.contains (x); + + if (consider[k]) + { + ys[k] + = (fabs (bezext[LEFT] - x) < EPS) + ? curve.control_[0][Y_AXIS] + : ((fabs (bezext[RIGHT] - x) < EPS) + ? curve.control_[3][Y_AXIS] + : curve.get_other_coordinate (X_AXIS, x)); + consider[k] = true; + + if (yext.contains (ys[k])) + do_shift = true; + } } - Encompass_info info (encompass_arr_[encompass_arr_.size () - 1], dir_); - // urg: - Slur* urg = (Slur*)this; - urg->interstaff_f_ = info.interstaff_f_; - d.y () += interstaff_f_; - - // prebreak - if (interstaff_f_ && (encompass_arr_.top () != spanned_drul_[RIGHT])) + Real offset = 0.0; + if (do_shift) { - Encompass_info info (encompass_arr_[encompass_arr_.size () - 1], dir_); - d.y () -= info.o_.y () - interstaff_f_; + k = 0; + Direction dir = get_grob_direction (script); + for (int d = LEFT; d <= RIGHT; d++) + { + offset = dir * (max (dir * offset, + dir * (ys[k] - yext[-dir] + dir * slur_padding))); + k++; + } } - notes.push (d); - - return notes; + return scm_make_real (offset); } -Interval -Slur::do_width () const +static Direction +get_default_dir (Grob *me) { - Real min_f = paper ()->get_var ("slur_x_minimum"); - Interval width_int = Bow::do_width (); - return width_int.length () < min_f ? Interval (0, min_f) : width_int; + Link_array encompasses + = extract_grob_array (me, ly_symbol2scm ("note-columns")); + + Direction d = DOWN; + for (int i = 0; i < encompasses.size (); i++) + { + if (Note_column::dir (encompasses[i]) < 0) + { + d = UP; + break; + } + } + return d; } -Array -Slur::get_rods () const +MAKE_SCHEME_CALLBACK (Slur, after_line_breaking, 1); +SCM +Slur::after_line_breaking (SCM smob) { - Array a; - Rod r; - r.item_l_drul_ = spanned_drul_; - r.distance_f_ = do_width ().length (); - a.push (r); - return a; + Spanner *me = dynamic_cast (unsmob_grob (smob)); + if (!scm_ilength (me->get_property ("note-columns"))) + { + me->suicide (); + return SCM_UNSPECIFIED; + } + + if (!get_grob_direction (me)) + set_grob_direction (me, get_default_dir (me)); + + if (scm_ilength (me->get_property ("control-points")) < 4) + set_slur_control_points (me); + + return SCM_UNSPECIFIED; } + +ADD_INTERFACE (Slur, "slur-interface", + "A slur", + "positions quant-score eccentricity encompass-objects control-points dash-period dash-fraction slur-details direction height-limit note-columns ratio thickness"); +