X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fdynamic-engraver.cc;h=019ef105db37ec8af9743e597e07154bab966aca;hb=07dc00d6c83be5b05f5ec16f1ed36b1cf41b885c;hp=c1d91728797ef43ef948fa833bf3411d9d46b0a1;hpb=f5cd261f30895d55144216ff4c134bf19126332b;p=lilypond.git diff --git a/lily/dynamic-engraver.cc b/lily/dynamic-engraver.cc index c1d9172879..019ef105db 100644 --- a/lily/dynamic-engraver.cc +++ b/lily/dynamic-engraver.cc @@ -7,6 +7,7 @@ */ #include "debug.hh" #include "dimensions.hh" +#include "dimension-cache.hh" #include "crescendo.hh" #include "musical-request.hh" #include "lookup.hh" @@ -22,195 +23,90 @@ #include "group-interface.hh" #include "directional-element-interface.hh" #include "staff-symbol-referencer.hh" +#include "translator-group.hh" +#include "axis-group-interface.hh" -#define DYN_LINE -#ifdef DYN_LINE +/* + TODO: + + * direction of text-dynamic-request if not equalt to direction + of line-spanner + + * FIXME: this has gotten a bit too hairy. + */ class Dynamic_line_spanner : public Spanner { public: Dynamic_line_spanner (); - - void add_element (Score_element*); + VIRTUAL_COPY_CONS(Score_element); void add_column (Note_column*); - Direction get_default_dir () const; - -protected: - virtual void do_add_processing (); - // URG: see Dynamic_engraver::do_removal_processing - friend class Dynamic_engraver; - virtual void do_post_processing (); - -private: - void translate_elements (Real); - Real get_extreme_y () const; + void add_element (Score_element*); }; Dynamic_line_spanner::Dynamic_line_spanner () { set_elt_property ("transparent", SCM_BOOL_T); -} - -void -Dynamic_line_spanner::add_element (Score_element* e) -{ - Group_interface gi (this, "elements"); - gi.add_element (e); - //? - Side_position_interface (e).set_axis (Y_AXIS); - add_dependency (e); + side_position (this).set_axis (Y_AXIS); + Axis_group_interface (this).set_interface (); + Axis_group_interface (this).set_axes (X_AXIS, Y_AXIS); } void Dynamic_line_spanner::add_column (Note_column* n) { - Group_interface gi (this, "note-columns"); - gi.add_element (n); - add_dependency (n); -} - -/* - Copied (urg: literally!) from slur. - Why not do this once, at post-processing stage? - */ -void -Dynamic_line_spanner::do_add_processing () -{ - Link_array encompass_arr = - Group_interface__extract_elements (this, (Note_column*)0, "note-columns"); - - if (encompass_arr.size ()) - { - set_bounds (LEFT, encompass_arr[0]); - if (encompass_arr.size () > 1) - set_bounds (RIGHT, encompass_arr.top ()); - } -} + if (!get_bound (LEFT)) + set_bound (LEFT, n); + else + set_bound (RIGHT, n); -#if 0 -Molecule -Dynamic_line_spanner::do_brew_molecule () const -{ - return Molecule (); + add_dependency (n); } -#endif -void -Dynamic_line_spanner::do_post_processing () -{ - translate_elements (get_extreme_y ()); -} void -Dynamic_line_spanner::translate_elements (Real dy) -{ - SCM s = get_elt_property ("elements"); - for (; gh_pair_p (s); s = gh_cdr (s)) - { - Score_element* se = unsmob_element (gh_car (s)); - se->translate_axis (dy, Y_AXIS); - } -} - -Direction -Dynamic_line_spanner::get_default_dir () const -{ - return DOWN; - //Direction dir = directional_element (this).get (); -} - -Real -Dynamic_line_spanner::get_extreme_y () const +Dynamic_line_spanner::add_element (Score_element* e) { - Link_array encompass_arr = - Group_interface__extract_elements (this, (Note_column*)0, "note-columns"); - - Staff_symbol_referencer_interface si (this); - int stafflines = si.line_count (); - //hurg? - stafflines = stafflines != 0 ? stafflines : 5; - Direction dir = get_default_dir (); - - Real staff_space = si.staff_space (); - // burp? when are these available? - staff_space = staff_space != 0 ? staff_space : 5 PT; - - // urg: TODO: padding - Real y = (stafflines / 2 + 1) * staff_space; - - for (int i = 0; i < encompass_arr.size (); i++) - { - Note_column* column = encompass_arr[i]; - Stem* stem = column->stem_l (); - if (stem) - { - Direction stem_dir = directional_element (stem).get (); - if ((stem_dir == dir) - && !stem->extent (Y_AXIS).empty_b ()) - { - y = y >? (stem->extent (Y_AXIS)[dir]) * dir; - } - else - { - y = y >? (column->extent (Y_AXIS)[dir]) * dir; - } - } - } - - return y * dir; + e->set_parent (this, Y_AXIS); + Axis_group_interface (this).add_element (e); } -#endif - -/* - TODO: - * why handle absolute and span requests in one cryptic engraver, - what about Span_dynamic_engraver? - - * hairpin - * text: - - `cresc. -- -- --' - - `cresc. poco a poco -- -- --' - */ - /** print text & hairpin dynamics. */ class Dynamic_engraver : public Engraver { - Text_item * abs_text_p_; - Text_item * cr_text_p_; - Crescendo * to_end_cresc_p_; + Text_item * text_p_; + Crescendo * finished_cresc_p_; Crescendo * cresc_p_; - Span_req * cresc_req_l_; - Array dynamic_req_l_arr_; + Text_script_req* text_req_l_; + Span_req * span_start_req_l_; + Drul_array span_req_l_drul_; -#ifdef DYN_LINE - /* - We probably need two of these: line-up above and below staff - */ - Dynamic_line_spanner* spanner_; + Dynamic_line_spanner* line_spanner_; + Dynamic_line_spanner* finished_line_spanner_; Moment last_request_mom_; -#endif + + Array pending_column_arr_; + Link_array pending_element_arr_; void typeset_all (); + public: VIRTUAL_COPY_CONS(Translator); - Dynamic_engraver(); + Dynamic_engraver (); protected: - void announce_element (Score_element_info); virtual void do_removal_processing (); virtual void acknowledge_element (Score_element_info); virtual bool do_try_music (Music *req_l); - virtual void do_process_requests(); - virtual void do_pre_move_processing(); - virtual void do_post_move_processing(); - virtual void typeset_element (Score_element*); + virtual void do_process_music (); + virtual void do_pre_move_processing (); + virtual void do_post_move_processing (); }; ADD_THIS_TRANSLATOR (Dynamic_engraver); @@ -226,230 +122,256 @@ Dynamic_engraver::announce_element (Score_element_info i) Dynamic_engraver::Dynamic_engraver () { - do_post_move_processing(); - abs_text_p_ = 0; - cr_text_p_ = 0; - to_end_cresc_p_ = cresc_p_ = 0; - cresc_req_l_ = 0; -#ifdef DYN_LINE - spanner_ = 0; -#endif + text_p_ = 0; + finished_cresc_p_ = 0; + line_spanner_ = 0; + finished_line_spanner_ = 0; + span_start_req_l_ = 0; + cresc_p_ =0; + + text_req_l_ = 0; + span_req_l_drul_[START] = 0; + span_req_l_drul_[STOP] = 0; } void -Dynamic_engraver::do_post_move_processing() +Dynamic_engraver::do_post_move_processing () { - dynamic_req_l_arr_.clear(); + text_req_l_ = 0; + span_req_l_drul_[START] = 0; + span_req_l_drul_[STOP] = 0; } -/* - ugr - */ bool Dynamic_engraver::do_try_music (Music * m) { - Request * r = dynamic_cast (m); - - if(Text_script_req * d = dynamic_cast (r)) + if (Text_script_req* d = dynamic_cast (m)) { - if (d->style_str_ != "dynamic") - return false; + if (d->style_str_ == "dynamic") + { + text_req_l_ = d; + return true; + } } - else if (Span_req * s = dynamic_cast (r)) + else if (Span_req* s = dynamic_cast (m)) { - if (s-> span_type_str_ != "crescendo" - && s->span_type_str_ != "decrescendo") - return false; + if ((s->span_type_str_ == "crescendo" + || s->span_type_str_ == "decrescendo")) + { + span_req_l_drul_[s->span_dir_] = s; + return true; + } } - else - return false; - -#ifdef DYN_LINE - if (!spanner_) - spanner_ = new Dynamic_line_spanner; - last_request_mom_ = now_mom (); -#endif - - for (int i=0; i < dynamic_req_l_arr_.size (); i++) - if (r->equal_b (dynamic_req_l_arr_[i])) - return true; - - dynamic_req_l_arr_.push (r); - return true; + return false; } - void -Dynamic_engraver::do_process_requests() +Dynamic_engraver::do_process_music () { - Crescendo* new_cresc_p=0; + if ((span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_) + && !line_spanner_ + && pending_element_arr_.size ()) + { + line_spanner_ = new Dynamic_line_spanner; + for (int i = 0; i < pending_column_arr_.size (); i++) + line_spanner_->add_column (pending_column_arr_[i]); + pending_column_arr_.clear (); + announce_element (Score_element_info + (line_spanner_, + text_req_l_ ? text_req_l_ : span_req_l_drul_[START])); + + } - for (int i=0; i < dynamic_req_l_arr_.size(); i++) + if (line_spanner_ && pending_element_arr_.size ()) { - if (Text_script_req *absd = - dynamic_cast ( dynamic_req_l_arr_[i])) - { - if (abs_text_p_) - { - dynamic_req_l_arr_[i]->warning (_("Got a dynamic already. Continuing dazed and confused.")); - continue; - } - - String loud = absd->text_str_; - - abs_text_p_ = new Text_item; - abs_text_p_->set_elt_property ("text", - ly_str02scm (loud.ch_C())); - abs_text_p_->set_elt_property ("style", gh_str02scm ("dynamic")); - abs_text_p_->set_elt_property ("script-priority", - gh_int2scm (100)); - -#ifdef DYN_LINE - assert (spanner_); - spanner_->add_element (abs_text_p_); -#else - Side_position_interface (abs_text_p_).set_axis (Y_AXIS); - - if (absd->get_direction ()) - { - abs_text_p_->set_elt_property ("direction", gh_int2scm (absd->get_direction ())); - } + for (int i = 0; i < pending_element_arr_.size (); i++) + line_spanner_->add_element (pending_element_arr_[i]); + pending_element_arr_.clear (); + } + /* + TODO: This should be optionised: + * break when group of dynamic requests ends + * break now (only if no cresc. in progress) + * continue through piece */ + if (span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_) + { + last_request_mom_ = now_mom (); + } + else + { + /* + During a (de)crescendo, pending request will not be cleared, + and a line-spanner will always be created, as \< \! are already + two requests. - /* - UGH UGH - */ - SCM prop = get_property ("dynamicDirection"); - if (!isdir_b (prop)) - { - prop = get_property ("verticalDirection"); - } + Maybe always creating a line-spanner for a (de)crescendo (see + below) is not a good idea: - if (isdir_b (prop) && to_dir (prop)) - abs_text_p_->set_elt_property ("direction", prop); + a\< b\p \!c - prop = get_property ("dynamicPadding"); - if (gh_number_p(prop)) - { - abs_text_p_->set_elt_property ("padding", prop); - } -#endif - announce_element (Score_element_info (abs_text_p_, absd)); + the \p will be centred on the line-spanner, and thus clash + with the hairpin. When axis-group code is in place, the \p + should move below the hairpin, which is probably better? - } - else if (Span_req *span_l - = dynamic_cast (dynamic_req_l_arr_[i])) + Urg, but line-spanner must always have at least same duration + as (de)crecsendo, b.o. line-breaking. + */ + if (now_mom () > last_request_mom_ && !span_start_req_l_) { - if (span_l->span_dir_ == STOP) + for (int i = 0; i < pending_element_arr_.size (); i++) { - if (!cresc_p_) + Score_element* e = pending_element_arr_[i]; + side_position (e).set_axis (Y_AXIS); + side_position (e).add_staff_support (); + + /* + UGH UGH + */ + Direction d = directional_element (e).get (); + if (!d) { - span_l->warning (_ ("Can't find (de)crescendo to end")); - } - else - { - assert (!to_end_cresc_p_); - to_end_cresc_p_ =cresc_p_; - - cresc_p_ = 0; + SCM s = get_property ("dynamicDirection"); + if (!isdir_b (s)) + s = get_property ("verticalDirection"); + if (isdir_b (s)) + d = to_dir (s); + directional_element (e).set (d); } + + SCM s = get_property ("dynamicPadding"); + if (gh_number_p (s)) + e->set_elt_property ("padding", s); + s = get_property ("dynamicMinimumSpace"); + if (gh_number_p (s)) + e->set_elt_property ("minimum-space", s); } - else if (span_l->span_dir_ == START) + pending_element_arr_.clear (); + if (line_spanner_) { - cresc_req_l_ = span_l; - assert (!new_cresc_p); - new_cresc_p = new Crescendo; - new_cresc_p->set_elt_property - ("grow-direction", - gh_int2scm ((span_l->span_type_str_ == "crescendo") - ? BIGGER : SMALLER)); - - SCM s = get_property (span_l->span_type_str_ + "Text"); - if (gh_string_p (s)) - { - cr_text_p_ = new Text_item; - cr_text_p_->set_elt_property ("text", s); - // urg - cr_text_p_->set_elt_property ("style", gh_str02scm ("italic")); - // ? - cr_text_p_->set_elt_property ("script-priority", - gh_int2scm (100)); - - /* - This doesn't work. - I'd like to have support like this: - | - x| - cresc. - - - - - or - | - x| - ff cresc. - - - - - */ - if (0) //abs_text_p_) - { - Side_position_interface (cr_text_p_).set_axis (X_AXIS); - Side_position_interface (cr_text_p_).add_support (abs_text_p_); - } - -#ifdef DYN_LINE - assert (spanner_); - spanner_->add_element (cr_text_p_); -#endif - - //Side_position_interface (cr_text_p_).set_axis (Y_AXIS); - announce_element (Score_element_info (cr_text_p_, span_l)); - } - - s = get_property (span_l->span_type_str_ + "Spanner"); - if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin") - { - new_cresc_p->set_elt_property ("spanner", s); - } - -#ifdef DYN_LINE - assert (spanner_); - spanner_->add_element (new_cresc_p); -#else - // what's the diff between side_position and Side_pos_iface? - side_position (new_cresc_p).set_axis (Y_AXIS); -#endif - announce_element (Score_element_info (new_cresc_p, span_l)); + for (int i = 0; i < pending_column_arr_.size (); i++) + line_spanner_->add_column (pending_column_arr_[i]); + pending_column_arr_.clear (); + finished_line_spanner_ = line_spanner_; + line_spanner_ = 0; } } + } + + if (text_req_l_) + { + String loud = text_req_l_->text_str_; + + text_p_ = new Text_item; + text_p_->set_elt_property ("text", + ly_str02scm (loud.ch_C ())); + text_p_->set_elt_property ("style", gh_str02scm ("dynamic")); + text_p_->set_elt_property ("script-priority", + gh_int2scm (100)); + if (Direction d=text_req_l_->get_direction ()) + directional_element (text_p_).set (d); + pending_element_arr_.push (text_p_); + text_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0)); + text_p_->add_offset_callback (Side_position_interface::aligned_on_self, + Y_AXIS); + announce_element (Score_element_info (text_p_, text_req_l_)); } - if (new_cresc_p) + if (span_req_l_drul_[STOP]) { - if (cresc_p_) + if (!cresc_p_) { - ::warning (_ ("Too many crescendi here")); - - typeset_element (cresc_p_); - + span_req_l_drul_[STOP]->warning + (_ ("can't find start of (de)crescendo")); + } + else + { + assert (!finished_cresc_p_); + cresc_p_->set_bound (RIGHT, get_staff_info ().musical_pcol_l ()); + finished_cresc_p_ = cresc_p_; cresc_p_ = 0; + span_start_req_l_ = 0; } - - cresc_p_ = new_cresc_p; - cresc_p_->set_bounds(LEFT,get_staff_info().musical_pcol_l ()); + } - // arrragh, brr, urg: we know how wide text is, no? - if (abs_text_p_) + if (span_req_l_drul_[START]) + { + if (span_start_req_l_) { - index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"), - LEFT, SCM_BOOL_T); - if (to_end_cresc_p_) - index_set_cell (to_end_cresc_p_->get_elt_property ("dynamic-drul"), - RIGHT, SCM_BOOL_T); + span_req_l_drul_[START]->warning + (span_start_req_l_->span_dir_ == 1 + ? + _ ("already have a crescendo") + : _ ("already have a decrescendo")); } - } + else + { + span_start_req_l_ = span_req_l_drul_[START]; + cresc_p_ = new Crescendo; + cresc_p_->set_elt_property + ("grow-direction", + gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo") + ? BIGGER : SMALLER)); + + SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text"); + if (gh_string_p (s)) + { + cresc_p_->set_elt_property ("start-text", s); + daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_ + + "Text", SCM_UNDEFINED); + } + + s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner"); + + + /* + TODO: Use symbols. + */ + if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin") + { + cresc_p_->set_elt_property ("spanner", s); + daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_ + + "Spanner", SCM_UNDEFINED); + } + + cresc_p_->set_bound (LEFT, get_staff_info ().musical_pcol_l ()); + + + /* + We know how wide the text is, if we can be sure that the + text already has relevant pointers into the paperdef, + and it has its font-size property set. + Since font-size may be set by a context higher up, we + can not be sure of the size. + + + We shouldn't try to do this stuff here, the Item should + do it when the score is finished. We could maybe + set a callback to have the Item do the alignment if + it is not a special symbol, like Crescendo. + */ + + + if (text_p_) + { + index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"), + LEFT, SCM_BOOL_T); + if (finished_cresc_p_) + index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"), + RIGHT, SCM_BOOL_T); + } + pending_element_arr_.push (cresc_p_); + cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0)); + cresc_p_->add_offset_callback + (Side_position_interface::aligned_on_self, Y_AXIS); + announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START])); + } + } } void -Dynamic_engraver::do_pre_move_processing() +Dynamic_engraver::do_pre_move_processing () { typeset_all (); } @@ -460,105 +382,53 @@ Dynamic_engraver::do_removal_processing () if (cresc_p_) { typeset_element (cresc_p_ ); - cresc_req_l_->warning (_ ("unended crescendo")); + span_start_req_l_->warning (_ ("unterminated (de)crescendo")); cresc_p_ =0; } -#ifdef DYN_LINE - if (spanner_) + typeset_all (); + if (line_spanner_) { - // URG urg. We did't get a post_processing call !? - spanner_->do_post_processing (); - typeset_element (spanner_); - spanner_ = 0; + side_position (line_spanner_).add_staff_support (); + typeset_element (line_spanner_); + line_spanner_ = 0; } -#endif - typeset_all (); } - void Dynamic_engraver::typeset_all () { - if (to_end_cresc_p_) + if (finished_cresc_p_) { - to_end_cresc_p_->set_bounds(RIGHT,get_staff_info().musical_pcol_l ()); - typeset_element (to_end_cresc_p_); - - to_end_cresc_p_ =0; - + typeset_element (finished_cresc_p_); + finished_cresc_p_ =0; } - if (abs_text_p_) + if (text_p_) { - typeset_element (abs_text_p_); - abs_text_p_ = 0; + typeset_element (text_p_); + text_p_ = 0; } - - if (cr_text_p_) + if (finished_line_spanner_) { - typeset_element (cr_text_p_); - cr_text_p_ = 0; + side_position (finished_line_spanner_).add_staff_support (); + typeset_element (finished_line_spanner_); + finished_line_spanner_ = 0; } -#ifdef DYN_LINE - /* - TODO: This should be optionised: - * break when group of dynamic requests ends - * break now - * continue through piece - */ - if (spanner_ && last_request_mom_ < now_mom ()) - { - typeset_element (spanner_); - spanner_ = 0; - } -#endif } -void -Dynamic_engraver::typeset_element (Score_element * e) -{ -#ifndef DYN_LINE - side_position(e).add_staff_support (); -#endif - Engraver::typeset_element (e); -} - -#ifdef DYN_LINE - void Dynamic_engraver::acknowledge_element (Score_element_info i) { - if (spanner_) + if (Note_column* n = dynamic_cast (i.elem_l_)) { - if (Note_column* n = dynamic_cast (i.elem_l_)) - spanner_->add_column (n); - } -} - -#else - -void -Dynamic_engraver::acknowledge_element (Score_element_info i) -{ - if (dynamic_cast (i.elem_l_) - || dynamic_cast (i.elem_l_) - ) - { - if (abs_text_p_) - Side_position_interface (abs_text_p_).add_support (i.elem_l_); - - if (cr_text_p_) ///&& !abs_text_p_) + if (line_spanner_) { - Side_position_interface (cr_text_p_).set_axis (Y_AXIS); - Side_position_interface (cr_text_p_).add_support (i.elem_l_); + side_position (line_spanner_).add_support (n); + line_spanner_->add_column (n); + } + else + { + pending_column_arr_.push (n); } - - if (to_end_cresc_p_) - Side_position_interface (to_end_cresc_p_).add_support (i.elem_l_); - - if (cresc_p_) - Side_position_interface(cresc_p_).add_support (i.elem_l_); } } - -#endif