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 process_music();
35 virtual void acknowledge_grob (Grob_info);
36 virtual void stop_translation_timestep();
37 virtual void initialize ();
38 virtual void create_grobs ();
39 virtual void finalize ();
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<Grob> arpeggios_;
51 Link_array<Note_req> mel_l_arr_;
52 Link_array<Grob> support_l_arr_;
53 Link_array<Item> forced_l_arr_;
54 Link_array<Grob> tied_l_arr_;
57 Item * grace_align_l_;
60 Local_key_engraver::Local_key_engraver()
64 last_keysig_ = SCM_EOL;
68 Local_key_engraver::initialize ()
70 last_keysig_ = get_property ("keySignature");
71 daddy_trans_l_->set_property ("localKeySignature", last_keysig_);
75 Local_key_engraver::create_grobs ()
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 Grob * 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 SCM prev_acc = (prev == SCM_BOOL_F) ? gh_int2scm(0) : gh_cdr (prev);
98 bool different = !gh_equal_p(prev_acc , gh_int2scm(a));
99 int p = gh_number_p(prev_acc) ? gh_scm2int(prev_acc) : 0;
101 bool tie_changes = tied_l_arr_.find_l (support_l) && different;
102 if ((to_boolean (note_l->get_mus_property ("force-accidental"))
103 || different) && !tie_changes)
107 key_item_p_ = new Item(get_property ("Accidentals"));
108 Local_key_item::set_interface (key_item_p_);
111 Staff_symbol_referencer::set_interface (key_item_p_);
113 announce_grob (key_item_p_, 0);
118 sign (p) * (p - a) == 1
121 Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
122 to_boolean (note_l->get_mus_property ("cautionary")),
124 Side_position::add_support (key_item_p_,support_l);
128 We should not record the accidental if it is the first
129 note and it is tied from the previous measure.
131 Checking whether it is tied also works mostly, but will it
132 always do the correct thing?
135 bool forget = to_boolean (get_property ("forgetAccidentals"));
139 Remember an alteration that is different both from
140 that of the tied note and of the key signature.
142 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
150 not really really correct if there are more than one
151 noteheads with the same notename.
153 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
163 daddy_trans_l_->set_property ("localKeySignature", localsig);
166 if (key_item_p_ && grace_align_l_)
168 Side_position::add_support (grace_align_l_,key_item_p_);
175 Hmm. Which one has to be on the left?
177 On which left, code or paper?
179 (Arpeggios are engraved left of accidentals, of course.)
181 for (int i=0; i < arpeggios_.size (); i++)
182 Side_position::add_support (arpeggios_[i], key_item_p_);
189 Local_key_engraver::finalize ()
191 // TODO: if grace ? signal accidentals to Local_key_engraver the
195 Local_key_engraver::stop_translation_timestep()
199 for (int i=0; i < support_l_arr_.size(); i++)
200 Side_position::add_support (key_item_p_,support_l_arr_[i]);
202 typeset_grob (key_item_p_);
210 support_l_arr_.clear();
211 forced_l_arr_.clear();
215 Local_key_engraver::acknowledge_grob (Grob_info info)
217 SCM wg= get_property ("weAreGraceContext");
219 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
220 bool he_gr = to_boolean (info.elem_l_->get_grob_property ("grace"));
222 Item * item = dynamic_cast<Item*> (info.elem_l_);
223 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
225 grace_align_l_ = item;
230 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
232 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
234 mel_l_arr_.push (note_l);
235 support_l_arr_.push (info.elem_l_);
237 else if (Tie::has_interface (info.elem_l_))
239 tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
241 else if (Arpeggio::has_interface (info.elem_l_))
243 arpeggios_.push (info.elem_l_);
249 ugh. repeated deep_copy generates lots of garbage.
252 Local_key_engraver::process_music()
254 SCM smp = get_property ("measurePosition");
255 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
257 SCM sig = get_property ("keySignature");
260 Detect key sig changes. If we haven't found any, check if at start
261 of measure, and set localKeySignature anyhow. */
262 if (last_keysig_ != sig)
264 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
269 if (!to_boolean (get_property ("noResetKey")))
270 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
276 ADD_THIS_TRANSLATOR(Local_key_engraver);