]> git.donarmstrong.com Git - lilypond.git/commitdiff
lilypond-1.5.15
authorfred <fred>
Wed, 27 Mar 2002 02:03:21 +0000 (02:03 +0000)
committerfred <fred>
Wed, 27 Mar 2002 02:03:21 +0000 (02:03 +0000)
input/regression/accidental-double.ly [new file with mode: 0644]
input/regression/accidental.ly
lily/accidental-engraver.cc [new file with mode: 0644]
lily/local-key-item.cc
lily/span-bar.cc
ly/engraver-init.ly
scm/grob-property-description.scm
scm/interface-description.scm

diff --git a/input/regression/accidental-double.ly b/input/regression/accidental-double.ly
new file mode 100644 (file)
index 0000000..eb37a7c
--- /dev/null
@@ -0,0 +1,15 @@
+\header {
+       texidoc = "If two forced accidentals happen at the same time, only one
+       sharp sign is printed."
+}
+
+
+\score { \notes \transpose c''
+   \context Staff <
+     \key g \major
+     \context Voice=va { \stemUp c' fis! }
+     \context Voice=vb { \stemDown c fis! }
+   >
+}
+
+
index 614995069da06ebbe5e8ac8aaedad4c965d23837..af01b459cf2cbc4f236223678118578a4a72cf51 100644 (file)
@@ -7,10 +7,9 @@ fourth show forced and courtesy accidentals.
 "
 }
 
