X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Flocal-key-engraver.cc;h=f8fd3516fffbbbc3c7d84aa74012a2033f274bd5;hb=9b40d66187029df3dca86fc5ecc65f64db315a48;hp=9029ea1eb40a0a04e7dda8ddb136da76c2112588;hpb=f6e3a77381e8eb67aa01195ec3945bd978f86aa8;p=lilypond.git diff --git a/lily/local-key-engraver.cc b/lily/local-key-engraver.cc index 9029ea1eb4..f8fd3516ff 100644 --- a/lily/local-key-engraver.cc +++ b/lily/local-key-engraver.cc @@ -1,118 +1,159 @@ /* local-key-engraver.cc -- implement Local_key_engraver - (c) 1997--1999 Han-Wen Nienhuys + (c) 1997--2000 Han-Wen Nienhuys */ #include "musical-request.hh" #include "command-request.hh" -#include "local-key-engraver.hh" #include "local-key-item.hh" -#include "key-engraver.hh" -#include "debug.hh" -#include "key-item.hh" +#include "item.hh" #include "tie.hh" -#include "note-head.hh" +#include "rhythmic-head.hh" #include "timing-translator.hh" #include "engraver-group-engraver.hh" #include "grace-align-item.hh" #include "staff-symbol-referencer.hh" +#include "side-position-interface.hh" +#include "engraver.hh" + + +/** + Make accidentals. Catches note heads, ties and notices key-change + events. Due to interaction with ties (which don't come together + with note heads), this needs to be in a context higher than Tie_engraver. + (FIXME). + + FIXME: should not compute vertical positioning of accidentals, but + get them from the noteheads + +*/ + + +struct Local_key_engraver : Engraver { + Item *key_item_p_; +protected: + VIRTUAL_COPY_CONS(Translator); + virtual void do_process_music(); + virtual void acknowledge_element (Score_element_info); + virtual void do_pre_move_processing(); + virtual void do_creation_processing (); + virtual void process_acknowledged (); + virtual void do_removal_processing (); +public: + + // todo -> property + SCM last_keysig_; + + Link_array mel_l_arr_; + Link_array support_l_arr_; + Link_array forced_l_arr_; + Link_array tied_l_arr_; + Local_key_engraver(); + + Item * grace_align_l_; +}; Local_key_engraver::Local_key_engraver() { - key_grav_l_ = 0; key_item_p_ =0; grace_align_l_ =0; + last_keysig_ = SCM_EOL; } void Local_key_engraver::do_creation_processing () { - /* - UGHGUHGUH. - - Breaks if Key_engraver is removed from under us. - */ - Translator * result = - daddy_grav_l()->get_simple_translator ("Key_engraver"); - - key_grav_l_ = dynamic_cast (result); - - if (!key_grav_l_) - { - warning (_ ("out of tune:")); - warning (_f ("Can't find: `%s'", "Key_engraver")); - } - else - { - local_key_ = key_grav_l_->key_; - } - - /* - TODO - (if we are grace) get key info from parent Local_key_engraver - */ + last_keysig_ = get_property ("keySignature"); + daddy_trans_l_->set_property ("localKeySignature", last_keysig_); } void Local_key_engraver::process_acknowledged () { - if (!key_item_p_ && mel_l_arr_.size()) + if (!key_item_p_ && mel_l_arr_.size()) { - SCM f = get_property ("forgetAccidentals",0); - bool forget = to_boolean (f); - for (int i=0; i < mel_l_arr_.size(); i++) + SCM localsig = get_property ("localKeySignature"); + + SCM f = get_property ("forgetAccidentals"); + bool forget = to_boolean (f); + for (int i=0; i < mel_l_arr_.size(); i++) + { + Score_element * support_l = support_l_arr_[i]; + Note_req * note_l = mel_l_arr_[i]; + + int n = note_l->pitch_.notename_i_; + int o = note_l->pitch_.octave_i_; + int a = note_l->pitch_.accidental_i_; + + /* see if there's a tie that "changes" the accidental */ + /* works because if there's a tie, the note to the left + is of the same pitch as the actual note */ + + SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig); + if (prev == SCM_BOOL_F) + prev = scm_assoc (gh_int2scm (n), localsig); + int prev_acc = (prev == SCM_BOOL_F) ? 0 : gh_scm2int (gh_cdr (prev)); + bool different = prev_acc != a; + + bool tie_changes = tied_l_arr_.find_l (support_l) && different; + if (!forget + && (note_l->forceacc_b_ || different) + && !tie_changes) { - Item * support_l = support_l_arr_[i]; - Note_req * note_l = mel_l_arr_[i]; - - /* see if there's a tie that "changes" the accidental */ - /* works because if there's a tie, the note to the left - is of the same pitch as the actual note */ - bool tie_changes = tied_l_arr_.find_l (support_l) - && !local_key_.different_acc (note_l->pitch_); - - if (!forget - - && ((note_l->forceacc_b_ - || !local_key_.different_acc (note_l->pitch_) - || local_key_.internal_forceacc (note_l->pitch_))) - - && !tie_changes) - { - if (!key_item_p_) - { - key_item_p_ = new Local_key_item; - Staff_symbol_referencer_interface si(key_item_p_); - si.set_interface (); + if (!key_item_p_) + { + key_item_p_ = new Item(get_property ("Accidentals")); + Local_key_item::set_interface (key_item_p_); + Side_position::set_axis (key_item_p_, X_AXIS); + Side_position::set_direction (key_item_p_, LEFT); + Staff_symbol_referencer::set_interface (key_item_p_); - announce_element (Score_element_info (key_item_p_, 0)); - } - - key_item_p_->add_pitch (note_l->pitch_, - note_l->cautionary_b_, - local_key_.double_to_single_acc(note_l->pitch_)); - key_item_p_->add_support (support_l); - } + announce_element (key_item_p_, 0); + } + + + bool extra_natural = + sign (prev_acc) * (prev_acc - a) == 1 + && abs(prev_acc) == 2; + + Local_key_item::add_pitch (key_item_p_, note_l->pitch_, + note_l->cautionary_b_, + extra_natural); + Side_position::add_support (key_item_p_,support_l); + } - if (!forget) - { - local_key_.set (note_l->pitch_); - if (!tied_l_arr_.find_l (support_l)) - { - local_key_.clear_internal_forceacc (note_l->pitch_); - } - else if (tie_changes) - { - local_key_.set_internal_forceacc (note_l->pitch_); - } - } + /* + We should not record the accidental if it is the first + note and it is tied from the previous measure. + + Checking whether it is tied also works mostly, but will it + always do the correct thing? + + */ + if (!forget && !tie_changes) + { + /* + not really really correct if there are more than one + noteheads with the same notename. + */ + localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o), + gh_int2scm (n)), + gh_int2scm (a)); + + } } + + + + + daddy_trans_l_->set_property ("localKeySignature", localsig); } - if (key_item_p_ && grace_align_l_) + + if (key_item_p_ && grace_align_l_) { - grace_align_l_->add_support (key_item_p_); - grace_align_l_ =0; + Side_position::add_support (grace_align_l_,key_item_p_); + grace_align_l_ =0; } } @@ -120,7 +161,7 @@ Local_key_engraver::process_acknowledged () void Local_key_engraver::do_removal_processing () { - // TODO: signal accidentals to Local_key_engraver the + // TODO: if grace ? signal accidentals to Local_key_engraver the } void @@ -129,7 +170,7 @@ Local_key_engraver::do_pre_move_processing() if (key_item_p_) { for (int i=0; i < support_l_arr_.size(); i++) - key_item_p_->add_support (support_l_arr_[i]); + Side_position::add_support (key_item_p_,support_l_arr_[i]); typeset_element (key_item_p_); key_item_p_ =0; @@ -145,51 +186,55 @@ Local_key_engraver::do_pre_move_processing() void Local_key_engraver::acknowledge_element (Score_element_info info) { - SCM wg= get_property ("weAreGraceContext", 0); + SCM wg= get_property ("weAreGraceContext"); bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg); - bool he_gr = info.elem_l_->get_elt_property ("grace") != SCM_UNDEFINED; + bool he_gr = to_boolean (info.elem_l_->get_elt_property ("grace")); - Grace_align_item * gai = dynamic_cast (info.elem_l_); - if (he_gr && !selfgr && gai) + Item * item = dynamic_cast (info.elem_l_); + if (he_gr && !selfgr && item && Grace_align_item::has_interface (item)) { - grace_align_l_ = gai; + grace_align_l_ = item; } - Note_req * note_l = dynamic_cast (info.req_l_); - Note_head * note_head = dynamic_cast (info.elem_l_); - - - if (he_gr != selfgr) return; - if (note_l && note_head) + Note_req * note_l = dynamic_cast (info.req_l_); + + if (note_l && Rhythmic_head::has_interface (info.elem_l_)) { mel_l_arr_.push (note_l); - support_l_arr_.push (note_head); + support_l_arr_.push (info.elem_l_); } - else if (Tie * tie_l = dynamic_cast (info.elem_l_)) + else if (Tie::has_interface (info.elem_l_)) { - tied_l_arr_.push (tie_l->head (RIGHT)); + tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT)); } } +/* + ugh. repeated deep_copy generates lots of garbage. + */ void -Local_key_engraver::do_process_requests() +Local_key_engraver::do_process_music() { - Translator * tr = daddy_grav_l()->get_simple_translator ("Timing_engraver"); // ugh - Timing_translator * time_C_ = dynamic_cast (tr); - - if (time_C_ && !time_C_->measure_position ()) + SCM smp = get_property ("measurePosition"); + Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0); + + SCM sig = get_property ("keySignature"); + + /* + Detect key sig changes. If we haven't found any, check if at start + of measure, and set localKeySignature anyhow. */ + if (last_keysig_ != sig) { - SCM n = get_property ("noResetKey",0); - bool no_res = to_boolean (n); - if (!no_res && key_grav_l_) - local_key_= key_grav_l_->key_; + daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig)); + last_keysig_ = sig; } - else if (key_grav_l_ && key_grav_l_->key_changed_b ()) + else if (!mp) { - local_key_ = key_grav_l_->key_; + if (!to_boolean (get_property ("noResetKey"))) + daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig)); } }