2 local-key-engraver.cc -- implement Local_key_engraver
4 (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 #include "musical-request.hh"
8 #include "command-request.hh"
9 #include "local-key-item.hh"
12 #include "rhythmic-head.hh"
13 #include "timing-translator.hh"
14 #include "engraver-group-engraver.hh"
15 #include "grace-align-item.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "side-position-interface.hh"
18 #include "engraver.hh"
22 Make accidentals. Catches note heads, ties and notices key-change
23 events. Due to interaction with ties (which don't come together
24 with note heads), this needs to be in a context higher than Tie_engraver.
27 FIXME: should not compute vertical positioning of accidentals, but
28 get them from the noteheads
33 struct Local_key_engraver : Engraver {
36 VIRTUAL_COPY_CONS(Translator);
37 virtual void do_process_music();
38 virtual void acknowledge_element (Score_element_info);
39 virtual void do_pre_move_processing();
40 virtual void do_creation_processing ();
41 virtual void process_acknowledged ();
42 virtual void do_removal_processing ();
48 Link_array<Note_req> mel_l_arr_;
49 Link_array<Score_element> support_l_arr_;
50 Link_array<Item> forced_l_arr_;
51 Link_array<Score_element> tied_l_arr_;
54 Item * grace_align_l_;
57 Local_key_engraver::Local_key_engraver()
61 last_keysig_ = SCM_EOL;
65 Local_key_engraver::do_creation_processing ()
67 last_keysig_ = get_property ("keySignature");
68 daddy_trans_l_->set_property ("localKeySignature", last_keysig_);
72 Local_key_engraver::process_acknowledged ()
74 if (!key_item_p_ && mel_l_arr_.size())
76 SCM localsig = get_property ("localKeySignature");
78 SCM f = get_property ("forgetAccidentals");
79 bool forget = to_boolean (f);
80 for (int i=0; i < mel_l_arr_.size(); i++)
82 Score_element * support_l = support_l_arr_[i];
83 Note_req * note_l = mel_l_arr_[i];
85 int n = note_l->pitch_.notename_i_;
86 int o = note_l->pitch_.octave_i_;
87 int a = note_l->pitch_.accidental_i_;
89 /* see if there's a tie that "changes" the accidental */
90 /* works because if there's a tie, the note to the left
91 is of the same pitch as the actual note */
93 SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig);
94 if (prev == SCM_BOOL_F)
95 prev = scm_assoc (gh_int2scm (n), localsig);
96 int prev_acc = (prev == SCM_BOOL_F) ? 0 : gh_scm2int (gh_cdr (prev));
97 bool different = prev_acc != a;
99 bool tie_changes = tied_l_arr_.find_l (support_l) && different;
101 && (note_l->forceacc_b_ || different)
106 key_item_p_ = new Item(get_property ("basicLocalKeyProperties"));
107 Local_key_item::set_interface (key_item_p_);
108 Side_position::set_axis (key_item_p_, X_AXIS);
109 Side_position::set_direction (key_item_p_, LEFT);
110 Staff_symbol_referencer::set_interface (key_item_p_);
112 announce_element (key_item_p_, 0);
117 sign (prev_acc) * (prev_acc - a) == 1
118 && abs(prev_acc) == 2;
120 Local_key_item::add_pitch (key_item_p_, note_l->pitch_,
121 note_l->cautionary_b_,
123 Side_position::add_support (key_item_p_,support_l);
127 We should not record the accidental if it is the first
128 note and it is tied from the previous measure.
130 Checking whether it is tied also works mostly, but will it
131 always do the correct thing?
134 if (!forget && !tie_changes)
137 not really really correct if there are more than one
138 noteheads with the same notename.
140 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
150 daddy_trans_l_->set_property ("localKeySignature", localsig);
153 if (key_item_p_ && grace_align_l_)
155 Side_position::add_support (grace_align_l_,key_item_p_);
162 Local_key_engraver::do_removal_processing ()
164 // TODO: if grace ? signal accidentals to Local_key_engraver the
168 Local_key_engraver::do_pre_move_processing()
172 for (int i=0; i < support_l_arr_.size(); i++)
173 Side_position::add_support (key_item_p_,support_l_arr_[i]);
175 typeset_element (key_item_p_);
182 support_l_arr_.clear();
183 forced_l_arr_.clear();
187 Local_key_engraver::acknowledge_element (Score_element_info info)
189 SCM wg= get_property ("weAreGraceContext");
191 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
192 bool he_gr = to_boolean (info.elem_l_->get_elt_property ("grace"));
194 Item * item = dynamic_cast<Item*> (info.elem_l_);
195 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
197 grace_align_l_ = item;
202 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
204 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
206 mel_l_arr_.push (note_l);
207 support_l_arr_.push (info.elem_l_);
209 else if (Tie::has_interface (info.elem_l_))
211 tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
216 ugh. repeated deep_copy generates lots of garbage.
219 Local_key_engraver::do_process_music()
221 SCM smp = get_property ("measurePosition");
222 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
224 SCM sig = get_property ("keySignature");
227 Detect key sig changes. If we haven't found any, check if at start
228 of measure, and set localKeySignature anyhow. */
229 if (last_keysig_ != sig)
231 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
236 if (!to_boolean (get_property ("noResetKey")))
237 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
243 ADD_THIS_TRANSLATOR(Local_key_engraver);