-foo = \notes\relative c''   {   \key as \major dis4 dis dis! dis? }
+foo = \notes\relative c''   {   \key as \major dis4 dis dis!^"force" dis? }
 
 \score {
-
   < \foo 
    \context NoteNames \foo
   >
diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc
new file mode 100644 (file)
index 0000000..46914f6
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+  local-key-engraver.cc -- implement accidental_engraver
+
+  (c)  1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+*/
+
+#include "musical-request.hh"
+#include "command-request.hh"
+#include "local-key-item.hh"
+#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"
+
+/**
+
+
+   FIXME: should not compute vertical positioning of accidentals, but
+   get them from the noteheads
+
+   The algorithm for accidentals should be documented, and made
+   tweakable.
+
+*/
+
+
+struct Accidental_engraver : Engraver {
+  Item *key_item_p_;
+protected:
+  TRANSLATOR_DECLARATIONS(Accidental_engraver);
+  virtual void process_music ();
+  virtual void acknowledge_grob (Grob_info);
+  virtual void stop_translation_timestep ();
+  virtual void initialize ();
+  virtual void create_grobs ();
+  virtual void finalize ();
+public:
+
+  // todo -> property
+  SCM last_keysig_;
+
+  /*
+    Urgh. Since the accidentals depend on lots of variables, we have to
+    store all information before we can really create the accidentals.
+   */
+  Link_array<Grob> arpeggios_;
+  
+  Link_array<Note_req> mel_l_arr_;
+  Link_array<Grob> support_l_arr_;
+  Link_array<Item> forced_l_arr_;
+  Link_array<Grob> tie_l_arr_;
+
+};
+
+Accidental_engraver::Accidental_engraver ()
+{
+  key_item_p_ =0;
+  last_keysig_ = SCM_EOL;
+}
+
+void
+Accidental_engraver::initialize ()
+{
+  last_keysig_ = get_property ("keySignature");
+  daddy_trans_l_->set_property ("localKeySignature",  last_keysig_);  
+}
+
+void
+Accidental_engraver::create_grobs ()
+{
+  if (!key_item_p_ && mel_l_arr_.size ()) 
+    {
+      SCM localsig = get_property ("localKeySignature");
+  
+      for (int i=0; i  < mel_l_arr_.size (); i++) 
+       {
+         Grob * support_l = support_l_arr_[i];
+         Note_req * note_l = mel_l_arr_[i];
+
+         int n = unsmob_pitch (note_l->get_mus_property ("pitch"))->notename_i_;
+         int o = unsmob_pitch (note_l->get_mus_property ("pitch"))->octave_i () ;
+         int a = unsmob_pitch (note_l->get_mus_property ("pitch"))->alteration_i_;
+         
+         /* see if there's a tie that "changes" the accidental */
+         /* works because if there's a tie, the note to the left
+            is of the same pitch as the actual note */
+
+         SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig);
+         if (prev == SCM_BOOL_F)
+           prev = scm_assoc (gh_int2scm (n), localsig);
+         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;
+
+         Grob *tie_break_reminder = 0;
+         bool tie_changes = false;
+         for (int i=0; i < tie_l_arr_.size (); i++)
+           if (support_l == Tie::head (tie_l_arr_[i], RIGHT))
+             {
+               tie_changes = different;
+               /* Enable accidentals for broken tie
+
+                  We only want an accidental on a broken tie,
+                  if the tie changes the accidental.
+                  
+                  Maybe check property noTieBreakForceAccidental? */
+               if (different)
+                 tie_break_reminder = tie_l_arr_[i];
+               break;
+             }
+
+         /* When do we want accidentals:
+
+            1. when property force-accidental is set, and not
+            tie_changes
+            2. when different and not tie-changes
+            3. maybe when at end of a tie: we must later see if
+            we're after a line break */
+         if (( (to_boolean (note_l->get_mus_property ("force-accidental"))
+               || different)
+              && !tie_changes)
+             || tie_break_reminder)
+           {
+             if (!key_item_p_) 
+               {
+                 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))
+                   Staff_symbol_referencer::set_position (key_item_p_, gh_scm2int (c0));
+                        
+                 announce_grob (key_item_p_, 0);
+               }
+
+             
+             bool extra_natural =
+               sign (p) * (p - a) == 1
+               && abs (p) == 2;
+
+             Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
+                                        to_boolean (note_l->get_mus_property ("cautionary")),
+                                        extra_natural,
+                                        tie_break_reminder);
+             Side_position_interface::add_support (key_item_p_,support_l);
+           }
+         
+         /*
+           We should not record the accidental if it is the first
+           note and it is tied from the previous measure.
+
+           Checking whether it is tied also works mostly, but will it
+           always do the correct thing?
+
+          */
+         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, gh_cons (gh_int2scm (o),
+                                                            gh_int2scm (n)),
+                                         SCM_BOOL_T); 
+
+           }
+         else if (!forget)
+           {
+             /*
+               not really really correct if there are more than one
+               noteheads with the same notename.
+              */
+             localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
+                                                            gh_int2scm (n)),
+                                         gh_int2scm (a)); 
+
+           }
+        }
+
+
+  
+  
+      daddy_trans_l_->set_property ("localKeySignature",  localsig);
+    }
+  
+
+  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.)
+       */
+      for (int i=0;  i < arpeggios_.size ();  i++)
+       Side_position_interface::add_support (arpeggios_[i], key_item_p_);
+
+      arpeggios_.clear ();
+    }
+}
+
+void
+Accidental_engraver::finalize ()
+{
+
+}
+
+void
+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]);
+
+      typeset_grob (key_item_p_);
+      key_item_p_ =0;
+    }
+
+
+  mel_l_arr_.clear ();
+  arpeggios_.clear ();
+  tie_l_arr_.clear ();
+  support_l_arr_.clear ();
+  forced_l_arr_.clear ();      
+}
+
+void
+Accidental_engraver::acknowledge_grob (Grob_info info)
+{
+  Note_req * note_l =  dynamic_cast <Note_req *> (info.req_l_);
+
+  if (note_l && Rhythmic_head::has_interface (info.grob_l_))
+    {
+      mel_l_arr_.push (note_l);
+      support_l_arr_.push (info.grob_l_);
+    }
+  else if (Tie::has_interface (info.grob_l_))
+    {
+      tie_l_arr_.push (info.grob_l_);
+    }
+  else if (Arpeggio::has_interface (info.grob_l_))
+    {
+      arpeggios_.push (info.grob_l_); 
+    }
+  
+}
+
+/*
+  ugh. repeated deep_copy generates lots of garbage.
+ */
+void
+Accidental_engraver::process_music ()
+{
+  SCM smp = get_property ("measurePosition");
+  Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
+
+  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.  */
+  if (last_keysig_ != sig) 
+    {
+      daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
+      last_keysig_ = sig;
+    }
+  else if (!mp.to_bool () )
+    {
+      if (!to_boolean (get_property ("noResetKey")))
+       daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
+    }
+}
+
+
+
+
+
+ENTER_DESCRIPTION(Accidental_engraver,
+/* descr */       "Make accidentals.  Catches note heads, ties and notices key-change
+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",
+/* write */       "");
index ff0172616907e7eadc6513d648bd5a212cf23ab9..1ffc2c696cca0a6d7d975b351bb981b1c210c412 100644 (file)
@@ -28,7 +28,7 @@ static SCM pitch_less_proc;
 void
 init_pitch_funcs ()
 {
-  pitch_less_proc = gh_new_procedure2_0 ("pits-less", &pitch_less);
+  pitch_less_proc = gh_new_procedure2_0 ("pitch-less", &pitch_less);
 }
 
 ADD_SCM_INIT_FUNC (lkpitch,init_pitch_funcs);
