X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;ds=sidebyside;f=lily%2Fauto-beam-engraver.cc;h=7e939e7c8e4ce4976b744087ec5f56558628bab7;hb=b638d530ac5a32a832646cdd2b680ce52d0764f0;hp=23698891e4f0d51f17dafea2ea23bc23a77444e0;hpb=3bcb994d1aae1a51345f33a7c0851ce9da7b4ede;p=lilypond.git diff --git a/lily/auto-beam-engraver.cc b/lily/auto-beam-engraver.cc index 23698891e4..7e939e7c8e 100644 --- a/lily/auto-beam-engraver.cc +++ b/lily/auto-beam-engraver.cc @@ -3,79 +3,190 @@ source file of the GNU LilyPond music typesetter - (c) 1999 Jan Nieuwenhuizen + (c) 1999--2000 Jan Nieuwenhuizen */ - +#include "beaming.hh" #include "auto-beam-engraver.hh" #include "musical-request.hh" #include "bar.hh" #include "beam.hh" -#include "grouping.hh" #include "rest.hh" #include "stem.hh" #include "debug.hh" -#include "time-description.hh" +#include "timing-engraver.hh" +#include "engraver-group-engraver.hh" ADD_THIS_TRANSLATOR (Auto_beam_engraver); + +/* + TODO: remove all references to Timing_engraver; should read properties. + + */ Auto_beam_engraver::Auto_beam_engraver () { - beam_p_ = 0; + stem_l_arr_p_ = 0; + shortest_mom_ = Moment (1, 8); finished_beam_p_ = 0; finished_grouping_p_ = 0; grouping_p_ = 0; + timer_l_ =0; } void -Auto_beam_engraver::do_process_requests () +Auto_beam_engraver::do_creation_processing () { - consider_end_and_begin (); + Translator * t = daddy_grav_l ()->get_simple_translator ("Timing_engraver"); + timer_l_ = dynamic_cast (t); } +bool +Auto_beam_engraver::do_try_music (Music*) +{ + return false; +} + void -Auto_beam_engraver::consider_end_and_begin () +Auto_beam_engraver::do_process_music () { - Time_description const *time = get_staff_info().time_C_; + consider_end_and_begin (shortest_mom_); +} - Scalar begin = get_property ("beamAutoBegin", 0); - Moment begin_mom = begin.to_rat (); +void +Auto_beam_engraver::consider_end_and_begin (Moment test_mom) +{ + if (!timer_l_) + return; + + int num; + int den; + timer_l_->get_time_signature (&num, &den); - Scalar end = get_property ("beamAutoEnd", 0); - Moment end_mom = end.to_rat (); + String time_str = String ("time") + to_str (num) + "_" + to_str (den); - if (mult_i_) + String type_str; + if (test_mom.num () != 1) + type_str = to_str (test_mom.num ()); + if (test_mom.den () != 1) + type_str = type_str + "_" + to_str (test_mom.den ()); + + /* + URG + + FIXME: SHOULD USE ALIST + + */ + + /* + Determine end moment for auto beaming (and begin, mostly 0==anywhere) + In order of increasing priority: + + i. every beat + ii. time_beamAutoEnd + iii. time_beamAutoEnd + iv. beamAutoEnd + v. beamAutoEnd + + + Rationale: + + [to be defined in config file] + i. easy catch-all rule + ii. exceptions for time signature + iii. exceptions for time signature, for specific duration type + + [user override] + iv. generic override + v. override for specific duration type + + The user overrides should be required for common cases. + */ + + /* + first guess: begin beam at any position + */ + Moment begin_mom (0); + /* + first guess: end beam at end of beat + */ + SCM one (get_property ("beatLength")); + + Moment end_mom; + if (unsmob_moment (one)) + end_mom = *unsmob_moment (one); + + /* + second guess: property generic time exception + */ + SCM begin = get_property ((time_str + "beamAutoBegin").ch_C()); + if (unsmob_moment (begin)) + begin_mom = * unsmob_moment (begin); + + SCM end = get_property ((time_str + "beamAutoEnd").ch_C()); + if (unsmob_moment (end)) + end_mom = * unsmob_moment (end); + + /* + third guess: property time exception, specific for duration type + */ + if (type_str.length_i ()) + { + SCM end_mult = get_property ((time_str + "beamAutoEnd" + type_str).ch_C()); + if (unsmob_moment (end_mult)) + end_mom = * unsmob_moment (end_mult); + + SCM begin_mult = get_property ((time_str + "beamAutoBegin" + type_str).ch_C()); + if (unsmob_moment (begin_mult)) + begin_mom = * unsmob_moment (begin_mult); + } + + /* + fourth guess [user override]: property plain generic + */ + begin = get_property ("beamAutoBegin"); + if (unsmob_moment (begin)) + begin_mom = * unsmob_moment (begin); + + + + end = get_property ("beamAutoEnd"); + if (unsmob_moment (end)) + end_mom = * unsmob_moment (end); + + /* + fifth guess [user override]: property plain, specific for duration type + */ + if (type_str.length_i ()) { - int type = 1 << (mult_i_ + 2); - Scalar end_mult = get_property (String ("beamAutoEnd") - + to_str (type), 0); - if (end_mult.length_i ()) - end_mom = end_mult.to_rat (); - else if (Moment (type, 4) / end_mom > Moment (4)) - end_mom /= Moment (type, 8); + SCM end_mult = get_property ((String ("beamAutoEnd") + type_str).ch_C()); + if (unsmob_moment (end_mult)) + end_mom = * unsmob_moment (end_mult); + + SCM begin_mult = get_property ((String ("beamAutoBegin") + type_str).ch_C()); + if (unsmob_moment (begin_mult)) + begin_mom = * unsmob_moment (begin_mult); } - Real f; + Rational r; if (end_mom) - f = fmod (time->whole_in_measure_, end_mom); + r = timer_l_->measure_position ().mod_rat (end_mom); else - f = Moment (1); + r = Moment (1); - // enge floots - Real epsilon_f = Moment (1, 512); - if (beam_p_ && (abs (f) < epsilon_f)) + if (stem_l_arr_p_ && !r) end_beam (); /* Allow already started autobeam to end */ - Scalar on = get_property ("beamAuto", 0); - if (!on.to_bool ()) + SCM on = get_property ("noAutoBeaming"); + if (to_boolean (on)) return; if (begin_mom) - f = fmod (time->whole_in_measure_, begin_mom); - if (!beam_p_ && (!begin_mom || (abs (f) < epsilon_f))) + r = timer_l_->measure_position ().mod_rat (begin_mom); + if (!stem_l_arr_p_ && (!begin_mom || !r)) begin_beam (); } @@ -83,48 +194,52 @@ Auto_beam_engraver::consider_end_and_begin () void Auto_beam_engraver::begin_beam () { - DOUT << String ("starting autobeam at: ") + now_moment ().str () + "\n"; - beam_p_ = new Beam; - grouping_p_ = new Rhythmic_grouping; - - /* urg, copied from Beam_engraver */ - Scalar prop = get_property ("beamslopedamping", 0); - if (prop.isnum_b ()) - beam_p_->damping_i_ = prop; - - prop = get_property ("beamquantisation", 0); - if (prop.isnum_b ()) - beam_p_->quantisation_ = (Beam::Quantisation)(int)prop; - - // must set minVerticalAlign = = maxVerticalAlign to get sane results - // see input/test/beam-interstaff.ly - prop = get_property ("minVerticalAlign", 0); - if (prop.isnum_b ()) - beam_p_->vertical_align_drul_[MIN] = prop; + assert (!stem_l_arr_p_); + stem_l_arr_p_ = new Array; + assert (!grouping_p_); + grouping_p_ = new Beaming_info_list; + beam_start_moment_ = now_mom (); + beam_start_location_ = timer_l_->measure_position (); +} - prop = get_property ("maxVerticalAlign", 0); - if (prop.isnum_b ()) - beam_p_->vertical_align_drul_[MAX] = prop; +Beam* +Auto_beam_engraver::create_beam_p () +{ + Beam* beam_p = new Beam (get_property ("basicBeamProperties")); - announce_element (Score_element_info (beam_p_, 0)); + for (int i = 0; i < stem_l_arr_p_->size (); i++) + { + /* + watch out for stem tremolos and abbreviation beams + */ + if ((*stem_l_arr_p_)[i]->beam_l ()) + { + return 0; + } + beam_p->add_stem ((*stem_l_arr_p_)[i]); + } + + announce_element (Score_element_info (beam_p, 0)); + + return beam_p; } void Auto_beam_engraver::end_beam () { - DOUT << String ("ending autobeam at: ") + now_moment ().str () + "\n"; - if (beam_p_->stems_.size () < 2) + if (stem_l_arr_p_->size () < 2) { - DOUT << "junking autombeam: less than two stems\n"; junk_beam (); } else { - finished_beam_p_ = beam_p_; - finished_grouping_p_ = grouping_p_; - beam_p_ = 0; + finished_beam_p_ = create_beam_p (); + if (finished_beam_p_) + finished_grouping_p_ = grouping_p_; + delete stem_l_arr_p_; + stem_l_arr_p_ = 0; grouping_p_ = 0; - mult_i_ = 0; + shortest_mom_ = Moment (1, 8); } } @@ -133,9 +248,8 @@ Auto_beam_engraver::typeset_beam () { if (finished_beam_p_) { - Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_; - rg_C->extend (finished_grouping_p_->interval()); - finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_); + finished_grouping_p_->beamify (); + finished_beam_p_->set_beaming (finished_grouping_p_); typeset_element (finished_beam_p_); finished_beam_p_ = 0; @@ -147,6 +261,17 @@ Auto_beam_engraver::typeset_beam () void Auto_beam_engraver::do_post_move_processing () { + /* + don't beam over skips + */ + if (stem_l_arr_p_) + { + Moment now = now_mom (); + if (extend_mom_ < now) + { + end_beam (); + } + } } void @@ -158,136 +283,133 @@ Auto_beam_engraver::do_pre_move_processing () void Auto_beam_engraver::do_removal_processing () { + /* finished beams may be typeset */ typeset_beam (); - if (beam_p_) - { - DOUT << "Unfinished beam\n"; - junk_beam (); - } + /* but unfinished may need another announce/acknowledge pass */ + if (stem_l_arr_p_) + junk_beam (); +} + +bool +Auto_beam_engraver::same_grace_state_b (Score_element* e) +{ + bool gr = e->get_elt_property ("grace") == SCM_BOOL_T; + SCM wg =get_property ("weAreGraceContext"); + return (to_boolean (wg)) == gr; } void Auto_beam_engraver::acknowledge_element (Score_element_info info) { - if (Beam *b = dynamic_cast (info.elem_l_)) + if (!same_grace_state_b (info.elem_l_) || !timer_l_) + return; + + if (stem_l_arr_p_) { - if (beam_p_) + if (Beam *b = dynamic_cast (info.elem_l_)) { - DOUT << "junking autobeam: beam encountered\n"; - junk_beam (); + end_beam (); } - } - if (Bar *b = dynamic_cast (info.elem_l_)) - { - if (beam_p_) + else if (Bar *b = dynamic_cast (info.elem_l_)) { - DOUT << "junking autobeam: bar encountered\n"; - junk_beam (); + end_beam (); + } + else if (Rest* rest_l = dynamic_cast (info.elem_l_)) + { + end_beam (); } } - - if (beam_p_) + + if (Stem* stem_l = dynamic_cast (info.elem_l_)) { Rhythmic_req *rhythmic_req = dynamic_cast (info.req_l_); if (!rhythmic_req) - return; - - if (dynamic_cast (info.elem_l_)) { - DOUT << "junking autobeam: rest encountered\n"; - end_beam (); + programming_error ("Stem must have rhythmic structure"); return; } - - Stem* stem_l = dynamic_cast (info.elem_l_); - if (!stem_l) - return; - - if (stem_l->beam_l_ && (stem_l->beam_l_ != beam_p_)) + + /* + Don't (start) auto-beam over empty stems; skips or rests + */ + if (!stem_l->heads_i ()) { - DOUT << "junking autobeam: beamed stem encountered\n"; - junk_beam (); + if (stem_l_arr_p_) + end_beam (); return; } - - /* - now that we have last_add_mom_, perhaps we can (should) do away - with these individual junk_beams - */ - if (rhythmic_req->duration_.durlog_i_<= 2) + if (stem_l->beam_l ()) { - DOUT << "ending autobeam: stem doesn't fit in beam\n"; - end_beam (); - return; + if (stem_l_arr_p_) + junk_beam (); + return ; } - - Moment start = get_staff_info().time_C_->whole_in_measure_; - if (!grouping_p_->child_fit_b (start)) + + int durlog =rhythmic_req->duration_.durlog_i_; + if (durlog <= 2) { - DOUT << "ending autobeam: stem doesn't fit in group\n"; - end_beam (); + if (stem_l_arr_p_) + end_beam (); + return; } - else + + /* + if shortest duration would change + reconsider ending/starting beam first. + */ + Moment mom = rhythmic_req->duration_.length_mom (); + consider_end_and_begin (mom); + if (!stem_l_arr_p_) + return; + if (mom < shortest_mom_) { - int m = (rhythmic_req->duration_.durlog_i_ - 2); - /* - if multiplicity would become greater, - reconsider ending/starting beam first. - */ - if (m > mult_i_) + if (stem_l_arr_p_->size ()) { - mult_i_ = m; - consider_end_and_begin (); + shortest_mom_ = mom; + consider_end_and_begin (shortest_mom_); + if (!stem_l_arr_p_) + return; } - mult_i_ = m; - grouping_p_->add_child (start, rhythmic_req->duration ()); - stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_; - beam_p_->add_stem (stem_l); - Moment now = now_moment (); - last_add_mom_ = now; - extend_mom_ = extend_mom_ >? now + rhythmic_req->duration (); + shortest_mom_ = mom; } + Moment now = now_mom (); + + grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_, + durlog - 2); + stem_l_arr_p_->push (stem_l); + last_add_mom_ = now; + extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom (); } } void Auto_beam_engraver::junk_beam () { - assert (beam_p_); - for (int i=0; i < beam_p_->stems_.size (); i++) - { - Stem* s = beam_p_->stems_[i]; - s->beams_i_drul_[LEFT] = 0; - s->beams_i_drul_[RIGHT] = 0; - s->mult_i_ = 0; - s->beam_l_ = 0; - } + assert (stem_l_arr_p_); - beam_p_->unlink (); - beam_p_ = 0; + delete stem_l_arr_p_; + stem_l_arr_p_ = 0; delete grouping_p_; grouping_p_ = 0; - mult_i_ = 0; + shortest_mom_ = Moment (1, 8); } void Auto_beam_engraver::process_acknowledged () { - if (beam_p_) + if (stem_l_arr_p_) { - Moment now = now_moment (); + Moment now = now_mom (); if ((extend_mom_ < now) || ((extend_mom_ == now) && (last_add_mom_ != now ))) { - DOUT << String ("junking autobeam: no stem added since: ") - + last_add_mom_.str () + "\n"; end_beam (); } - else if (!beam_p_->stems_.size ()) + else if (!stem_l_arr_p_->size ()) { - DOUT << "junking started autobeam: no stems\n"; junk_beam (); } } } +