]> git.donarmstrong.com Git - lilypond.git/blob - lily/accidental-engraver.cc
* lily/translator.cc (derived_mark): new function.
[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--2004 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 "event.hh"
15 #include "item.hh"
16 #include "protected-scm.hh"
17 #include "rhythmic-head.hh"
18 #include "side-position-interface.hh"
19 #include "spanner.hh"
20 #include "tie.hh"
21 #include "warn.hh"
22
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   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 ();
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 /*
81   TODO:
82
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
86   those.
87  */
88
89 static void
90 set_property_on_children (Context *trans, char const *sym, SCM val)
91 {
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))
94     {
95       Context *trg = unsmob_context (ly_car (p));
96       set_property_on_children (trg, sym, ly_deep_copy (val));
97     }
98 }
99
100 Accidental_engraver::Accidental_engraver ()
101 {
102   accidental_placement_ = 0;
103   last_keysig_ = SCM_EOL;
104 }
105
106 void
107 Accidental_engraver::derived_mark () const
108 {
109   scm_gc_mark (last_keysig_);
110 }
111
112 void
113 Accidental_engraver::update_local_key_signature ()
114 {
115   last_keysig_ = get_property ("keySignature");
116   set_property_on_children (context (), "localKeySignature", last_keysig_);
117
118   Context *trans = context ()->get_parent_context ();
119
120   /* Huh. Don't understand what this is good for. --hwn.  */
121   while (trans && trans->where_defined (ly_symbol2scm ("localKeySignature")))
122     {
123       trans->set_property ("localKeySignature", ly_deep_copy (last_keysig_));
124       trans = trans->get_parent_context ();
125     }
126 }
127
128 void
129 Accidental_engraver::initialize ()
130 {
131   update_local_key_signature (); 
132 }
133
134
135 /** Calculate the number of accidentals on basis of the current local key
136     sig (passed as argument)
137     
138     * First check step+octave (taking into account barnumbers if necessary).
139    
140     * Then check the global signature (only step).
141   
142     Return number of accidentals (0, 1 or 2).  */
143 static int
144 number_accidentals_from_sig (bool *different, SCM sig, Pitch *pitch,
145                              int curbarnum, SCM laziness, bool ignore_octave)
146 {
147   int n = pitch->get_notename ();
148   int o = pitch->get_octave ();
149   int a = pitch->get_alteration ();
150
151   SCM prev_alt = SCM_BOOL_F;
152
153   if (!ignore_octave)
154     {
155       SCM prev_local
156         = scm_assoc (scm_cons (scm_int2num (o), scm_int2num (n)), sig);
157
158       if (ly_c_pair_p (prev_local))
159         {
160           if (ly_c_pair_p (ly_cdr (prev_local))
161               && scm_is_number (laziness))
162             {
163               int barnum = scm_to_int (ly_cddr (prev_local));
164
165               prev_local = scm_cons (ly_car (prev_local), ly_cadr (prev_local));
166               if (curbarnum <= barnum + scm_to_int (laziness))
167                 prev_alt = prev_local;
168             }
169         }
170     }
171
172   if (prev_alt == SCM_BOOL_F)
173     prev_alt = scm_assoc (scm_int2num (n), sig);
174
175   prev_alt =  (prev_alt == SCM_BOOL_F) ? scm_int2num (0) : ly_cdr (prev_alt); 
176     
177   /* UGH. prev_acc can be #t in case of ties. What is this for?  */
178   int p = scm_is_number (prev_alt) ? scm_to_int (prev_alt) : 0;
179
180   int num;
181   if (a == p && scm_is_number (prev_alt))
182     num = 0;
183   else if ( (abs (a)<abs (p) || p*a<0) && a != 0 )
184     num = 2;
185   else
186     num = 1;
187
188   *different = (a != p);
189   return num;
190 }
191
192 static int
193 number_accidentals (bool *different,
194                     Pitch *pitch, Context *origin,
195                     SCM accidentals, int curbarnum)
196 {
197   int number = 0;
198
199   *different = false;
200   if (ly_c_pair_p (accidentals) && !scm_is_symbol (ly_car (accidentals)))
201     warning (_f ("Accidental typesetting list must begin with context-name: %s", 
202                  ly_scm2string (ly_car (accidentals)).to_str0 ()));
203   
204   for (; ly_c_pair_p (accidentals) && origin;
205        accidentals = ly_cdr (accidentals))
206     {
207       // If pair then it is a new accidentals typesetting rule to be checked
208       SCM rule = ly_car (accidentals);
209       if (ly_c_pair_p (rule))
210         {
211           SCM type = ly_car (rule);
212           SCM laziness = ly_cdr (rule);
213           SCM localsig = origin->get_property ("localKeySignature");
214           
215           bool same_octave_b = 
216             scm_is_eq (ly_symbol2scm ("same-octave"), type);
217           bool any_octave_b = 
218             scm_is_eq (ly_symbol2scm ("any-octave"), type);
219
220           if (same_octave_b || any_octave_b)
221             {
222               bool d = false;
223               int n = number_accidentals_from_sig
224                 (&d, localsig, pitch, curbarnum, laziness, any_octave_b);
225               *different = *different || d;
226               number = max (number, n);     
227             }
228           else
229             warning (_f ("ignoring unknown accidental: %s", 
230                          ly_symbol2string (type).to_str0 ()));
231         }
232       
233
234       /*
235         if symbol then it is a context name. Scan parent contexts to find it.
236       */
237       else if (scm_is_symbol (rule))
238         {
239           Context *dad = origin;
240           while (dad && !dad->is_alias (rule))
241             dad = dad->get_parent_context ();
242       
243           if (dad)
244             origin = dad;
245         }
246       else warning (_f ("Accidental rule must be pair or context-name; Found %s", 
247                         ly_scm2string (rule).to_str0 ()));
248     }
249
250   return number;
251 }
252
253 int
254 Accidental_engraver::get_bar_number ()
255 {
256   SCM barnum = get_property ("currentBarNumber");
257   SCM smp = get_property ("measurePosition");
258
259   int bn = robust_scm2int (barnum, 0);
260   
261   Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
262   if (mp.main_part_ < Rational (0))
263     bn--;
264   
265   return bn;
266 }
267
268 void
269 Accidental_engraver::process_acknowledged_grobs ()
270 {
271   if (accidentals_.size () && !accidentals_.top ().done_)
272     {
273       SCM accidentals =  get_property ("autoAccidentals");
274       SCM cautionaries =  get_property ("autoCautionaries");
275       int barnum = get_bar_number ();
276       
277       bool extra_natural_b = get_property ("extraNatural") == SCM_BOOL_T;
278       for (int i = 0; i < accidentals_.size (); i++) 
279         {
280           if (accidentals_[i].done_ )
281             continue;
282           accidentals_[i].done_  = true;
283           Grob *support = accidentals_[i].head_;
284           Music *note = accidentals_[i].melodic_;
285           Context *origin = accidentals_[i].origin_;
286
287           Pitch *pitch = unsmob_pitch (note->get_property ("pitch"));
288           if (!pitch)
289             continue;
290
291           bool different = false;
292           bool different_caut = false;
293           
294           int num = number_accidentals (&different,
295                                         pitch, origin,
296                                         accidentals, barnum);
297           int num_caut = number_accidentals (&different_caut,
298                                              pitch, origin,
299                                              cautionaries, barnum);
300
301           bool cautionary = to_boolean (note->get_property ("cautionary"));
302           
303           if (num_caut > num)
304             {
305               num = num_caut;
306               different = different_caut;
307               cautionary = true;
308             }
309
310           if (num == 0 && to_boolean (note->get_property ("force-accidental")))
311             num = 1;
312           
313
314           /*
315             Can not look for ties: it's not guaranteed that they reach
316             us before the notes
317            */
318         
319           if (num)
320             {
321               /*
322                 We construct the accidentals at the originating Voice
323                 level, so that we get the property settings for
324                 Accidental from the respective Voice.
325                */
326               Grob *a
327                 = make_item_from_properties (accidentals_[i].origin_trans_,
328                                              ly_symbol2scm ("Accidental"),
329                                              note->self_scm ());
330               a->set_parent (support, Y_AXIS);
331
332               if (!accidental_placement_)
333                 accidental_placement_ = make_item ("AccidentalPlacement",
334                                                    a->self_scm ());
335               Accidental_placement::add_accidental (accidental_placement_, a);
336               SCM accs = scm_cons (scm_int2num (pitch->get_alteration ()),
337                                    SCM_EOL);
338               if (num == 2 && extra_natural_b)
339                 accs = scm_cons (scm_int2num (0), accs);
340
341               /* TODO: add cautionary option in accidental. */
342
343               if (cautionary)
344                 a->set_property ("cautionary", SCM_BOOL_T);
345               
346               support->set_property ("accidental-grob", a->self_scm ());
347
348               a->set_property ("accidentals", accs);
349               accidentals_[i].accidental_ = a;
350
351               /*
352                 We add the accidentals to the support of the arpeggio,
353                 so it is put left of the accidentals.
354               */
355               for (int i = 0;  i < left_objects_.size ();  i++)
356                 Side_position_interface::add_support (left_objects_[i], a);
357               for (int i = 0;  i < right_objects_.size ();  i++)
358                 Side_position_interface::add_support (a, right_objects_[i]);
359             }
360         }
361     }
362 }
363
364 void
365 Accidental_engraver::finalize ()
366 {
367   last_keysig_ = SCM_EOL;
368 }
369
370 void
371 Accidental_engraver::stop_translation_timestep ()
372 {
373   for (int j = ties_.size (); j--;)
374     {
375       Grob *r = Tie::head (ties_[j], RIGHT);
376       for (int i = accidentals_.size ();  i--;)
377         if (accidentals_[i].head_ == r)
378           {
379             if (Grob *g = accidentals_[i].accidental_)
380               {
381                 g->set_property ("tie", ties_[j]->self_scm ());
382                 accidentals_[i].tied_ = true;
383               }
384             ties_.del (j);
385             break;
386           }
387     }
388
389   for (int i = accidentals_.size (); i--;) 
390     {
391       int barnum = get_bar_number ();
392
393       Music *note = accidentals_[i].melodic_;
394       Context * origin = accidentals_[i].origin_;
395
396       Pitch *pitch = unsmob_pitch (note->get_property ("pitch"));
397       if (!pitch)
398         continue;
399
400       int n = pitch->get_notename ();
401       int o = pitch->get_octave ();
402       int a = pitch->get_alteration ();
403       SCM key = scm_cons (scm_int2num (o), scm_int2num (n));
404
405       while (origin
406              && origin->where_defined (ly_symbol2scm ("localKeySignature")))
407         {
408           /*
409             huh? we set props all the way to the top? 
410           */
411           SCM localsig = origin->get_property ("localKeySignature");
412           bool change = false;
413           if (accidentals_[i].tied_)
414             {
415               /*
416                 Remember an alteration that is different both from
417                 that of the tied note and of the key signature.
418               */
419               localsig = ly_assoc_front_x
420                 (localsig, key, scm_cons (SCM_BOOL_T, scm_int2num (barnum)));
421
422               change = true;
423             }
424           else
425             {
426               /*
427                 not really really correct if there are more than one
428                 noteheads with the same notename.
429               */
430               localsig = ly_assoc_front_x (localsig, key,
431                                            scm_cons (scm_int2num (a),
432                                                      scm_int2num (barnum)));
433               change = true;
434             }
435
436           if (change)
437             origin->set_property ("localKeySignature", localsig);
438
439           origin = origin->get_parent_context ();
440         }
441     }
442
443   accidental_placement_ = 0;
444   accidentals_.clear ();
445   left_objects_.clear ();
446   right_objects_.clear ();
447 }
448
449 void
450 Accidental_engraver::acknowledge_grob (Grob_info info)
451 {
452   Music *note = info.music_cause ();
453
454   if (note
455       && note->is_mus_type ("note-event")
456       && Rhythmic_head::has_interface (info.grob_))
457     {
458       if (to_boolean ( get_property ("harmonicAccidentals"))
459           || !ly_c_equal_p (info.grob_->get_property ("style"),
460                           ly_symbol2scm ("harmonic")))
461         {
462           
463           Accidental_entry entry ;
464           entry.head_ = info.grob_;
465           entry.origin_trans_ = dynamic_cast<Engraver*> (info.origin_trans_);
466           entry.origin_ = info.origin_trans_->context ();
467           entry.melodic_ = note;
468
469           accidentals_.push (entry);
470         }
471     }
472   else if (Tie::has_interface (info.grob_))
473     ties_.push (dynamic_cast<Spanner*> (info.grob_));
474   else if (Arpeggio::has_interface (info.grob_))
475     left_objects_.push (info.grob_); 
476   else if (info.grob_
477            ->internal_has_interface (ly_symbol2scm ("finger-interface")))
478     left_objects_.push (info.grob_); 
479 }
480
481 void
482 Accidental_engraver::process_music ()
483 {
484   SCM sig = get_property ("keySignature");
485   /* Detect key sig changes.
486      Update all parents and children.  */
487   if (last_keysig_ != sig)
488     update_local_key_signature ();
489 }
490
491 ENTER_DESCRIPTION (Accidental_engraver,
492                    "Make accidentals.  "
493                    "Catch note heads, ties and notices key-change events.  "
494                    "This engraver usually lives at Staff level, but "
495                    "reads the settings for Accidental at @code{Voice} level, " 
496                    "so you can @code{\\override} them at @code{Voice}. "
497                    ,
498                    "Accidental"
499                    ,
500                    ""
501                    ,
502                    "arpeggio-interface "
503                    "finger-interface "
504                    "rhythmic-head-interface "
505                    "tie-interface "
506                    ,
507                    "autoAccidentals "
508                    "autoCautionaries "
509                    "extraNatural "
510                    "harmonicAccidentals "
511                    "localKeySignature"
512                    ,
513                    "localKeySignature"
514                    );