@@ -40,7 +40,10 @@ Local_key_item::add_pitch (Grob*me, Pitch p, bool cautionary, bool natural,
 {
   SCM acs = me->get_grob_property ("accidentals");
   SCM pitch = p.smobbed_copy ();
-  SCM opts = SCM_EOL;
+  SCM opts = scm_assoc (pitch, acs);
+  bool new_pitch = !gh_pair_p (opts);
+  opts= new_pitch ? SCM_EOL : gh_cdr (opts);
+  
   if (cautionary)
     opts = gh_cons (ly_symbol2scm ("cautionary"), opts);
   if (natural)
@@ -52,8 +55,13 @@ Local_key_item::add_pitch (Grob*me, Pitch p, bool cautionary, bool natural,
       opts = gh_cons (ly_symbol2scm ("tie-break-reminder"), opts);
     }
 
-  pitch = gh_cons (pitch, opts);
-  acs = scm_merge_x (acs, gh_cons (pitch, SCM_EOL), pitch_less_proc);
+  if (new_pitch)
+    {
+      pitch = gh_cons (pitch, opts);
+      acs = scm_merge_x (acs, gh_cons (pitch, SCM_EOL), pitch_less_proc);
+    }
+  else
+    scm_assoc_set_x (acs, pitch, opts);
 
   me->set_grob_property ("accidentals", acs);
 }
index 01020ca6260b85a50e372435e89270abc1bb80ca..1700d181fc2e02ec3090478fe177b573b158245a 100644 (file)
@@ -177,17 +177,24 @@ void
 Span_bar::evaluate_glyph (Grob*me)
 {
   SCM elts = me->get_grob_property ("elements");
-  Grob * b = unsmob_grob (ly_car (elts));
-  SCM glsym =ly_symbol2scm ("glyph");
-  SCM gl =b ->get_grob_property (glsym);
+  SCM glyph_symbol = ly_symbol2scm ("glyph");
+  SCM gl = SCM_EOL;
+
+  while (gh_pair_p (elts))
+    {
+      gl =  unsmob_grob (gh_car (elts))->get_grob_property (glyph_symbol);
+      if (gh_string_p (gl))
+       break;
+      elts =gh_cdr (elts);
+    }
+
   if (!gh_string_p (gl))
     {
       me->suicide ();
-      return ; 
+      return;
     }
-
-  String type = ly_scm2string (gl);
   
+  String type = ly_scm2string (gl);
   if (type == "|:") 
     {
       type = ".|";
@@ -202,8 +209,8 @@ Span_bar::evaluate_glyph (Grob*me)
     }
 
   gl = ly_str02scm (type.ch_C ());
-  if (scm_equal_p (me->get_grob_property (glsym), gl) != SCM_BOOL_T)
-    me->set_grob_property (glsym, gl);
+  if (scm_equal_p (me->get_grob_property (glyph_symbol), gl) != SCM_BOOL_T)
+    me->set_grob_property (glyph_symbol, gl);
 }
 
 Interval
index 6261811a13244229551ed15f5fa5ca89533f5348..450d5b7784079e36b15b17bc1e19be7d24c87adb 100644 (file)
@@ -27,7 +27,7 @@ StaffContext=\translator {
        \consists "Staff_symbol_engraver"
        \consists "Collision_engraver"
        \consists "Rest_collision_engraver"
-       \consists "Local_key_engraver"
+       \consists "Accidental_engraver"
        \consists "Piano_pedal_engraver"
        \consists "Instrument_name_engraver"
 
@@ -379,6 +379,8 @@ ScoreContext = \translator {
 
        tupletNumberFormatFunction = #denominator-tuplet-formatter
        
+       subdivideBeams = ##f
+
        keyAccidentalOrder = #'(
          (6 . -1) (2  . -1) (5 . -1 ) (1  . -1) (4  . -1) (0  . -1) (3  . -1)
         (3  . 1) (0 . 1) (4 . 1) (1 . 1) (5 . 1) (2 . 1) (6 . 1)
index 9b8ec528b7d941e10b7a5551a95334fde78bff3c..3f808ba8bf0a5e0d61f442120ce4f5e5e2764eec 100644 (file)
@@ -29,6 +29,9 @@
 (grob-property-description 'X-offset-callbacks list? "list of functions, each taking an grob and axis argument. The function determine the position relative to this grob's parent. The last one in the list is called first.")
 (grob-property-description 'Y-extent-callback procedure? "see @code{X-extent-callback}.")
 (grob-property-description 'Y-offset-callbacks list? "see @code{X-offset-callbacks}.")
+(grob-property-description 'accidentals list? "Alist with (PITCH
+. OPTION-LIST) entries. OPTION-LIST can contain 'cautionary, 'natural
+and 'tie-break-reminder ")
 (grob-property-description 'add-stem boolean? "Add stem to porrectus?.")
 (grob-property-description 'after-line-breaking-callback procedure? "Procedure taking a grob as argument.
 This procedure is called (using dependency resolution) after line breaking. Return value is ignored.")
index 8bd3ca2ed723e055539bcf7134a805486d09b151..9d2249cac2d4eb3de7ac11c9f6364c9da09c92a5 100644 (file)
 (lily-interface
  'accidentals-interface
  "Accidentals"
- '(
+ '(accidentals
    left-padding 
    right-padding 
    ))