]> git.donarmstrong.com Git - lilypond.git/commitdiff
lilypond-1.5.27
authorfred <fred>
Wed, 27 Mar 2002 02:04:48 +0000 (02:04 +0000)
committerfred <fred>
Wed, 27 Mar 2002 02:04:48 +0000 (02:04 +0000)
33 files changed:
Documentation/regression-test.tely
input/regression/spacing-accidental-staffs.ly
input/regression/tie-busy-grobs.ly [new file with mode: 0644]
lily/accidental-engraver.cc
lily/chord-name.cc
lily/completion-note-heads-engraver.cc
lily/grob-pq-engraver.cc [new file with mode: 0644]
lily/include/grob-info.hh
lily/include/lily-guile.hh
lily/include/lyric-combine-music-iterator.hh
lily/include/note-column.hh
lily/include/note-spacing.hh
lily/include/paper-column.hh
lily/line-of-score.cc
lily/lyric-combine-music-iterator.cc
lily/music-iterator.cc
lily/note-column.cc
lily/note-heads-engraver.cc
lily/note-spacing-engraver.cc [new file with mode: 0644]
lily/note-spacing.cc
lily/paper-column.cc
lily/rhythmic-column-engraver.cc
lily/separating-line-group-engraver.cc
lily/spacing-wish.cc [new file with mode: 0644]
lily/staff-spacing.cc
lily/stem-engraver.cc
lily/text-item.cc
lily/translator-group.cc
ly/engraver-init.ly
scm/grob-description.scm
scm/grob-property-description.scm
scm/interface-description.scm
scm/translator-property-description.scm

index 0f7791c577248d13f890472a80787b1554d99c2f..42f5aad17e944de1e6a011e0ccb56fe708f47764 100644 (file)
@@ -165,6 +165,8 @@ Grace note do weird things with timing. Fragile.
 
 @lilypondfile[printfilename]{tie.ly}
 
+@lilypondfile[printfilename]{tie-busy-grobs.ly}
+
 @lilypondfile[printfilename]{tie-chord.ly}
 
 @lilypondfile[printfilename]{tie-accidental.ly}
index 58d1ecf1c9ebb0d99edfc6b67e2047716a1df888..175be7badeb5c68f3552c847742dc3939b54c334 100644 (file)
@@ -4,13 +4,14 @@ texidoc = "Accidentals in different staffs don't effect the
 spacing of the quarter notes here."
 }
 
-\score { \notes \relative c'' < \context Staff = SA {
+\score { \notes \relative c'' < \context Staff = SA { \time 8/4
+
 c4 c4 cis4 cis4
-c4 c4 c4 c
+cis4 cis4 cis4 cis
 
 
  }
-   { \key d \major c2 c2 c2 cis2  } >
+   { \key d \major cis2 cis2 cis2 cis!2  } >
 
    \paper { linewidth = -1. } 
  }
diff --git a/input/regression/tie-busy-grobs.ly b/input/regression/tie-busy-grobs.ly
new file mode 100644 (file)
index 0000000..719d196
--- /dev/null
@@ -0,0 +1,16 @@
+\header {
+
+texidoc = "Tie engraver uses @code{busyGrobs} to keep track of
+note heads. Test if this queue works by throwing many  mixed tuplets at it." 
+
+}
+
+\score
+{
+\notes \context Staff \relative c'' 
+ <
+  \context Voice { \voiceOne \times 2/3 { c'8~  c8~ c8~ c8~ c8~ c8 } }
+  \context Voice= VII { \voiceThree  { b,8 ~ b8 ~ b8 ~  b8 }}
+  \context Voice = VIII { \voiceTwo \times 2/5 { a,4 ~a4 ~a4~ a4~ a4 }}
+ >
+}
index 015b515e66a972bbc3b48491ced86810d5c7a6e2..0f9b126eb3f8685e87622429f1d2a789e071396a 100644 (file)
@@ -54,7 +54,7 @@ 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_;
 
@@ -155,19 +155,20 @@ Accidental_engraver::create_grobs ()
       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 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 (abs(num_caut)>abs(num)) {
-           num=num_caut;
-           cautionary=true;
-         }
+         if (abs(num_caut)>abs(num))
+           {
+             num=num_caut;
+             cautionary=true;
+           }
+         
          bool different=num<0;
          num=abs(num);
 
@@ -200,7 +201,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))
@@ -215,6 +215,8 @@ Accidental_engraver::create_grobs ()
                                         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 ());
            }
          
 
@@ -258,11 +260,9 @@ Accidental_engraver::create_grobs ()
   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_);
@@ -282,8 +282,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;
@@ -293,7 +293,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 ();      
 }
 
