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