2 accidental-engraver.cc -- implement accidental_engraver
4 (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5 Modified 2001--2002 by Rune Zedeler <rz@daimi.au.dk>
12 #include "rhythmic-head.hh"
13 #include "engraver-group-engraver.hh"
14 #include "accidental-placement.hh"
15 #include "side-position-interface.hh"
16 #include "engraver.hh"
17 #include "arpeggio.hh"
20 #include "protected-scm.hh"
23 struct Accidental_entry {
33 Accidental_entry::Accidental_entry ()
43 struct Accidental_engraver : Engraver {
45 TRANSLATOR_DECLARATIONS (Accidental_engraver);
46 virtual void process_music ();
47 virtual void acknowledge_grob (Grob_info);
48 virtual void stop_translation_timestep ();
49 virtual void initialize ();
50 virtual void process_acknowledged_grobs ();
51 virtual void finalize ();
54 Protected_scm last_keysig_;
57 Urgh. Since the accidentals depend on lots of variables, we have to
58 store all information before we can really create the accidentals.
60 Link_array<Grob> left_objects_;
61 Link_array<Grob> right_objects_;
63 Grob * accidental_placement_;
65 Array<Accidental_entry> accidentals_;
66 Link_array<Spanner> ties_;
73 set_property_on_children (Context * trans, const char * sym, SCM val)
75 trans->set_property (sym, val);
76 for (SCM p = trans->children_contexts (); ly_c_pair_p (p); p = ly_cdr (p))
78 Context *trg = unsmob_context (ly_car (p));
79 set_property_on_children (trg, sym, ly_deep_copy (val));
83 Accidental_engraver::Accidental_engraver ()
85 accidental_placement_ = 0;
86 last_keysig_ = SCM_EOL;
90 Accidental_engraver::initialize ()
92 last_keysig_ = get_property ("keySignature");
94 Context * trans_ = context ();
97 trans_ -> set_property ("localKeySignature",
98 ly_deep_copy (last_keysig_));
99 trans_ = trans_->get_parent_context ();
101 set_property_on_children (context (),"localKeySignature", last_keysig_);
106 calculates the number of accidentals on basis of the current local key
107 sig (passed as argument)
109 Returns number of accidentals (0, 1 or 2).
113 number_accidentals_from_sig (bool *different,
114 SCM sig, Pitch *pitch, SCM curbarnum, SCM lazyness,
117 int n = pitch->get_notename ();
118 int o = pitch->get_octave ();
119 int a = pitch->get_alteration ();
120 int curbarnum_i = ly_scm2int (curbarnum);
125 prev = ly_assoc_cdr (scm_int2num (n), sig);
127 prev = scm_assoc (scm_cons (scm_int2num (o), scm_int2num (n)), sig);
129 /* should really be true unless prev == SCM_BOOL_F */
130 if (ly_c_pair_p (prev) && ly_c_pair_p (ly_cdr (prev)))
132 accbarnum_i = ly_scm2int (ly_cddr (prev));
133 prev = scm_cons (ly_car (prev), ly_cadr (prev));
136 /* If an accidental was not found or the accidental was too old */
137 if (prev == SCM_BOOL_F ||
138 (ly_c_number_p (lazyness) && curbarnum_i > accbarnum_i + ly_scm2int (lazyness)))
139 prev = scm_assoc (scm_int2num (n), sig);
142 SCM prev_acc = (prev == SCM_BOOL_F) ? scm_int2num (0) : ly_cdr (prev);
144 int p = ly_c_number_p (prev_acc) ? ly_scm2int (prev_acc) : 0;
147 if (a == p && ly_c_number_p (prev_acc))
149 else if ( (abs (a)<abs (p) || p*a<0) && a != 0 )
154 *different = (a != p);
159 number_accidentals (bool *different,
160 Pitch *pitch, Context * origin,
161 SCM accidentals, SCM curbarnum)
166 if (ly_c_pair_p (accidentals) && !ly_c_symbol_p (ly_car (accidentals)))
167 warning (_f ("Accidental typesetting list must begin with context-name: %s",
168 ly_scm2string (ly_car (accidentals)).to_str0 ()));
170 for (; ly_c_pair_p (accidentals) && origin; accidentals = ly_cdr (accidentals))
172 // If pair then it is a new accidentals typesetting rule to be checked
173 SCM rule = ly_car (accidentals);
174 if (ly_c_pair_p (rule))
176 SCM type = ly_car (rule);
177 SCM lazyness = ly_cdr (rule);
178 SCM localsig = origin->get_property ("localKeySignature");
181 ly_c_eq_p (ly_symbol2scm ("same-octave"), type);
183 ly_c_eq_p (ly_symbol2scm ("any-octave"), type);
185 if (same_octave_b || any_octave_b)
188 int n = number_accidentals_from_sig
189 (&d, localsig, pitch, curbarnum, lazyness, any_octave_b);
190 *different = *different || d;
191 number = max (number, n);
194 warning (_f ("ignoring unknown accidental: %s",
195 ly_symbol2string (type).to_str0 ()));
200 if symbol then it is a context name. Scan parent contexts to find it.
202 else if (ly_c_symbol_p (rule))
204 Context * dad = origin;
205 while (dad && !dad->is_alias (rule))
206 dad = dad->get_parent_context ();
211 else warning (_f ("Accidental rule must be pair or context-name; Found %s",
212 ly_scm2string (rule).to_str0 ()));
219 Accidental_engraver::get_bar_num ()
221 SCM barnum = get_property ("currentBarNumber");
222 SCM smp = get_property ("measurePosition");
224 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
225 if (mp.main_part_ < Rational (0)
226 && ly_c_number_p (barnum))
227 barnum = scm_int2num (ly_scm2int (barnum) - 1);
233 Accidental_engraver::process_acknowledged_grobs ()
235 if (accidentals_.size () && !accidentals_.top ().done_)
237 SCM accidentals = get_property ("autoAccidentals");
238 SCM cautionaries = get_property ("autoCautionaries");
239 SCM barnum = get_bar_num ();
241 bool extra_natural_b = get_property ("extraNatural") == SCM_BOOL_T;
242 for (int i = 0; i < accidentals_.size (); i++)
244 if (accidentals_[i].done_ )
246 accidentals_[i].done_ = true;
247 Grob * support = accidentals_[i].head_;
248 Music * note = accidentals_[i].melodic_;
249 Context * origin = accidentals_[i].origin_;
251 Pitch * pitch = unsmob_pitch (note->get_property ("pitch"));
255 bool different = false;
256 bool different_caut = false;
258 int num = number_accidentals (&different,
260 accidentals, barnum);
261 int num_caut = number_accidentals (&different_caut,
263 cautionaries, barnum);
265 bool cautionary = to_boolean (note->get_property ("cautionary"));
270 different = different_caut;
274 if (num == 0 && to_boolean (note->get_property ("force-accidental")))
279 Can not look for ties: it's not guaranteed that they reach
286 We construct the accidentals at the originating Voice
287 level, so that we get the property settings for
288 Accidental from the respective Voice.
290 Grob * a = make_item_from_properties (origin,
291 ly_symbol2scm ("Accidental"));
292 a->set_parent (support, Y_AXIS);
294 if (!accidental_placement_)
296 accidental_placement_ = make_item ("AccidentalPlacement");
297 announce_grob (accidental_placement_, a->self_scm ());
300 Accidental_placement::add_accidental (accidental_placement_, a);
301 announce_grob (a, SCM_EOL);
304 SCM accs = scm_cons (scm_int2num (pitch->get_alteration ()), SCM_EOL);
305 if (num == 2 && extra_natural_b)
306 accs = scm_cons (scm_int2num (0), accs);
310 add cautionary option in accidental.
315 a->set_property ("cautionary", SCM_BOOL_T);
319 support->set_property ("accidental-grob", a->self_scm ());
321 a->set_property ("accidentals", accs);
322 accidentals_[i].accidental_ = a;
325 We add the accidentals to the support of the arpeggio,
326 so it is put left of the accidentals.
328 for (int i = 0; i < left_objects_.size (); i++)
329 Side_position_interface::add_support (left_objects_[i], a);
330 for (int i = 0; i < right_objects_.size (); i++)
331 Side_position_interface::add_support (a, right_objects_[i]);
341 Accidental_engraver::finalize ()
343 last_keysig_ = SCM_EOL;
347 Accidental_engraver::stop_translation_timestep ()
349 for (int j = ties_.size (); j --; )
351 Grob * r = Tie::head (ties_[j], RIGHT);
352 for (int i = accidentals_.size (); i--;)
353 if (accidentals_[i].head_ == r)
355 if (Grob * g = accidentals_[i].accidental_)
357 g->set_property ("tie", ties_[j]->self_scm ());
358 accidentals_[i].tied_ = true;
366 for (int i = accidentals_.size (); i--;)
368 SCM barnum = get_bar_num ();
370 Music * note = accidentals_[i].melodic_;
371 Context * origin = accidentals_[i].origin_;
373 Pitch * pitch = unsmob_pitch (note->get_property ("pitch"));
377 int n = pitch->get_notename ();
378 int o = pitch->get_octave ();
379 int a = pitch->get_alteration ();
380 SCM on_s = scm_cons (scm_int2num (o), scm_int2num (n));
385 huh? we set props all the way to the top?
387 SCM localsig = origin->get_property ("localKeySignature");
389 if (accidentals_[i].tied_)
392 Remember an alteration that is different both from
393 that of the tied note and of the key signature.
395 localsig = ly_assoc_front_x
396 (localsig, on_s, scm_cons (SCM_BOOL_T, barnum));
403 not really really correct if there are more than one
404 noteheads with the same notename.
406 localsig = ly_assoc_front_x
407 (localsig, on_s, scm_cons (scm_int2num (a), barnum));
413 origin->set_property ("localKeySignature", localsig);
414 origin = origin->get_parent_context ();
418 for (int i = 0; i < accidentals_.size (); i++)
420 if (Grob *a = accidentals_[i].accidental_)
424 if (accidental_placement_)
425 typeset_grob (accidental_placement_);
427 accidental_placement_ = 0;
429 accidentals_.clear ();
430 left_objects_.clear ();
431 right_objects_.clear ();
435 Accidental_engraver::acknowledge_grob (Grob_info info)
437 Music * note = info.music_cause ();
440 && note->is_mus_type ("note-event")
441 && Rhythmic_head::has_interface (info.grob_))
443 if (to_boolean ( get_property ("harmonicAccidentals"))
444 || !ly_c_equal_p (info.grob_->get_property ("style"),
445 ly_symbol2scm ("harmonic")))
448 Accidental_entry entry ;
449 entry.head_ = info.grob_;
450 entry.origin_ = info.origin_trans_->context ();
451 entry.melodic_ = note;
453 accidentals_.push (entry);
456 else if (Tie::has_interface (info.grob_))
458 ties_.push (dynamic_cast<Spanner*> (info.grob_));
460 else if (Arpeggio::has_interface (info.grob_))
462 left_objects_.push (info.grob_);
464 else if (info.grob_->internal_has_interface (ly_symbol2scm ("finger-interface")))
466 left_objects_.push (info.grob_);
471 Accidental_engraver::process_music ()
473 SCM sig = get_property ("keySignature");
475 /* Detect key sig changes.
476 Update all parents and children
478 if (last_keysig_ != sig)
480 Context * trans_ = context ();
483 trans_ -> set_property ("localKeySignature", ly_deep_copy (sig));
484 trans_ = trans_->get_parent_context ();
486 set_property_on_children (context (),"localKeySignature", sig);
496 ENTER_DESCRIPTION (Accidental_engraver,
497 "Make accidentals. Catches note heads, ties and notices key-change "
498 "events. This engraver usually lives at Staff level, but "
499 "reads the settings for Accidental at @code{Voice} level, "
500 "so you can @code{\\override} them at @code{Voice}. "
505 "finger-interface rhythmic-head-interface tie-interface arpeggio-interface",
506 "localKeySignature harmonicAccidentals extraNatural autoAccidentals autoCautionaries",
507 "localKeySignature");