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> support_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;
159 for (int i=0; i < mel_l_arr_.size (); i++)
161 Grob * support_l = support_l_arr_[i];
162 Note_req * note_l = mel_l_arr_[i];
164 int num = number_accidentals(localsig,note_l,accidentals_l,barnum);
165 int num_caut = number_accidentals(localsig,note_l,cautionaries_l,barnum);
166 bool cautionary = to_boolean (note_l->get_mus_property ("cautionary"));
167 if (abs(num_caut)>abs(num)) {
171 bool different=num<0;
174 /* see if there's a tie that "changes" the accidental */
175 /* works because if there's a tie, the note to the left
176 is of the same pitch as the actual note */
179 Grob *tie_break_reminder = 0;
180 bool tie_changes = false;
181 for (int i=0; i < tie_l_arr_.size (); i++)
182 if (support_l == Tie::head (tie_l_arr_[i], RIGHT))
184 tie_changes = different;
185 /* Enable accidentals for broken tie
187 We only want an accidental on a broken tie,
188 if the tie changes the accidental.
190 Maybe check property noTieBreakForceAccidental? */
192 tie_break_reminder = tie_l_arr_[i];
200 key_item_p_ = new Item (get_property ("Accidentals"));
201 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);
222 We should not record the accidental if it is the first
223 note and it is tied from the previous measure.
225 Checking whether it is tied also works mostly, but will it
226 always do the correct thing?
229 Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch"));
230 int n = pitch->notename_i_;
231 int o = pitch->octave_i_;
232 int a = pitch->alteration_i_;
233 SCM on = gh_cons (gh_int2scm (o), gh_int2scm (n));
237 Remember an alteration that is different both from
238 that of the tied note and of the key signature.
240 localsig = ly_assoc_front_x
241 (localsig, on, gh_cons(SCM_BOOL_T,barnum));
246 not really really correct if there are more than one
247 noteheads with the same notename.
249 localsig = ly_assoc_front_x
250 (localsig, on, gh_cons(gh_int2scm (a),barnum));
254 daddy_trans_l_->set_property ("localKeySignature", localsig);
261 Hmm. Which one has to be on the left?
263 On which left, code or paper?
265 (Arpeggios are engraved left of accidentals, of course.)
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 < support_l_arr_.size (); i++)
286 Side_position_interface::add_support (key_item_p_,support_l_arr_[i]);
288 typeset_grob (key_item_p_);
296 support_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 support_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");