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"
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 ();
49 Urgh. Since the accidentals depend on lots of variables, we have to
50 store all information before we can really create the accidentals.
52 Link_array<Score_element> arpeggios_;
54 Link_array<Note_req> mel_l_arr_;
55 Link_array<Score_element> support_l_arr_;
56 Link_array<Item> forced_l_arr_;
57 Link_array<Score_element> tied_l_arr_;
60 Item * grace_align_l_;
63 Local_key_engraver::Local_key_engraver()
67 last_keysig_ = SCM_EOL;
71 Local_key_engraver::do_creation_processing ()
73 last_keysig_ = get_property ("keySignature");
74 daddy_trans_l_->set_property ("localKeySignature", last_keysig_);
78 Local_key_engraver::process_acknowledged ()
80 if (!key_item_p_ && mel_l_arr_.size())
82 SCM localsig = get_property ("localKeySignature");
84 SCM f = get_property ("forgetAccidentals");
85 bool forget = to_boolean (f);
86 for (int i=0; i < mel_l_arr_.size(); i++)
88 Score_element * support_l = support_l_arr_[i];
89 Note_req * note_l = mel_l_arr_[i];
91 int n = note_l->pitch_.notename_i_;
92 int o = note_l->pitch_.octave_i_;
93 int a = note_l->pitch_.accidental_i_;
95 /* see if there's a tie that "changes" the accidental */
96 /* works because if there's a tie, the note to the left
97 is of the same pitch as the actual note */
99 SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig);
100 if (prev == SCM_BOOL_F)
101 prev = scm_assoc (gh_int2scm (n), localsig);
102 int prev_acc = (prev == SCM_BOOL_F) ? 0 : gh_scm2int (gh_cdr (prev));
103 bool different = prev_acc != a;
105 bool tie_changes = tied_l_arr_.find_l (support_l) && different;
107 && (note_l->forceacc_b_ || different)
112 key_item_p_ = new Item(get_property ("Accidentals"));
113 Local_key_item::set_interface (key_item_p_);
116 Staff_symbol_referencer::set_interface (key_item_p_);
118 announce_element (key_item_p_, 0);
123 sign (prev_acc) * (prev_acc - a) == 1
124 && abs(prev_acc) == 2;
126 Local_key_item::add_pitch (key_item_p_, note_l->pitch_,
127 note_l->cautionary_b_,
129 Side_position::add_support (key_item_p_,support_l);
133 We should not record the accidental if it is the first
134 note and it is tied from the previous measure.
136 Checking whether it is tied also works mostly, but will it
137 always do the correct thing?
140 if (!forget && !tie_changes)
143 not really really correct if there are more than one
144 noteheads with the same notename.
146 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
156 daddy_trans_l_->set_property ("localKeySignature", localsig);
159 if (key_item_p_ && grace_align_l_)
161 Side_position::add_support (grace_align_l_,key_item_p_);
168 Hmm. Which one has to be on the left?
170 for (int i=0; i < arpeggios_.size (); i++)
171 Side_position::add_support (arpeggios_[i], key_item_p_);
178 Local_key_engraver::do_removal_processing ()
180 // TODO: if grace ? signal accidentals to Local_key_engraver the
184 Local_key_engraver::do_pre_move_processing()
188 for (int i=0; i < support_l_arr_.size(); i++)
189 Side_position::add_support (key_item_p_,support_l_arr_[i]);
191 typeset_element (key_item_p_);
199 support_l_arr_.clear();
200 forced_l_arr_.clear();
204 Local_key_engraver::acknowledge_element (Score_element_info info)
206 SCM wg= get_property ("weAreGraceContext");
208 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
209 bool he_gr = to_boolean (info.elem_l_->get_elt_property ("grace"));
211 Item * item = dynamic_cast<Item*> (info.elem_l_);
212 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
214 grace_align_l_ = item;
219 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
221 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
223 mel_l_arr_.push (note_l);
224 support_l_arr_.push (info.elem_l_);
226 else if (Tie::has_interface (info.elem_l_))
228 tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
230 else if (Arpeggio::has_interface (info.elem_l_))
232 arpeggios_.push (info.elem_l_);
238 ugh. repeated deep_copy generates lots of garbage.
241 Local_key_engraver::do_process_music()
243 SCM smp = get_property ("measurePosition");
244 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
246 SCM sig = get_property ("keySignature");
249 Detect key sig changes. If we haven't found any, check if at start
250 of measure, and set localKeySignature anyhow. */
251 if (last_keysig_ != sig)
253 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
258 if (!to_boolean (get_property ("noResetKey")))
259 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
265 ADD_THIS_TRANSLATOR(Local_key_engraver);