From e22333e86580918f2b5c5167fd4881758f4d43a7 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Sat, 13 Jul 2002 01:30:04 +0000 Subject: [PATCH] complete rewrite of multiplicity. This fixes 16th knees code. (quanting): add french beaming support (property french-beaming) --- ChangeLog | 8 + Documentation/regression-test.tely | 4 + input/regression/beam-french.ly | 14 + input/regression/beam-funky.ly | 31 ++ input/regression/beams.ly | 12 + lily/beam.cc | 710 +++++++++++++++-------------- lily/include/beam.hh | 12 +- lily/include/lily-guile.hh | 4 +- lily/include/stem.hh | 1 - lily/lily-guile.cc | 2 +- lily/script.cc | 2 +- lily/slur.cc | 14 +- lily/stem-tremolo.cc | 20 +- lily/stem.cc | 43 +- lily/text-spanner.cc | 12 +- lily/tie.cc | 2 +- lily/tuplet-bracket.cc | 6 +- scm/grob-property-description.scm | 10 +- scm/slur.scm | 2 +- 19 files changed, 499 insertions(+), 410 deletions(-) create mode 100644 input/regression/beam-french.ly create mode 100644 input/regression/beam-funky.ly create mode 100644 input/regression/beams.ly diff --git a/ChangeLog b/ChangeLog index 566160ab81..90b0d805af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2002-07-13 Han-Wen + + * lily/beam.cc: complete rewrite of multiplicity. This fixes 16th + knees code. + (quanting): add french beaming support (property french-beaming) + + + 2002-07-12 Han-Wen * input/regression/grace-auto-beam.ly: new file diff --git a/Documentation/regression-test.tely b/Documentation/regression-test.tely index b140bdf65f..cecc2fa4f9 100644 --- a/Documentation/regression-test.tely +++ b/Documentation/regression-test.tely @@ -152,6 +152,10 @@ Grace note do weird things with timing. Fragile. @section Beams +@lilypondfile[printfilename]{beams.ly} + +@lilypondfile[printfilename]{beam-funky.ly} + @lilypondfile[printfilename]{beaming.ly} @lilypondfile[printfilename]{beam-concave.ly} diff --git a/input/regression/beam-french.ly b/input/regression/beam-french.ly new file mode 100644 index 0000000000..a953925323 --- /dev/null +++ b/input/regression/beam-french.ly @@ -0,0 +1,14 @@ + +\header { + texidoc = "French style beaming. In french beaming, the stems do not go to the outer beams." +} + +\score { \notes +\relative c' + { + \property Voice.Beam \override #'french-beaming = ##t + [c16 c c c] + [c8 c16 c16 c8] + [c8 c16 e16 g8] + + }} diff --git a/input/regression/beam-funky.ly b/input/regression/beam-funky.ly new file mode 100644 index 0000000000..cf4ba665a4 --- /dev/null +++ b/input/regression/beam-funky.ly @@ -0,0 +1,31 @@ +\header { + texidoc = "Knee beaming. (funky)" +} + +\score { \notes +\relative c' + { + + \property Voice.subdivideBeams = ##t + \time 8/8 + [c,16 g'''16 + c,,,16 g'''16 + c,,,16 g'''16 + c,,,16 g'''16 ] + + [c,,,16 c c c + b''' b b b] + + \transpose a, { \relative b'' { [g,16 g'''16 + g,,,16 g'''16 + g,,,16 g'''16 + g,,,16 g'''16 + g g,,, + g''' g,,, + g''' g,,, + g''' g,,,] } } + + } +\paper { linewidth = -1. } + + } diff --git a/input/regression/beams.ly b/input/regression/beams.ly new file mode 100644 index 0000000000..634c0eca19 --- /dev/null +++ b/input/regression/beams.ly @@ -0,0 +1,12 @@ +\header { + texidoc = "beams (simple)" +} +\score { \notes +\relative c' + { + [c16 c8.] + [c8. c16] + [c8 c16 c16 c8] + [c8 c16 e16 g8] + + }} diff --git a/lily/beam.cc b/lily/beam.cc index 2e223aaecc..a71e306beb 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -9,21 +9,18 @@ */ /* - [TODO] - - * Fix TODO * Junk stem_info. - - * Remove #'direction from beam. A beam has no direction per se. - It may only set directions for stems. - - * Rewrite stem_beams. * Use Number_pair i.s.o Interval to represent (yl, yr). +Notes: + + - Stems run to the Y-center of the beam. - */ + - beam_space is the offset between Y centers of the beam. + +*/ #include // tanh. @@ -70,6 +67,33 @@ shrink_extra_weight (Real x) return fabs (x) * ((x < 0) ? 1.5 : 1.0); } +// move to somewhree? +Slice +int_list_to_slice (SCM l) +{ + Slice s; + s.set_empty (); + for (; gh_pair_p (l); l = gh_cdr (l)) + { + if (gh_number_p (gh_car (l))) + s.add_point (gh_scm2int (gh_car (l))); + } + + return s; +} + +// move to stem? +Slice +stem_beam_multiplicity (Grob *stem) +{ + SCM beaming= stem->get_grob_property ("beaming"); + Slice l = int_list_to_slice (gh_car (beaming)); + Slice r = int_list_to_slice (gh_cdr (beaming)); + l.unite (r); + + return l; +} + void Beam::add_stem (Grob *me, Grob *s) { @@ -84,33 +108,32 @@ Beam::add_stem (Grob *me, Grob *s) } Real -Beam::get_interbeam (Grob *me) +Beam::get_beam_space (Grob *me) { SCM func = me->get_grob_property ("space-function"); - SCM s = gh_call2 (func, me->self_scm (), gh_int2scm (get_multiplicity (me))); + SCM s = gh_call2 (func, me->self_scm (), gh_int2scm (get_beam_count (me))); return gh_scm2double (s); } /* - Maximum multiplicity. + Maximum beam_count. */ int -Beam::get_multiplicity (Grob *me) +Beam::get_beam_count (Grob *me) { int m = 0; for (SCM s = me->get_grob_property ("stems"); gh_pair_p (s); s = ly_cdr (s)) { Grob *sc = unsmob_grob (ly_car (s)); - - if (Stem::has_interface (sc)) - m = m >? Stem::beam_count (sc, LEFT) >? Stem::beam_count (sc, RIGHT); + + m = m >? (stem_beam_multiplicity (sc).length () + 1); } return m; } MAKE_SCHEME_CALLBACK (Beam, space_function, 2); SCM -Beam::space_function (SCM smob, SCM multiplicity) +Beam::space_function (SCM smob, SCM beam_count) { Grob *me = unsmob_grob (smob); @@ -119,11 +142,11 @@ Beam::space_function (SCM smob, SCM multiplicity) Real thickness = gh_scm2double (me->get_grob_property ("thickness")) * staff_space; - Real interbeam = gh_scm2int (multiplicity) < 4 + Real beam_space = gh_scm2int (beam_count) < 4 ? (2*staff_space + line - thickness) / 2.0 : (3*staff_space + line - thickness) / 3.0; - return gh_double2scm (interbeam); + return gh_double2scm (beam_space); } @@ -174,12 +197,259 @@ Beam::before_line_breaking (SCM smob) consider_auto_knees (me, d); set_stem_directions (me, d); + + connect_beams (me); + set_stem_shorten (me); } return SCM_EOL; } + + +void +Beam::connect_beams (Grob *me) +{ + Link_array stems= + Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems"); + + Slice last_int; + last_int.set_empty(); + for (int i = 0; i< stems.size(); i++) + { + Grob *this_stem = stems[i]; + SCM this_beaming = this_stem->get_grob_property ("beaming"); + + Direction this_dir = Directional_element_interface::get(this_stem); + if (i > 0) + { + int start_point = last_int [this_dir]; + + Direction d = LEFT; + Slice new_slice ; + do + { + if (d == RIGHT && i == stems.size()-1) + continue; + + new_slice.set_empty(); + SCM s = index_get_cell (this_beaming, d); + for (; gh_pair_p (s); s = gh_cdr (s)) + { + int new_beam_pos = + start_point - this_dir * gh_scm2int (gh_car (s)); + + new_slice.add_point (new_beam_pos); + gh_set_car_x (s, gh_int2scm (new_beam_pos)); + } + } + while (flip (&d) != LEFT); + + last_int = new_slice; + } + else + { + SCM s = gh_cdr (this_beaming); + for (; gh_pair_p (s); s = gh_cdr (s)) + { + int np = - this_dir * gh_scm2int (gh_car(s)); + gh_set_car_x (s, gh_int2scm (np)); + last_int.add_point (np); + } + } + } +} + +MAKE_SCHEME_CALLBACK (Beam, brew_molecule, 1); +SCM +Beam::brew_molecule (SCM grob) +{ + Grob *me = unsmob_grob (grob); + Link_array stems= + Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems"); + Grob* xcommon = common_refpoint_of_array (stems, me, X_AXIS); + + Real x0, dx; + if (visible_stem_count (me)) + { + // ugh -> use commonx + x0 = first_visible_stem (me)->relative_coordinate (xcommon, X_AXIS); + dx = last_visible_stem (me)->relative_coordinate (xcommon, X_AXIS) - x0; + } + else + { + x0 = stems[0]->relative_coordinate (xcommon, X_AXIS); + dx = stems.top ()->relative_coordinate (xcommon, X_AXIS) - x0; + } + + SCM posns = me->get_grob_property ("positions"); + Interval pos; + if (!ly_number_pair_p (posns)) + { + programming_error ("No beam posns"); + pos = Interval (0,0); + } + else + pos= ly_scm2interval (posns); + + Real dy = pos.delta (); + Real dydx = dy && dx ? dy/dx : 0; + + Real thick = gh_scm2double (me->get_grob_property ("thickness")); + Real bdy = get_beam_space (me); + + SCM last_beaming = SCM_EOL;; + Real last_xposn = -1; + Real last_width = -1 ; + + + + Molecule the_beam; + Real lt = me->paper_l ()->get_var ("linethickness"); + for (int i = 0; i< stems.size(); i++) + { + Grob * st =stems[i]; + + SCM this_beaming = st->get_grob_property ("beaming"); + Real xposn = st->relative_coordinate (xcommon, X_AXIS); + Real stem_width = gh_scm2double (st->get_grob_property ("thickness")) *lt; + + if (i > 0) + { + SCM left = gh_cdr (last_beaming); + SCM right = gh_car (this_beaming); + + Array fullbeams; + Array lfliebertjes; + Array rfliebertjes; + + for (SCM s = left; + gh_pair_p (s); s =gh_cdr (s)) + { + int b = gh_scm2int (gh_car (s)); + if (scm_memq (gh_car(s), right) != SCM_BOOL_F) + { + fullbeams.push (b); + } + else + { + lfliebertjes.push (b); + } + } + for (SCM s = right; + gh_pair_p (s); s =gh_cdr (s)) + { + int b = gh_scm2int (gh_car (s)); + if (scm_memq (gh_car(s), left) == SCM_BOOL_F) + { + rfliebertjes.push (b); + } + } + + + Real w = xposn - last_xposn; + Real stem_offset = 0.0; + Real width_corr = 0.0; + if (i == 1) + { + stem_offset -= last_width/2; + width_corr += last_width/2; + } + + if (i == stems.size() -1) + { + width_corr += stem_width/2; + } + + Molecule whole = Lookup::beam (dydx, w + width_corr, thick); + for (int j = fullbeams.size(); j--;) + { + Molecule b (whole); + b.translate_axis (last_xposn - x0 + stem_offset, X_AXIS); + b.translate_axis (dydx * (last_xposn - x0) + bdy * fullbeams[j], Y_AXIS); + the_beam.add_molecule (b); + } + + if (lfliebertjes.size() || rfliebertjes.size()) + { + + Real nw_f; + if (!Stem::first_head (st)) + nw_f = 0; + else + { + int t = Stem::duration_log (st); + + SCM proc = me->get_grob_property ("flag-width-function"); + SCM result = gh_call1 (proc, gh_int2scm (t)); + nw_f = gh_scm2double (result); + } + + /* Half beam should be one note-width, + but let's make sure two half-beams never touch */ + + Real w = xposn - last_xposn; + w = w/2 relative_coordinate (xcommon, X_AXIS), X_AXIS); + the_beam.translate_axis (pos[LEFT], Y_AXIS); + +#if (DEBUG_QUANTING) + { + /* + This code prints the demerits for each beam. Perhaps this + should be switchable for those who want to twiddle with the + parameters. + */ + String str; + if (1) + { + str += to_str (gh_scm2int (me->get_grob_property ("best-idx"))); + str += ":"; + } + str += to_str (gh_scm2double (me->get_grob_property ("quant-score")), + "%.2f"); + + SCM properties = Font_interface::font_alist_chain (me); + + + Molecule tm = Text_item::text2molecule (me, ly_str02scm (str.ch_C ()), properties); + the_beam.add_at_edge (Y_AXIS, UP, tm, 5.0); + } +#endif + + + + return the_beam.smobbed_copy(); +} + + + + Direction Beam::get_default_dir (Grob *me) { @@ -326,7 +596,7 @@ Beam::set_stem_shorten (Grob *m) Real forced_fraction = forced_stem_count (me) / visible_stem_count (me); - int multiplicity = get_multiplicity (me); + int beam_count = get_beam_count (me); SCM shorten = me->get_grob_property ("beamed-stem-shorten"); if (shorten == SCM_EOL) @@ -336,7 +606,7 @@ Beam::set_stem_shorten (Grob *m) Real staff_space = Staff_symbol_referencer::staff_space (me); SCM shorten_elt = scm_list_ref (shorten, - gh_int2scm (multiplicity rbase_lengths; Drul_array dirs_found(0,0); + + bool french = to_boolean (me->get_grob_property ("french-beaming")); for (int i= 0; i < stems.size(); i++) { Grob*s = stems[i]; stem_infos.push (Stem::calc_stem_info (s)); dirs_found[stem_infos.top ().dir_] = true; - Real b = calc_stem_y (me, s, Interval (1,0), false); + Real b = calc_stem_y (me, s, Interval (1,0), french && i > 0&& (i < stems.size () -1)); lbase_lengths.push (b); - Real a = calc_stem_y (me, s, Interval (0,1), false); + Real a = calc_stem_y (me, s, Interval (0,1), french && i > 0&& (i < stems.size () -1)); rbase_lengths.push (a); } @@ -503,8 +775,8 @@ Beam::quanting (SCM smob) } Real rad = Staff_symbol_referencer::staff_radius (me); - int multiplicity = get_multiplicity (me); - Real interbeam = multiplicity < 4 + int beam_count = get_beam_count (me); + Real beam_space = beam_count < 4 ? (2*ss + slt - thickness) / 2.0 : (3*ss + slt - thickness) / 3.0; @@ -513,8 +785,8 @@ Beam::quanting (SCM smob) { qscores[i].demerits += score_forbidden_quants (me, qscores[i].yl, qscores[i].yr, - rad, slt, thickness, interbeam, - multiplicity, ldir, rdir); + rad, slt, thickness, beam_space, + beam_count, ldir, rdir); } @@ -623,8 +895,8 @@ Beam::score_forbidden_quants (Grob*me, Real yl, Real yr, Real rad, Real slt, - Real thickness, Real interbeam, - int multiplicity, + Real thickness, Real beam_space, + int beam_count, Direction ldir, Direction rdir) { Real dy = yr - yl; @@ -635,8 +907,8 @@ Beam::score_forbidden_quants (Grob*me, if (fabs (yr) < rad && fabs ( my_modf (yr) - 0.5) < 1e-3) dem += INTER_QUANT_PENALTY; - // todo: use multiplicity of outer stems. - if (multiplicity >= 2) + // todo: use beam_count of outer stems. + if (beam_count >= 2) { Real straddle = 0.0; @@ -645,10 +917,10 @@ Beam::score_forbidden_quants (Grob*me, Real hang = 1.0 - (thickness - slt) / 2; - if (fabs (yl - ldir * interbeam) < rad + if (fabs (yl - ldir * beam_space) < rad && fabs (my_modf (yl) - inter) < 1e-3) dem += SECONDARY_BEAM_DEMERIT; - if (fabs (yr - rdir * interbeam) < rad + if (fabs (yr - rdir * beam_space) < rad && fabs (my_modf (yr) - inter) < 1e-3) dem += SECONDARY_BEAM_DEMERIT; @@ -665,7 +937,7 @@ Beam::score_forbidden_quants (Grob*me, // hmm, without Interval/Drul_array, you get ~ 4x same code... - if (fabs (yl - ldir * interbeam) < rad + inter) + if (fabs (yl - ldir * beam_space) < rad + inter) { if (ldir == UP && dy <= eps && fabs (my_modf (yl) - sit) < eps) @@ -676,7 +948,7 @@ Beam::score_forbidden_quants (Grob*me, dem += SECONDARY_BEAM_DEMERIT; } - if (fabs (yr - rdir * interbeam) < rad + inter) + if (fabs (yr - rdir * beam_space) < rad + inter) { if (rdir == UP && dy >= eps && fabs (my_modf (yr) - sit) < eps) @@ -687,9 +959,9 @@ Beam::score_forbidden_quants (Grob*me, dem += SECONDARY_BEAM_DEMERIT; } - if (multiplicity >= 3) + if (beam_count >= 3) { - if (fabs (yl - 2 * ldir * interbeam) < rad + inter) + if (fabs (yl - 2 * ldir * beam_space) < rad + inter) { if (ldir == UP && dy <= eps && fabs (my_modf (yl) - straddle) < eps) @@ -700,7 +972,7 @@ Beam::score_forbidden_quants (Grob*me, dem += SECONDARY_BEAM_DEMERIT; } - if (fabs (yr - 2 * rdir * interbeam) < rad + inter) + if (fabs (yr - 2 * rdir * beam_space) < rad + inter) { if (rdir == UP && dy >= eps && fabs (my_modf (yr) - straddle) < eps) @@ -1062,24 +1334,35 @@ Beam::slope_damping (SCM smob) return SCM_UNSPECIFIED; } +Slice +where_are_the_whole_beams(SCM beaming) +{ + Slice l; + + for( SCM s = gh_car (beaming); gh_pair_p (s) ; s = gh_cdr (s)) + { + if (scm_memq (gh_car (s), gh_cdr (beaming)) != SCM_BOOL_F) + + l.add_point (gh_scm2int (gh_car (s))); + } + + return l; +} + /* Calculate the Y position of the stem-end, given the Y-left, Y-right in POS, and for stem S. - If CORRECT, correct for multiplicity of beam in case of knees. + If CORRECT, correct for beam_count of beam in case of knees. TODO: junk CORRECT from this. */ Real -Beam::calc_stem_y (Grob *me, Grob* s, Interval pos, bool correct) +Beam::calc_stem_y (Grob *me, Grob* s, Interval pos, bool french) { - int beam_multiplicity = get_multiplicity (me); - int stem_multiplicity = (Stem::duration_log (s) - 2) >? 0; - - Real thick = gh_scm2double (me->get_grob_property ("thickness")); - Real interbeam = get_interbeam (me); + Real beam_space = get_beam_space (me); // ugh -> use commonx Grob * fvs = first_visible_stem (me); @@ -1089,58 +1372,26 @@ Beam::calc_stem_y (Grob *me, Grob* s, Interval pos, bool correct) Real dx = fvs ? lvs->relative_coordinate (0, X_AXIS) - x0 : 0.0; Real r = s->relative_coordinate (0, X_AXIS) - x0; Real dy = pos.delta (); - Real stem_y = (dy && dx - ? r / dx - * dy - : 0) + pos[LEFT]; + Real stem_y_beam0 = (dy && dx + ? r / dx + * dy + : 0) + pos[LEFT]; - Direction my_dir = Directional_element_interface::get (s); - Direction first_dir = fvs? Directional_element_interface::get (fvs) : my_dir; - if (correct && my_dir != first_dir) + + Direction my_dir = Directional_element_interface::get (s); + SCM beaming = s->get_grob_property ("beaming"); + + Real stem_y = stem_y_beam0; + if (french) { - /* - WTF is happening here ? - - It looks as if this is some kind of fixup for multiple kneed - beams to get a piece of stem at the #. - - - x - | - =======| - |======# - | - | - x - - Rules for this kind of stuff are hairy. In any event, the - current stem should look at the multiplicity of its - predecessor. - - --hwn. - - */ - - // FIXME, hairy stuff - stem_y += my_dir * (thick / 2 + (beam_multiplicity - 1) * interbeam); - - // huh, why not for first visible? - - /* - What the heck is happening here?? - */ - Grob *last_visible = last_visible_stem (me); - if (last_visible) - { - if ( Staff_symbol_referencer::staff_symbol_l (s) - != Staff_symbol_referencer::staff_symbol_l (last_visible)) - stem_y += Directional_element_interface::get (me) - * (beam_multiplicity - stem_multiplicity) * interbeam; - } - else - programming_error ("No last visible stem"); + stem_y += beam_space * where_are_the_whole_beams (beaming)[-my_dir]; + } + else + { + stem_y += (stem_beam_multiplicity(s)[my_dir]) * beam_space; } + return stem_y; } @@ -1165,30 +1416,16 @@ Beam::set_stem_lengths (Grob *me) Interval pos = ly_scm2interval (me->get_grob_property ("positions")); Real staff_space = Staff_symbol_referencer::staff_space (me); - /* - DOCUMENT THIS. - */ -#if 0 - Real thick = gh_scm2double (me->get_grob_property ("thickness")); - Direction dir = Directional_element_interface::get (me); - bool ps_testing = to_boolean (ly_symbol2scm ("ps-testing")); -#endif - + bool french = to_boolean (me->get_grob_property ("french-beaming")); + for (int i=0; i < stems.size (); i++) { Item* s = stems[i]; if (Stem::invisible_b (s)) continue; - Real stem_y = calc_stem_y (me, s, pos, true); + Real stem_y = calc_stem_y (me, s, pos, french && i > 0&& (i < stems.size () -1)); -#if 0 - // doesn't play well with dvips - if (ps_testing) - if (Stem::get_direction (s) == dir) - stem_y += Stem::get_direction (s) * thick / 2; -#endif - /* caution: stem measures in staff-positions */ Real id = me->relative_coordinate (common, Y_AXIS) - stems[i]->relative_coordinate (common, Y_AXIS); @@ -1205,13 +1442,21 @@ Beam::set_beaming (Grob *me, Beaming_info_list *beaming) Direction d = LEFT; for (int i=0; i < stems.size (); i++) { + /* + Don't overwrite user settings. + */ + do { - /* Don't overwrite user override (?) */ - if (Stem::beam_count (stems[i], d) == -1 - /* Don't set beaming for outside of outer stems */ - && ! (d == LEFT && i == 0) - && ! (d == RIGHT && i == stems.size () -1)) + /* Don't set beaming for outside of outer stems */ + if ((d == LEFT && i == 0) + ||(d == RIGHT && i == stems.size () -1)) + continue; + + + SCM beaming_prop = stems[i]->get_grob_property ("beaming"); + if (beaming_prop == SCM_EOL || + index_get_cell (beaming_prop, d) == SCM_EOL) { int b = beaming->infos_.elem (i).beams_i_drul_[d]; Stem::set_beaming (stems[i], b, d); @@ -1221,239 +1466,6 @@ Beam::set_beaming (Grob *me, Beaming_info_list *beaming) } } - - -/* - beams to go with one stem. - - FIXME: clean me up: - - The beam should be constructed by one function that knows where the - X and Y points are, and only inspects the stems to obtain - multiplicity and stem directions. - - */ -Molecule -Beam::stem_beams (Grob *me, Item *here, Item *next, Item *prev, Real dydx) -{ - // ugh -> use commonx - if ((next - && ! (next->relative_coordinate (0, X_AXIS) - > here->relative_coordinate (0, X_AXIS))) - || (prev - && ! (prev->relative_coordinate (0, X_AXIS) - < here->relative_coordinate (0, X_AXIS)))) - programming_error ("Beams are not left-to-right"); - - Real thick = gh_scm2double (me->get_grob_property ("thickness")); - Real bdy = get_interbeam (me); - - Molecule leftbeams; - Molecule rightbeams; - - Real nw_f; - if (!Stem::first_head (here)) - nw_f = 0; - else - { - int t = Stem::duration_log (here); - - SCM proc = me->get_grob_property ("flag-width-function"); - SCM result = gh_call1 (proc, gh_int2scm (t)); - nw_f = gh_scm2double (result); - } - - - /* [Tremolo] beams on whole notes may not have direction set? */ - Direction dir = Directional_element_interface::get (here); - - /* half beams extending to the left. */ - if (prev) - { - int lhalfs= lhalfs = Stem::beam_count (here, LEFT) - - Stem::beam_count (prev, RIGHT); - int lwholebeams= Stem::beam_count (here, LEFT) - relative_coordinate (0, X_AXIS) - - prev->relative_coordinate (0, X_AXIS); - Real stem_w = gh_scm2double (prev->get_grob_property ("thickness")) - // URG - * me->paper_l ()->get_var ("linethickness"); - - w = w/2 relative_coordinate (0, X_AXIS) - - here->relative_coordinate (0, X_AXIS); - - Real stem_w = gh_scm2double (next->get_grob_property ("thickness")) - // URG - * me->paper_l ()->get_var ("linethickness"); - - Molecule a = Lookup::beam (dydx, w + stem_w, thick); - a.translate_axis (- stem_w/2, X_AXIS); - int j = 0; - Real gap_f = 0; - - SCM gap = me->get_grob_property ("gap"); - if (gh_number_p (gap)) - { - int gap_i = gh_scm2int ((gap)); - int nogap = rwholebeams - gap_i; - - for (; j < nogap; j++) - { - Molecule b (a); - b.translate_axis (-dir * bdy * j, Y_AXIS); - rightbeams.add_molecule (b); - } - if (Stem::invisible_b (here)) - gap_f = nw_f; - else - gap_f = nw_f / 2; - w -= 2 * gap_f; - a = Lookup::beam (dydx, w + stem_w, thick); - } - - for (; j < rwholebeams; j++) - { - Molecule b (a); - Real tx = 0; - if (Stem::invisible_b (here)) - // ugh, see chord-tremolo.ly - tx = (-dir + 1) / 2 * nw_f * 1.5 + gap_f/4; - else - tx = gap_f; - b.translate (Offset (tx, -dir * bdy * j)); - rightbeams.add_molecule (b); - } - - w = w/2 get_grob_property ("stems"))) - return SCM_EOL; - Real x0, dx; - Link_arraystems = - Pointer_group_interface__extract_grobs (me, (Item*) 0, "stems"); - if (visible_stem_count (me)) - { - // ugh -> use commonx - x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS); - dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0; - } - else - { - x0 = stems[0]->relative_coordinate (0, X_AXIS); - dx = stems.top ()->relative_coordinate (0, X_AXIS) - x0; - } - - SCM posns = me->get_grob_property ("positions"); - Interval pos; - if (!ly_number_pair_p (posns)) - { - programming_error ("No beam posns"); - pos = Interval (0,0); - } - else - pos= ly_scm2interval (posns); - Real dy = pos.delta (); - Real dydx = dy && dx ? dy/dx : 0; - - - for (int i=0; i < stems.size (); i++) - { - Item *item = stems[i]; - Item *prev = (i > 0)? stems[i-1] : 0; - Item *next = (i < stems.size ()-1) ? stems[i+1] :0; - - - - Molecule sb = stem_beams (me, item, next, prev, dydx); - Real x = item->relative_coordinate (0, X_AXIS) - x0; - sb.translate (Offset (x, x * dydx + pos[LEFT])); - - - mol.add_molecule (sb); - } - - mol.translate_axis (x0 - - dynamic_cast (me) - ->get_bound (LEFT)->relative_coordinate (0, X_AXIS), - X_AXIS); - -#if (DEBUG_QUANTING) - { - /* - This code prints the demerits for each beam. Perhaps this - should be switchable for those who want to twiddle with the - parameters. - */ - String str; - if (1) - { - str += to_str (gh_scm2int (me->get_grob_property ("best-idx"))); - str += ":"; - } - str += to_str (gh_scm2double (me->get_grob_property ("quant-score")), - "%.2f"); - - SCM properties = Font_interface::font_alist_chain (me); - - - Molecule tm = Text_item::text2molecule (me, ly_str02scm (str.ch_C ()), properties); - mol.add_at_edge (Y_AXIS, UP, tm, 5.0); - } -#endif - - return mol.smobbed_copy (); -} - int Beam::forced_stem_count (Grob *me) { @@ -1609,6 +1621,6 @@ the ideal slope, how close the result is to the ideal stems, etc.). We take the best scoring combination. ", - "position-callbacks concaveness-gap concaveness-threshold dir-function quant-score auto-knee-gap gap chord-tremolo beamed-stem-shorten shorten least-squares-dy damping flag-width-function neutral-direction positions space-function thickness"); + "french-beaming position-callbacks concaveness-gap concaveness-threshold dir-function quant-score auto-knee-gap gap chord-tremolo beamed-stem-shorten shorten least-squares-dy damping flag-width-function neutral-direction positions space-function thickness"); diff --git a/lily/include/beam.hh b/lily/include/beam.hh index 91198c8a64..02a4556b91 100644 --- a/lily/include/beam.hh +++ b/lily/include/beam.hh @@ -24,13 +24,14 @@ public: static void add_stem (Grob*,Grob*); static void set_beaming (Grob*,Beaming_info_list *); static void set_stemlens (Grob*); - static int get_multiplicity (Grob*me); - static Real get_interbeam (Grob*me); + static int get_beam_count (Grob*me); + static Real get_beam_space (Grob*me); + static void connect_beams (Grob*me); DECLARE_SCHEME_CALLBACK (space_function, (SCM, SCM)); DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM)); DECLARE_SCHEME_CALLBACK (before_line_breaking, (SCM)); DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM)); - + /* position callbacks */ DECLARE_SCHEME_CALLBACK (least_squares, (SCM)); DECLARE_SCHEME_CALLBACK (check_concave, (SCM)); @@ -47,15 +48,12 @@ public: int, Direction, Direction); - static Molecule stem_beams (Grob*,Item *here, Item *next, Item *prev, - Real dydx); - private: static Direction get_default_dir (Grob*); static void set_stem_directions (Grob*, Direction ); static void consider_auto_knees (Grob*, Direction d); static void set_stem_shorten (Grob*); - static Real calc_stem_y (Grob*, Grob* s, Interval pos, bool correct); + static Real calc_stem_y (Grob*, Grob* s, Interval pos, bool french); static void set_stem_lengths (Grob*); static int forced_stem_count (Grob*); }; diff --git a/lily/include/lily-guile.hh b/lily/include/lily-guile.hh index db02d97369..2012c4fdb2 100644 --- a/lily/include/lily-guile.hh +++ b/lily/include/lily-guile.hh @@ -207,8 +207,8 @@ bool to_boolean (SCM s); void init_ly_protection (); unsigned int ly_scm_hash (SCM s); -SCM index_cell (SCM cellp, Direction d); -SCM index_set_cell (SCM cellp, Direction d, SCM val); +SCM index_get_cell (SCM cell, Direction d); +SCM index_set_cell (SCM cell, Direction d, SCM val); diff --git a/lily/include/stem.hh b/lily/include/stem.hh index 0e93750714..13146d2165 100644 --- a/lily/include/stem.hh +++ b/lily/include/stem.hh @@ -19,7 +19,6 @@ public: static Array note_head_positions (Grob*); static int duration_log (Grob*) ; - static int beam_count (Grob*,Direction) ; static void set_beaming (Grob*,int, Direction d); static Grob * beam_l (Grob*); static Grob * first_head (Grob*) ; diff --git a/lily/lily-guile.cc b/lily/lily-guile.cc index 8630c6d68e..8e31e897e6 100644 --- a/lily/lily-guile.cc +++ b/lily/lily-guile.cc @@ -218,7 +218,7 @@ ly_scm2string (SCM s) } SCM -index_cell (SCM s, Direction d) +index_get_cell (SCM s, Direction d) { assert (d); return (d == LEFT) ? ly_car (s) : ly_cdr (s); diff --git a/lily/script.cc b/lily/script.cc index 8ff25c0988..7fc2c4843b 100644 --- a/lily/script.cc +++ b/lily/script.cc @@ -28,7 +28,7 @@ Script_interface::get_molecule (Grob * me, Direction d) if (key == ly_symbol2scm ("feta")) { return Font_interface::get_default_font (me)->find_by_name ("scripts-" + - ly_scm2string (index_cell (ly_cdr (s), d))); + ly_scm2string (index_get_cell (ly_cdr (s), d))); } else if (key == ly_symbol2scm ("accordion")) { diff --git a/lily/slur.cc b/lily/slur.cc index 0e86220d10..1861eb18c4 100644 --- a/lily/slur.cc +++ b/lily/slur.cc @@ -159,8 +159,8 @@ Slur::check_slope (Grob *me) Direction d = (Direction) (- dir * (sign (dy))); SCM a = me->get_grob_property ("attachment-offset"); Drul_array o; - o[LEFT] = ly_scm2offset (index_cell (a, LEFT)); - o[RIGHT] = ly_scm2offset (index_cell (a, RIGHT)); + o[LEFT] = ly_scm2offset (index_get_cell (a, LEFT)); + o[RIGHT] = ly_scm2offset (index_get_cell (a, RIGHT)); o[d][Y_AXIS] -= (limit - slope) * dx * dir / staff_space; o[d][Y_AXIS] *= Directional_element_interface::get (me); @@ -196,7 +196,7 @@ Slur::set_extremities (Grob *me) do { - if (!gh_symbol_p (index_cell (att, dir))) + if (!gh_symbol_p (index_get_cell (att, dir))) { for (SCM s = me->get_grob_property ("extremity-rules"); s != SCM_EOL; s = ly_cdr (s)) @@ -290,7 +290,7 @@ Slur::get_attachment (Grob *me, Direction dir, Grob **common) { SCM s = me->get_grob_property ("attachment"); - if (!gh_symbol_p (index_cell (s, dir))) + if (!gh_symbol_p (index_get_cell (s, dir))) { s = set_extremities (me); } @@ -393,7 +393,7 @@ Slur::get_attachment (Grob *me, Direction dir, - me->relative_coordinate (common[Y_AXIS], Y_AXIS); } - Offset off = ly_scm2offset (index_cell (me->get_grob_property + Offset off = ly_scm2offset (index_get_cell (me->get_grob_property ("attachment-offset"), dir)) * staff_space; @@ -642,8 +642,8 @@ Slur::get_curve (Grob*me) if (!Directional_element_interface::get (me) - || ! gh_symbol_p (index_cell (attach, LEFT)) - || ! gh_symbol_p (index_cell (attach, RIGHT))) + || ! gh_symbol_p (index_get_cell (attach, LEFT)) + || ! gh_symbol_p (index_get_cell (attach, RIGHT))) set_extremities (me); if (!gh_pair_p (me->get_grob_property ("control-points"))) diff --git a/lily/stem-tremolo.cc b/lily/stem-tremolo.cc index 612a5ad1ec..dc31df0270 100644 --- a/lily/stem-tremolo.cc +++ b/lily/stem-tremolo.cc @@ -107,23 +107,27 @@ Stem_tremolo::brew_molecule (SCM smob) --hwn. */ - Real interbeam = beam ? Beam::get_interbeam (beam) : 0.81; + Real beam_space = beam ? Beam::get_beam_space (beam) : 0.81; Molecule mol; for (int i = 0; i < tremolo_flags; i++) { Molecule b (a); - b.translate_axis (interbeam * i, Y_AXIS); + b.translate_axis (beam_space * i, Y_AXIS); mol.add_molecule (b); } Direction stemdir = Stem::get_direction (stem); Interval mol_ext = mol.extent (Y_AXIS); // ugh, rather calc from Stem_tremolo_req - int beams_i = (beam) - ? (Stem::beam_count (stem, RIGHT) >? Stem::beam_count (stem, LEFT)) - : 0; + + /* + TODO. + */ + assert(false); + + int beams_i = 0; Real beamthickness = 0.0; SCM sbt = (beam) ? beam->get_grob_property ("thickness") : SCM_EOL ; if (gh_number_p (sbt)) @@ -134,7 +138,7 @@ Stem_tremolo::brew_molecule (SCM smob) Real end_y = Stem::stem_end_position (stem) *ss/2 - stemdir * (beams_i * beamthickness - + ((beams_i -1) >? 0) * interbeam); + + ((beams_i -1) >? 0) * beam_space); /* the 0.33 ss is to compensate for the size of the note head @@ -142,7 +146,7 @@ Stem_tremolo::brew_molecule (SCM smob) Real chord_start_y = Stem::chord_start_y (stem) + 0.33 * ss * stemdir; - Real padding = interbeam; + Real padding = beam_space; /* if there is not enough space, center on remaining space, @@ -154,7 +158,7 @@ Stem_tremolo::brew_molecule (SCM smob) } else { - mol.translate_axis (end_y - stemdir * interbeam + mol.translate_axis (end_y - stemdir * beam_space -mol_ext [stemdir] , Y_AXIS); } diff --git a/lily/stem.cc b/lily/stem.cc index 7b61a8cfa5..f7a8752e9f 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -35,28 +35,25 @@ #include "dot-column.hh" void -Stem::set_beaming (Grob*me ,int i, Direction d) +Stem::set_beaming (Grob*me, int beam_count, Direction d) { SCM pair = me->get_grob_property ("beaming"); if (!gh_pair_p (pair)) { - pair = gh_cons (gh_int2scm (-1),gh_int2scm (-1)); - me-> set_grob_property ("beaming", pair); + pair = gh_cons (SCM_EOL, SCM_EOL); + me->set_grob_property ("beaming", pair); } - index_set_cell (pair, d, gh_int2scm (i)); -} -int -Stem::beam_count (Grob*me,Direction d) -{ - SCM p=me->get_grob_property ("beaming"); - if (gh_pair_p (p)) - return gh_scm2int (index_cell (p,d)); - else - return -1; + SCM l = index_get_cell (pair, d); + for( int i = 0; i< beam_count; i++) + { + l = gh_cons (gh_int2scm (i), l); + } + index_set_cell (pair, d, l); } + Interval Stem::head_positions (Grob*me) { @@ -807,8 +804,8 @@ Stem::calc_stem_info (Grob*me) Real half_space = staff_space / 2; Grob * beam = beam_l (me); - int multiplicity = Beam::get_multiplicity (beam); - Real interbeam_f = Beam::get_interbeam (beam); + int beam_count = Beam::get_beam_count (beam); + Real beam_space_f = Beam::get_beam_space (beam); Real thick = gh_scm2double (beam->get_grob_property ("thickness")); @@ -830,14 +827,14 @@ Stem::calc_stem_info (Grob*me) a.push (gh_scm2double (ly_car (q))); - Real minimum_length = a[multiplicity get_grob_property ("beamed-lengths"); a.clear (); for (SCM q = s; q != SCM_EOL; q = ly_cdr (q)) a.push (gh_scm2double (ly_car (q))); - Real stem_length = a[multiplicity ? 0 >? (- 2 * half_space - thick - + (multiplicity > 0) * thick - + interbeam_f * (multiplicity - 1)); + + (beam_count > 0) * thick + + beam_space_f * (beam_count - 1)); } @@ -887,6 +884,7 @@ Stem::calc_stem_info (Grob*me) if (gh_number_p (s)) ideal_y -= gh_scm2double (s); +#if 0 Grob *common = me->common_refpoint (beam, Y_AXIS); /* @@ -904,7 +902,8 @@ Stem::calc_stem_info (Grob*me) ideal_y += interstaff_f; shortest_y += interstaff_f; - +#endif + ideal_y *= mydir; shortest_y *= mydir; diff --git a/lily/text-spanner.cc b/lily/text-spanner.cc index ebcac1ee55..a29ffe614e 100644 --- a/lily/text-spanner.cc +++ b/lily/text-spanner.cc @@ -101,7 +101,7 @@ Text_spanner::brew_molecule (SCM smob) /* Don't repeat edge text for broken end */ if (!broken[d]) { - SCM text = index_cell (edge_text, d); + SCM text = index_get_cell (edge_text, d); edge[d] = Text_item::text2molecule (me, text, properties); if (!edge[d].empty_b ()) edge[d].align_to (Y_AXIS, CENTER); @@ -152,9 +152,9 @@ Text_spanner::brew_molecule (SCM smob) do { Real dx = ( gh_pair_p (ew) ? - gh_scm2double (index_cell (ew, d)) * d : + gh_scm2double (index_get_cell (ew, d)) * d : 0 ); - Real dy = gh_scm2double (index_cell (s, d)) * - dir; + Real dy = gh_scm2double (index_get_cell (s, d)) * - dir; if (dy) { edge_line[d] = Line_spanner::line_molecule (me, thick, dx, dy); @@ -230,11 +230,11 @@ Text_spanner::setup_pedal_bracket(Spanner *me) height[d] = 0; shorten[d] = 0; if ( ly_number_pair_p (ew) ) - width[d] += gh_scm2double (index_cell (ew, d)); + width[d] += gh_scm2double (index_get_cell (ew, d)); if ( !broken[d] && (ly_number_pair_p (eh) ) ) - height[d] += gh_scm2double (index_cell (eh, d)); + height[d] += gh_scm2double (index_get_cell (eh, d)); if ( ly_number_pair_p (sp) ) - shorten[d] += gh_scm2double (index_cell (sp, d)); + shorten[d] += gh_scm2double (index_get_cell (sp, d)); } while (flip (&d) != LEFT); diff --git a/lily/tie.cc b/lily/tie.cc index 5bac5978e7..bcf59d80f1 100644 --- a/lily/tie.cc +++ b/lily/tie.cc @@ -57,7 +57,7 @@ Grob* Tie::head (Grob*me, Direction d) { SCM c = me->get_grob_property ("heads"); - c = index_cell (c, d); + c = index_get_cell (c, d); return unsmob_grob (c); } diff --git a/lily/tuplet-bracket.cc b/lily/tuplet-bracket.cc index 881bff5550..dadd51f04b 100644 --- a/lily/tuplet-bracket.cc +++ b/lily/tuplet-bracket.cc @@ -178,11 +178,11 @@ Tuplet_bracket::brew_molecule (SCM smob) do { width[d] = height[d] = shorten[d] = 0.0; if ( ly_number_pair_p (ew) ) - width[d] += gh_scm2double (index_cell (ew, d)); + width[d] += gh_scm2double (index_get_cell (ew, d)); if ( ly_number_pair_p (eh) ) - height[d] += gh_scm2double (index_cell (eh, d)) * - dir; + height[d] += gh_scm2double (index_get_cell (eh, d)) * - dir; if ( ly_number_pair_p (sp) ) - shorten[d] += gh_scm2double (index_cell (sp, d)); + shorten[d] += gh_scm2double (index_get_cell (sp, d)); } while (flip (&d) != LEFT); diff --git a/scm/grob-property-description.scm b/scm/grob-property-description.scm index 3d505d67c5..0213d85852 100644 --- a/scm/grob-property-description.scm +++ b/scm/grob-property-description.scm @@ -104,7 +104,13 @@ In the case of alignment grobs, this should contain only one number.") (grob-property-description 'beamed-lengths list? "list of stem lengths given beam multiplicity .") (grob-property-description 'beamed-minimum-lengths list? "list of minimum stem lengths given beam multiplicity.") (grob-property-description 'beamed-stem-shorten list? "shorten beamed stems in forced direction.") -(grob-property-description 'beaming number-pair? "number of beams extending to left and right.") +(grob-property-description 'beaming pair? + "Pair of number lists. Each number list +specifies which beams to make. 0 is the central beam, 1 is the next +beam toward the note etc. This information is used to determine how to +connect the beaming patterns from stem to stem inside a beam.") + + (grob-property-description 'beautiful number? "number that dictates when a slur should be de-uglyfied. It correlates with the enclosed area between noteheads and slurs. A value of 0.1 yields only undisturbed slurs, a value of 5 will tolerate quite high blown slurs.") (grob-property-description 'before-line-breaking-callback procedure? "Procedure taking grob as argument. This procedure is called (using dependency resolution) before line breaking, but after generating discretionary items. Return value is ignored.") @@ -206,6 +212,8 @@ collision_note_width that overides automatic collision settings. This is used by @ref{note-collision-interface}.") (grob-property-description 'fraction number-pair? "fraction of a time signature.") +(grob-property-description 'french-beaming boolean? "Use French +beaming style: stems stop at innermost beams.") (grob-property-description 'full-size-change boolean? "if set, don't make a change clef smaller.") (grob-property-description 'glyph string? "a string determining what (style) of glyph is typeset. Valid choices depend on the function that is reading this property. .") diff --git a/scm/slur.scm b/scm/slur.scm index 6cdeeb1a93..51445d3a54 100644 --- a/scm/slur.scm +++ b/scm/slur.scm @@ -69,7 +69,7 @@ (let ((beaming (ly-get-grob-property stem 'beaming))) ;; (display "beaming (") (display dir) (display "): ") (write beaming) (newline) (if (pair? beaming) - (>= (if (= dir -1) (cdr beaming) (car beaming)) + (>= (length (if (= dir -1) (cdr beaming) (car beaming))) 1) #f)))))) 'stem) -- 2.39.2