@@ -305,7 +305,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_))
     {
index 5595759236497b5e46ad44620b9483ac9ef7e2f5..2c0e717a89bef94498f513a3933485df340f2696 100644 (file)
@@ -27,11 +27,6 @@ Chord_name::after_line_breaking (SCM smob)
   if (to_boolean (s))
     {
       if (Paper_column::rank_i (me->column_l ()) -
-         /*
-           hmm, what's my column number in this line?
-           why doesn't this work?
-           me->line_l ()->rank_i_ > 2)
-         */
          me->line_l ()->spanned_rank_iv ()[LEFT] > 1)
        me->suicide ();
     }
index 85609c295a798272175a488d70ead6c1a88b4761..6d1157560d9cc98a9a513c93b03d3a127a30c14c 100644 (file)
 #include "score-engraver.hh"
 #include "warn.hh"
 
-/**
-  make balls and rests
+/*
+
+  How does this work?
+
+  When we catch the note, we predict the end of the note. We keep the
+  requests living until we reach the predicted end-time.
+
+  Every time process_music() is called and there are note requests, we
+  figure out how long the note to typeset should be. It should be no
+  longer than what's specified, than what is left to do and it should
+  not cross barlines.
+  
+  We copy the reqs into scratch note reqs, to make sure that we get
+  all durations exactly right.
  */
+
 class Completion_heads_engraver : public Engraver
 {
   Link_array<Item> note_p_arr_;
@@ -72,8 +85,9 @@ Completion_heads_engraver::try_music (Music *m)
     }
   else if (dynamic_cast<Busy_playing_req*> (m))
     {
-      return now_mom () < note_end_mom_;
+      return note_req_l_arr_.size ();
     }
+  
   return false;
   
 }
