]> git.donarmstrong.com Git - lilypond.git/blob - lily/accidental-engraver.cc
* lily/include/translator.icc: new file.
[lilypond.git] / lily / accidental-engraver.cc
1 /*
2   accidental-engraver.cc -- implement accidental_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   Modified 2001--2002 by Rune Zedeler <rz@daimi.au.dk>
8 */
9
10 #include "accidental-placement.hh"
11 #include "arpeggio.hh"
12 #include "context.hh"
13 #include "engraver.hh"
14 #include "protected-scm.hh"
15 #include "rhythmic-head.hh"
16 #include "side-position-interface.hh"
17 #include "tie.hh"
18 #include "warn.hh"
19 #include "music.hh"
20 #include "pitch.hh"
21
22 #include "translator.icc"
23
24 class Accidental_entry
25 {
26 public:
27   bool done_;
28   Music *melodic_;
29   Grob *accidental_;
30   Context *origin_;
31   Engraver *origin_trans_;
32   Grob *head_;
33   bool tied_;
34
35   Accidental_entry ();
36 };
37
38 Accidental_entry::Accidental_entry ()
39 {
40   tied_ = false;
41   done_ = false;
42   melodic_ = 0;
43   accidental_ = 0;
44   origin_ = 0;
45   head_ = 0;
46 }
47
48 class Accidental_engraver : public Engraver
49 {
50 public:
51   int get_bar_number ();
52   void update_local_key_signature ();
53
54 protected:
55   TRANSLATOR_DECLARATIONS (Accidental_engraver);
56   PRECOMPUTED_VIRTUAL void process_music ();
57   virtual void acknowledge_grob (Grob_info);
58   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
59   virtual void initialize ();
60   PRECOMPUTED_VIRTUAL void process_acknowledged ();
61   virtual void finalize ();
62
63   virtual void derived_mark () const;
64 public:
65   SCM last_keysig_;     // ugh.
66
67   /* Urgh. Since the accidentals depend on lots of variables, we have
68      to store all information before we can really create the
69      accidentals.  */
70   Link_array<Grob> left_objects_;
71   Link_array<Grob> right_objects_;
72
73   Grob *accidental_placement_;
74
75   Array<Accidental_entry> accidentals_;
76   Link_array<Spanner> ties_;
77 };
78
79 /*
80   TODO:
81
82   ugh, it is not clear what properties are mutable and which
83   aren't. eg. localKeySignature is changed at runtime, which means
84   that references in grobs should always store ly_deep_copy ()s of
85   those.
86 */
87
88 static void
89 set_property_on_children (Context *trans, char const *sym, SCM val)
90 {
91   trans->set_property (sym, ly_deep_copy (val));
92   for (SCM p = trans->children_contexts (); scm_is_pair (p); p = scm_cdr (p))
93     {
94       Context *trg = unsmob_context (scm_car (p));
95       set_property_on_children (trg, sym, ly_deep_copy (val));
96     }
97 }
98
99 Accidental_engraver::Accidental_engraver ()
100 {
101   accidental_placement_ = 0;
102   last_keysig_ = SCM_EOL;
103 }
104
105 void
106 Accidental_engraver::derived_mark () const
107 {
108   scm_gc_mark (last_keysig_);
109 }
110
111 void
112 Accidental_engraver::update_local_key_signature ()
113 {
114   last_keysig_ = get_property ("keySignature");
115   set_property_on_children (context (), "localKeySignature", last_keysig_);
116
117   Context *trans = context ()->get_parent_context ();
118
119   /* Huh. Don't understand what this is good for. --hwn.  */
120   while (trans && trans->where_defined (ly_symbol2scm ("localKeySignature")))
121     {
122       trans->set_property ("localKeySignature", ly_deep_copy (last_keysig_));
123       trans = trans->get_parent_context ();
124     }
125 }
126
127 void
128 Accidental_engraver::initialize ()
129 {
130   update_local_key_signature ();
131 }
132
133 /** Calculate the number of accidentals on basis of the current local key
134     sig (passed as argument)
135
136     * First check step+octave (taking into account barnumbers if necessary).
137
138     * Then check the global signature (only step).
139
140     Return number of accidentals (0, 1 or 2).  */
141
142 static bool
143 recent_enough (int bar_number, SCM alteration_def, SCM laziness)
144 {
145   if (scm_is_number (alteration_def)
146       || laziness == SCM_BOOL_T)
147     return true;
148
149   return (bar_number <= scm_to_int (scm_cdr (alteration_def)) + scm_to_int (laziness));
150 }
151
152 static int
153 extract_alteration (SCM alteration_def)
154 {
155   if (scm_is_number (alteration_def))
156     return scm_to_int (alteration_def);
157   else if (scm_is_pair (alteration_def))
158     return scm_to_int (scm_car (alteration_def));
159   else if (alteration_def == SCM_BOOL_F)
160     return 0;
161   else
162     assert (0);
163   return 0;
164 }
165
166 bool
167 is_tied (SCM alteration_def)
168 {
169   return (alteration_def == SCM_BOOL_T)
170     || (scm_is_pair (alteration_def) && scm_car (alteration_def) == SCM_BOOL_T);
171 }
172
173 static int
174 number_accidentals_from_sig (bool *different, SCM sig, Pitch *pitch,
175                              int bar_number, SCM laziness, bool ignore_octave)
176 {
177   int n = pitch->get_notename ();
178   int o = pitch->get_octave ();
179
180   SCM previous_alteration = SCM_BOOL_F;
181
182   SCM from_same_octave = ly_assoc_get (scm_cons (scm_int2num (o),
183                                                  scm_int2num (n)), sig, SCM_BOOL_F);
184   SCM from_key_signature = ly_assoc_get (scm_int2num (n), sig, SCM_BOOL_F);
185   SCM from_other_octaves = SCM_BOOL_F;
186   for (SCM s = sig; scm_is_pair (s); s = scm_cdr (s))
187     {
188       SCM entry = scm_car (s);
189       if (scm_is_pair (scm_car (entry))
190           && scm_cdar (entry) == scm_int2num (n))
191         from_other_octaves = scm_cdr (entry);
192     }
193
194   if (from_same_octave != SCM_BOOL_F
195       && recent_enough (bar_number, from_same_octave, laziness))
196     {
197       previous_alteration = from_same_octave;
198     }
199   else if (ignore_octave
200            && from_other_octaves != SCM_BOOL_F
201            && recent_enough (bar_number, from_other_octaves, laziness))
202     {
203       previous_alteration = from_other_octaves;
204     }
205   else if (from_key_signature != SCM_BOOL_F)
206     {
207       previous_alteration = from_key_signature;
208     }
209
210   int num = 1;
211   if (is_tied (previous_alteration))
212     {
213       num = 1;
214       *different = true;
215     }
216   else
217     {
218       int prev = extract_alteration (previous_alteration);
219       int alter = pitch->get_alteration ();
220
221       if (alter == prev)
222         num = 0;
223       else if ((abs (alter) < abs (prev) || prev * alter < 0) && alter != 0)
224         num = 2;
225       *different = (alter != prev);
226     }
227   return num;
228 }
229
230 static int
231 number_accidentals (bool *different,
232                     Pitch *pitch, Context *origin,
233                     SCM accidentals, int bar_number)
234 {
235   int number = 0;
236
237   *different = false;
238   if (scm_is_pair (accidentals) && !scm_is_symbol (scm_car (accidentals)))
239     warning (_f ("accidental typesetting list must begin with context-name: %s",
240                  ly_scm2string (scm_car (accidentals)).to_str0 ()));
241
242   for (; scm_is_pair (accidentals) && origin;
243        accidentals = scm_cdr (accidentals))
244     {
245       // If pair then it is a new accidentals typesetting rule to be checked
246       SCM rule = scm_car (accidentals);
247       if (scm_is_pair (rule))
248         {
249           SCM type = scm_car (rule);
250           SCM laziness = scm_cdr (rule);
251           SCM localsig = origin->get_property ("localKeySignature");
252
253           bool same_octave_b
254             = scm_is_eq (ly_symbol2scm ("same-octave"), type);
255           bool any_octave_b
256             = scm_is_eq (ly_symbol2scm ("any-octave"), type);
257
258           if (same_octave_b || any_octave_b)
259             {
260               bool d = false;
261               int n = number_accidentals_from_sig
262                 (&d, localsig, pitch, bar_number, laziness, any_octave_b);
263               *different = *different || d;
264               number = max (number, n);
265             }
266           else
267             warning (_f ("ignoring unknown accidental: %s",
268                          ly_symbol2string (type).to_str0 ()));
269         }
270
271       /* if symbol then it is a context name.  Scan parent contexts to
272          find it. */
273       else if (scm_is_symbol (rule))
274         {
275           Context *dad = origin;
276           while (dad && !dad->is_alias (rule))
277             dad = dad->get_parent_context ();
278
279           if (dad)
280             origin = dad;
281         }
282       else
283         warning (_f ("pair or context-name expected for accidental rule, found %s",
284                      ly_scm2string (rule).to_str0 ()));
285     }
286
287   return number;
288 }
289
290 int
291 Accidental_engraver::get_bar_number ()
292 {
293   SCM barnum = get_property ("currentBarNumber");
294   SCM smp = get_property ("measurePosition");
295
296   int bn = robust_scm2int (barnum, 0);
297
298   Moment mp = robust_scm2moment (smp, Moment (0));
299   if (mp.main_part_ < Rational (0))
300     bn--;
301
302   return bn;
303 }
304
305 void
306 Accidental_engraver::process_acknowledged ()
307 {
308   if (accidentals_.size () && !accidentals_.top ().done_)
309     {
310       SCM accidentals = get_property ("autoAccidentals");
311       SCM cautionaries = get_property ("autoCautionaries");
312       int barnum = get_bar_number ();
313
314       bool extra_natural_b = get_property ("extraNatural") == SCM_BOOL_T;
315       for (int i = 0; i < accidentals_.size (); i++)
316         {
317           if (accidentals_[i].done_)
318             continue;
319           accidentals_[i].done_ = true;
320           Grob *support = accidentals_[i].head_;
321           Music *note = accidentals_[i].melodic_;
322           Context *origin = accidentals_[i].origin_;
323
324           Pitch *pitch = unsmob_pitch (note->get_property ("pitch"));
325           if (!pitch)
326             continue;
327
328           bool different = false;
329           bool different_caut = false;
330
331           int num = number_accidentals (&different,
332                                         pitch, origin,
333                                         accidentals, barnum);
334           int num_caut = number_accidentals (&different_caut,
335                                              pitch, origin,
336                                              cautionaries, barnum);
337
338           bool cautionary = to_boolean (note->get_property ("cautionary"));
339
340           if (num_caut > num)
341             {
342               num = num_caut;
343               different = different_caut;
344               cautionary = true;
345             }
346
347           if (num == 0 && to_boolean (note->get_property ("force-accidental")))
348             num = 1;
349
350           /* Cannot look for ties: it's not guaranteed that they reach
351              us before the notes. */
352           if (num)
353             {
354               /*
355                 We construct the accidentals at the originating Voice
356                 level, so that we get the property settings for
357                 Accidental from the respective Voice.
358               */
359               Grob *a
360                 = make_item_from_properties (accidentals_[i].origin_trans_,
361                                              ly_symbol2scm ("Accidental"),
362                                              note->self_scm (),
363                                              "Accidental");
364               a->set_parent (support, Y_AXIS);
365
366               if (!accidental_placement_)
367                 accidental_placement_ = make_item ("AccidentalPlacement",
368                                                    a->self_scm ());
369               Accidental_placement::add_accidental (accidental_placement_, a);
370               SCM accs = scm_cons (scm_int2num (pitch->get_alteration ()),
371                                    SCM_EOL);
372               if (num == 2 && extra_natural_b)
373                 accs = scm_cons (scm_int2num (0), accs);
374
375               /* TODO: add cautionary option in accidental. */
376
377               if (cautionary)
378                 a->set_property ("cautionary", SCM_BOOL_T);
379
380               support->set_object ("accidental-grob", a->self_scm ());
381
382               a->set_property ("accidentals", accs);
383               accidentals_[i].accidental_ = a;
384
385               /*
386                 We add the accidentals to the support of the arpeggio,
387                 so it is put left of the accidentals.
388               */
389               for (int i = 0; i < left_objects_.size (); i++)
390                 Side_position_interface::add_support (left_objects_[i], a);
391               for (int i = 0; i < right_objects_.size (); i++)
392                 Side_position_interface::add_support (a, right_objects_[i]);
393             }
394         }
395     }
396 }
397
398 void
399 Accidental_engraver::finalize ()
400 {
401   last_keysig_ = SCM_EOL;
402 }
403
404 void
405 Accidental_engraver::stop_translation_timestep ()
406 {
407   for (int j = ties_.size (); j--;)
408     {
409       Grob *r = Tie::head (ties_[j], RIGHT);
410       for (int i = accidentals_.size (); i--;)
411         if (accidentals_[i].head_ == r)
412           {
413             if (Grob *g = accidentals_[i].accidental_)
414               {
415                 g->set_object ("tie", ties_[j]->self_scm ());
416                 accidentals_[i].tied_ = true;
417               }
418             ties_.del (j);
419             break;
420           }
421     }
422
423   for (int i = accidentals_.size (); i--;)
424     {
425       int barnum = get_bar_number ();
426
427       Music *note = accidentals_[i].melodic_;
428       Context *origin = accidentals_[i].origin_;
429
430       Pitch *pitch = unsmob_pitch (note->get_property ("pitch"));
431       if (!pitch)
432         continue;
433
434       int n = pitch->get_notename ();
435       int o = pitch->get_octave ();
436       int a = pitch->get_alteration ();
437       SCM key = scm_cons (scm_int2num (o), scm_int2num (n));
438
439       while (origin
440              && origin->where_defined (ly_symbol2scm ("localKeySignature")))
441         {
442           /*
443             huh? we set props all the way to the top?
444           */
445           SCM localsig = origin->get_property ("localKeySignature");
446           bool change = false;
447           if (accidentals_[i].tied_)
448             {
449               /*
450                 Remember an alteration that is different both from
451                 that of the tied note and of the key signature.
452               */
453               localsig = ly_assoc_front_x
454                 (localsig, key, scm_cons (SCM_BOOL_T, scm_int2num (barnum)));
455
456               change = true;
457             }
458           else
459             {
460               /*
461                 not really really correct if there are more than one
462                 noteheads with the same notename.
463               */
464               localsig = ly_assoc_front_x (localsig, key,
465                                            scm_cons (scm_int2num (a),
466                                                      scm_int2num (barnum)));
467               change = true;
468             }
469
470           if (change)
471             origin->set_property ("localKeySignature", localsig);
472
473           origin = origin->get_parent_context ();
474         }
475     }
476
477   accidental_placement_ = 0;
478   accidentals_.clear ();
479   left_objects_.clear ();
480   right_objects_.clear ();
481 }
482
483 void
484 Accidental_engraver::acknowledge_grob (Grob_info info)
485 {
486   Music *note = info.music_cause ();
487
488   if (note
489       && note->is_mus_type ("note-event")
490       && Rhythmic_head::has_interface (info.grob ()))
491     {
492       if (to_boolean (get_property ("harmonicAccidentals"))
493           || !ly_is_equal (info.grob ()->get_property ("style"),
494                             ly_symbol2scm ("harmonic")))
495         {
496           Accidental_entry entry;
497           entry.head_ = info.grob ();
498           entry.origin_trans_ = dynamic_cast<Engraver *> (info.origin_translator ());
499           entry.origin_ = entry.origin_trans_->context ();
500           entry.melodic_ = note;
501
502           accidentals_.push (entry);
503         }
504     }
505   else if (Tie::has_interface (info.grob ()))
506     ties_.push (dynamic_cast<Spanner *> (info.grob ()));
507   else if (Arpeggio::has_interface (info.grob ()))
508     left_objects_.push (info.grob ());
509   else if (info.grob ()
510            ->internal_has_interface (ly_symbol2scm ("finger-interface")))
511     left_objects_.push (info.grob ());
512 }
513
514 void
515 Accidental_engraver::process_music ()
516 {
517   SCM sig = get_property ("keySignature");
518   /* Detect key sig changes.
519      Update all parents and children.  */
520   if (last_keysig_ != sig)
521     update_local_key_signature ();
522 }
523
524 ADD_TRANSLATOR (Accidental_engraver,
525                 "Make accidentals.  "
526                 "Catch note heads, ties and notices key-change events.  "
527                 "This engraver usually lives at Staff level, but "
528                 "reads the settings for Accidental at @code{Voice} level, "
529                 "so you can @code{\\override} them at @code{Voice}. ",
530                 "Accidental",
531                 "",
532                 "arpeggio-interface "
533                 "finger-interface "
534                 "rhythmic-head-interface "
535                 "tie-interface ",
536                 "autoAccidentals "
537                 "autoCautionaries "
538                 "extraNatural "
539                 "harmonicAccidentals "
540                 "localKeySignature",
541                 "localKeySignature");