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;
101 Grob *tie_break_cautionary = 0;
102 bool tie_changes = false;
103 for (int i=0; i < tie_l_arr_.size (); i++)
104 if (support_l == Tie::head (tie_l_arr_[i], RIGHT))
106 tie_changes = different;
108 // don't do this, yet. the accidentals can't be
110 tie_break_cautionary = tie_l_arr_[i];
115 /* When do we want accidentals:
117 1. when property force-accidental is set, and not
119 2. when different and not tie-changes
120 3. maybe when at end of a tie: we must later see if
121 we're after a line break */
122 if (((to_boolean (note_l->get_mus_property ("force-accidental"))
125 || tie_break_cautionary)
129 key_item_p_ = new Item(get_property ("Accidentals"));
130 Local_key_item::set_interface (key_item_p_);
133 Staff_symbol_referencer::set_interface (key_item_p_);
135 announce_grob (key_item_p_, 0);
140 sign (p) * (p - a) == 1
143 Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
144 to_boolean (note_l->get_mus_property ("cautionary")),
146 tie_break_cautionary);
147 Side_position::add_support (key_item_p_,support_l);
151 We should not record the accidental if it is the first
152 note and it is tied from the previous measure.
154 Checking whether it is tied also works mostly, but will it
155 always do the correct thing?
158 bool forget = to_boolean (get_property ("forgetAccidentals"));
162 Remember an alteration that is different both from
163 that of the tied note and of the key signature.
166 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
174 not really really correct if there are more than one
175 noteheads with the same notename.
177 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
187 daddy_trans_l_->set_property ("localKeySignature", localsig);
190 if (key_item_p_ && grace_align_l_)
192 Side_position::add_support (grace_align_l_,key_item_p_);
199 Hmm. Which one has to be on the left?
201 On which left, code or paper?
203 (Arpeggios are engraved left of accidentals, of course.)
205 for (int i=0; i < arpeggios_.size (); i++)
206 Side_position::add_support (arpeggios_[i], key_item_p_);
213 Local_key_engraver::finalize ()
215 // TODO: if grace ? signal accidentals to Local_key_engraver the
219 Local_key_engraver::stop_translation_timestep()
223 for (int i=0; i < support_l_arr_.size(); i++)
224 Side_position::add_support (key_item_p_,support_l_arr_[i]);
226 typeset_grob (key_item_p_);
234 support_l_arr_.clear();
235 forced_l_arr_.clear();
239 Local_key_engraver::acknowledge_grob (Grob_info info)
241 SCM wg= get_property ("weAreGraceContext");
243 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
244 bool he_gr = to_boolean (info.elem_l_->get_grob_property ("grace"));
246 Item * item = dynamic_cast<Item*> (info.elem_l_);
247 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
249 grace_align_l_ = item;
254 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
256 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
258 mel_l_arr_.push (note_l);
259 support_l_arr_.push (info.elem_l_);
261 else if (Tie::has_interface (info.elem_l_))
263 tie_l_arr_.push (info.elem_l_);
265 else if (Arpeggio::has_interface (info.elem_l_))
267 arpeggios_.push (info.elem_l_);
273 ugh. repeated deep_copy generates lots of garbage.
276 Local_key_engraver::process_music()
278 SCM smp = get_property ("measurePosition");
279 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
281 SCM sig = get_property ("keySignature");
284 Detect key sig changes. If we haven't found any, check if at start
285 of measure, and set localKeySignature anyhow. */
286 if (last_keysig_ != sig)
288 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
293 if (!to_boolean (get_property ("noResetKey")))
294 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
300 ADD_THIS_TRANSLATOR(Local_key_engraver);