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 "engraver-group-engraver.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "side-position-interface.hh"
18 #include "engraver.hh"
19 #include "arpeggio.hh"
25 FIXME: should not compute vertical positioning of accidentals, but
26 get them from the noteheads
28 The algorithm for accidentals should be documented, and made
34 struct Accidental_engraver : Engraver {
37 TRANSLATOR_DECLARATIONS(Accidental_engraver);
38 virtual void process_music ();
39 virtual void acknowledge_grob (Grob_info);
40 virtual void stop_translation_timestep ();
41 virtual void initialize ();
42 virtual void create_grobs ();
43 virtual void finalize ();
50 Urgh. Since the accidentals depend on lots of variables, we have to
51 store all information before we can really create the accidentals.
53 Link_array<Grob> arpeggios_;
55 Link_array<Note_req> mel_l_arr_;
56 Link_array<Grob> head_l_arr_;
57 Link_array<Item> forced_l_arr_;
58 Link_array<Grob> tie_l_arr_;
63 Accidental_engraver::Accidental_engraver ()
66 last_keysig_ = SCM_EOL;
70 Accidental_engraver::initialize ()
72 last_keysig_ = get_property ("keySignature");
73 daddy_trans_l_->set_property ("localKeySignature", last_keysig_);
76 /** calculates the number of accidentals on basis of the current local key sig
77 * (passed as argument).
78 * Returns number of accidentals (0, 1 or 2).
79 * Negative (-1 or -2) if accidental has changed.
82 number_accidentals (SCM sig, Note_req * note_l, SCM curbarnum, SCM lazyness,
85 Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch"));
86 int n = pitch->notename_i_;
87 int o = pitch->octave_i_;
88 int a = pitch->alteration_i_;
89 int curbarnum_i = gh_scm2int(curbarnum);
93 prev = ly_assoc_cdr (gh_int2scm (n), sig);
95 prev = gh_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), sig);
96 /* should really be true unless prev==SCM_BOOL_F */
97 if(gh_pair_p(prev) && gh_pair_p(ly_cdr(prev))) {
98 accbarnum_i = gh_scm2int(ly_cddr(prev));
99 prev = gh_cons(ly_car(prev),ly_cadr(prev));
101 /* If an accidental was not found or the accidental was too old */
102 if (prev == SCM_BOOL_F ||
103 (gh_number_p(lazyness) && curbarnum_i>accbarnum_i+gh_scm2int(lazyness)))
104 prev = gh_assoc (gh_int2scm (n), sig);
105 SCM prev_acc = (prev == SCM_BOOL_F) ? gh_int2scm (0) : ly_cdr (prev);
107 int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0;
110 if (a==p && !to_boolean (note_l->get_mus_property ("force-accidental")) && gh_number_p(prev_acc)) num=0;
111 else if ( (abs(a)<abs(p) || p*a<0) && a!=0 ) num=2;
114 return a==p ? num : -num;
118 number_accidentals (SCM localsig, Note_req * note_l, SCM accidentals_l,
122 while(gh_pair_p(accidentals_l)) {
123 if(gh_pair_p(ly_car(accidentals_l))) {
124 SCM type = gh_caar(accidentals_l);
125 SCM lazyness = gh_cdar(accidentals_l);
126 bool measure_same_octave_b =
127 gh_eq_p(ly_symbol2scm("measure-same-octave"),type);
128 bool measure_any_octave_b =
129 gh_eq_p(ly_symbol2scm("measure-any-octave"),type);
130 if(measure_same_octave_b || measure_any_octave_b) {
131 int n = number_accidentals
132 (localsig,note_l,curbarnum,lazyness,measure_any_octave_b);
134 number = max(number,abs(n));
136 else warning(_f("unknown accidental typesetting: %s",
137 ly_symbol2string(type).ch_C()));
139 else warning(_f("Accidental typesetting must be pair: %s",
140 ly_scm2string(ly_car(accidentals_l)).ch_C()));
141 accidentals_l = ly_cdr(accidentals_l);
143 return diff ? -number : number;
147 Accidental_engraver::create_grobs ()
149 if (!key_item_p_ && mel_l_arr_.size ())
151 SCM localsig = get_property ("localKeySignature");
152 SCM accidentals_l = get_property ("autoAccidentals");
153 SCM cautionaries_l = get_property ("autoCautionaries");
154 SCM barnum = get_property ("currentBarNumber");
156 bool extra_natural_b = get_property ("extraNatural")==SCM_BOOL_T;
157 for (int i=0; i < mel_l_arr_.size (); i++)
159 Grob * support_l = head_l_arr_[i];
160 Note_req * note_l = mel_l_arr_[i];
162 int num = number_accidentals(localsig,note_l,accidentals_l,barnum);
163 int num_caut = number_accidentals(localsig,note_l,cautionaries_l,barnum);
164 bool cautionary = to_boolean (note_l->get_mus_property ("cautionary"));
165 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_);
203 Staff_symbol_referencer::set_interface (key_item_p_);
204 SCM c0 = get_property ("centralCPosition");
205 if (gh_number_p (c0))
206 Staff_symbol_referencer::set_position (key_item_p_, gh_scm2int (c0));
208 announce_grob (key_item_p_, 0);
212 Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
214 num==2 && extra_natural_b,
216 Side_position_interface::add_support (key_item_p_,support_l);
218 support_l->set_grob_property ("accidentals", key_item_p_->self_scm ());
223 We should not record the accidental if it is the first
224 note and it is tied from the previous measure.
226 Checking whether it is tied also works mostly, but will it
227 always do the correct thing?
230 Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch"));
231 int n = pitch->notename_i_;
232 int o = pitch->octave_i_;
233 int a = pitch->alteration_i_;
234 SCM on = gh_cons (gh_int2scm (o), gh_int2scm (n));
238 Remember an alteration that is different both from
239 that of the tied note and of the key signature.
241 localsig = ly_assoc_front_x
242 (localsig, on, gh_cons(SCM_BOOL_T,barnum));
247 not really really correct if there are more than one
248 noteheads with the same notename.
250 localsig = ly_assoc_front_x
251 (localsig, on, gh_cons(gh_int2scm (a),barnum));
255 daddy_trans_l_->set_property ("localKeySignature", localsig);
262 We add the accidentals to the support of the arpeggio, so it is put left of the
266 for (int i=0; i < arpeggios_.size (); i++)
267 Side_position_interface::add_support (arpeggios_[i], key_item_p_);
274 Accidental_engraver::finalize ()
280 Accidental_engraver::stop_translation_timestep ()
284 for (int i=0; i < head_l_arr_.size (); i++)
285 Side_position_interface::add_support (key_item_p_,head_l_arr_[i]);
287 typeset_grob (key_item_p_);
295 head_l_arr_.clear ();
296 forced_l_arr_.clear ();
300 Accidental_engraver::acknowledge_grob (Grob_info info)
302 Note_req * note_l = dynamic_cast <Note_req *> (info.music_cause ());
304 if (note_l && Rhythmic_head::has_interface (info.grob_l_))
306 mel_l_arr_.push (note_l);
307 head_l_arr_.push (info.grob_l_);
309 else if (Tie::has_interface (info.grob_l_))
311 tie_l_arr_.push (info.grob_l_);
313 else if (Arpeggio::has_interface (info.grob_l_))
315 arpeggios_.push (info.grob_l_);
321 ugh. repeated deep_copy generates lots of garbage.
324 Accidental_engraver::process_music ()
326 SCM smp = get_property ("measurePosition");
327 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
329 SCM sig = get_property ("keySignature");
331 /* Detect key sig changes. */
332 if (last_keysig_ != sig)
334 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
343 ENTER_DESCRIPTION(Accidental_engraver,
344 /* descr */ "Make accidentals. Catches note heads, ties and notices key-change
345 events. Due to interaction with ties (which don't come together
346 with note heads), this needs to be in a context higher than Tie_engraver. FIXME",
347 /* creats*/ "Accidentals",
348 /* acks */ "rhythmic-head-interface tie-interface arpeggio-interface",
349 /* reads */ "localKeySignature extraNatural autoAccidentals autoCautionaries",
350 /* write */ "localKeySignature");