diff --git a/lily/grob-pq-engraver.cc b/lily/grob-pq-engraver.cc
new file mode 100644 (file)
index 0000000..fad29ac
--- /dev/null
@@ -0,0 +1,159 @@
+/*   
+  grob-pq-engraver.cc --  implement Grob_pq_engraver
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+*/
+
+#include "translator-group.hh"
+#include "engraver.hh"
+#include "grob.hh"
+#include "warn.hh"
+
+struct Grob_mom
+{
+  Grob * grob_ ;
+  Moment end_;
+  Grob_mom () {}
+  Grob_mom (Grob*gr, Moment e)
+  {
+    grob_ = gr;
+    end_ = e;
+  }
+};
+
+int compare  (Grob_mom const &a, Grob_mom const &b)
+{
+  return Moment::compare (a.end_, b.end_);
+}
+
+class Grob_pq_engraver: public Engraver
+{
+public:
+  TRANSLATOR_DECLARATIONS(Grob_pq_engraver);
+
+  Array<Grob_mom> current_grobs_;
+protected:
+  virtual void initialize ();
+  virtual void acknowledge_grob (Grob_info);
+  virtual void start_translation_timestep ();
+  virtual void stop_translation_timestep ();
+};
+
+
+Grob_pq_engraver::Grob_pq_engraver()
+{
+}
+
+
+void
+Grob_pq_engraver::initialize ()
+{
+  daddy_trans_l_->set_property ("busyGrobs", SCM_EOL); 
+}
+
+void
+Grob_pq_engraver::acknowledge_grob (Grob_info gi)
+{
+  Music  * m = gi.music_cause ();
+
+  if (m)
+    {
+      Moment n = now_mom ();
+      Moment l = m->length_mom ();
+
+      if (!l.to_bool ())
+       return ;
+      
+      if (n.grace_part_)
+       {
+         l.grace_part_ = l.main_part_;
+         l.main_part_ = 0;
+       }
+
+      current_grobs_.push (Grob_mom (gi.grob_l_, n + l));
+    }
+}
+
+void
+Grob_pq_engraver::stop_translation_timestep ()
+{
+  Moment now = now_mom();
+
+  current_grobs_.sort (&compare);
+
+  SCM busy = get_property ("busyGrobs");
+  while (gh_pair_p (busy) && *unsmob_moment (gh_caar (busy)) == now)
+    {
+      busy = gh_cdr (busy);
+    }
+  
+  SCM start = busy;
+  SCM * current_cell = &start;
+
+  int  i = 0; 
+  while (i  < current_grobs_.size ())
+    {
+      Moment stop;
+      stop.set_infinite (1);
+      
+      if (gh_pair_p (busy))
+       {
+         SCM h = gh_car (busy);
+         stop = *unsmob_moment (gh_car (h));
+       }
+
+      Moment current_stop = current_grobs_[i].end_;
+      if (current_stop <= stop)
+       {
+         SCM new_entry = gh_cons (current_stop.smobbed_copy(),
+                                  current_grobs_[i].grob_->self_scm ());
+
+         /*
+           Insert before BUSY.
+          */
+         i ++;
+         *current_cell = gh_cons (new_entry, busy);
+         current_cell = SCM_CDRLOC(*current_cell);
+       }
+      else
+       {
+         /*
+           if current_stop > stop, then stop != infty, and we
+           apparently have a next entry */
+         busy = gh_cdr (busy);
+         current_cell = SCM_CDRLOC(*current_cell);
+       }
+    }
+
+  current_grobs_.clear ();
+  daddy_trans_l_->set_property ("busyGrobs", start);
+}
+
+void
+Grob_pq_engraver::start_translation_timestep ()
+{
+ Moment now = now_mom();
+
+  SCM start_busy = get_property ("busyGrobs");
+  SCM busy = start_busy;
+  while (gh_pair_p (busy) && *unsmob_moment (gh_caar (busy)) < now)
+    {
+      programming_error ("Skipped something ?!");
+      
+      busy = gh_cdr (busy);
+    }
+
+  if (start_busy != busy)
+    daddy_trans_l_->set_property ("busyGrobs", busy);
+}
+
+
+ENTER_DESCRIPTION(Grob_pq_engraver,
+/* descr */       "Administrate when certain grobs (eg. note heads) stop playing.
+",
+/* creats*/       "",
+/* acks  */       "grob-interface",
+/* reads */       "busyGrobs",
+/* write */       "busyGrobs");
index 6d8868214c033bf31b53639ed1e0a58cef24c9ed..578c20730a05768101372fe9517a2229ae8bb8a0 100644 (file)
@@ -30,7 +30,6 @@ struct Grob_info {
     GC errors if you don't use music or grobs as a cause.
   */
   SCM cause_;
-
 public:
   Music * music_cause ();
   Link_array<Translator> origin_trans_l_arr (Translator*) const;
index 26c2a8a3001732a7ff94c2521813288dbbc52e11..7788833f4b19641dd9fa71d6f539fa59a9a641e8 100644 (file)
@@ -92,7 +92,15 @@ SCM ly_write2scm (SCM s);
 SCM ly_deep_copy (SCM);
 SCM ly_truncate_list (int k, SCM l );
 
+
+#if (__GNUC__ > 2)
+/*
+  todo: should add check for x86 as well
+ */
 #define CACHE_SYMBOLS
+#endif
+
+
 #ifdef CACHE_SYMBOLS
 
 
@@ -103,8 +111,6 @@ SCM ly_truncate_list (int k, SCM l );
  */
 SCM my_gh_symbol2scm (const char* x);
 
-// #warning: CACHE_SYMBOLS
-
 /*
   Using this trick we cache the value of gh_symbol2scm ("fooo") where
   "fooo" is a constant string. This is done at the cost of one static
index dae14c81dcbf2b159cecd4e7952370c21dbd97b1..8544673a21f1d0e1eac466c36108814325079be2 100644 (file)
@@ -25,11 +25,12 @@ protected:
   virtual Moment pending_moment () const;
   virtual void process (Moment);
   virtual Music_iterator *try_music_in_children (Music *) const;
-
+  
   virtual bool ok () const;
   virtual ~Lyric_combine_music_iterator ();
 
 private:
+  bool get_busy_status ()const ;
   Music_iterator * music_iter_p_;
   Music_iterator * lyric_iter_p_;
 };
index 5f24f7284eab18a4aa54386cab6d9e32a2fa6d63..647ac34cb74efe9383d500b503eb8bbaa0a55970 100644 (file)
@@ -29,6 +29,7 @@ public:
     JUNKME.
     */
 
+  static Grob * accidentals (Grob*me);
   static Direction dir (Grob*me);
   static Slice head_positions_interval (Grob* me);
   static Direction static_dir (Grob*);
index ed92e0651967f9de210795a50d3e2df9d31199c7..1905c72e85550fa9d5dd9666332e5b83ef9244ca 100644 (file)
@@ -15,7 +15,11 @@ source file of the GNU LilyPond music typesetter
 class Note_spacing
 {
 public:
-  static bool has_interface (Grob*);  
+  static bool has_interface (Grob*);
+
+  static Real get_spacing (Grob *me);
+
+  DECLARE_SCHEME_CALLBACK(before_line_breaking,(SCM));
 };
 
 #endif /* NOTE_SPACING_HH */
index 507ba6f0fe47fcbddad6299c35df3c29b73d6ab2..4a21edaffc888e7f349ade9dd07b10ec6b9d6d10 100644 (file)
@@ -19,9 +19,6 @@ class Paper_column : public Item
 public:
   VIRTUAL_COPY_CONS (Grob);
 
-  /*
-    Not (yet) in scm, because of messy effects when a column commits suicide.
-   */
   int  rank_i_;
   virtual void do_break_processing ();
   virtual Paper_column *column_l () const;
@@ -30,9 +27,10 @@ public:
   /// if lines are broken then this column is in #line#
   Line_of_score *line_l_;
 
-  /// which  one (left =0)
   static int rank_i (Grob*);
 
+  DECLARE_SCHEME_CALLBACK(brew_molecule, (SCM));
+  
   Paper_column (SCM);
   static bool musical_b (Grob *);
   static Moment when_mom (Grob*);
index 96f00ce5ba18578e386cf5ba10416300ed2c3304..eaadc08fa5dab1981799e7ab91fa990a2f85a909 100644 (file)
@@ -127,13 +127,16 @@ Line_of_score::output_lines ()
     }
 }
 
