]> git.donarmstrong.com Git - lilypond.git/blob - lily/accidental-engraver.cc
* input/regression/accidental-tie.ly (mus): new file
[lilypond.git] / lily / accidental-engraver.cc
1 /*
2   accidental-engraver.cc -- implement accidental_engraver
3
4   (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5   Modified 2001--2002 by Rune Zedeler <rz@daimi.au.dk>
6 */
7
8 #include "event.hh"
9 #include "spanner.hh"
10 #include "item.hh"
11 #include "tie.hh"
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"
18 #include "warn.hh"
19 #include "context.hh"
20 #include "protected-scm.hh"
21
22
23 struct Accidental_entry {
24   bool done_;
25   Music * melodic_;
26   Grob * accidental_;
27   Context *origin_;
28   Grob*  head_;
29   bool tied_;
30   Accidental_entry();
31 };
32
33 Accidental_entry::Accidental_entry()
34 {
35   tied_ = false;
36   done_ = false;
37   melodic_ =0;
38   accidental_ = 0;
39   origin_ = 0;
40   head_ = 0;
41 }
42
43 struct Accidental_engraver : Engraver {
44 protected:
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 ();
52 public:
53
54   Protected_scm last_keysig_;
55
56   /*
57     Urgh. Since the accidentals depend on lots of variables, we have to
58     store all information before we can really create the accidentals.
59   */
60   Link_array<Grob> left_objects_;
61   Link_array<Grob> right_objects_;
62
63   Grob * accidental_placement_;
64
65   /*
66     The next 
67    */
68   Array<Accidental_entry> accidentals_;
69   Link_array<Spanner> ties_;
70
71   SCM get_bar_num ();
72 };
73
74
75 static void
76 set_property_on_children (Context * trans, const char * sym, SCM val)
77 {
78   trans->set_property (sym, val);
79   for (SCM p = trans->context_list_; gh_pair_p (p); p = ly_cdr(p))
80     {
81       Context *trg =  unsmob_context (ly_car (p));
82       set_property_on_children(trg, sym, ly_deep_copy(val));
83     }
84 }
85
86 Accidental_engraver::Accidental_engraver ()
87 {
88   accidental_placement_ = 0;
89   last_keysig_ = SCM_EOL;
90 }
91
92 void
93 Accidental_engraver::initialize ()
94 {
95   last_keysig_ = get_property ("keySignature");
96
97   Context * trans_ = daddy_context_;
98   while (trans_)
99     {
100       trans_ -> set_property ("localKeySignature",
101                               ly_deep_copy (last_keysig_));
102       trans_ = trans_->daddy_context_;
103     }
104   set_property_on_children (daddy_context_,"localKeySignature", last_keysig_);
105 }
106
107 /*
108
109   calculates the number of accidentals on basis of the current local key
110   sig (passed as argument)
111
112   Returns number of accidentals (0, 1 or 2).
113   Negative (-1 or -2) if accidental has changed.
114
115 */
116 static int
117 number_accidentals_from_sig (bool *different,
118                              SCM sig, Pitch *pitch, SCM curbarnum, SCM lazyness, 
119                              bool ignore_octave)
120 {
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);
125   int accbarnum_i = 0;
126
127   SCM prev;
128   if (ignore_octave)
129     prev = ly_assoc_cdr (scm_int2num (n), sig);
130   else
131     prev = scm_assoc (gh_cons (scm_int2num (o), scm_int2num (n)), sig);
132
133   /* should really be true unless prev == SCM_BOOL_F */
134   if (gh_pair_p (prev) && gh_pair_p (ly_cdr (prev)))
135     {
136       accbarnum_i = gh_scm2int (ly_cddr (prev));
137       prev = gh_cons (ly_car (prev), ly_cadr (prev));
138     }
139   
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);
144
145
146   SCM prev_acc = (prev == SCM_BOOL_F) ? scm_int2num (0) : ly_cdr (prev);
147
148   int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0;
149
150   int num;
151   if (a == p && gh_number_p (prev_acc))
152     num = 0;
153   else if ( (abs (a)<abs (p) || p*a<0) && a != 0 )
154     num = 2;
155   else
156     num = 1;
157
158   *different = (a != p);
159   return num;
160 }
161
162 static int
163 number_accidentals (bool *different,
164                     Pitch *pitch, Context * origin, 
165                     SCM accidentals, SCM curbarnum)
166 {
167   int number = 0;
168
169   *different = false;
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 ()));
173   
174   for (; gh_pair_p (accidentals) && origin; accidentals = gh_cdr (accidentals))
175     {
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))
179         {
180           SCM type = gh_car (rule);
181           SCM lazyness = gh_cdr (rule);
182           SCM localsig = origin->get_property ("localKeySignature");
183           
184           bool same_octave_b = 
185             gh_eq_p (ly_symbol2scm ("same-octave"), type);
186           bool any_octave_b = 
187             gh_eq_p (ly_symbol2scm ("any-octave"), type);
188
189           if (same_octave_b || any_octave_b)
190             {
191               bool d = false;
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);     
196             }
197           else
198             warning (_f ("unknown accidental typesetting: %s. Ignored", 
199                          ly_symbol2string (type).to_str0 ()));
200         }
201       
202
203       /*
204         if symbol then it is a context name. Scan parent contexts to find it.
205       */
206       else if (gh_symbol_p (rule))
207         {
208           Context * dad = origin;
209           while (dad && !dad->is_alias (rule))
210             dad = dad->daddy_context_;
211       
212           if (dad)
213             origin = dad;
214         }
215       else warning (_f ("Accidental rule must be pair or context-name; Found %s", 
216                         ly_scm2string (rule).to_str0 ()));
217     }
218
219   return number;
220 }
221
222 SCM
223 Accidental_engraver::get_bar_num ()
224 {
225    SCM barnum = get_property ("currentBarNumber");
226       SCM smp = get_property("measurePosition");
227       
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);
232       
233
234       return barnum ;
235   
236 }
237
238 void
239 Accidental_engraver::process_acknowledged_grobs ()
240 {
241   if (accidentals_.size () && !accidentals_.top().done_)
242     {
243       //SCM localsig = get_property ("localKeySignature");
244       SCM accidentals =  get_property ("autoAccidentals");
245       SCM cautionaries =  get_property ("autoCautionaries");
246       SCM barnum = get_bar_num ();
247       
248       bool extra_natural_b = get_property ("extraNatural") == SCM_BOOL_T;
249       for (int i = 0; i  < accidentals_.size (); i++) 
250         {
251           if (accidentals_[i].done_ )
252             continue;
253           accidentals_[i].done_  = true;
254           Grob * support = accidentals_[i].head_;
255           Music * note = accidentals_[i].melodic_;
256           Context * origin = accidentals_[i].origin_;
257
258           Pitch * pitch = unsmob_pitch (note->get_mus_property ("pitch"));
259           if (!pitch)
260             continue;
261
262           bool different = false;
263           bool different_caut = false;
264           
265           int num = number_accidentals (&different,
266                                         pitch, origin,
267                                         accidentals, barnum);
268           int num_caut = number_accidentals (&different_caut,
269                                              pitch, origin,
270                                              cautionaries, barnum);
271
272           bool cautionary = to_boolean (note->get_mus_property ("cautionary"));
273           
274           if (num_caut > num)
275             {
276               num = num_caut;
277               different = different_caut;
278               cautionary = true;
279             }
280
281           if (num == 0 && to_boolean (note->get_mus_property ("force-accidental")))
282             num = 1;
283           
284
285           /*
286             Can not look for ties: it's not guaranteed that they reach
287             us before the notes
288            */
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))
294               {
295                 tie_changes = different;
296                 if (different)
297                   tie_break_reminder = ties_[j];
298                 break;
299               }
300
301           if (num)
302             {
303               /*
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.
307                */
308               Grob * a = make_item_from_properties (origin,
309                                                     ly_symbol2scm ("Accidental"));
310               a->set_parent (support, Y_AXIS);
311
312               if (!accidental_placement_)
313                 {
314                   accidental_placement_ = make_item ("AccidentalPlacement");
315                   announce_grob (accidental_placement_, a->self_scm());
316                 }
317               
318               Accidental_placement::add_accidental (accidental_placement_, a);
319               announce_grob (a, SCM_EOL);
320
321               
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);
325
326               /* TODO:
327
328               add cautionary option in accidental.
329                */
330
331               if (cautionary)
332                 {
333                   a->set_grob_property ("cautionary", SCM_BOOL_T);
334                 }
335               
336               if (tie_break_reminder)
337                 {
338                   // TODO.
339                   a->set_grob_property ("tie", tie_break_reminder->self_scm());
340                 }
341               
342               
343               support->set_grob_property ("accidental-grob", a->self_scm ());
344
345               a->set_grob_property ("accidentals", accs);
346               accidentals_[i].accidental_ = a;
347
348               /*
349                 We add the accidentals to the support of the arpeggio,
350                 so it is put left of the accidentals.
351               */
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]);
356             }
357         }
358     }
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_grob_property ("tie", ties_[j]->self_scm ());
382                 accidentals_[i].tied_   = true;
383               }
384             
385             ties_.del (j);
386             break;
387           }
388     }
389
390   for (int i = accidentals_.size (); i--;) 
391     {
392       SCM barnum = get_bar_num ();
393
394       Music * note = accidentals_[i].melodic_;
395       Context * origin = accidentals_[i].origin_;
396
397       Pitch * pitch = unsmob_pitch (note->get_mus_property ("pitch"));
398       if (!pitch)
399         continue;
400       
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));
405
406       while (origin)
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, on_s, gh_cons (SCM_BOOL_T, 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
431                 (localsig, on_s, gh_cons (scm_int2num (a), barnum));
432
433               change = true;
434             }
435
436           if (change)
437             origin->set_property ("localKeySignature",  localsig);
438           origin = origin->daddy_context_;
439         }
440     }
441   
442   for (int i = 0; i < accidentals_.size(); i++)
443     {
444       if (Grob *a = accidentals_[i].accidental_)
445         typeset_grob (a);
446     }
447
448   if (accidental_placement_)
449     typeset_grob(accidental_placement_);
450   accidental_placement_ = 00;
451   
452   accidentals_.clear();
453   left_objects_.clear ();
454   right_objects_.clear ();
455 }
456
457 void
458 Accidental_engraver::acknowledge_grob (Grob_info info)
459 {
460   Music * note =  info.music_cause ();
461
462   if (note
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"))
466       )
467     {
468       Accidental_entry entry ;
469       entry.head_ = info.grob_;
470       entry.origin_ = info.origin_trans_->daddy_context_;
471       entry.melodic_ = note;
472
473       accidentals_.push (entry);
474     }
475   else if (Tie::has_interface (info.grob_))
476     {
477       ties_.push (dynamic_cast<Spanner*> (info.grob_));
478     }
479   else if (Arpeggio::has_interface (info.grob_))
480     {
481       left_objects_.push (info.grob_); 
482     }
483   else if (info.grob_->internal_has_interface (ly_symbol2scm("finger-interface")))
484     {
485       left_objects_.push (info.grob_); 
486     }
487 }
488
489 void
490 Accidental_engraver::process_music ()
491 {
492   SCM sig = get_property ("keySignature");
493
494   /* Detect key sig changes.
495      Update all parents and children
496   */
497   if (last_keysig_ != sig)
498     {
499       Context * trans_ = daddy_context_;
500       while (trans_)
501         {
502           trans_ -> set_property ("localKeySignature",  ly_deep_copy (sig));
503           trans_ = trans_->daddy_context_;
504         }
505       set_property_on_children(daddy_context_,"localKeySignature", sig);
506
507       last_keysig_ = sig;
508     }
509 }
510
511
512
513
514
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}. "
520                    ,
521                    
522                    "Accidental",
523                    "",
524                "finger-interface rhythmic-head-interface tie-interface arpeggio-interface",
525                "localKeySignature extraNatural autoAccidentals autoCautionaries",
526                    "localKeySignature");