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_reminder = 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;
107 /* Enable accidentals for broken tie
109 We only want an accidental on a broken tie,
110 if the tie changes the accidental.
112 Maybe check property noTieBreakForceAccidental? */
114 tie_break_reminder = tie_l_arr_[i];
118 /* When do we want accidentals:
120 1. when property force-accidental is set, and not
122 2. when different and not tie-changes
123 3. maybe when at end of a tie: we must later see if
124 we're after a line break */
125 if (((to_boolean (note_l->get_mus_property ("force-accidental"))
128 || tie_break_reminder)
132 key_item_p_ = new Item(get_property ("Accidentals"));
133 Local_key_item::set_interface (key_item_p_);
136 Staff_symbol_referencer::set_interface (key_item_p_);
138 announce_grob (key_item_p_, 0);
143 sign (p) * (p - a) == 1
146 Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
147 to_boolean (note_l->get_mus_property ("cautionary")),
150 Side_position::add_support (key_item_p_,support_l);
154 We should not record the accidental if it is the first
155 note and it is tied from the previous measure.
157 Checking whether it is tied also works mostly, but will it
158 always do the correct thing?
161 bool forget = to_boolean (get_property ("forgetAccidentals"));
165 Remember an alteration that is different both from
166 that of the tied note and of the key signature.
169 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
177 not really really correct if there are more than one
178 noteheads with the same notename.
180 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
190 daddy_trans_l_->set_property ("localKeySignature", localsig);
193 if (key_item_p_ && grace_align_l_)
195 Side_position::add_support (grace_align_l_,key_item_p_);
202 Hmm. Which one has to be on the left?
204 On which left, code or paper?
206 (Arpeggios are engraved left of accidentals, of course.)
208 for (int i=0; i < arpeggios_.size (); i++)
209 Side_position::add_support (arpeggios_[i], key_item_p_);
216 Local_key_engraver::finalize ()
218 // TODO: if grace ? signal accidentals to Local_key_engraver the
222 Local_key_engraver::stop_translation_timestep()
226 for (int i=0; i < support_l_arr_.size(); i++)
227 Side_position::add_support (key_item_p_,support_l_arr_[i]);
229 typeset_grob (key_item_p_);
237 support_l_arr_.clear();
238 forced_l_arr_.clear();
242 Local_key_engraver::acknowledge_grob (Grob_info info)
244 SCM wg= get_property ("weAreGraceContext");
246 bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
247 bool he_gr = to_boolean (info.elem_l_->get_grob_property ("grace"));
249 Item * item = dynamic_cast<Item*> (info.elem_l_);
250 if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
252 grace_align_l_ = item;
257 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
259 if (note_l && Rhythmic_head::has_interface (info.elem_l_))
261 mel_l_arr_.push (note_l);
262 support_l_arr_.push (info.elem_l_);
264 else if (Tie::has_interface (info.elem_l_))
266 tie_l_arr_.push (info.elem_l_);
268 else if (Arpeggio::has_interface (info.elem_l_))
270 arpeggios_.push (info.elem_l_);
276 ugh. repeated deep_copy generates lots of garbage.
279 Local_key_engraver::process_music()
281 SCM smp = get_property ("measurePosition");
282 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
284 SCM sig = get_property ("keySignature");
287 Detect key sig changes. If we haven't found any, check if at start
288 of measure, and set localKeySignature anyhow. */
289 if (last_keysig_ != sig)
291 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
296 if (!to_boolean (get_property ("noResetKey")))
297 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
303 ADD_THIS_TRANSLATOR(Local_key_engraver);