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 = unsmob_pitch (note_l->get_mus_property ("pitch"))->notename_i_;
87 int o = unsmob_pitch (note_l->get_mus_property ("pitch"))->octave_i () ;
88 int a = unsmob_pitch (note_l->get_mus_property ("pitch"))->alteration_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 ((to_boolean (note_l->get_mus_property ("force-accidental"))
102 || different) && !tie_changes)
106 key_item_p_ = new Item(get_property ("Accidentals"));
107 Local_key_item::set_interface (key_item_p_);
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_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
121 to_boolean (note_l->get_mus_property ("cautionary")),
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 bool forget = to_boolean (get_property ("forgetAccidentals"));
135 if (!forget && !tie_changes)
138 not really really correct if there are more than one
139 noteheads with the same notename.
141 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
151 daddy_trans_l_->set_property ("localKeySignature", localsig);
154 if (key_item_p_ && grace_align_l_)
156 Side_position::add_support (grace_align_l_,key_item_p_);
163 Hmm. Which one has to be on the left?
165 On which left, code or paper?
167 (Arpeggios are engraved left of accidentals, of course.)
169 for (int i=0; i < arpeggios_.size (); i++)
170 Side_position::add_support (arpeggios_[i], key_item_p_);
177 Local_key_engraver::do_removal_processing ()
179 // TODO: if grace ? signal accidentals to Local_key_engraver the
183 Local_key_engraver::do_pre_move_processing()
187 for (int i=0; i < support_l_arr_.size(); i++)
188 Side_position::add_support (key_item_p_,support_l_arr_[i]);
190 typeset_element (key_item_p_);
198 support_l_arr_.clear();
199 forced_l_arr_.clear();
203 Local_key_engraver::acknowledge_element (Score_element_info info)
205 SCM wg= get_property ("weAreGraceContext");
207 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
208 bool he_gr = to_boolean (info.elem_l_->get_elt_property ("grace"));
210 Item * item = dynamic_cast<Item*> (info.elem_l_);
211 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
213 grace_align_l_ = item;
218 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
220 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
222 mel_l_arr_.push (note_l);
223 support_l_arr_.push (info.elem_l_);
225 else if (Tie::has_interface (info.elem_l_))
227 tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
229 else if (Arpeggio::has_interface (info.elem_l_))
231 arpeggios_.push (info.elem_l_);
237 ugh. repeated deep_copy generates lots of garbage.
240 Local_key_engraver::do_process_music()
242 SCM smp = get_property ("measurePosition");
243 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
245 SCM sig = get_property ("keySignature");
248 Detect key sig changes. If we haven't found any, check if at start
249 of measure, and set localKeySignature anyhow. */
250 if (last_keysig_ != sig)
252 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
257 if (!to_boolean (get_property ("noResetKey")))
258 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
264 ADD_THIS_TRANSLATOR(Local_key_engraver);