+
+
+
 /*
   Find the loose columns in POSNS, and drape them around the columns
   specified in BETWEEN-COLS.  */
 void
 set_loose_columns (Line_of_score* which, Column_x_positions const *posns)
 {
-  for (int i = 0; i<posns->loose_cols_.size (); i++)
+  for (int i = 0; i < posns->loose_cols_.size (); i++)
     {
       int divide_over = 1;
       Item *loose = dynamic_cast<Item*> (posns->loose_cols_[i]);
@@ -145,24 +148,30 @@ set_loose_columns (Line_of_score* which, Column_x_positions const *posns)
       
       Item * left = 0;
       Item * right = 0;
-      while (1)
+      do
        {
          SCM between = loose->get_grob_property ("between-cols");
          if (!gh_pair_p (between))
            break;
 
-         if (!left)
+
+         Item * l=dynamic_cast<Item*> (unsmob_grob (ly_car (between)));
+         Item * r=dynamic_cast<Item*> (unsmob_grob (ly_cdr (between)));
+
+         if (!(l && r))
+           break ;
+         
+         if (!left && l)
            {
-             left = dynamic_cast<Item*> (unsmob_grob (ly_car (between)));
-             left = left->column_l ();
+             left = l->column_l ();
            }
-         divide_over ++;       
-         loose = dynamic_cast<Item*> (unsmob_grob (ly_cdr (between)));
-         loose = loose->column_l ();
-       }
 
-      right = loose;
+         divide_over ++;
 
+         loose = right = r->column_l ();
+       }
+      while (1);
+      
       Real rx = right->relative_coordinate (right->get_parent (X_AXIS), X_AXIS);
       Real lx = left->relative_coordinate (left->get_parent (X_AXIS), X_AXIS);
 
index 6052b89ffd8e80577b71bfe46617d68e27449ea9..e7e7901e871316edd1c0391023be5cdcaed85eaa 100644 (file)
@@ -11,6 +11,9 @@
 #include "lyric-combine-music-iterator.hh"
 #include "lyric-combine-music.hh"
 #include "musical-request.hh"
+#include "note-head.hh"
+#include "grob.hh"
+
 
 /*
   Ugh, why static?
@@ -59,6 +62,37 @@ Lyric_combine_music_iterator::construct_children ()
   lyric_iter_p_ = get_iterator_p (m->lyrics_l ());
 }
 
+bool
+Lyric_combine_music_iterator::get_busy_status () const
+{
+  /*
+    We have to use both the request and the busyGrobs queue.  The
+    busyGrobs queue doesn't contain any notes that have started this
+    instant.  */
+  if (try_music (busy_req))
+    return true;
+  
+  Translator_group * tr = music_iter_p_->report_to_l ();
+
+  SCM grobs = tr->get_property ("busyGrobs");
+  Moment now = tr->now_mom();
+  for (; gh_pair_p (grobs); grobs = gh_cdr (grobs))
+    {
+      SCM grob = gh_cdar (grobs);
+      Moment end  =*unsmob_moment (gh_caar (grobs));
+
+      
+      /*
+       This is slightly ugh: we are now confunding the frontend
+       (iterators) and the backend (note heads) */
+      if (end > now
+         && Note_head::has_interface (unsmob_grob (grob)))
+       return true;
+    }
+
+  return false;
+}
+
 void
 Lyric_combine_music_iterator::process (Moment m)
 {
@@ -68,8 +102,7 @@ Lyric_combine_music_iterator::process (Moment m)
   
   music_iter_p_->process (m);
 
-  bool busy = try_music (busy_req);
-  if (busy)
+  if ( get_busy_status ())
     {
       bool melisma_b = try_music (melisma_playing_req);
       if (!melisma_b)
@@ -101,10 +134,10 @@ Lyric_combine_music_iterator::~Lyric_combine_music_iterator ()
 Lyric_combine_music_iterator::Lyric_combine_music_iterator (Lyric_combine_music_iterator const & src)
     : Music_iterator (src)
 {
-
   lyric_iter_p_ = src.lyric_iter_p_ ? src.lyric_iter_p_->clone () : 0;
   music_iter_p_ = src.music_iter_p_ ? src.music_iter_p_->clone () : 0;  
 }
+
 Music_iterator*
 Lyric_combine_music_iterator::try_music_in_children (Music *m) const
 {
index f27f2f0d7775dc839427044aa4f3a44ba3d52228..4135a6c98864a3dae82dff11f5812666df3d09f6 100644 (file)
@@ -161,6 +161,12 @@ Music_iterator::get_iterator_p (Music *m) const
   return p;
 }
 
+/*
+  TODO: rename to prevent confusion between Translator::try_music and
+  Iterator::try_music
+  
+ */
+
 Music_iterator*
 Music_iterator::try_music (Music *m) const
 {
index 56a29d08a3d313501e0d8db8241e2fe28018206a..95b2cd67ed9f8ace6e4e59cff8aa628d6a7d4894 100644 (file)
@@ -37,7 +37,6 @@ Note_column::shift_compare (Grob *const &p1, Grob *const&p2)
 void
 Note_column::set_interface (Grob* me)
 {
-  me->set_grob_property ("note-heads", SCM_EOL);  
   me->set_interface (ly_symbol2scm ("note-column-interface"));
   
   Axis_group_interface::set_interface (me);
@@ -140,3 +139,21 @@ Note_column::has_interface (Grob*me)
 {
   return me && me->has_interface (ly_symbol2scm ("note-column-interface"));
 }
+
+/*
+  Return the first Accidentals grob that we find in a note-head. 
+ */
+Grob* 
+Note_column::accidentals (Grob *me)
+{
+  SCM heads = me->get_grob_property ("note-heads");
+  for (;gh_pair_p (heads); heads =gh_cdr (heads))
+    {
+      Grob * h = unsmob_grob (gh_car (heads));
+      Grob *a = h ? unsmob_grob(h->get_grob_property ("accidentals")) : 0;
+      if (a)
+       return a;
+    }
+
+  return 0;
+}
index 2a9b5e49e450ca59eb1189379d2de90e9e7dc7b4..96938212e46312f81c9b7e2c97b221af631e1e34 100644 (file)
@@ -24,7 +24,7 @@ class Note_heads_engraver : public Engraver
   
   Link_array<Item> dot_p_arr_;
   Link_array<Note_req> note_req_l_arr_;
-  Moment note_end_mom_;
+
 public:
   TRANSLATOR_DECLARATIONS(Note_heads_engraver);
 
@@ -47,14 +47,13 @@ Note_heads_engraver::try_music (Music *m)
   if (Note_req * n =dynamic_cast <Note_req *> (m))
     {
       note_req_l_arr_.push (n);
-      note_end_mom_  = note_end_mom_ >? now_mom () + m->length_mom ();
-      
       return true;
     }
   else if (dynamic_cast<Busy_playing_req*> (m))
     {
-      return now_mom () < note_end_mom_;
+      return note_req_l_arr_.size ();
     }
+  
   return false;
 }
 
diff --git a/lily/note-spacing-engraver.cc b/lily/note-spacing-engraver.cc
new file mode 100644 (file)
index 0000000..47b11ae
--- /dev/null
@@ -0,0 +1,99 @@
+#if 0
+/*   
+  note-spacing-engraver.cc --  implement  Note_spacing_engraver.
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+*/
+
+#include "grob.hh"
+#include "moment.hh"
+#include "engraver.hh"
+#include "note-spacing.hh"
+#include "note-column.hh"
+
+/*
+  Originally, we tried to have this functionality at Staff_level
+  
+  - by simply using the sequence of Separation-item as
+  spacing-sequences. Unfortunately, this fucks up if there are
+  different kinds of tuplets combined (8th and 8ths triplets combined
+  made the program believe there were 1/12 th notes.).
+
+
+  - We also created them from Rhythmic_column_engraver, but this has
+  the problem that voices can appear and disappear at will, leaving
+  lots of loose ends (the StaffSpacing don't know where to connect the
+  last note of the voice on the right with)
+  
+ */
+
+struct Grob_moment_tuple
+{
+  Link_array<Grob> current_heads_;
+  Link_array<Grob> todo_heads_;
+  
+  Moment length_;
+  
+  static int time_compare (Grob_moment_tuple const &a, Grob_moment_tuple const &b)
+  {
+    return Moment::compare (a.length_, b.length_);
+  }
+};
+
+class Note_spacing_engraver : public Engraver
+{
+public:
+  TRANSLATOR_DECLARATIONS(Note_spacing_engraver);
+
+
+protected:
+  Array<Grob_moment_tuple> lengths_found_;
+
+  virtual void acknowledge_grob (Grob_info);
+};
+
+Note_spacing_engraver::Note_spacing_engraver()
+{
+}
+
+
+void
+Note_spacing_engraver::acknowledge_grob (Grob_info gi)
+{
+  if (Note_head::has_interface (gi.grob_l_))
+    {
+      Music *m = gi.music_cause();
+      Moment now = now_mom ();
+      Moment len = m->length_mom(); 
+      if (now.grace_part_ && len.main_part_)
+       {
+         len.grace_part_ += len.main_part_;
+         len.main_part_ = 0;
+       }
+      
+      for (int  i=0; i <  
+    }
+  Note_column::has_interface (gi.grob_l_))
+    {
+      Grob *head  =Note_column::first_head (gi.grob_l_);
+
+      head->
+    }
+}
+
+
+
+ENTER_DESCRIPTION(Note_spacing_engraver,
+/* descr */       "This engraver creates spacing objects. It should be placed at staff
+level, but will also function at voice level.
+
+",
+/* creats*/       "NoteSpacing",
+/* acks  */       "rhythmic-column-interface",
+/* reads */       "",
+/* write */       "");
+
+#endif
index 81eb2aa03bb73d822732c4247527ccc8930bc0cf..0628ffab827b7a675b54ebfb2ff99d8bfdb3522d 100644 (file)
@@ -1,17 +1,88 @@
 /*   
-note-spacing.cc --  implement 
+  note-spacing.cc -- implement Note_spacing
 
-source file of the GNU LilyPond music typesetter
+  source file of the GNU LilyPond music typesetter
 
-(c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+*/
 
- */
 
+#include "paper-column.hh"
+#include "item.hh"
+#include "moment.hh"
 #include "note-spacing.hh"
 #include "grob.hh"
+#include "note-column.hh"
+#include "warn.hh"
 
 bool
 Note_spacing::has_interface (Grob* g)
 {
   return g && g->has_interface (ly_symbol2scm ("note-spacing-interface"));
 }
+
+
+
+Real
+Note_spacing::get_spacing (Grob *me)
+{
+  Drul_array<SCM> props(me->get_grob_property ("left-items"),
+                       me->get_grob_property ("right-items"));
+  Direction d = LEFT;
+  Drul_array<Interval> extents;
+  do
+    {
+      for (SCM  s = props[d]; gh_pair_p (s); s = gh_cdr (s))
+       {
+         Item * it= dynamic_cast<Item*> (unsmob_grob (gh_car(s)));
+         extents[d].unite (it->extent (it->column_l (), X_AXIS));
+
+         if (d == RIGHT)
+           {
+             Grob * accs = Note_column::accidentals (it);
+             if (accs)
+               extents[d].unite (accs->extent (it->column_l (), X_AXIS));
+           }
+       }
+
+      if (extents[d].empty_b ())
+       extents[d] = Interval (0,0);
+    }
+  while (flip (&d) != LEFT);
+
+  /*
+    
+    What's sticking out at the left of the right side has less
+    influence.
+
+  */
+  Real dx= extents[LEFT][RIGHT] - 0.5 * extents[RIGHT][LEFT];
+  return dx;
+}
+
+
+MAKE_SCHEME_CALLBACK(Note_spacing, before_line_breaking, 1)
+SCM
+Note_spacing::before_line_breaking (SCM g)
+{
+  Grob * me = unsmob_grob (g);
+  SCM right = me->get_grob_property ("right-items");
+
+  if (gh_pair_p (right))
+    right = gh_car (right);
+  
+  Grob *right_grob = unsmob_grob (right);
+
+  Item * ri = dynamic_cast<Item*> (right_grob);
+  if (!ri)
+    {
+      int r = Paper_column::rank_i (dynamic_cast<Item*>(me)->column_l ());
+      programming_error (_f("Spacing wish column %d has no right item.", r));
+    }
+  else
+    {
+      me->set_grob_property ("right-column", ri->column_l ()->self_scm());
+    }
+  
+  return SCM_UNSPECIFIED;
+}
index 14774ed651be5a0fa4d2f2fd844e18af457a2af5..789a9cfa7362f83c2b9ac2983b3af3209cdc149d 100644 (file)
@@ -5,12 +5,32 @@
 
   (c)  1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
 */
+
 #include "moment.hh"
 #include "paper-column.hh"
 #include "paper-score.hh"
 #include "debug.hh"
 #include "axis-group-interface.hh"
 #include "spaceable-grob.hh"
+#include "molecule.hh"
+#include "text-item.hh"
+#include "lookup.hh"
+#include "font-interface.hh"
+
+
+/*
+  Paper_columns form the top-most item parent. (The Paper_columns X
+  parent is Line_of_score, which is a spanner.)
+
+  Paper_columns form the units for the spacing engine. They are
+  numbered, the first (leftmost) is column 0. Numbering happens before
+  line-breaking, and columns are not renumbered after line breaking.
+
+  Since many columns go unused, you should only use the rank field to
+  get ordering information.  Two adjacent columns may have
+  non-adjacent numbers.
+  
+ */
 
 void
 Paper_column::do_break_processing ()
@@ -73,6 +93,7 @@ Paper_column::musical_b (Grob *me)
   
 }
   
+
 bool
 Paper_column::used_b (Grob*me)
 {
@@ -80,3 +101,29 @@ Paper_column::used_b (Grob*me)
     || gh_pair_p (me->get_grob_property ("bounded-by-me"))
     ;
 }
+
+/*
+  Print a vertical line and  the rank number, to aid debugging.  
+ */
+
+MAKE_SCHEME_CALLBACK(Paper_column,brew_molecule,1);
+SCM
+Paper_column::brew_molecule (SCM p)
+{
+  Grob *me = unsmob_grob (p);
+
+  String r = to_str (Paper_column::rank_i (me));
+  SCM properties = Font_interface::font_alist_chain (me);
+  
+  Molecule t = Text_item::text2molecule (me, ly_str02scm (r.ch_C()),
+                                        properties);
+  t.align_to (X_AXIS, CENTER);
+  t.align_to (Y_AXIS, DOWN);
+  
+  Molecule l = Lookup::filledbox (Box (Interval (-0.01, 0.01),
+                                      Interval (-2, -1)));
+
+  t.add_molecule (l);
+  return t.smobbed_copy ();                                            
+}
+
index c87409c450567a0dc6311bc46077f85475362f4f..84bd2ae16c8549947405b4669172d9244665d326 100644 (file)
@@ -58,15 +58,6 @@ Rhythmic_column_engraver::create_grobs ()
          note_column_ = new Item (get_property ("NoteColumn"));
          Note_column::set_interface (note_column_);
          announce_grob (note_column_, 0);
-
-         spacing_ = new Item (get_property ("NoteSpacing"));
-         spacing_->set_grob_property ("left-item", note_column_->self_scm ());
-         announce_grob (spacing_, 0);
-
-         if (last_spacing_)
-           {
-             last_spacing_->set_grob_property ("right-item" , note_column_->self_scm ());
-           }
        }
 
       for (int i=0; i < rhead_l_arr_.size (); i++)
index fc8679494ff79591bd4451b13f6c0618f8f710dd..57100c952ec5402b9439fca66beb55a8107ca6ae 100644 (file)
 #include "axis-group-interface.hh"
 #include "note-spacing.hh"
 
+
+struct Spacings
+{
+  Item * staff_spacing_;
+  Link_array<Item> note_spacings_;
+
+  Spacings ()
+  {
+    staff_spacing_ = 0;
+  }
+
+  bool empty( )const
+  {
+    return !staff_spacing_ && !note_spacings_.size (); 
+  }
+  void clear () {
+    staff_spacing_ = 0;
+    note_spacings_.clear();
+  }
+};
+
 class Separating_line_group_engraver : public Engraver
 {
 protected:
@@ -22,9 +43,8 @@ protected:
   Item * musical_malt_p_;
   Item * last_musical_malt_p_;
 
-  Item * last_note_spacing_;
-  Item * current_note_spacing_;
-  Item * staff_spacing_;
+  Spacings current_spacings_;
+  Spacings last_spacings_;
   
   Spanner * sep_span_p_;
   
@@ -32,16 +52,13 @@ protected:
   virtual void initialize ();
   virtual void finalize ();
   virtual void stop_translation_timestep ();
+  virtual void start_translation_timestep ();  
 public:
   TRANSLATOR_DECLARATIONS(Separating_line_group_engraver);
 };
 
 Separating_line_group_engraver::Separating_line_group_engraver ()
 {
-  last_note_spacing_ = 0;
-  current_note_spacing_ = 0;
-  staff_spacing_ =0;
-  
   sep_span_p_ = 0;
   break_malt_p_ = 0;
   musical_malt_p_ =0;
@@ -59,9 +76,21 @@ Separating_line_group_engraver::initialize ()
 void
 Separating_line_group_engraver::finalize ()
 {
-  sep_span_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentCommandColumn")));
+  SCM ccol = get_property ("currentCommandColumn");
+  sep_span_p_->set_bound (RIGHT, unsmob_grob (ccol));
   typeset_grob (sep_span_p_);
   sep_span_p_ =0;
+
+  for  (int i= 0 ; i < last_spacings_.note_spacings_.size(); i++)
+    {
+      last_spacings_.note_spacings_[i]->set_grob_property ("right-items", gh_cons (ccol, SCM_EOL));
+    }
+
+  if(last_spacings_.staff_spacing_
+     && last_spacings_.staff_spacing_->column_l () == unsmob_grob (ccol))
+    {
+      last_spacings_.staff_spacing_->suicide ();
+    }
 }
 
 void
@@ -77,7 +106,7 @@ Separating_line_group_engraver::acknowledge_grob (Grob_info i)
 
   if (Note_spacing::has_interface (it)) 
     {
-      current_note_spacing_ =  it;
+      current_spacings_.note_spacings_.push (it);
       return ;
     }
   
@@ -95,19 +124,38 @@ Separating_line_group_engraver::acknowledge_grob (Grob_info i)
 
       if (p_ref_ == break_malt_p_)
        {
-         staff_spacing_ = new Item (get_property ("StaffSpacing"));
-         staff_spacing_->set_grob_property ("left-item", break_malt_p_->self_scm ());
-         announce_grob (staff_spacing_, 0);
-
-         if (last_note_spacing_)
-           last_note_spacing_->set_grob_property ("right-item",
-                                                  break_malt_p_->self_scm ());
+         Item *it  = new Item (get_property ("StaffSpacing"));
+         current_spacings_.staff_spacing_ = it;
+         it->set_grob_property ("left-items", gh_cons (break_malt_p_->self_scm (), SCM_EOL));
+         
+         announce_grob (it, 0);
+
+         if (int i = last_spacings_.note_spacings_.size ())
+           {
+             SCM break_malt = gh_cons (break_malt_p_->self_scm (), SCM_EOL);
+             for (; i--;)
+               last_spacings_.note_spacings_[i]
+                 ->set_grob_property ("right-items",break_malt);
+                                    
+           }
+         else if (last_spacings_.staff_spacing_)
+           {
+             
+             last_spacings_.staff_spacing_->set_grob_property ("right-items",
+                                                               gh_cons (break_malt_p_->self_scm(), SCM_EOL));
+           }
        }
     }
 
   Separation_item::add_item (p_ref_,it);
 }
 
