]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/accidental-engraver.cc
release: 1.5.29
[lilypond.git] / lily / accidental-engraver.cc
index 65b83a1b611ca39563e546f1102286229a61d83e..ee82be6f1c0006f34a9b23df24c795de89aa3b46 100644 (file)
@@ -1,7 +1,7 @@
 /*
   accidental-engraver.cc -- implement accidental_engraver
 
-  (c)  1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c)  1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
   Modified 2001 by Rune Zedeler <rz@daimi.au.dk>
 */
 
 #include "item.hh"
 #include "tie.hh"
 #include "rhythmic-head.hh"
-#include "timing-translator.hh"
 #include "engraver-group-engraver.hh"
 
 #include "staff-symbol-referencer.hh"
 #include "side-position-interface.hh"
 #include "engraver.hh"
 #include "arpeggio.hh"
+#include "warn.hh"
 
 /**
 
@@ -53,12 +53,13 @@ public:
   Link_array<Grob> arpeggios_;
   
   Link_array<Note_req> mel_l_arr_;
-  Link_array<Grob> support_l_arr_;
+  Link_array<Grob> head_l_arr_;
   Link_array<Item> forced_l_arr_;
   Link_array<Grob> tie_l_arr_;
 
 };
 
+
 Accidental_engraver::Accidental_engraver ()
 {
   key_item_p_ =0;
@@ -70,7 +71,6 @@ Accidental_engraver::initialize ()
 {
   last_keysig_ = get_property ("keySignature");
   daddy_trans_l_->set_property ("localKeySignature",  last_keysig_);  
-  daddy_trans_l_->set_property ("lazyKeySignature",   last_keysig_);  
 }
 
 /** calculates the number of accidentals on basis of the current local key sig
@@ -79,61 +79,97 @@ Accidental_engraver::initialize ()
   *   Negative (-1 or -2) if accidental has changed.
   **/
 static int
-number_accidentals (SCM sig, Note_req * note_l)
+number_accidentals (SCM sig, Note_req * note_l, SCM curbarnum, SCM lazyness,
+                   bool ignore_octave_b)
 {
   Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch"));
   int n = pitch->notename_i_;
-  int o = pitch->octave_i () ;
+  int o = pitch->octave_i_;
   int a = pitch->alteration_i_;
-  
-  SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), sig);
-  if (prev == SCM_BOOL_F)
-    prev = scm_assoc (gh_int2scm (n), sig);
+  int curbarnum_i = gh_scm2int(curbarnum);
+  int accbarnum_i = 0;
+  SCM prev;
+  if (ignore_octave_b)
+    prev = ly_assoc_cdr (gh_int2scm (n), sig);
+  else
+    prev = gh_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), sig);
+  /* should really be true unless prev==SCM_BOOL_F */
+  if(gh_pair_p(prev) && gh_pair_p(ly_cdr(prev))) {
+    accbarnum_i = gh_scm2int(ly_cddr(prev));
+    prev = gh_cons(ly_car(prev),ly_cadr(prev));
+  }
+  /* If an accidental was not found or the accidental was too old */
+  if (prev == SCM_BOOL_F ||
+      (gh_number_p(lazyness) && curbarnum_i>accbarnum_i+gh_scm2int(lazyness)))
+    prev = gh_assoc (gh_int2scm (n), sig);
   SCM prev_acc = (prev == SCM_BOOL_F) ? gh_int2scm (0) : ly_cdr (prev);
 
-  bool different = !gh_equal_p (prev_acc , gh_int2scm (a));
   int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0;
 
   int num;
-  if (a==p && !to_boolean (note_l->get_mus_property ("force-accidental"))) num=0;
+  if (a==p && !to_boolean (note_l->get_mus_property ("force-accidental")) && gh_number_p(prev_acc)) num=0;
   else if ( (abs(a)<abs(p) || p*a<0) && a!=0 ) num=2;
   else num=1;
   
   return a==p ? num : -num;
 }
 
