2 accidental-engraver.cc -- implement accidental_engraver
4 (c) 1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5 Modified 2001 by Rune Zedeler <rz@daimi.au.dk>
8 #include "musical-request.hh"
9 #include "command-request.hh"
10 #include "local-key-item.hh"
13 #include "rhythmic-head.hh"
14 #include "timing-translator.hh"
15 #include "engraver-group-engraver.hh"
17 #include "staff-symbol-referencer.hh"
18 #include "side-position-interface.hh"
19 #include "engraver.hh"
20 #include "arpeggio.hh"
26 FIXME: should not compute vertical positioning of accidentals, but
27 get them from the noteheads
29 The algorithm for accidentals should be documented, and made
35 struct Accidental_engraver : Engraver {
38 TRANSLATOR_DECLARATIONS(Accidental_engraver);
39 virtual void process_music ();
40 virtual void acknowledge_grob (Grob_info);
41 virtual void stop_translation_timestep ();
42 virtual void initialize ();
43 virtual void create_grobs ();
44 virtual void finalize ();
51 Urgh. Since the accidentals depend on lots of variables, we have to
52 store all information before we can really create the accidentals.
54 Link_array<Grob> arpeggios_;
56 Link_array<Note_req> mel_l_arr_;
57 Link_array<Grob> head_l_arr_;
58 Link_array<Item> forced_l_arr_;
59 Link_array<Grob> tie_l_arr_;
64 Accidental_engraver::Accidental_engraver ()
67 last_keysig_ = SCM_EOL;
71 Accidental_engraver::initialize ()
73 last_keysig_ = get_property ("keySignature");
74 daddy_trans_l_->set_property ("localKeySignature", last_keysig_);
77 /** calculates the number of accidentals on basis of the current local key sig
78 * (passed as argument).
79 * Returns number of accidentals (0, 1 or 2).
80 * Negative (-1 or -2) if accidental has changed.
83 number_accidentals (SCM sig, Note_req * note_l, SCM curbarnum, SCM lazyness,
86 Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch"));
87 int n = pitch->notename_i_;
88 int o = pitch->octave_i_;
89 int a = pitch->alteration_i_;
90 int curbarnum_i = gh_scm2int(curbarnum);
94 prev = ly_assoc_cdr (gh_int2scm (n), sig);
96 prev = gh_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), sig);
97 /* should really be true unless prev==SCM_BOOL_F */
98 if(gh_pair_p(prev) && gh_pair_p(ly_cdr(prev))) {
99 accbarnum_i = gh_scm2int(ly_cddr(prev));
100 prev = gh_cons(ly_car(prev),ly_cadr(prev));
102 /* If an accidental was not found or the accidental was too old */
103 if (prev == SCM_BOOL_F ||
104 (gh_number_p(lazyness) && curbarnum_i>accbarnum_i+gh_scm2int(lazyness)))
105 prev = gh_assoc (gh_int2scm (n), sig);
106 SCM prev_acc = (prev == SCM_BOOL_F) ? gh_int2scm (0) : ly_cdr (prev);
108 int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0;
111 if (a==p && !to_boolean (note_l->get_mus_property ("force-accidental")) && gh_number_p(prev_acc)) num=0;
112 else if ( (abs(a)<abs(p) || p*a<0) && a!=0 ) num=2;
115 return a==p ? num : -num;
119 number_accidentals (SCM localsig, Note_req * note_l, SCM accidentals_l,
123 while(gh_pair_p(accidentals_l)) {
124 if(gh_pair_p(ly_car(accidentals_l))) {
125 SCM type = gh_caar(accidentals_l);
126 SCM lazyness = gh_cdar(accidentals_l);
127 bool measure_same_octave_b =
128 gh_eq_p(ly_symbol2scm("measure-same-octave"),type);
129 bool measure_any_octave_b =
130 gh_eq_p(ly_symbol2scm("measure-any-octave"),type);
131 if(measure_same_octave_b || measure_any_octave_b) {
132 int n = number_accidentals
133 (localsig,note_l,curbarnum,lazyness,measure_any_octave_b);
135 number = max(number,abs(n));
137 else warning(_f("unknown accidental typesetting: %s",
138 ly_symbol2string(type).ch_C()));
140 else warning(_f("Accidental typesetting must be pair: %s",
141 ly_scm2string(ly_car(accidentals_l)).ch_C()));
142 accidentals_l = ly_cdr(accidentals_l);
144 return diff ? -number : number;
148 Accidental_engraver::create_grobs ()
150 if (!key_item_p_ && mel_l_arr_.size ())
152 SCM localsig = get_property ("localKeySignature");
153 SCM accidentals_l = get_property ("autoAccidentals");
154 SCM cautionaries_l = get_property ("autoCautionaries");
155 SCM barnum = get_property ("currentBarNumber");
157 bool extra_natural_b = get_property ("extraNatural")==SCM_BOOL_T;
158 for (int i=0; i < mel_l_arr_.size (); i++)
160 Grob * support_l = head_l_arr_[i];
161 Note_req * note_l = mel_l_arr_[i];
163 int num = number_accidentals(localsig,note_l,accidentals_l,barnum);
164 int num_caut = number_accidentals(localsig,note_l,cautionaries_l,barnum);
165 bool cautionary = to_boolean (note_l->get_mus_property ("cautionary"));
166 if (abs(num_caut)>abs(num))
172 bool different=num<0;
175 /* see if there's a tie that "changes" the accidental */
176 /* works because if there's a tie, the note to the left
177 is of the same pitch as the actual note */
180 Grob *tie_break_reminder = 0;
181 bool tie_changes = false;
182 for (int i=0; i < tie_l_arr_.size (); i++)
183 if (support_l == Tie::head (tie_l_arr_[i], RIGHT))
185 tie_changes = different;
186 /* Enable accidentals for broken tie
188 We only want an accidental on a broken tie,
189 if the tie changes the accidental.
191 Maybe check property noTieBreakForceAccidental? */
193 tie_break_reminder = tie_l_arr_[i];
201 key_item_p_ = new Item (get_property ("Accidentals"));
202 Local_key_item::set_interface (key_item_p_);
204 Staff_symbol_referencer::set_interface (key_item_p_);
205 SCM c0 = get_property ("centralCPosition");
206 if (gh_number_p (c0))
207 Staff_symbol_referencer::set_position (key_item_p_, gh_scm2int (c0));
209 announce_grob (key_item_p_, 0);
213 Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
215 num==2 && extra_natural_b,
217 Side_position_interface::add_support (key_item_p_,support_l);
219 support_l->set_grob_property ("accidentals", key_item_p_->self_scm ());
224 We should not record the accidental if it is the first
225 note and it is tied from the previous measure.
227 Checking whether it is tied also works mostly, but will it
228 always do the correct thing?
231 Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch"));
232 int n = pitch->notename_i_;
233 int o = pitch->octave_i_;
234 int a = pitch->alteration_i_;
235 SCM on = gh_cons (gh_int2scm (o), gh_int2scm (n));
239 Remember an alteration that is different both from
240 that of the tied note and of the key signature.
242 localsig = ly_assoc_front_x
243 (localsig, on, gh_cons(SCM_BOOL_T,barnum));
248 not really really correct if there are more than one
249 noteheads with the same notename.
251 localsig = ly_assoc_front_x
252 (localsig, on, gh_cons(gh_int2scm (a),barnum));
256 daddy_trans_l_->set_property ("localKeySignature", localsig);
263 We add the accidentals to the support of the arpeggio, so it is put left of the
267 for (int i=0; i < arpeggios_.size (); i++)
268 Side_position_interface::add_support (arpeggios_[i], key_item_p_);
275 Accidental_engraver::finalize ()
281 Accidental_engraver::stop_translation_timestep ()
285 for (int i=0; i < head_l_arr_.size (); i++)
286 Side_position_interface::add_support (key_item_p_,head_l_arr_[i]);
288 typeset_grob (key_item_p_);
296 head_l_arr_.clear ();
297 forced_l_arr_.clear ();
301 Accidental_engraver::acknowledge_grob (Grob_info info)
303 Note_req * note_l = dynamic_cast <Note_req *> (info.music_cause ());
305 if (note_l && Rhythmic_head::has_interface (info.grob_l_))
307 mel_l_arr_.push (note_l);
308 head_l_arr_.push (info.grob_l_);
310 else if (Tie::has_interface (info.grob_l_))
312 tie_l_arr_.push (info.grob_l_);
314 else if (Arpeggio::has_interface (info.grob_l_))
316 arpeggios_.push (info.grob_l_);
322 ugh. repeated deep_copy generates lots of garbage.
325 Accidental_engraver::process_music ()
327 SCM smp = get_property ("measurePosition");
328 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
330 SCM sig = get_property ("keySignature");
332 /* Detect key sig changes. */
333 if (last_keysig_ != sig)
335 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
344 ENTER_DESCRIPTION(Accidental_engraver,
345 /* descr */ "Make accidentals. Catches note heads, ties and notices key-change
346 events. Due to interaction with ties (which don't come together
347 with note heads), this needs to be in a context higher than Tie_engraver. FIXME",
348 /* creats*/ "Accidentals",
349 /* acks */ "rhythmic-head-interface tie-interface arpeggio-interface",
350 /* reads */ "localKeySignature extraNatural autoAccidentals autoCautionaries",
351 /* write */ "localKeySignature");