+void
+Separating_line_group_engraver::start_translation_timestep ()
+{
+
+}
+
 void
 Separating_line_group_engraver::stop_translation_timestep ()
 {
@@ -119,23 +167,30 @@ Separating_line_group_engraver::stop_translation_timestep ()
       break_malt_p_ =0;
     }
 
-  if (staff_spacing_)
+  if (Item * sp = current_spacings_.staff_spacing_)
     {
+      /*
+       TODO: should really look at the left-items of following
+       note-spacing grobs.
+       */
       if (musical_malt_p_)
-       staff_spacing_->set_grob_property ("right-item", musical_malt_p_->self_scm());
+       sp->set_grob_property ("right-items", musical_malt_p_->self_scm());
+
+      typeset_grob (sp);
+    }
 
-      typeset_grob (staff_spacing_);
-      staff_spacing_ = 0;
+  if (!current_spacings_.empty ())
+    {
+      last_spacings_ = current_spacings_;
     }
+
+  current_spacings_.clear ();
   
   if (musical_malt_p_)
     {
       Separating_group_spanner::add_spacing_unit (sep_span_p_, musical_malt_p_);
       typeset_grob (musical_malt_p_);
     }
-
-  last_note_spacing_ = current_note_spacing_ ;
-  current_note_spacing_ =0 ;
   
   musical_malt_p_ =0;
 }
