2 local-key-engraver.cc -- implement Local_key_engraver
4 (c) 1997--2001 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> tie_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;
103 a. at right end of a tie -> tie_changes := different
104 b. at right end of broken tie -> tie_broken
106 Ugh: we're never case b., even when tie should be broken,
107 are we maybe called *before* line breaking?
109 bool tie_broken = false;
110 bool tie_changes = false;
111 for (int i=0; i < tie_l_arr_.size (); i++)
112 if (support_l == Tie::head (tie_l_arr_[i], RIGHT))
114 tie_changes = different;
115 Spanner *sp = dynamic_cast<Spanner*> (tie_l_arr_[i]);
116 if (!Tie::head (tie_l_arr_[i], LEFT)
117 || (sp && sp->broken_into_l_arr_.size ()
118 && !Tie::head (sp->broken_into_l_arr_[0], LEFT)))
125 When do we want ties:
127 1. when property force-accidental is set, and not tie_changes
128 2. when different and not tie-changes
129 3. always after a line break -> why doesn't this work?
131 if (((to_boolean (note_l->get_mus_property ("force-accidental"))
138 key_item_p_ = new Item(get_property ("Accidentals"));
139 Local_key_item::set_interface (key_item_p_);
142 Staff_symbol_referencer::set_interface (key_item_p_);
144 announce_grob (key_item_p_, 0);
149 sign (p) * (p - a) == 1
152 Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
153 to_boolean (note_l->get_mus_property ("cautionary")),
155 Side_position::add_support (key_item_p_,support_l);
159 We should not record the accidental if it is the first
160 note and it is tied from the previous measure.
162 Checking whether it is tied also works mostly, but will it
163 always do the correct thing?
166 bool forget = to_boolean (get_property ("forgetAccidentals"));
170 Remember an alteration that is different both from
171 that of the tied note and of the key signature.
174 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
182 not really really correct if there are more than one
183 noteheads with the same notename.
185 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
195 daddy_trans_l_->set_property ("localKeySignature", localsig);
198 if (key_item_p_ && grace_align_l_)
200 Side_position::add_support (grace_align_l_,key_item_p_);
207 Hmm. Which one has to be on the left?
209 On which left, code or paper?
211 (Arpeggios are engraved left of accidentals, of course.)
213 for (int i=0; i < arpeggios_.size (); i++)
214 Side_position::add_support (arpeggios_[i], key_item_p_);
221 Local_key_engraver::finalize ()
223 // TODO: if grace ? signal accidentals to Local_key_engraver the
227 Local_key_engraver::stop_translation_timestep()
231 for (int i=0; i < support_l_arr_.size(); i++)
232 Side_position::add_support (key_item_p_,support_l_arr_[i]);
234 typeset_grob (key_item_p_);
242 support_l_arr_.clear();
243 forced_l_arr_.clear();
247 Local_key_engraver::acknowledge_grob (Grob_info info)
249 SCM wg= get_property ("weAreGraceContext");
251 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
252 bool he_gr = to_boolean (info.elem_l_->get_grob_property ("grace"));
254 Item * item = dynamic_cast<Item*> (info.elem_l_);
255 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
257 grace_align_l_ = item;
262 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
264 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
266 mel_l_arr_.push (note_l);
267 support_l_arr_.push (info.elem_l_);
269 else if (Tie::has_interface (info.elem_l_))
271 tie_l_arr_.push (info.elem_l_);
273 else if (Arpeggio::has_interface (info.elem_l_))
275 arpeggios_.push (info.elem_l_);
281 ugh. repeated deep_copy generates lots of garbage.
284 Local_key_engraver::process_music()
286 SCM smp = get_property ("measurePosition");
287 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
289 SCM sig = get_property ("keySignature");
292 Detect key sig changes. If we haven't found any, check if at start
293 of measure, and set localKeySignature anyhow. */
294 if (last_keysig_ != sig)
296 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
301 if (!to_boolean (get_property ("noResetKey")))
302 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
308 ADD_THIS_TRANSLATOR(Local_key_engraver);