+static int
+number_accidentals (SCM localsig, Note_req * note_l, SCM accidentals_l,
+                   SCM curbarnum) {
+  int number=0;
+  int diff=0;
+  while(gh_pair_p(accidentals_l)) {
+    if(gh_pair_p(ly_car(accidentals_l))) {
+      SCM type = gh_caar(accidentals_l);
+      SCM lazyness = gh_cdar(accidentals_l);
+      bool measure_same_octave_b =
+       gh_eq_p(ly_symbol2scm("measure-same-octave"),type);
+      bool measure_any_octave_b =
+       gh_eq_p(ly_symbol2scm("measure-any-octave"),type);
+      if(measure_same_octave_b || measure_any_octave_b) {
+       int n = number_accidentals
+         (localsig,note_l,curbarnum,lazyness,measure_any_octave_b);
+       diff |= n<0;
+       number = max(number,abs(n));     
+      }
+      else warning(_f("unknown accidental typesetting: %s",
+                     ly_symbol2string(type).ch_C()));
+    }
+    else warning(_f("Accidental typesetting must be pair: %s",
+                     ly_scm2string(ly_car(accidentals_l)).ch_C()));
+    accidentals_l = ly_cdr(accidentals_l);
+  }
+  return diff ? -number : number;
+}
+
 void
 Accidental_engraver::create_grobs ()
 {
   if (!key_item_p_ && mel_l_arr_.size ()) 
     {
       SCM localsig = get_property ("localKeySignature");
-      SCM lazysig = get_property ("lazyKeySignature");
+      SCM accidentals_l =  get_property ("autoAccidentals");
+      SCM cautionaries_l =  get_property ("autoCautionaries");
+      SCM barnum = get_property ("currentBarNumber");
 
+      bool extra_natural_b = get_property ("extraNatural")==SCM_BOOL_T;
       for (int i=0; i  < mel_l_arr_.size (); i++) 
        {
-         Grob * support_l = support_l_arr_[i];
+         Grob * support_l = head_l_arr_[i];
          Note_req * note_l = mel_l_arr_[i];
 
-         int local_num = number_accidentals(localsig,note_l);
-         bool local_diff = local_num<0; local_num = abs(local_num);
-         int lazy_num = number_accidentals(lazysig,note_l);
-         bool lazy_diff = lazy_num<0; lazy_num = abs(lazy_num);
-
-         int num = local_num;;
-         bool different= local_diff;
+         int num = number_accidentals(localsig,note_l,accidentals_l,barnum);
+         int num_caut = number_accidentals(localsig,note_l,cautionaries_l,barnum);
          bool cautionary = to_boolean (note_l->get_mus_property ("cautionary"));
-         if (to_boolean (get_property ("noResetKey"))) {
-           num = lazy_num;
-           different = lazy_diff;
-         }
-         else if (gh_equal_p (get_property ("autoReminders"),ly_symbol2scm("cautionary"))
-                  || gh_equal_p (get_property ("autoReminders"),ly_symbol2scm("accidental"))) {
-           num = max(local_num,lazy_num);
-           if (gh_equal_p (get_property ("autoReminders"),ly_symbol2scm("cautionary"))
-               && lazy_num>local_num)
-             cautionary = true;
-         }
+         if (abs(num_caut)>abs(num))
+           {
+             num=num_caut;
+             cautionary=true;
+           }
+         
+         bool different=num<0;
+         num=abs(num);
 
          /* see if there's a tie that "changes" the accidental */
          /* works because if there's a tie, the note to the left
@@ -164,7 +200,6 @@ Accidental_engraver::create_grobs ()
                  key_item_p_ = new Item (get_property ("Accidentals"));
                  Local_key_item::set_interface (key_item_p_);
 
-                 
                  Staff_symbol_referencer::set_interface (key_item_p_);
                  SCM c0 = get_property ("centralCPosition");
                  if (gh_number_p (c0))
@@ -176,9 +211,11 @@ Accidental_engraver::create_grobs ()
              
              Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
                                         cautionary,
-                                        num==2,
+                                        num==2 && extra_natural_b,
                                         tie_break_reminder);
              Side_position_interface::add_support (key_item_p_,support_l);
+             
+             support_l->set_grob_property ("accidentals", key_item_p_->self_scm ());
            }
          
 
@@ -188,48 +225,43 @@ Accidental_engraver::create_grobs ()
 
            Checking whether it is tied also works mostly, but will it
            always do the correct thing?
-           (???? -Rune )
           */
          
          Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch"));
          int n = pitch->notename_i_;
-         int o = pitch->octave_i () ;
+         int o = pitch->octave_i_;
          int a = pitch->alteration_i_;
          SCM on = gh_cons (gh_int2scm (o), gh_int2scm (n));
-         bool forget = to_boolean (get_property ("forgetAccidentals"));
          if (tie_changes)
            {
              /*
                Remember an alteration that is different both from
                that of the tied note and of the key signature.
               */
-             localsig = scm_assoc_set_x (localsig, on, SCM_BOOL_T); 
-             lazysig = scm_assoc_set_x  (lazysig,  on, SCM_BOOL_T); 
+             localsig = ly_assoc_front_x
+               (localsig, on, gh_cons(SCM_BOOL_T,barnum));
            }
-         else if (!forget)
+         else
            {
              /*
                not really really correct if there are more than one
                noteheads with the same notename.
               */
-             localsig = scm_assoc_set_x (localsig, on, gh_int2scm (a)); 
-             lazysig = scm_assoc_set_x  (lazysig,  on, gh_int2scm (a)); 
+             localsig = ly_assoc_front_x
+               (localsig, on, gh_cons(gh_int2scm (a),barnum)); 
            }
         }
   
       daddy_trans_l_->set_property ("localKeySignature",  localsig);
-      daddy_trans_l_->set_property ("lazyKeySignature",   lazysig);
     }
   
-
+  
   if (key_item_p_)
     {
       /*
-       Hmm. Which one has to be on the left?
-
-       On which left, code or paper?
-
- (Arpeggios are engraved left of accidentals, of course.)
+       We add the accidentals to the support of the arpeggio, so it is put left of the
+       accidentals. 
+       
        */
       for (int i=0;  i < arpeggios_.size ();  i++)
        Side_position_interface::add_support (arpeggios_[i], key_item_p_);
@@ -249,8 +281,8 @@ Accidental_engraver::stop_translation_timestep ()
 {
   if (key_item_p_)
     {
-      for (int i=0; i < support_l_arr_.size (); i++)
-       Side_position_interface::add_support (key_item_p_,support_l_arr_[i]);
+      for (int i=0; i < head_l_arr_.size (); i++)
+       Side_position_interface::add_support (key_item_p_,head_l_arr_[i]);
 
       typeset_grob (key_item_p_);
       key_item_p_ =0;
@@ -260,7 +292,7 @@ Accidental_engraver::stop_translation_timestep ()
   mel_l_arr_.clear ();
   arpeggios_.clear ();
   tie_l_arr_.clear ();
-  support_l_arr_.clear ();
+  head_l_arr_.clear ();
   forced_l_arr_.clear ();      
 }
 
@@ -272,7 +304,7 @@ Accidental_engraver::acknowledge_grob (Grob_info info)
   if (note_l && Rhythmic_head::has_interface (info.grob_l_))
     {
       mel_l_arr_.push (note_l);
-      support_l_arr_.push (info.grob_l_);
+      head_l_arr_.push (info.grob_l_);
     }
   else if (Tie::has_interface (info.grob_l_))
     {
@@ -296,19 +328,12 @@ Accidental_engraver::process_music ()
 
   SCM sig = get_property ("keySignature");
 
-  /*
-    Detect key sig changes. If we haven't found any, check if at start
-    of measure, and set localKeySignature anyhow.  */
+  /* Detect key sig changes. */
   if (last_keysig_ != sig) 
     {
       daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
-      daddy_trans_l_->set_property ("lazyKeySignature",  ly_deep_copy (sig));
       last_keysig_ = sig;
     }
-  else if (!mp.to_bool () )
-    {
-       daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
-    }
 }
 
 
@@ -321,5 +346,5 @@ events.  Due to interaction with ties (which don't come together
 with note heads), this needs to be in a context higher than Tie_engraver. FIXME",
 /* creats*/       "Accidentals",
 /* acks  */       "rhythmic-head-interface tie-interface arpeggio-interface",
-/* reads */       "localKeySignature forgetAccidentals noResetKey autoReminders",
-/* write */       "");
+/* reads */       "localKeySignature extraNatural autoAccidentals autoCautionaries",
+/* write */       "localKeySignature");