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 void deprecated_process_music();
35 virtual void acknowledge_grob (Grob_info);
36 virtual void stop_translation_timestep();
37 virtual void do_creation_processing ();
38 virtual void create_grobs ();
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<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::do_creation_processing ()
70 last_keysig_ = get_property ("keySignature");
71 daddy_trans_l_->set_property ("localKeySignature", last_keysig_);
75 Local_key_engraver::create_grobs ()
77 deprecated_process_music ();
79 if (!key_item_p_ && mel_l_arr_.size())
81 SCM localsig = get_property ("localKeySignature");
83 for (int i=0; i < mel_l_arr_.size(); i++)
85 Grob * support_l = support_l_arr_[i];
86 Note_req * note_l = mel_l_arr_[i];
88 int n = unsmob_pitch (note_l->get_mus_property ("pitch"))->notename_i_;
89 int o = unsmob_pitch (note_l->get_mus_property ("pitch"))->octave_i () ;
90 int a = unsmob_pitch (note_l->get_mus_property ("pitch"))->alteration_i_;
92 /* see if there's a tie that "changes" the accidental */
93 /* works because if there's a tie, the note to the left
94 is of the same pitch as the actual note */
96 SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig);
97 if (prev == SCM_BOOL_F)
98 prev = scm_assoc (gh_int2scm (n), localsig);
99 int prev_acc = (prev == SCM_BOOL_F) ? 0 : gh_scm2int (gh_cdr (prev));
100 bool different = prev_acc != a;
102 bool tie_changes = tied_l_arr_.find_l (support_l) && different;
103 if ((to_boolean (note_l->get_mus_property ("force-accidental"))
104 || different) && !tie_changes)
108 key_item_p_ = new Item(get_property ("Accidentals"));
109 Local_key_item::set_interface (key_item_p_);
112 Staff_symbol_referencer::set_interface (key_item_p_);
114 announce_grob (key_item_p_, 0);
119 sign (prev_acc) * (prev_acc - a) == 1
120 && abs(prev_acc) == 2;
122 Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
123 to_boolean (note_l->get_mus_property ("cautionary")),
125 Side_position::add_support (key_item_p_,support_l);
129 We should not record the accidental if it is the first
130 note and it is tied from the previous measure.
132 Checking whether it is tied also works mostly, but will it
133 always do the correct thing?
136 bool forget = to_boolean (get_property ("forgetAccidentals"));
137 if (!forget && !tie_changes)
140 not really really correct if there are more than one
141 noteheads with the same notename.
143 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
153 daddy_trans_l_->set_property ("localKeySignature", localsig);
156 if (key_item_p_ && grace_align_l_)
158 Side_position::add_support (grace_align_l_,key_item_p_);
165 Hmm. Which one has to be on the left?
167 On which left, code or paper?
169 (Arpeggios are engraved left of accidentals, of course.)
171 for (int i=0; i < arpeggios_.size (); i++)
172 Side_position::add_support (arpeggios_[i], key_item_p_);
179 Local_key_engraver::do_removal_processing ()
181 // TODO: if grace ? signal accidentals to Local_key_engraver the
185 Local_key_engraver::stop_translation_timestep()
189 for (int i=0; i < support_l_arr_.size(); i++)
190 Side_position::add_support (key_item_p_,support_l_arr_[i]);
192 typeset_grob (key_item_p_);
200 support_l_arr_.clear();
201 forced_l_arr_.clear();
205 Local_key_engraver::acknowledge_grob (Grob_info info)
207 SCM wg= get_property ("weAreGraceContext");
209 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
210 bool he_gr = to_boolean (info.elem_l_->get_grob_property ("grace"));
212 Item * item = dynamic_cast<Item*> (info.elem_l_);
213 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
215 grace_align_l_ = item;
220 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
222 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
224 mel_l_arr_.push (note_l);
225 support_l_arr_.push (info.elem_l_);
227 else if (Tie::has_interface (info.elem_l_))
229 tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
231 else if (Arpeggio::has_interface (info.elem_l_))
233 arpeggios_.push (info.elem_l_);
239 ugh. repeated deep_copy generates lots of garbage.
242 Local_key_engraver::deprecated_process_music()
244 SCM smp = get_property ("measurePosition");
245 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
247 SCM sig = get_property ("keySignature");
250 Detect key sig changes. If we haven't found any, check if at start
251 of measure, and set localKeySignature anyhow. */
252 if (last_keysig_ != sig)
254 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
259 if (!to_boolean (get_property ("noResetKey")))
260 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
266 ADD_THIS_TRANSLATOR(Local_key_engraver);