diff --git a/lily/spacing-wish.cc b/lily/spacing-wish.cc
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
index 771760ca52929f4898b60dc717c6156e53fe8480..a662f541331e5ea5ade65188b2b6f662c28e4e40 100644 (file)
@@ -15,3 +15,4 @@ Staff_spacing::has_interface (Grob* g)
 {
   return g && g->has_interface (ly_symbol2scm ("staff-spacing-interface"));
 }
+
index 5ab49f9227d321d3e64c8e29f3996093a0eaaf4a..aba73c027fe77d0a6ef2717649863427b646362a 100644 (file)
@@ -105,6 +105,10 @@ Stem_engraver::acknowledge_grob (Grob_info i)
                                                gh_int2scm (tremolo_flags));
                }
            }
+
+         /*
+           We announce the cause of the head as cause of the stem.
+           The stem needs a rhythmic structure to fit it into a beam.  */
          announce_grob (stem_p_, i.music_cause ());
        }
 
index e4320a3dafee35193f2d17989dddc2f79335f832..1f83982d06538ccd11996d9f5b2df431dd387b5c 100644 (file)
@@ -122,9 +122,18 @@ Text_item::lookup_text (Grob *me, Font_metric*fm, SCM text)
   return Molecule (fm->text_dimension (ly_scm2string (text)), list);
 }
 
