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))
150 return (bar_number <= scm_to_int (ly_cdr (alteration_def)) + scm_to_int (laziness));
154 extract_alteration (SCM alteration_def)
156 if (scm_is_number (alteration_def))
157 return scm_to_int (alteration_def);
158 else if (ly_c_pair_p (alteration_def))
159 return scm_to_int (ly_car (alteration_def));
160 else if (alteration_def == SCM_BOOL_F)
168 number_accidentals_from_sig (bool *different, SCM sig, Pitch *pitch,
169 int bar_number, SCM laziness, bool ignore_octave)
171 int n = pitch->get_notename ();
172 int o = pitch->get_octave ();
174 SCM previous_alteration = SCM_BOOL_F;
177 SCM from_same_octave = ly_assoc_get (scm_cons (scm_int2num (o),
178 scm_int2num (n)), sig, SCM_BOOL_F);
179 SCM from_key_signature = ly_assoc_get (scm_int2num (n), sig, SCM_BOOL_F);
180 SCM from_other_octaves = SCM_BOOL_F;
181 for (SCM s = sig ; ly_c_pair_p (s); s = ly_cdr (s))
183 SCM entry = ly_car (s);
184 if (ly_c_pair_p (ly_car (entry))
185 && ly_cdar (entry) == scm_int2num (n))
186 from_other_octaves = ly_cdr (entry);
190 if (from_same_octave != SCM_BOOL_F
191 && recent_enough (bar_number, from_same_octave, laziness))
193 previous_alteration = from_same_octave;
195 else if (ignore_octave
196 && from_other_octaves != SCM_BOOL_F
197 && recent_enough (bar_number, from_other_octaves, laziness))
199 previous_alteration = from_other_octaves;
201 else if (from_key_signature != SCM_BOOL_F)
203 previous_alteration = from_key_signature;
206 /* UGH. prev_acc can be #t in case of ties. What is this for? */
208 int prev = extract_alteration (previous_alteration);
209 int alter = pitch->get_alteration ();
213 else if ((abs (alter) < abs (prev) || prev*alter < 0) && alter != 0)
216 *different = (alter != prev);
221 number_accidentals (bool *different,
222 Pitch *pitch, Context *origin,
223 SCM accidentals, int bar_number)
228 if (ly_c_pair_p (accidentals) && !scm_is_symbol (ly_car (accidentals)))
229 warning (_f ("Accidental typesetting list must begin with context-name: %s",
230 ly_scm2string (ly_car (accidentals)).to_str0 ()));
232 for (; ly_c_pair_p (accidentals) && origin;
233 accidentals = ly_cdr (accidentals))
235 // If pair then it is a new accidentals typesetting rule to be checked
236 SCM rule = ly_car (accidentals);
237 if (ly_c_pair_p (rule))
239 SCM type = ly_car (rule);
240 SCM laziness = ly_cdr (rule);
241 SCM localsig = origin->get_property ("localKeySignature");
244 scm_is_eq (ly_symbol2scm ("same-octave"), type);
246 scm_is_eq (ly_symbol2scm ("any-octave"), type);
248 if (same_octave_b || any_octave_b)
251 int n = number_accidentals_from_sig
252 (&d, localsig, pitch, bar_number, laziness, any_octave_b);
253 *different = *different || d;
254 number = max (number, n);
257 warning (_f ("ignoring unknown accidental: %s",
258 ly_symbol2string (type).to_str0 ()));
263 if symbol then it is a context name. Scan parent contexts to find it.
265 else if (scm_is_symbol (rule))
267 Context *dad = origin;
268 while (dad && !dad->is_alias (rule))
269 dad = dad->get_parent_context ();
274 else warning (_f ("Accidental rule must be pair or context-name; Found %s",
275 ly_scm2string (rule).to_str0 ()));
282 Accidental_engraver::get_bar_number ()
284 SCM barnum = get_property ("currentBarNumber");
285 SCM smp = get_property ("measurePosition");
287 int bn = robust_scm2int (barnum, 0);
289 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
290 if (mp.main_part_ < Rational (0))
297 Accidental_engraver::process_acknowledged_grobs ()
299 if (accidentals_.size () && !accidentals_.top ().done_)
301 SCM accidentals = get_property ("autoAccidentals");
302 SCM cautionaries = get_property ("autoCautionaries");
303 int barnum = get_bar_number ();
305 bool extra_natural_b = get_property ("extraNatural") == SCM_BOOL_T;
306 for (int i = 0; i < accidentals_.size (); i++)
308 if (accidentals_[i].done_ )
310 accidentals_[i].done_ = true;
311 Grob *support = accidentals_[i].head_;
312 Music *note = accidentals_[i].melodic_;
313 Context *origin = accidentals_[i].origin_;
315 Pitch *pitch = unsmob_pitch (note->get_property ("pitch"));
319 bool different = false;
320 bool different_caut = false;
322 int num = number_accidentals (&different,
324 accidentals, barnum);
325 int num_caut = number_accidentals (&different_caut,
327 cautionaries, barnum);
329 bool cautionary = to_boolean (note->get_property ("cautionary"));
334 different = different_caut;
338 if (num == 0 && to_boolean (note->get_property ("force-accidental")))
343 Can not look for ties: it's not guaranteed that they reach
350 We construct the accidentals at the originating Voice
351 level, so that we get the property settings for
352 Accidental from the respective Voice.
355 = make_item_from_properties (accidentals_[i].origin_trans_,
356 ly_symbol2scm ("Accidental"),
358 a->set_parent (support, Y_AXIS);
360 if (!accidental_placement_)
361 accidental_placement_ = make_item ("AccidentalPlacement",
363 Accidental_placement::add_accidental (accidental_placement_, a);
364 SCM accs = scm_cons (scm_int2num (pitch->get_alteration ()),
366 if (num == 2 && extra_natural_b)
367 accs = scm_cons (scm_int2num (0), accs);
369 /* TODO: add cautionary option in accidental. */
372 a->set_property ("cautionary", SCM_BOOL_T);
374 support->set_property ("accidental-grob", a->self_scm ());
376 a->set_property ("accidentals", accs);
377 accidentals_[i].accidental_ = a;
380 We add the accidentals to the support of the arpeggio,
381 so it is put left of the accidentals.
383 for (int i = 0; i < left_objects_.size (); i++)
384 Side_position_interface::add_support (left_objects_[i], a);
385 for (int i = 0; i < right_objects_.size (); i++)
386 Side_position_interface::add_support (a, right_objects_[i]);
393 Accidental_engraver::finalize ()
395 last_keysig_ = SCM_EOL;
399 Accidental_engraver::stop_translation_timestep ()
401 for (int j = ties_.size (); j--;)
403 Grob *r = Tie::head (ties_[j], RIGHT);
404 for (int i = accidentals_.size (); i--;)
405 if (accidentals_[i].head_ == r)
407 if (Grob *g = accidentals_[i].accidental_)
409 g->set_property ("tie", ties_[j]->self_scm ());
410 accidentals_[i].tied_ = true;
417 for (int i = accidentals_.size (); i--;)
419 int barnum = get_bar_number ();
421 Music *note = accidentals_[i].melodic_;
422 Context * origin = accidentals_[i].origin_;
424 Pitch *pitch = unsmob_pitch (note->get_property ("pitch"));
428 int n = pitch->get_notename ();
429 int o = pitch->get_octave ();
430 int a = pitch->get_alteration ();
431 SCM key = scm_cons (scm_int2num (o), scm_int2num (n));
434 && origin->where_defined (ly_symbol2scm ("localKeySignature")))
437 huh? we set props all the way to the top?
439 SCM localsig = origin->get_property ("localKeySignature");
441 if (accidentals_[i].tied_)
444 Remember an alteration that is different both from
445 that of the tied note and of the key signature.
447 localsig = ly_assoc_front_x
448 (localsig, key, scm_cons (SCM_BOOL_T, scm_int2num (barnum)));
455 not really really correct if there are more than one
456 noteheads with the same notename.
458 localsig = ly_assoc_front_x (localsig, key,
459 scm_cons (scm_int2num (a),
460 scm_int2num (barnum)));
465 origin->set_property ("localKeySignature", localsig);
467 origin = origin->get_parent_context ();
471 accidental_placement_ = 0;
472 accidentals_.clear ();
473 left_objects_.clear ();
474 right_objects_.clear ();
478 Accidental_engraver::acknowledge_grob (Grob_info info)
480 Music *note = info.music_cause ();
483 && note->is_mus_type ("note-event")
484 && Rhythmic_head::has_interface (info.grob_))
486 if (to_boolean ( get_property ("harmonicAccidentals"))
487 || !ly_c_equal_p (info.grob_->get_property ("style"),
488 ly_symbol2scm ("harmonic")))
491 Accidental_entry entry ;
492 entry.head_ = info.grob_;
493 entry.origin_trans_ = dynamic_cast<Engraver*> (info.origin_trans_);
494 entry.origin_ = info.origin_trans_->context ();
495 entry.melodic_ = note;
497 accidentals_.push (entry);
500 else if (Tie::has_interface (info.grob_))
501 ties_.push (dynamic_cast<Spanner*> (info.grob_));
502 else if (Arpeggio::has_interface (info.grob_))
503 left_objects_.push (info.grob_);
505 ->internal_has_interface (ly_symbol2scm ("finger-interface")))
506 left_objects_.push (info.grob_);
510 Accidental_engraver::process_music ()
512 SCM sig = get_property ("keySignature");
513 /* Detect key sig changes.
514 Update all parents and children. */
515 if (last_keysig_ != sig)
516 update_local_key_signature ();
519 ENTER_DESCRIPTION (Accidental_engraver,
521 "Catch note heads, ties and notices key-change events. "
522 "This engraver usually lives at Staff level, but "
523 "reads the settings for Accidental at @code{Voice} level, "
524 "so you can @code{\\override} them at @code{Voice}. "
530 "arpeggio-interface "
532 "rhythmic-head-interface "
538 "harmonicAccidentals "