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"
19 #include "arpeggio.hh"
24 FIXME: should not compute vertical positioning of accidentals, but
25 get them from the noteheads
30 struct Local_key_engraver : Engraver {
33 VIRTUAL_COPY_CONS(Translator);
34 virtual void do_process_music();
35 virtual void acknowledge_element (Score_element_info);
36 virtual void do_pre_move_processing();
37 virtual void do_creation_processing ();
38 virtual void process_acknowledged ();
39 virtual void do_removal_processing ();
46 Urgh. Since the accidentals depend on lots of variables, we have to
47 store all information before we can really create the accidentals.
49 Link_array<Score_element> arpeggios_;
51 Link_array<Note_req> mel_l_arr_;
52 Link_array<Score_element> support_l_arr_;
53 Link_array<Item> forced_l_arr_;
54 Link_array<Score_element> tied_l_arr_;
57 Item * grace_align_l_;
60 Local_key_engraver::Local_key_engraver()
64 last_keysig_ = SCM_EOL;
68 Local_key_engraver::do_creation_processing ()
70 last_keysig_ = get_property ("keySignature");
71 daddy_trans_l_->set_property ("localKeySignature", last_keysig_);
75 Local_key_engraver::process_acknowledged ()
77 if (!key_item_p_ && mel_l_arr_.size())
79 SCM localsig = get_property ("localKeySignature");
81 for (int i=0; i < mel_l_arr_.size(); i++)
83 Score_element * support_l = support_l_arr_[i];
84 Note_req * note_l = mel_l_arr_[i];
86 int n = note_l->pitch_.notename_i_;
87 int o = note_l->pitch_.octave_i_;
88 int a = note_l->pitch_.accidental_i_;
90 /* see if there's a tie that "changes" the accidental */
91 /* works because if there's a tie, the note to the left
92 is of the same pitch as the actual note */
94 SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig);
95 if (prev == SCM_BOOL_F)
96 prev = scm_assoc (gh_int2scm (n), localsig);
97 int prev_acc = (prev == SCM_BOOL_F) ? 0 : gh_scm2int (gh_cdr (prev));
98 bool different = prev_acc != a;
100 bool tie_changes = tied_l_arr_.find_l (support_l) && different;
101 if ((note_l->forceacc_b_ || different) && !tie_changes)
105 key_item_p_ = new Item(get_property ("Accidentals"));
106 Local_key_item::set_interface (key_item_p_);
109 Staff_symbol_referencer::set_interface (key_item_p_);
111 announce_element (key_item_p_, 0);
116 sign (prev_acc) * (prev_acc - a) == 1
117 && abs(prev_acc) == 2;
119 Local_key_item::add_pitch (key_item_p_, note_l->pitch_,
120 note_l->cautionary_b_,
122 Side_position::add_support (key_item_p_,support_l);
126 We should not record the accidental if it is the first
127 note and it is tied from the previous measure.
129 Checking whether it is tied also works mostly, but will it
130 always do the correct thing?
133 bool forget = to_boolean (get_property ("forgetAccidentals"));
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 Hmm. Which one has to be on the left?
164 for (int i=0; i < arpeggios_.size (); i++)
165 Side_position::add_support (arpeggios_[i], key_item_p_);
172 Local_key_engraver::do_removal_processing ()
174 // TODO: if grace ? signal accidentals to Local_key_engraver the
178 Local_key_engraver::do_pre_move_processing()
182 for (int i=0; i < support_l_arr_.size(); i++)
183 Side_position::add_support (key_item_p_,support_l_arr_[i]);
185 typeset_element (key_item_p_);
193 support_l_arr_.clear();
194 forced_l_arr_.clear();
198 Local_key_engraver::acknowledge_element (Score_element_info info)
200 SCM wg= get_property ("weAreGraceContext");
202 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
203 bool he_gr = to_boolean (info.elem_l_->get_elt_property ("grace"));
205 Item * item = dynamic_cast<Item*> (info.elem_l_);
206 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
208 grace_align_l_ = item;
213 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
215 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
217 mel_l_arr_.push (note_l);
218 support_l_arr_.push (info.elem_l_);
220 else if (Tie::has_interface (info.elem_l_))
222 tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
224 else if (Arpeggio::has_interface (info.elem_l_))
226 arpeggios_.push (info.elem_l_);
232 ugh. repeated deep_copy generates lots of garbage.
235 Local_key_engraver::do_process_music()
237 SCM smp = get_property ("measurePosition");
238 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
240 SCM sig = get_property ("keySignature");
243 Detect key sig changes. If we haven't found any, check if at start
244 of measure, and set localKeySignature anyhow. */
245 if (last_keysig_ != sig)
247 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
252 if (!to_boolean (get_property ("noResetKey")))
253 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
259 ADD_THIS_TRANSLATOR(Local_key_engraver);