X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fhairpin.cc;h=9e6d179c8b56dd347a3ebdfebdb097125aedeb2c;hb=0b544cfb7332615ef809b71b57ab656741311ae1;hp=87f32017a491ca7b9d6a669bf8e25fa4c3c45c10;hpb=c3ff1c6cd20e15e9036ee7120012e05b1d62a46d;p=lilypond.git diff --git a/lily/hairpin.cc b/lily/hairpin.cc index 87f32017a4..9e6d179c8b 100644 --- a/lily/hairpin.cc +++ b/lily/hairpin.cc @@ -1,14 +1,27 @@ /* - hairpin.cc -- implement Hairpin + This file is part of LilyPond, the GNU music typesetter. - source file of the GNU LilyPond music typesetter + Copyright (C) 1997--2014 Han-Wen Nienhuys - (c) 1997--2007 Han-Wen Nienhuys + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . */ #include "hairpin.hh" +#include "axis-group-interface.hh" #include "dimensions.hh" +#include "directional-element-interface.hh" #include "international.hh" #include "line-interface.hh" #include "output-def.hh" @@ -18,51 +31,84 @@ #include "staff-symbol-referencer.hh" #include "text-interface.hh" #include "note-column.hh" +#include "system.hh" #include "warn.hh" -MAKE_SCHEME_CALLBACK (Hairpin, after_line_breaking, 1); +MAKE_SCHEME_CALLBACK (Hairpin, pure_height, 3); SCM -Hairpin::after_line_breaking (SCM smob) +Hairpin::pure_height (SCM smob, SCM, SCM) { - Spanner *me = dynamic_cast (unsmob_grob (smob)); - consider_suicide (me); + Grob *me = unsmob_grob (smob); + Real height = robust_scm2double (me->get_property ("height"), 0.0) + * Staff_symbol_referencer::staff_space (me); - return SCM_UNSPECIFIED; + Real thickness = robust_scm2double (me->get_property ("thickness"), 1) + * Staff_symbol_referencer::line_thickness (me); + + height += thickness / 2; + return ly_interval2scm (Interval (-height, height)); } -void -Hairpin::consider_suicide (Spanner*me) +MAKE_SCHEME_CALLBACK (Hairpin, broken_bound_padding, 1); +SCM +Hairpin::broken_bound_padding (SCM smob) { - Drul_array broken; - Drul_array bounds; - Direction d = LEFT; - do + Spanner *me = unsmob_spanner (smob); + Item *r_bound = me->get_bound (RIGHT); + if (r_bound->break_status_dir () != -1) { - bounds[d] = me->get_bound (d); - broken[d] = bounds[d]->break_status_dir () != CENTER; + me->warning (_ ("Asking for broken bound padding at a non-broken bound.")); + return scm_from_double (0.0); + } + + System *sys = dynamic_cast (me->get_system ()); + Direction dir = get_grob_direction (me->get_parent (Y_AXIS)); + if (!dir) + return scm_from_double (0.0); + + Grob *my_vertical_axis_group = Grob::get_vertical_axis_group (me); + Drul_array vertical_axis_groups; + for (DOWN_and_UP (d)) + vertical_axis_groups[d] = d == dir + ? sys->get_neighboring_staff (d, my_vertical_axis_group, Interval_t (me->spanned_rank_interval ())) + : my_vertical_axis_group; + + if (!vertical_axis_groups[dir]) + return scm_from_double (0.0); + + Drul_array span_bars (0, 0); + for (DOWN_and_UP (d)) + { + extract_grob_set (vertical_axis_groups[d], "elements", elts); + for (vsize i = elts.size (); i--;) + if (elts[i]->internal_has_interface (ly_symbol2scm ("bar-line-interface")) + && dynamic_cast (elts[i])->break_status_dir () == -1) + { + SCM hsb = elts[i]->get_property ("has-span-bar"); + if (!scm_is_pair (hsb)) + break; + + span_bars[d] = unsmob_grob ((d == UP ? scm_car : scm_cdr) (hsb)); + break; + } + + if (!span_bars[d]) + return scm_from_double (0.0); } - while (flip (&d) != LEFT); - if (broken[LEFT] - && ly_is_equal (bounds[RIGHT]->get_column ()->get_property ("when"), - bounds[LEFT]->get_property ("when"))) - me->suicide (); - + if (span_bars[DOWN] != span_bars[UP]) + return scm_from_double (0.0); + + return scm_from_double (robust_scm2double (me->get_property ("bound-padding"), 0.5) + / 2.0); } MAKE_SCHEME_CALLBACK (Hairpin, print, 1); - SCM Hairpin::print (SCM smob) { - Spanner *me = dynamic_cast (unsmob_grob (smob)); + Spanner *me = unsmob_spanner (smob); - if (Spanner *orig = dynamic_cast (me->original ())) - { - for (vsize i = 0; i < orig->broken_intos_.size (); i++) - Hairpin::consider_suicide (orig->broken_intos_[i]); - } - SCM s = me->get_property ("grow-direction"); if (!is_direction (s)) { @@ -75,23 +121,23 @@ Hairpin::print (SCM smob) Drul_array broken; Drul_array bounds; - Direction d = LEFT; - do + for (LEFT_and_RIGHT (d)) { bounds[d] = me->get_bound (d); broken[d] = bounds[d]->break_status_dir () != CENTER; } - while (flip (&d) != LEFT); - broken[RIGHT] = broken[RIGHT] && me->broken_neighbor (RIGHT); - broken[RIGHT] = broken[RIGHT] && me->broken_neighbor (RIGHT)->is_live (); - if (broken[RIGHT]) { Spanner *next = me->broken_neighbor (RIGHT); - Stencil *s = next->get_stencil (); - if (!s || s->is_empty ()) - broken[RIGHT] = false; + // Hairpin-parts suicide in after-line-breaking if they need not be drawn + if (next) + { + (void) next->get_property ("after-line-breaking"); + broken[RIGHT] = next->is_live (); + } + else + broken[RIGHT] = false; } Grob *common = bounds[LEFT]->common_refpoint (bounds[RIGHT], X_AXIS); @@ -101,8 +147,8 @@ Hairpin::print (SCM smob) Use the height and thickness of the hairpin when making a circled tip */ bool circled_tip = ly_scm2bool (me->get_property ("circled-tip")); - Real height = robust_scm2double (me->get_property ("height"), 0.2) * - Staff_symbol_referencer::staff_space (me); + Real height = robust_scm2double (me->get_property ("height"), 0.2) + * Staff_symbol_referencer::staff_space (me); /* FIXME: 0.525 is still just a guess... */ @@ -110,104 +156,128 @@ Hairpin::print (SCM smob) Real thick = 1.0; if (circled_tip) thick = robust_scm2double (me->get_property ("thickness"), 1.0) - * Staff_symbol_referencer::line_thickness (me); + * Staff_symbol_referencer::line_thickness (me); - do + for (LEFT_and_RIGHT (d)) { Item *b = bounds[d]; + Interval e = Axis_group_interface::generic_bound_extent (b, common, X_AXIS); + x_points[d] = b->relative_coordinate (common, X_AXIS); if (broken [d]) - { - if (d == LEFT) - x_points[d] = b->extent (common, X_AXIS)[RIGHT]; - } + { + if (d == LEFT) + x_points[d] = e[-d]; + else + { + Real broken_bound_padding + = robust_scm2double (me->get_property ("broken-bound-padding"), 0.0); + extract_grob_set (me, "concurrent-hairpins", chp); + for (vsize i = 0; i < chp.size (); i++) + { + Spanner *span_elt = dynamic_cast (chp[i]); + if (span_elt->get_bound (RIGHT)->break_status_dir () == LEFT) + broken_bound_padding = max (broken_bound_padding, + robust_scm2double (span_elt->get_property ("broken-bound-padding"), 0.0)); + } + x_points[d] -= d * broken_bound_padding; + } + } else - { - if (Text_interface::has_interface (b)) - { - Interval e = b->extent (common, X_AXIS); - if (!e.is_empty ()) - x_points[d] = e[-d] - d * padding; - } - else - { - bool neighbor_found = false; - extract_grob_set (me, "adjacent-hairpins", pins); - for (vsize i = 0; i < pins.size (); i++) - { - /* - FIXME: this will fuck up in case of polyphonic - notes in other voices. Need to look at note-columns - in the current staff/voice. - */ - - Spanner *pin = dynamic_cast (pins[i]); - if (pin - && (pin->get_bound (LEFT)->get_column () == b->get_column () - || pin->get_bound (RIGHT)->get_column () == b->get_column ())) - neighbor_found = true; - } - - Interval e = robust_relative_extent (b, common, X_AXIS); - if (neighbor_found) - { - /* - Handle back-to-back hairpins with a circle in the middle - */ - if (circled_tip && (grow_dir != d)) - x_points[d] = e.center () + d * (rad - thick / 2.0); - /* - If we're hung on a paper column, that means we're not - adjacent to a text-dynamic, and we may move closer. We - make the padding a little smaller, here. - */ - else - x_points[d] = e.center () - d * padding / 3; - } - else - { - if (Note_column::has_interface (b) - && Note_column::has_rests (b)) - x_points[d] = e[-d]; - else - x_points[d] = e[d]; - - Item *bound = me->get_bound (d); - if (bound->is_non_musical (bound)) - x_points[d] -= d * padding; - } - } - } + { + if (Text_interface::has_interface (b)) + { + if (!e.is_empty ()) + x_points[d] = e[-d] - d * padding; + } + else + { + bool neighbor_found = false; + Spanner *adjacent = NULL; + extract_grob_set (me, "adjacent-spanners", neighbors); + for (vsize i = 0; i < neighbors.size (); i++) + { + /* + FIXME: this will fuck up in case of polyphonic + notes in other voices. Need to look at note-columns + in the current staff/voice. + */ + adjacent = dynamic_cast (neighbors[i]); + if (adjacent + && (adjacent->get_bound (-d)->get_column () + == b->get_column ())) + { + neighbor_found = true; + break; + } + } + + if (neighbor_found) + { + if (Hairpin::has_interface (adjacent)) + { + /* + Handle back-to-back hairpins with a circle in the middle + */ + if (circled_tip && (grow_dir != d)) + x_points[d] = e.center () + d * (rad - thick / 2.0); + /* + If we're hung on a paper column, that means we're not + adjacent to a text-dynamic, and we may move closer. We + make the padding a little smaller, here. + */ + else + x_points[d] = e.center () - d * padding / 3; + } + // Our neighbor is a dynamic text spanner. + // If we end on the text, pad as for text dynamics + else if (d == RIGHT) + x_points[d] = e[-d] - d * padding; + } + else + { + if (d == RIGHT // end at the left edge of a rest + && Note_column::has_interface (b) + && Note_column::has_rests (b)) + x_points[d] = e[-d]; + else + x_points[d] = e[d]; + + if (Item::is_non_musical (b)) + x_points[d] -= d * padding; + } + } + } } - while (flip (&d) != LEFT); Real width = x_points[RIGHT] - x_points[LEFT]; + if (width < 0) { me->warning (_ ((grow_dir < 0) ? "decrescendo too small" - : "crescendo too small")); + : "crescendo too small")); width = 0; } bool continued = broken[Direction (-grow_dir)]; + bool continuing = broken[Direction (grow_dir)]; Real starth = 0; Real endh = 0; if (grow_dir < 0) { - starth = height; - endh = continued ? height / 2 : 0.0; + starth = continuing ? 2 * height / 3 : height; + endh = continued ? height / 3 : 0.0; } else { - starth = continued ? height / 2 : 0.0; - endh = height; + starth = continued ? height / 3 : 0.0; + endh = continuing ? 2 * height / 3 : height; } /* should do relative to staff-symbol staff-space? */ - Stencil mol; Real x = 0.0; @@ -218,14 +288,14 @@ Hairpin::print (SCM smob) if (circled_tip && !broken[tip_dir]) { if (grow_dir > 0) - x = rad * 2.0; + x = rad * 2.0; else if (grow_dir < 0) - width -= rad *2.0; + width -= rad * 2.0; } mol = Line_interface::line (me, Offset (x, starth), Offset (width, endh)); mol.add_stencil (Line_interface::line (me, - Offset (x, -starth), - Offset (width, -endh))); + Offset (x, -starth), + Offset (width, -endh))); /* Support al/del niente notation by putting a circle at the @@ -234,34 +304,36 @@ Hairpin::print (SCM smob) if (circled_tip) { Box extent (Interval (-rad, rad), Interval (-rad, rad)); - + /* Hmmm, perhaps we should have a Lookup::circle () method? */ Stencil circle (extent, - scm_list_4 (ly_symbol2scm ("circle"), - scm_from_double (rad), - scm_from_double (thick), - SCM_BOOL_F)); + scm_list_4 (ly_symbol2scm ("circle"), + scm_from_double (rad), + scm_from_double (thick), + SCM_BOOL_F)); /* - don't add another circle the hairpin is broken + don't add another circle if the hairpin is broken */ if (!broken[tip_dir]) - mol.add_at_edge (X_AXIS, tip_dir, Stencil (circle), 0); + mol.add_at_edge (X_AXIS, tip_dir, Stencil (circle), 0); } mol.translate_axis (x_points[LEFT] - - bounds[LEFT]->relative_coordinate (common, X_AXIS), - X_AXIS); + - bounds[LEFT]->relative_coordinate (common, X_AXIS), + X_AXIS); return mol.smobbed_copy (); } ADD_INTERFACE (Hairpin, - "A hairpin crescendo/decrescendo.", - - /* props */ - "adjacent-hairpins " - "circled-tip " - "bound-padding " - "grow-direction " - "height " - ); + "A hairpin crescendo or decrescendo.", + + /* properties */ + "adjacent-spanners " + "circled-tip " + "concurrent-hairpins " + "broken-bound-padding " + "bound-padding " + "grow-direction " + "height " + );