2 accidental-engraver.cc -- implement accidental_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Modified 2001--2002 by Rune Zedeler <rz@daimi.au.dk>
10 #include "accidental-placement.hh"
11 #include "arpeggio.hh"
13 #include "engraver.hh"
16 #include "protected-scm.hh"
17 #include "rhythmic-head.hh"
18 #include "side-position-interface.hh"
24 class Accidental_entry
31 Engraver *origin_trans_;
38 Accidental_entry::Accidental_entry ()
48 class Accidental_engraver : public Engraver
51 int get_bar_number ();
52 void update_local_key_signature ();
55 TRANSLATOR_DECLARATIONS (Accidental_engraver);
56 virtual void process_music ();
57 virtual void acknowledge_grob (Grob_info);
58 virtual void stop_translation_timestep ();
59 virtual void initialize ();
60 virtual void process_acknowledged_grobs ();
61 virtual void finalize ();
63 virtual void derived_mark () const;
65 SCM last_keysig_; // ugh.
67 /* Urgh. Since the accidentals depend on lots of variables, we have
68 to store all information before we can really create the
70 Link_array<Grob> left_objects_;
71 Link_array<Grob> right_objects_;
73 Grob *accidental_placement_;
75 Array<Accidental_entry> accidentals_;
76 Link_array<Spanner> ties_;
83 ugh, it is not clear what properties are mutable and which
84 aren't. eg. localKeySignature is changed at runtime, which means
85 that references in grobs should always store ly_deep_copy ()s of
90 set_property_on_children (Context *trans, char const *sym, SCM val)
92 trans->set_property (sym, ly_deep_copy (val));
93 for (SCM p = trans->children_contexts (); ly_c_pair_p (p); p = ly_cdr (p))
95 Context *trg = unsmob_context (ly_car (p));
96 set_property_on_children (trg, sym, ly_deep_copy (val));
100 Accidental_engraver::Accidental_engraver ()
102 accidental_placement_ = 0;
103 last_keysig_ = SCM_EOL;
107 Accidental_engraver::derived_mark () const
109 scm_gc_mark (last_keysig_);
113 Accidental_engraver::update_local_key_signature ()
115 last_keysig_ = get_property ("keySignature");
116 set_property_on_children (context (), "localKeySignature", last_keysig_);
118 Context *trans = context ()->get_parent_context ();
120 /* Huh. Don't understand what this is good for. --hwn. */
121 while (trans && trans->where_defined (ly_symbol2scm ("localKeySignature")))
123 trans->set_property ("localKeySignature", ly_deep_copy (last_keysig_));
124 trans = trans->get_parent_context ();
129 Accidental_engraver::initialize ()
131 update_local_key_signature ();
135 /** Calculate the number of accidentals on basis of the current local key
136 sig (passed as argument)
138 * First check step+octave (taking into account barnumbers if necessary).
140 * Then check the global signature (only step).
142 Return number of accidentals (0, 1 or 2). */
145 recent_enough (int bar_number, SCM alteration_def, SCM laziness)
147 if (scm_is_number (alteration_def)
148 || laziness== SCM_BOOL_T)
151 return (bar_number <= scm_to_int (ly_cdr (alteration_def)) + scm_to_int (laziness));
155 extract_alteration (SCM alteration_def)
157 if (scm_is_number (alteration_def))
158 return scm_to_int (alteration_def);
159 else if (ly_c_pair_p (alteration_def))
160 return scm_to_int (ly_car (alteration_def));
161 else if (alteration_def == SCM_BOOL_F)
169 number_accidentals_from_sig (bool *different, SCM sig, Pitch *pitch,
170 int bar_number, SCM laziness, bool ignore_octave)
172 int n = pitch->get_notename ();
173 int o = pitch->get_octave ();
175 SCM previous_alteration = SCM_BOOL_F;
178 SCM from_same_octave = ly_assoc_get (scm_cons (scm_int2num (o),
179 scm_int2num (n)), sig, SCM_BOOL_F);
180 SCM from_key_signature = ly_assoc_get (scm_int2num (n), sig, SCM_BOOL_F);
181 SCM from_other_octaves = SCM_BOOL_F;
182 for (SCM s = sig ; ly_c_pair_p (s); s = ly_cdr (s))
184 SCM entry = ly_car (s);
185 if (ly_c_pair_p (ly_car (entry))
186 && ly_cdar (entry) == scm_int2num (n))
187 from_other_octaves = ly_cdr (entry);
191 if (from_same_octave != SCM_BOOL_F
192 && recent_enough (bar_number, from_same_octave, laziness))
194 previous_alteration = from_same_octave;
196 else if (ignore_octave
197 && from_other_octaves != SCM_BOOL_F
198 && recent_enough (bar_number, from_other_octaves, laziness))
200 previous_alteration = from_other_octaves;
202 else if (from_key_signature != SCM_BOOL_F)
204 previous_alteration = from_key_signature;
207 /* UGH. prev_acc can be #t in case of ties. What is this for? */
209 int prev = extract_alteration (previous_alteration);
210 int alter = pitch->get_alteration ();
214 else if ((abs (alter) < abs (prev) || prev*alter < 0) && alter != 0)
217 *different = (alter != prev);
222 number_accidentals (bool *different,
223 Pitch *pitch, Context *origin,
224 SCM accidentals, int bar_number)
229 if (ly_c_pair_p (accidentals) && !scm_is_symbol (ly_car (accidentals)))
230 warning (_f ("Accidental typesetting list must begin with context-name: %s",
231 ly_scm2string (ly_car (accidentals)).to_str0 ()));
233 for (; ly_c_pair_p (accidentals) && origin;
234 accidentals = ly_cdr (accidentals))
236 // If pair then it is a new accidentals typesetting rule to be checked
237 SCM rule = ly_car (accidentals);
238 if (ly_c_pair_p (rule))
240 SCM type = ly_car (rule);
241 SCM laziness = ly_cdr (rule);
242 SCM localsig = origin->get_property ("localKeySignature");
245 scm_is_eq (ly_symbol2scm ("same-octave"), type);
247 scm_is_eq (ly_symbol2scm ("any-octave"), type);
249 if (same_octave_b || any_octave_b)
252 int n = number_accidentals_from_sig
253 (&d, localsig, pitch, bar_number, laziness, any_octave_b);
254 *different = *different || d;
255 number = max (number, n);
258 warning (_f ("ignoring unknown accidental: %s",
259 ly_symbol2string (type).to_str0 ()));
264 if symbol then it is a context name. Scan parent contexts to find it.
266 else if (scm_is_symbol (rule))
268 Context *dad = origin;
269 while (dad && !dad->is_alias (rule))
270 dad = dad->get_parent_context ();
275 else warning (_f ("Accidental rule must be pair or context-name; Found %s",
276 ly_scm2string (rule).to_str0 ()));
283 Accidental_engraver::get_bar_number ()
285 SCM barnum = get_property ("currentBarNumber");
286 SCM smp = get_property ("measurePosition");
288 int bn = robust_scm2int (barnum, 0);
290 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
291 if (mp.main_part_ < Rational (0))
298 Accidental_engraver::process_acknowledged_grobs ()
300 if (accidentals_.size () && !accidentals_.top ().done_)
302 SCM accidentals = get_property ("autoAccidentals");
303 SCM cautionaries = get_property ("autoCautionaries");
304 int barnum = get_bar_number ();
306 bool extra_natural_b = get_property ("extraNatural") == SCM_BOOL_T;
307 for (int i = 0; i < accidentals_.size (); i++)
309 if (accidentals_[i].done_ )
311 accidentals_[i].done_ = true;
312 Grob *support = accidentals_[i].head_;
313 Music *note = accidentals_[i].melodic_;
314 Context *origin = accidentals_[i].origin_;
316 Pitch *pitch = unsmob_pitch (note->get_property ("pitch"));
320 bool different = false;
321 bool different_caut = false;
323 int num = number_accidentals (&different,
325 accidentals, barnum);
326 int num_caut = number_accidentals (&different_caut,
328 cautionaries, barnum);
330 bool cautionary = to_boolean (note->get_property ("cautionary"));
335 different = different_caut;
339 if (num == 0 && to_boolean (note->get_property ("force-accidental")))
344 Can not look for ties: it's not guaranteed that they reach
351 We construct the accidentals at the originating Voice
352 level, so that we get the property settings for
353 Accidental from the respective Voice.
356 = make_item_from_properties (accidentals_[i].origin_trans_,
357 ly_symbol2scm ("Accidental"),
359 a->set_parent (support, Y_AXIS);
361 if (!accidental_placement_)
362 accidental_placement_ = make_item ("AccidentalPlacement",
364 Accidental_placement::add_accidental (accidental_placement_, a);
365 SCM accs = scm_cons (scm_int2num (pitch->get_alteration ()),
367 if (num == 2 && extra_natural_b)
368 accs = scm_cons (scm_int2num (0), accs);
370 /* TODO: add cautionary option in accidental. */
373 a->set_property ("cautionary", SCM_BOOL_T);
375 support->set_property ("accidental-grob", a->self_scm ());
377 a->set_property ("accidentals", accs);
378 accidentals_[i].accidental_ = a;
381 We add the accidentals to the support of the arpeggio,
382 so it is put left of the accidentals.
384 for (int i = 0; i < left_objects_.size (); i++)
385 Side_position_interface::add_support (left_objects_[i], a);
386 for (int i = 0; i < right_objects_.size (); i++)
387 Side_position_interface::add_support (a, right_objects_[i]);
394 Accidental_engraver::finalize ()
396 last_keysig_ = SCM_EOL;
400 Accidental_engraver::stop_translation_timestep ()
402 for (int j = ties_.size (); j--;)
404 Grob *r = Tie::head (ties_[j], RIGHT);
405 for (int i = accidentals_.size (); i--;)
406 if (accidentals_[i].head_ == r)
408 if (Grob *g = accidentals_[i].accidental_)
410 g->set_property ("tie", ties_[j]->self_scm ());
411 accidentals_[i].tied_ = true;
418 for (int i = accidentals_.size (); i--;)
420 int barnum = get_bar_number ();
422 Music *note = accidentals_[i].melodic_;
423 Context * origin = accidentals_[i].origin_;
425 Pitch *pitch = unsmob_pitch (note->get_property ("pitch"));
429 int n = pitch->get_notename ();
430 int o = pitch->get_octave ();
431 int a = pitch->get_alteration ();
432 SCM key = scm_cons (scm_int2num (o), scm_int2num (n));
435 && origin->where_defined (ly_symbol2scm ("localKeySignature")))
438 huh? we set props all the way to the top?
440 SCM localsig = origin->get_property ("localKeySignature");
442 if (accidentals_[i].tied_)
445 Remember an alteration that is different both from
446 that of the tied note and of the key signature.
448 localsig = ly_assoc_front_x
449 (localsig, key, scm_cons (SCM_BOOL_T, scm_int2num (barnum)));
456 not really really correct if there are more than one
457 noteheads with the same notename.
459 localsig = ly_assoc_front_x (localsig, key,
460 scm_cons (scm_int2num (a),
461 scm_int2num (barnum)));
466 origin->set_property ("localKeySignature", localsig);
468 origin = origin->get_parent_context ();
472 accidental_placement_ = 0;
473 accidentals_.clear ();
474 left_objects_.clear ();
475 right_objects_.clear ();
479 Accidental_engraver::acknowledge_grob (Grob_info info)
481 Music *note = info.music_cause ();
484 && note->is_mus_type ("note-event")
485 && Rhythmic_head::has_interface (info.grob_))
487 if (to_boolean ( get_property ("harmonicAccidentals"))
488 || !ly_c_equal_p (info.grob_->get_property ("style"),
489 ly_symbol2scm ("harmonic")))
492 Accidental_entry entry ;
493 entry.head_ = info.grob_;
494 entry.origin_trans_ = dynamic_cast<Engraver*> (info.origin_trans_);
495 entry.origin_ = info.origin_trans_->context ();
496 entry.melodic_ = note;
498 accidentals_.push (entry);
501 else if (Tie::has_interface (info.grob_))
502 ties_.push (dynamic_cast<Spanner*> (info.grob_));
503 else if (Arpeggio::has_interface (info.grob_))
504 left_objects_.push (info.grob_);
506 ->internal_has_interface (ly_symbol2scm ("finger-interface")))
507 left_objects_.push (info.grob_);
511 Accidental_engraver::process_music ()
513 SCM sig = get_property ("keySignature");
514 /* Detect key sig changes.
515 Update all parents and children. */
516 if (last_keysig_ != sig)
517 update_local_key_signature ();
520 ENTER_DESCRIPTION (Accidental_engraver,
522 "Catch note heads, ties and notices key-change events. "
523 "This engraver usually lives at Staff level, but "
524 "reads the settings for Accidental at @code{Voice} level, "
525 "so you can @code{\\override} them at @code{Voice}. "
531 "arpeggio-interface "
533 "rhythmic-head-interface "
539 "harmonicAccidentals "