+/*
+  TODO:
+
+  DOCME.
+
+
+  MARKUP_TEXT must be compound (may not be simple string.)
+  
+ */
 Molecule
 Text_item::markup_text2molecule (Grob *me, SCM markup_text,
-                              SCM alist_chain)
+                                SCM alist_chain)
 {
   SCM sheet = me->paper_l ()->style_sheet_;
   SCM f = ly_cdr (scm_assoc (ly_symbol2scm ("markup-to-properties"), sheet));
index aac575c38bd7e33085857ee39c567e951e9315a3..34e8d0c63e5a81d3507e2c331af5440bbc1e7a5f 100644 (file)
@@ -247,7 +247,7 @@ static void
 static_each (SCM list, Method_pointer method)
 {
   for (SCM p = list; gh_pair_p (p); p = ly_cdr (p))
- (unsmob_translator (ly_car (p))->*method) ();
   (unsmob_translator (ly_car (p))->*method) ();
   
 }
 
index 003d380d3f0a84db1387e5c86ccc227f0168773f..0e1f1e718108c0afb33b105708d3c38f6042aef6 100644 (file)
@@ -31,7 +31,8 @@ StaffContext=\translator {
        \consists "Accidental_engraver"
        \consists "Piano_pedal_engraver"
        \consists "Instrument_name_engraver"
-
+       \consists "Grob_pq_engraver"
+       
        \consistsend "Axis_group_engraver"
        
        MinimumVerticalExtent = #'(-4 . 4)
index fd68506d0da1958a4f7d031e7b035ddb1ea4a85b..3938da7413f5b62d9a08930efee1018ccb45bea1 100644 (file)
                 ))
              
        (SpacingSpanner . (
-               (spacing-procedure . ,Spacing_spanner::set_springs)
+               (spacing-procedure . ;; ,Third_spacing_spanner::set_springs
+                                       ,Spacing_spanner::set_springs
+                                  )
                (stem-spacing-correction . 0.5)
                (grace-space-factor . 0.8)
 
index 0df5480c15c2bb0bbce27f0810e8ec268f4230df..0d018c3d971ada032d313ef83de935aa5e0b1e89 100644 (file)
@@ -248,7 +248,8 @@ FIXME: also pair? (cons LEFT RIGHT)
 (grob-property-description 'non-default boolean? "not set because of existence of a bar?.")
 (grob-property-description 'note-character string? "character to print in a note head.")
 (grob-property-description 'note-width number? "unit for horizontal translation, measured in staff-space.")
-(grob-property-description 'number-gap number? "size of the gap for the number in a tuplet.")
+(grob-property-description 'note-heads list? "List of note head grobs")
+(grob-property-description 'number-gap number? "size of the gap for tohe number in a tuplet.")
 (grob-property-description 'old-accidentals list? "list of (pitch, accidental) pairs.")
 (grob-property-description 'origin ly-input-location? "location in input file of the definition.")
 (grob-property-description 'outer-stem-length-limit number? "catch
index 1e2fda7b37705f4daabc44b4cdc3e8a08bfe1793..ce5f960c3fecec7ebf85060bdb9213d8cc30bb75 100644 (file)
  'note-column-interface
  "Stem and noteheads combined"
  '(
+   note-heads
    horizontal-shift 
    force-hshift 
    ))
index f5b1adaf40f129d631049c7437709ca998aa6d53..93aabd8cdd575c33576d2a7e083019f7ce372161 100644 (file)
@@ -141,6 +141,10 @@ key signatures after the bar lines:
        )
 @end example
 ")
+(translator-property-description 'busyGrobs list? "
+a queue of (END-MOMENT . GROB) conses. This is for internal (C++) use only.
+Use at your own risk. 
+")
 (translator-property-description 'centralCPosition number? "Place of the central C. Usually determined by looking at clefPosition and clefGlyph.")
 (translator-property-description 'changeMoment moment-pair? "duration that voices are examined for differences, when part-combining.  Usually unset or zero when combining threads into one voice, and 1 (or the duration of one measure) when combining voices into one staff.")
 (translator-property-description 'chordChanges boolean? "Only show changes in chords scheme?")