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_;
68 Array<Accidental_entry> accidentals_;
69 Link_array<Spanner> ties_;
76 set_property_on_children (Context * trans, const char * sym, SCM val)
78 trans->set_property (sym, val);
79 for (SCM p = trans->context_list_; gh_pair_p (p); p = ly_cdr(p))
81 Context *trg = unsmob_context (ly_car (p));
82 set_property_on_children(trg, sym, ly_deep_copy(val));
86 Accidental_engraver::Accidental_engraver ()
88 accidental_placement_ = 0;
89 last_keysig_ = SCM_EOL;
93 Accidental_engraver::initialize ()
95 last_keysig_ = get_property ("keySignature");
97 Context * trans_ = daddy_context_;
100 trans_ -> set_property ("localKeySignature",
101 ly_deep_copy (last_keysig_));
102 trans_ = trans_->daddy_context_;
104 set_property_on_children (daddy_context_,"localKeySignature", last_keysig_);
109 calculates the number of accidentals on basis of the current local key
110 sig (passed as argument)
112 Returns number of accidentals (0, 1 or 2).
113 Negative (-1 or -2) if accidental has changed.
117 number_accidentals_from_sig (bool *different,
118 SCM sig, Pitch *pitch, SCM curbarnum, SCM lazyness,
121 int n = pitch->get_notename ();
122 int o = pitch->get_octave();
123 int a = pitch->get_alteration ();
124 int curbarnum_i = gh_scm2int (curbarnum);
129 prev = ly_assoc_cdr (scm_int2num (n), sig);
131 prev = scm_assoc (gh_cons (scm_int2num (o), scm_int2num (n)), sig);
133 /* should really be true unless prev == SCM_BOOL_F */
134 if (gh_pair_p (prev) && gh_pair_p (ly_cdr (prev)))
136 accbarnum_i = gh_scm2int (ly_cddr (prev));
137 prev = gh_cons (ly_car (prev), ly_cadr (prev));
140 /* If an accidental was not found or the accidental was too old */
141 if (prev == SCM_BOOL_F ||
142 (gh_number_p (lazyness) && curbarnum_i > accbarnum_i + gh_scm2int (lazyness)))
143 prev = scm_assoc (scm_int2num (n), sig);
146 SCM prev_acc = (prev == SCM_BOOL_F) ? scm_int2num (0) : ly_cdr (prev);
148 int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0;
151 if (a == p && gh_number_p (prev_acc))
153 else if ( (abs (a)<abs (p) || p*a<0) && a != 0 )
158 *different = (a != p);
163 number_accidentals (bool *different,
164 Pitch *pitch, Context * origin,
165 SCM accidentals, SCM curbarnum)
170 if (gh_pair_p (accidentals) && !gh_symbol_p (ly_car (accidentals)))
171 warning (_f ("Accidental typesetting list must begin with context-name: %s",
172 ly_scm2string (ly_car (accidentals)).to_str0 ()));
174 for (; gh_pair_p (accidentals) && origin; accidentals = gh_cdr (accidentals))
176 // If pair then it is a new accidentals typesetting rule to be checked
177 SCM rule = gh_car (accidentals);
178 if (gh_pair_p (rule))
180 SCM type = gh_car (rule);
181 SCM lazyness = gh_cdr (rule);
182 SCM localsig = origin->get_property ("localKeySignature");
185 gh_eq_p (ly_symbol2scm ("same-octave"), type);
187 gh_eq_p (ly_symbol2scm ("any-octave"), type);
189 if (same_octave_b || any_octave_b)
192 int n = number_accidentals_from_sig
193 (&d, localsig, pitch, curbarnum, lazyness, any_octave_b);
194 *different = *different || d;
195 number = max (number, n);
198 warning (_f ("unknown accidental typesetting: %s. Ignored",
199 ly_symbol2string (type).to_str0 ()));
204 if symbol then it is a context name. Scan parent contexts to find it.
206 else if (gh_symbol_p (rule))
208 Context * dad = origin;
209 while (dad && !dad->is_alias (rule))
210 dad = dad->daddy_context_;
215 else warning (_f ("Accidental rule must be pair or context-name; Found %s",
216 ly_scm2string (rule).to_str0 ()));
223 Accidental_engraver::get_bar_num ()
225 SCM barnum = get_property ("currentBarNumber");
226 SCM smp = get_property("measurePosition");
228 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
229 if (mp.main_part_ < Rational (0)
230 && gh_number_p (barnum))
231 barnum = scm_int2num (gh_scm2int (barnum) - 1);
239 Accidental_engraver::process_acknowledged_grobs ()
241 if (accidentals_.size () && !accidentals_.top().done_)
243 //SCM localsig = get_property ("localKeySignature");
244 SCM accidentals = get_property ("autoAccidentals");
245 SCM cautionaries = get_property ("autoCautionaries");
246 SCM barnum = get_bar_num ();
248 bool extra_natural_b = get_property ("extraNatural") == SCM_BOOL_T;
249 for (int i = 0; i < accidentals_.size (); i++)
251 if (accidentals_[i].done_ )
253 accidentals_[i].done_ = true;
254 Grob * support = accidentals_[i].head_;
255 Music * note = accidentals_[i].melodic_;
256 Context * origin = accidentals_[i].origin_;
258 Pitch * pitch = unsmob_pitch (note->get_mus_property ("pitch"));
262 bool different = false;
263 bool different_caut = false;
265 int num = number_accidentals (&different,
267 accidentals, barnum);
268 int num_caut = number_accidentals (&different_caut,
270 cautionaries, barnum);
272 bool cautionary = to_boolean (note->get_mus_property ("cautionary"));
277 different = different_caut;
281 if (num == 0 && to_boolean (note->get_mus_property ("force-accidental")))
286 Can not look for ties: it's not guaranteed that they reach
289 /* See if there's a tie that makes the accidental disappear */
290 Grob *tie_break_reminder = 0;
291 bool tie_changes = false;
292 for (int j = 0; j < ties_.size (); j++)
293 if (support == Tie::head (ties_[j], RIGHT))
295 tie_changes = different;
297 tie_break_reminder = ties_[j];
304 We construct the accidentals at the originating Voice
305 level, so that we get the property settings for
306 Accidental from the respective Voice.
308 Grob * a = make_item_from_properties (origin,
309 ly_symbol2scm ("Accidental"));
310 a->set_parent (support, Y_AXIS);
312 if (!accidental_placement_)
314 accidental_placement_ = make_item ("AccidentalPlacement");
315 announce_grob (accidental_placement_, a->self_scm());
318 Accidental_placement::add_accidental (accidental_placement_, a);
319 announce_grob (a, SCM_EOL);
322 SCM accs = gh_cons (scm_int2num (pitch->get_alteration ()), SCM_EOL);
323 if (num == 2 && extra_natural_b)
324 accs = gh_cons (scm_int2num (0), accs);
328 add cautionary option in accidental.
333 a->set_grob_property ("cautionary", SCM_BOOL_T);
336 if (tie_break_reminder)
339 a->set_grob_property ("tie", tie_break_reminder->self_scm());
343 support->set_grob_property ("accidental-grob", a->self_scm ());
345 a->set_grob_property ("accidentals", accs);
346 accidentals_[i].accidental_ = a;
349 We add the accidentals to the support of the arpeggio,
350 so it is put left of the accidentals.
352 for (int i = 0; i < left_objects_.size (); i++)
353 Side_position_interface::add_support (left_objects_[i], a);
354 for (int i = 0; i < right_objects_.size (); i++)
355 Side_position_interface::add_support (a, right_objects_[i]);
365 Accidental_engraver::finalize ()
367 last_keysig_ = SCM_EOL;
371 Accidental_engraver::stop_translation_timestep ()
373 for (int j = ties_.size (); j --; )
375 Grob * r = Tie::head (ties_[j], RIGHT);
376 for (int i = accidentals_.size (); i--;)
377 if (accidentals_[i].head_ == r)
379 if (Grob * g = accidentals_[i].accidental_)
381 g->set_grob_property ("tie", ties_[j]->self_scm ());
382 accidentals_[i].tied_ = true;
390 for (int i = accidentals_.size (); i--;)
392 SCM barnum = get_bar_num ();
394 Music * note = accidentals_[i].melodic_;
395 Context * origin = accidentals_[i].origin_;
397 Pitch * pitch = unsmob_pitch (note->get_mus_property ("pitch"));
401 int n = pitch->get_notename ();
402 int o = pitch->get_octave ();
403 int a = pitch->get_alteration ();
404 SCM on_s = gh_cons (scm_int2num (o), scm_int2num (n));
409 huh? we set props all the way to the top?
411 SCM localsig = origin->get_property ("localKeySignature");
413 if (accidentals_[i].tied_)
416 Remember an alteration that is different both from
417 that of the tied note and of the key signature.
419 localsig = ly_assoc_front_x
420 (localsig, on_s, gh_cons (SCM_BOOL_T, barnum));
427 not really really correct if there are more than one
428 noteheads with the same notename.
430 localsig = ly_assoc_front_x
431 (localsig, on_s, gh_cons (scm_int2num (a), barnum));
437 origin->set_property ("localKeySignature", localsig);
438 origin = origin->daddy_context_;
442 for (int i = 0; i < accidentals_.size(); i++)
444 if (Grob *a = accidentals_[i].accidental_)
448 if (accidental_placement_)
449 typeset_grob(accidental_placement_);
450 accidental_placement_ = 00;
452 accidentals_.clear();
453 left_objects_.clear ();
454 right_objects_.clear ();
458 Accidental_engraver::acknowledge_grob (Grob_info info)
460 Music * note = info.music_cause ();
463 && note->is_mus_type ("note-event")
464 && Rhythmic_head::has_interface (info.grob_)
465 && !gh_equal_p (info.grob_->get_grob_property ("style"), ly_symbol2scm ("harmonic"))
468 Accidental_entry entry ;
469 entry.head_ = info.grob_;
470 entry.origin_ = info.origin_trans_->daddy_context_;
471 entry.melodic_ = note;
473 accidentals_.push (entry);
475 else if (Tie::has_interface (info.grob_))
477 ties_.push (dynamic_cast<Spanner*> (info.grob_));
479 else if (Arpeggio::has_interface (info.grob_))
481 left_objects_.push (info.grob_);
483 else if (info.grob_->internal_has_interface (ly_symbol2scm("finger-interface")))
485 left_objects_.push (info.grob_);
490 Accidental_engraver::process_music ()
492 SCM sig = get_property ("keySignature");
494 /* Detect key sig changes.
495 Update all parents and children
497 if (last_keysig_ != sig)
499 Context * trans_ = daddy_context_;
502 trans_ -> set_property ("localKeySignature", ly_deep_copy (sig));
503 trans_ = trans_->daddy_context_;
505 set_property_on_children(daddy_context_,"localKeySignature", sig);
515 ENTER_DESCRIPTION (Accidental_engraver,
516 "Make accidentals. Catches note heads, ties and notices key-change "
517 "events. This engraver usually lives at Staff level, but "
518 "reads the settings for Accidental at @code{Voice} level, "
519 "so you can @code{\\override} them at @code{Voice}. "
524 "finger-interface rhythmic-head-interface tie-interface arpeggio-interface",
525 "localKeySignature extraNatural autoAccidentals autoCautionaries",
526 "localKeySignature");