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 On which left, code or paper?
166 (Arpeggios are engraved left of accidentals, of course.)
168 for (int i=0; i < arpeggios_.size (); i++)
169 Side_position::add_support (arpeggios_[i], key_item_p_);
176 Local_key_engraver::do_removal_processing ()
178 // TODO: if grace ? signal accidentals to Local_key_engraver the
182 Local_key_engraver::do_pre_move_processing()
186 for (int i=0; i < support_l_arr_.size(); i++)
187 Side_position::add_support (key_item_p_,support_l_arr_[i]);
189 typeset_element (key_item_p_);
197 support_l_arr_.clear();
198 forced_l_arr_.clear();
202 Local_key_engraver::acknowledge_element (Score_element_info info)
204 SCM wg= get_property ("weAreGraceContext");
206 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
207 bool he_gr = to_boolean (info.elem_l_->get_elt_property ("grace"));
209 Item * item = dynamic_cast<Item*> (info.elem_l_);
210 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
212 grace_align_l_ = item;
217 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
219 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
221 mel_l_arr_.push (note_l);
222 support_l_arr_.push (info.elem_l_);
224 else if (Tie::has_interface (info.elem_l_))
226 tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
228 else if (Arpeggio::has_interface (info.elem_l_))
230 arpeggios_.push (info.elem_l_);
236 ugh. repeated deep_copy generates lots of garbage.
239 Local_key_engraver::do_process_music()
241 SCM smp = get_property ("measurePosition");
242 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
244 SCM sig = get_property ("keySignature");
247 Detect key sig changes. If we haven't found any, check if at start
248 of measure, and set localKeySignature anyhow. */
249 if (last_keysig_ != sig)
251 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
256 if (!to_boolean (get_property ("noResetKey")))
257 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
263 ADD_THIS_TRANSLATOR(Local_key_engraver);