]> git.donarmstrong.com Git - lilypond.git/commitdiff
release: 1.5.27 release/1.5.27
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Mon, 24 Dec 2001 13:50:08 +0000 (14:50 +0100)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Mon, 24 Dec 2001 13:50:08 +0000 (14:50 +0100)
52 files changed:
ChangeLog
Documentation/regression-test.tely
Documentation/user/converters.itely
Documentation/user/refman.itely
INSTALL.txt
VERSION
input/regression/spacing-accidental-staffs.ly
input/regression/tie-busy-grobs.ly [new file with mode: 0644]
input/test/staff-size.ly
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/third-try.cc
lily/tie-engraver.cc
lily/translator-group.cc
lilypond-mode.el
ly/drumpitch-init.ly
ly/engraver-init.ly
make/lilypond.redhat.spec.in
make/lilypond.suse.spec.in
make/out/lilypond.lsm
make/out/lilypond.mandrake.spec
make/out/lilypond.redhat.spec
make/out/lilypond.suse.spec
scm/font.scm
scm/grob-description.scm
scm/grob-property-description.scm
scm/interface-description.scm
scm/translator-property-description.scm
scripts/lilypond-book.py
tex/lilyponddefs.tex

index ca802f93a58334ca3d3f22186e404cacd468cffa..ded1e51b59177d7bab1f3383167d771fa22859fc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,16 +1,56 @@
-2001-12-16  Jan Nieuwenhuizen  <janneke@gnu.org>
+2001-12-24  Han-Wen Nienhuys  <hanwen@cs.uu.nl>
+
+       * VERSION: 1.5.27 released.
+
+       * Documentation/user/refman.itely (Bar numbers): added bar number
+       documentation.
+
+       * scm/font.scm (make-style-sheet): Fixes to make staff-sizes work
+       again.
+
+2001-12-22  Mats Bengtsson  <matsb@matsb@s3.kth.se>
+
+       * tex/lilyponddefs.tex: Make sure interscorelinefill=1 doesn't
+       spread the last few lines all over the last page of a score.
+
+2001-12-24  Han-Wen  <hanwen@cs.uu.nl>
+
+       * lily/third-try.cc: 3rd try at revising spacing
+       engine. Not yet finished.
+
+       * lily/paper-column.cc (brew_molecule): print debugging marks on a
+       paper-column.
+
+       * lily/tie-engraver.cc (class Tie_engraver): Use busyGrobs for
+       collecting past note heads.
+
+       * lily/note-heads-engraver.cc (try_music): Remove end_mom_
+       stuff.
 
+       * lily/grob-pq-engraver.cc (class Grob_pq_engraver): New file, new
+       class. Keep a queue of grobs that are still playing in busyGrobs. 
+
+       * lily/lyric-combine-music-iterator.cc (get_busy_status): New
+       function. Use busyGrobs to detect playing notes.
+       
+2001-12-16  Jan Nieuwenhuizen  <janneke@gnu.org>
        * Documentation/topdocs/INSTALL.texi: Added note about broken
        python-2.1.  Updated note for Debian's broken (well, broken for
        our use anyway) tex configuration.
-
+       
        * scripts/lilypond-book.py (re_dict): python2.2 fix.
-
+       
        * stepmake/stepmake/c++-rules.make ($(outdir)/%.hh): 
        ($(outdir)/%.cc): Adapted to bison-1.30; added bison < 1.30 fix.
-
+       
        * scripts/lilypond-book.py (bounding_box_dimensions): Bugfix.
        (But left margin of png's still misses a few pixels.  Arg.)
+       
+2001-12-16  Heikki Junes  <hjunes@cc.hut.fi>
+
+       * lilypond-mode.el (LilyPond-command-next-midi): Make
+       possible to kill midi-process (using "C-c C-m").
 
 2001-12-14  Han-Wen  <hanwen@cs.uu.nl>
 
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 1d1e75b1b921c669c90f8fa9af45b89f384a6428..dceade26385e9d71e27d18a034712f21839a6f61 100644 (file)
@@ -16,6 +16,9 @@
 @node midi2ly
 @section midi2ly
 
+@cindex MIDI
+@cindex importing MIDI
+
 Midi2ly translates a MIDI input file to a LilyPond source file. MIDI
 (Music Instrument Digital Interface) is a standard for digital
 instruments: it specifies cabling, a serial protocol and a file format.
@@ -80,6 +83,10 @@ C to parse the MIDI files.
 @node etf2ly
 @section etf2ly
 
+@cindex ETF
+@cindex enigma
+@cindex Finale
+@cindex Coda Technology
 
 ETF (Enigma Transport Format) is a format used by Coda Music
 Technology's Finale product. This program will convert part of an ETF
@@ -117,6 +124,9 @@ etf2ly.
 ABC is a fairly simple ASCII based format. It is described at
 @uref{http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt}.
 
+@cindex ABC
+@cindex Importing ABC
+
 @subsection Invoking abc2ly
 
 @example
@@ -172,6 +182,9 @@ abc2ly ignores the ABC beaming.
 PMX is a MusiXTeX preprocessor written by Don Simons, see
 @uref{http://icking-music-archive.sunsite.dk/Misc/Music/musixtex/software/pmx/}.
 
+@cindex PMX
+@cindex MusiXTeX
+@cindex Simons, Don
 
 @subsection Invoking pmx2ly
 
@@ -196,6 +209,9 @@ version information
 @node musedata2ly
 @section musedata2ly
 
+@cindex Musedata
+@cindex CCARH
+
 Musedata (@uref{http://www.musedata.org/}) is an electronic library of
 classical music scores, currently comprising about 800 composition
 dating from 1700 to 1825.  The music is encoded in so-called Musedata
@@ -234,6 +250,9 @@ MUP (Music Publisher) is a shareware music notation program by Arkkra
 Enterprises.  It is also the name of the input format.  Mup2ly will
 convert part of a Mup file to a ready-to-use LilyPond file.
 
+@cindex MUP
+@cindex Arkkra
+
 @subsection Invoking mup2ly
 
 @example
index 12adf9a8c4d4c93d1ae8f73327f6c8ba79a0b766..2dbad10f96ad0e131354e80c416f8f873e02d4cf 100644 (file)
@@ -141,7 +141,7 @@ brevity we omit obligatory lint such as @code{\score} blocks and
 * Notes::                       
 * Pitches::                     
 * Rests::                       
-* Skips::
+* Skips::                       
 * Durations::                   
 * Ties::                        
 * Tuplets::                     
@@ -2512,8 +2512,20 @@ The grob is @internalsref{RehearsalMark} in @internalsref{Score} context. See
 @node Bar numbers
 @subsection Bar numbers
 
-Bar numbers (grob: @internalsref{BarNumber}) are printed at the start of the
-line. See @code{input/test/boxed-molecule.ly} for boxed bar numbers.
+
+@cindex bar numbers
+@cindex measure numbers
+@cindex currentBarNumber
+
+Bar numbers are @internalsref{BarNumber} grobs.  They are printed at the
+start of the line.  The number itself is a property that can be set by
+modifying the @code{currentBarNumber} property, i.e.
+@example
+  \property Score.currentBarNumber = #217
+@end example
+
+If you want boxed bar numbers, see the example file
+@code{input/test/boxed-molecule.ly}.
 
 @refbugs
 
index 176a50e06294a188b13bc3f047654e60773d3ee2..058e0d97e771b06880d166e4fba5b2ed33cb6c4e 100644 (file)
@@ -27,6 +27,7 @@ INSTALL - compiling and installing GNU LilyPond
     Debian GNU/Linux
   Problems
     FLex-2.5.4a and gcc-3.0
+    Python-2.1[.1]
     Linux-2.4.0, Guile-1.4 -with-threads
     NetBSD
     Solaris:
@@ -128,9 +129,10 @@ Compilation
    * A reasonably new C++ compiler:  EGCS 1.1, GCC 2.95.2 or newer.
      Check out the gcc site (ftp://ftp.gnu.org/gnu/gcc/).
 
-   * Python 1.5, Check out the python website (http://www.python.org).
+   * Python (version 1.5 or newer; not 2.1.x) Check out the python
+     website (http://www.python.org).
 
-   * GUILE 1.3.4 or newer,  check out the GUILE webpage
+   * GUILE 1.4 or newer,  check out the GUILE webpage
      (http://www.gnu.org/software/guile/guile.html).  Version 1.4 is
      recommended for better performance.
 
@@ -388,18 +390,28 @@ running `apt-get' as root:
 
    Debian's TeX installation is a bit short on memory, you may want to
 increase it like this:
-     --- /etc/texmf/texmf.cnf.dpkg     Sun Jan 28 14:12:14 2001
-     +++ /etc/texmf/texmf.cnf  Fri Apr 27 11:09:35 2001
-     @ -384,8 +384,8 @
+     --- texmf.cnf.orig        Sun Dec 16 23:47:07 2001
+     +++ texmf.cnf     Sun Dec 16 23:46:34 2001
+     @ -411,8 +411,8 @
       main_memory.context = 1500000
       main_memory.mpost = 1000000
       main_memory = 263000 % words of inimemory available; also applies to inimf&mp
      -extra_mem_top = 0    % extra high memory for chars, tokens, etc.
      -extra_mem_bot = 0    % extra low memory for boxes, glue, breakpoints, etc.
-     +extra_mem_top = 100000    % extra high memory for chars, tokens, etc.
-     +extra_mem_bot = 100000    % extra low memory for boxes, glue, breakpoints, etc.
+     +extra_mem_top = 1000000    % extra high memory for chars, tokens, etc.
+     +extra_mem_bot = 1000000    % extra low memory for boxes, glue, breakpoints, etc.
      
-      obj_tab_size.context = 256000
+      obj_tab_size.context = 300000
+     
+     @ -430,7 +430,7 @
+      % Max number of characters in all strings, including all error messages,
+      % help texts, font names, control sequences.  These values apply to TeX and MP.
+      pool_size.context = 750000
+     -pool_size = 125000
+     +pool_size = 250000
+      % Minimum pool space after TeX/MP's own strings; must be at least
+      % 25000 less than pool_size, but doesn't need to be nearly that large.
+      string_vacancies.context = 45000
 
    You could also export `extra_mem_top' and `extra_mem_bot' as
 environment variables if you do not want to or cannot modify
@@ -507,6 +519,12 @@ LilyPond with gcc-3.0 you may do:
 
    Note that this is fixed in Debian/unstable for flex >= 2.5.4a-13.
 
+Python-2.1[.1]
+--------------
+
+   Regular expressions are broken in Python 2.1.[.1], either upgrade or
+downgrade python.
+
 Linux-2.4.0, Guile-1.4 -with-threads
 ------------------------------------
 
diff --git a/VERSION b/VERSION
index 8c2c4cc4854a5ae0165712ef847082ffef4a8c4a..c939db38f530fde0d45b9743e924db1bd0e6ce70 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1,8 +1,8 @@
 PACKAGE_NAME=LilyPond
 MAJOR_VERSION=1
 MINOR_VERSION=5
-PATCH_LEVEL=26
-MY_PATCH_LEVEL=jcn1
+PATCH_LEVEL=27
+MY_PATCH_LEVEL=
 
 # use the above to send patches: MY_PATCH_LEVEL is always empty for a
 # released version.
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 854d6cc4ab8959a3415b3618f2f81d0e4455a57d..3dbe63ee081f07e1eb63283caa74b7d9eb70ce89 100644 (file)
@@ -1,16 +1,19 @@
 \version "1.3.146"
 \score {
   \notes \relative c' < \context Voice {
-       \property Staff.staffSpace = #10
+   \context Staff \outputproperty #(make-type-checker 'staff-symbol-interface)
+       #'staff-space = #(/ 16 20)
+
        \property Staff.fontSize = #-1
        \property Voice.fontSize = #-1
        
-       \property Voice . dynamicDirection = \up \stemDown
-%\key gis \major
+       \dynamicUp\stemDown
+
+       %\key gis \major
        c8 d [e f g a] b c \ff
   }
 
-\context Staff = VB {  \property Voice . dynamicDirection = \down c,,4 \ff c c c  }
+\context Staff = VB {  \dynamicDown c,,4 \ff c c c  }
 
 >
 \paper { linewidth = -1. }
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 b66e5f61290a18381697e5772d340e13a489d130..bfc1a34ac8597f9e4229f32d5a7ae8c2059bb3a7 100644 (file)
   (c) 1999--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
   
  */
+#include "line-of-score.hh"
+#include "paper-score.hh"
+#include "paper-column.hh"
+#include "item.hh"
+#include "moment.hh"
+#include "note-spacing.hh"
+#include "misc.hh"
+#include "warn.hh"
 
+/*
+  paper-column:
 
-#include "paper-column.hh"
+    right-neighbors = List of spacing-wish grobs that are close to the
+    current column.
+  
+ */
 
 
 class Third_spacing_spanner
 {
 public:
-  void find_loose_columns () {}
-  void prune_loose_colunms (Link_array<Grob> *cols);
-  void find_loose_columns (Link_array<Grob> cols);
+  static Real default_bar_spacing (Grob*,Grob*,Grob*,Moment)  ;
+  static Real note_spacing (Grob*,Grob*,Grob*,Moment)  ;
+  static Real get_duration_space (Grob*,Moment dur, Moment shortest) ;
+  
+  static   void breakable_column_spacing (Item* l, Item *r);
+  static  void find_loose_columns () {}
+  static  void prune_loose_colunms (Link_array<Grob> *cols);
+  static void find_loose_columns (Link_array<Grob> cols);
+  static void set_explicit_neighbor_columns (Link_array<Grob> cols);
+  static void set_implicit_neighbor_columns (Link_array<Grob> cols);
+  static void do_measure (Grob*me,Link_array<Grob> *cols);
+  DECLARE_SCHEME_CALLBACK (set_springs, (SCM ));
 };
 
 
 
+/*
+  Return whether COL is fixed to its neighbors by some kind of spacing
+  constraint.
+*/
 static bool
-fixed_neighbor (Grob *col, SCM nm)
+loose_column (Grob *l, Grob *c, Grob *r) 
 {
-  SCM l = col->internal_get_grob_property (nm);
+  SCM rns = c->get_grob_property ("right-neighbors");
+  SCM lns = c->get_grob_property ("left-neighbors");
+
+ /*
+    If this column doesn't have a proper neighbor, we should really
+    make it loose, but spacing it correctly is more than we can
+    currently can handle.
+
+    (this happens in the following situation:
+
+       |
+       |    clef G 
+      *
+
+       |               |      ||
+       |               |      || 
+      O               O       ||
+
+
+    the column containing the clef is really loose, and should be
+    attached right to the first column, but that is a lot of work for
+    such a border line case.
 
-  if (!gh_pair_p (l))
+    )
+    
+  */  
+  if (!gh_pair_p (lns) || !gh_pair_p (rns))
     return false;
 
-  Item * left = dynamic_cast<Item*>  (unsmob_grob (gh_car (l)));
-  return abs (Paper_column::rank_i (left->column_l ()) - Paper_column::rank_i (col)) == 1 ;
+  Item * l_neighbor = dynamic_cast<Item*>  (unsmob_grob (gh_car (lns)));
+  Item * r_neighbor = dynamic_cast<Item*>  (unsmob_grob (gh_car (rns)));
+
+  if (!l_neighbor || !r_neighbor)
+    return false;
+
+  l_neighbor = l_neighbor->column_l();
+  r_neighbor = r_neighbor->column_l();
+
+  if (l == l_neighbor && r == r_neighbor)
+    return false;
+
+
+  /*
+    Only declare loose if the bounds make a little sense.  This means
+    some cases (two isolated, consecutive clef changes) won't be
+    nicely folded, but hey, then don't do that.
+  */
+  if( (Paper_column::musical_b (l_neighbor) || Item::breakable_b (l_neighbor))
+      && (Paper_column::musical_b (r_neighbor) || Item::breakable_b (r_neighbor)))
+    {
+      return true;
+    }
+
+
+  /*
+    If in doubt: we're not loose; the spacing engine should space for
+    it, risking suboptimal spacing.
+
+    (Otherwise, we might risk core dumps, and other weird stuff.)
+
+
+  */
+  return false;
 }
 
+/*
+  Remove columns that are not tightly fitting from COLS. In the
+  removed columns, set 'between-cols to the columns where it is in
+  between.
+*/
 void
 Third_spacing_spanner::prune_loose_colunms (Link_array<Grob> *cols)
 {
-   for (int i=cols->size ();  i--; )
-     {
-
-       if (Item::breakable_b (cols->elem(i)))
-        continue;
-       
-       if (!fixed_neighbor (cols->elem(i), ly_symbol2scm ("left-neighbors"))
-          || !fixed_neighbor (cols->elem(i), ly_symbol2scm ("right-neighbors")))
-        cols->del (i);
-     }
+  Link_array<Grob> newcols;
+  
+  for (int i=0; i < cols->size ();  i++)
+    {
+      if (Item::breakable_b (cols->elem(i)) || Paper_column::musical_b (cols->elem (i)))
+       {
+         newcols.push (cols->elem(i));
+         continue;
+       }
+
+      Grob *c = cols->elem(i);
+      if (loose_column (cols->elem (i-1), c, cols->elem (i+1)))
+       {
+         SCM lns = c->get_grob_property ("left-neighbors");
+         lns = gh_pair_p (lns) ? gh_car (lns) : SCM_BOOL_F;
+
+         SCM rns = c->get_grob_property ("right-neighbors");
+         rns = gh_pair_p (rns) ? gh_car (rns) : SCM_BOOL_F;
+
+         /*
+           Either object can be non existent, if the score ends
+           prematurely.
+          */
+         rns = gh_car (unsmob_grob (rns)->get_grob_property ("right-items"));
+         c->set_grob_property ("between-cols", gh_cons (lns,
+                                                        rns));
+       }
+      else
+       {
+         newcols.push (c);
+       }
+    }
+
+  *cols = newcols;
 }
 
+/*
+  Set neighboring columns determined by the spacing-wishes grob property.  
+*/
 void
-Third_spacing_spanner::find_loose_columns (Link_array<Grob> cols)
+Third_spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
 {
-  for (int i=0; i< cols.size(); i++)
+  for (int i=0; i < cols.size(); i++)
     {
       SCM right_neighbors = SCM_EOL;
       int min_rank = 100000;   // inf.
-      
-      for (SCM s = cols[i]-> get_grob_property ("spacing-wishes");
-          gh_pair_p (s); s = gh_cdr (s))
-       {
-         Grob * wish = unsmob_grob (gh_car (s));
 
-         Grob * left = unsmob_grob (wish->get_grob_property ("left-item"));
-         Grob * right = unsmob_grob (wish->get_grob_property ("right-item"));
 
-         Item * li = dynamic_cast<Item*> (left);
-         Item * ri = dynamic_cast<Item*> (right);        
 
-         assert (li->column_l () == cols[i]);
+      SCM wishes=  cols[i]-> get_grob_property ("spacing-wishes");
+      for (SCM s =wishes; gh_pair_p (s); s = gh_cdr (s))
+       {
+         Item * wish = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
+
+         Item * lc = wish->column_l ();
+         Grob * right = unsmob_grob (wish->get_grob_property ("right-column"));
+
+         if (!right)
+           continue;
 
-         Item * rc = ri->column_l ();
-         Item * lc = li->column_l ();
-         int newrank = Paper_column::rank_i (lc);
+         Item * rc = dynamic_cast<Item*> (right);
 
-         SCM neighbors = rc->get_grob_property ("left-neighbors");
-         Item  * left_neighbor = gh_pair_p (neighbors)
-           ? dynamic_cast<Item*> (unsmob_grob (gh_car (neighbors))) : 0;
+         int right_rank = Paper_column::rank_i (rc);
+         int left_rank = Paper_column::rank_i (lc);      
 
-         left_neighbor = left_neighbor->column_l ();
-         if (left_neighbor)
+         /*
+           update the left column.
+          */
+         if (right_rank <= min_rank)
            {
-             int oldrank = Paper_column::rank_i (left_neighbor->column_l ());
+             if (right_rank < min_rank)
+               right_neighbors  =SCM_EOL;
+             
+             min_rank = right_rank;
+             right_neighbors = gh_cons (wish->self_scm (), right_neighbors);
+           }
 
-             if (newrank > oldrank)
-               {
-                 neighbors= gh_cons (wish->self_scm (), SCM_EOL);
-               }
-             else if (newrank == oldrank)
-               {
-                 neighbors = gh_cons (wish->self_scm (), neighbors); 
-               }
+         /*
+           update the right column of the wish.
+          */
+         int maxrank = 0;
+         SCM left_neighs = rc->get_grob_property ("left-neighbors");
+         if (gh_pair_p (left_neighs)
+             && unsmob_grob (gh_car (left_neighs)))
+           {
+             Item * it = dynamic_cast<Item*> (unsmob_grob (gh_car (left_neighs)));
+             maxrank = Paper_column::rank_i (it->column_l());
            }
 
-         if (newrank < min_rank)
+         if (left_rank >= maxrank)
            {
-             right_neighbors = gh_cons (wish->self_scm(), SCM_EOL);
-             min_rank = newrank;
+             if (left_rank > maxrank)
+               left_neighs = SCM_EOL;
+
+             left_neighs = gh_cons (wish->self_scm (), left_neighs);
+             rc->set_grob_property ("left-neighbors", right_neighbors);
            }
-         else if (newrank == min_rank)
+       }
+
+      if (gh_pair_p (right_neighbors))
+       {
+         cols[i]->set_grob_property ("right-neighbors", right_neighbors);
+       }
+    }
+}
+
+/*
+  Set neighboring columns that have no left/right-neighbor set
+  yet. Only do breakable non-musical columns, and musical columns. 
+*/
+void
+Third_spacing_spanner::set_implicit_neighbor_columns (Link_array<Grob> cols)
+{
+  for (int i = 0; i < cols.size (); i++)
+    {
+      Item * it = dynamic_cast<Item*>(cols[i]);
+      if (!Item::breakable_b (it) && !Paper_column::musical_b (it))
+       continue;
+
+      // it->breakable || it->musical
+      SCM ln = cols[i] ->get_grob_property ("left-neighbors");
+      if (!gh_pair_p (ln) && i ) 
+       {
+         cols[i]->set_grob_property ("left-neighbors", cols[i-1]->self_scm());
+       }
+
+      SCM rn = cols[i] ->get_grob_property ("right-neighbors");
+      if (!gh_pair_p (rn) && i < cols.size () - 1) 
+       {
+         cols[i]->set_grob_property ("right-neighbors", cols[i + 1]->self_scm());
+       }
+    }
+}
+
+
+MAKE_SCHEME_CALLBACK (Third_spacing_spanner, set_springs,1);
+SCM
+Third_spacing_spanner::set_springs (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+
+  Link_array<Grob> all (me->pscore_l_->line_l_->column_l_arr ()) ;
+
+  set_explicit_neighbor_columns (all);
+  prune_loose_colunms (&all);
+  set_implicit_neighbor_columns (all);
+  
+  int j = 0;
+  for (int i = 1; i < all.size (); i++)
+    {
+      Grob *sc = all[i];
+      if (Item::breakable_b (sc))
+        {
+         Link_array<Grob> measure (all.slice (j, i+1));          
+          do_measure (me, &measure);
+         j = i;
+        }
+    }
+
+  return SCM_UNSPECIFIED;
+}
+
+
+void
+Third_spacing_spanner::do_measure (Grob*me, Link_array<Grob> *cols) 
+{
+  Moment shortest_in_measure;
+
+  /*
+    space as if this duration  is present. 
+  */
+  Moment base_shortest_duration = *unsmob_moment (me->get_grob_property ("maximum-duration-for-spacing"));
+  shortest_in_measure.set_infinite (1);
+
+  for (int i =0 ; i < cols->size (); i++)  
+    {
+      if (Paper_column::musical_b (cols->elem (i)))
+       {
+         Moment *when = unsmob_moment (cols->elem (i)->get_grob_property  ("when"));
+
+         /*
+           ignore grace notes for shortest notes.
+         */
+         if (when && when->grace_part_)
+           continue;
+         
+         SCM  st = cols->elem (i)->get_grob_property ("shortest-starter-duration");
+         Moment this_shortest = *unsmob_moment (st);
+         shortest_in_measure = shortest_in_measure <? this_shortest;
+       }
+    }
+  
+  Array<Spring> springs;
+
+  for (int i= 0; i < cols->size () - 1; i++)
+    {
+      Item * l = dynamic_cast<Item*> (cols->elem (i));
+      Item * r =  dynamic_cast<Item*> (cols->elem (i+1));
+
+      Paper_column * lc = dynamic_cast<Paper_column*> (l);
+      Paper_column * rc = dynamic_cast<Paper_column*> (r);
+
+      if (!Paper_column::musical_b (l))
+       {
+         breakable_column_spacing (l, r);
+
+         /*
+           
+           The case that the right part is broken as well is rather
+           rare, but it is possible, eg. with a single empty measure,
+           or if one staff finishes a tad earlier than the rest.
+           
+          */
+         Item *lb = l->find_prebroken_piece (RIGHT);
+         Item *rb = r->find_prebroken_piece (LEFT);
+         
+         if (lb)
+           breakable_column_spacing (lb,r);
+
+         if (rb)
+           breakable_column_spacing (l, rb);
+         if (lb && rb)
+           breakable_column_spacing (lb, rb);
+         
+         continue ; 
+       }
+      
+      Real note_space = note_spacing (me,lc, rc, shortest_in_measure <? base_shortest_duration);
+      Real hinterfleisch = note_space;
+      Real headwid = gh_scm2double (me->get_grob_property ("arithmetic-multiplier"));
+
+      SCM seq  = lc->get_grob_property ("right-neighbors");
+
+      Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
+      
+      /*
+       hinterfleisch = hind-meat = amount of space following a note.
+
+       
+       We adjust the space following a note only if the next note
+       happens after the current note (this is set in the grob
+       property SPACING-SEQUENCE.  */
+
+      Real stretch_distance = note_space;
+      if (shortest_in_measure <= dt)
+       {
+         /*
+           currently SPACING-SEQUENCE is set in
+           Separating_group_spanner::find_musical_sequences (), which
+           works neatly for one-voice-per staff, however,
+
+           it can't find out the actual duration of the notes on a
+           staff, so when putting tuplets and normal patterns it gets
+           confused, (ie. believes that < { c8 c8 } { d8 d8 d8 }*2/3
+           > contains 1/12 notes. ).
+
+           here we kludge, by checking if the distance we're spacing
+           for is less than the shortest note.
+
+           TODO:
+
+           Move SPACING-SEQUENCE detection into a voice
+           level-engraver --or-- make sure that every column has
+           access to the note head.
+
+         */
+         for (SCM s = seq; gh_pair_p (s); s = ly_cdr (s))
            {
-             right_neighbors = gh_cons (wish->self_scm (), right_neighbors); 
+             Grob * wish = unsmob_grob (gh_car (s));
+
+             // TODO; configgable.
+             if (Note_spacing::has_interface (wish))
+               {
+                 hinterfleisch += -headwid + Note_spacing::get_spacing (wish);
+               }
+
+             // should move into Note_spacing
+             // hinterfleisch += stem_dir_correction (me, l, r);
            }
+
+         // ? why.
+         if (gh_pair_p (seq))
+           stretch_distance -= headwid;
+       }      
+      Spring s;
+      s.distance_f_ = hinterfleisch;
+      s.strength_f_ = 1 / stretch_distance;
+
+      s.item_l_drul_[LEFT] = l;
+      s.item_l_drul_[RIGHT] = r;
+
+      s.add_to_cols();
+      if (r->find_prebroken_piece (LEFT))
+       {
+         s.item_l_drul_[RIGHT] = r->find_prebroken_piece(LEFT);
+         s.add_to_cols();
        }
+    }
+
+}
+
+
+/*
+  Read hints from L (todo: R) and generate springs.
+ */
+void
+Third_spacing_spanner::breakable_column_spacing (Item* l, Item *r)
+{
+  Spring s;
 
-      cols[i]->set_grob_property ("right-neighbors", right_neighbors);
+  Real break_dist = 0.0;
+  SCM espace = l->get_grob_property ("extra-space");
+  if (gh_pair_p (espace))
+    break_dist += gh_scm2double (ly_cdr (espace));
+
+  if (!break_dist)
+    break_dist = 1.0;
+
+  Real break_stretch = 0.0;
+
+  // todo: naming of "distance"
+  espace = l->get_grob_property ("stretch-distance");
+  if (gh_pair_p (espace))
+    break_stretch += gh_scm2double (ly_cdr (espace));
+
+  if (!break_stretch)
+    break_stretch = 1.0;
+  
+  s.distance_f_ = break_dist;
+  s.strength_f_ = 1/break_stretch;
+  s.item_l_drul_[LEFT] = l;
+  s.item_l_drul_[RIGHT] = r;
+
+  s.add_to_cols ();
+}
+
+
+/**
+  Get the measure wide ant for arithmetic spacing.
+
+  @see
+  John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
+  OSU-CISRC-10/87-TR35, Department of Computer and Information Science,
+  The Ohio State University, 1987.
+
+  */
+Real
+Third_spacing_spanner::get_duration_space (Grob*me, Moment d, Moment shortest) 
+{
+  Real log =  log_2 (shortest.main_part_);
+  Real k = gh_scm2double (me->get_grob_property ("arithmetic-basicspace"))
+    - log;
+
+  Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
+  
+  return (log_2 (compdur) + k) * gh_scm2double (me->get_grob_property ("arithmetic-multiplier"));
+}
+
+
+Real
+Third_spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
+                                  Moment shortest) 
+{
+  Moment shortest_playing_len = 0;
+  SCM s = lc->get_grob_property ("shortest-playing-duration");
+
+
+  if (unsmob_moment (s))
+    shortest_playing_len = *unsmob_moment (s);
+  
+  if (! shortest_playing_len.to_bool ())
+    {
+      programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).str ());
+      shortest_playing_len = 1;
+    }
+  
+  if (! shortest.to_bool ())
+    {
+      programming_error ("no minimum in measure at " + Paper_column::when_mom (lc).str ());
+      shortest = 1;
+    }
+  Moment delta_t = Paper_column::when_mom (rc) - Paper_column::when_mom (lc);
+  Real dist = 0.0;
+
+  if (delta_t.main_part_)
+    {
+      dist = get_duration_space (me, shortest_playing_len, shortest);
+      dist *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
+    }
+  else if (delta_t.grace_part_)
+    {
+      dist = get_duration_space (me, shortest, shortest);
+
+      Real grace_fact = 1.0;
+      SCM gf = me->get_grob_property ("grace-space-factor");
+      if (gh_number_p (gf))
+       grace_fact = gh_scm2double (gf);
+
+      dist *= grace_fact; 
+    }
+
+#if 0
+  /*
+    TODO: figure out how to space grace notes.
+   */
+
+  dist *= 
+    +  grace_fact * (double) (delta_t.grace_part_ / shortest_playing_len.main_part_);
+
+
+  Moment *lm = unsmob_moment (lc->get_grob_property ("when"));
+  Moment *rm = unsmob_moment (rc->get_grob_property ("when"));
+
+  if (lm && rm)
+    {
+      if (lm->grace_part_ && rm->grace_part_)
+       dist *= 0.5;
+      else if (!rm->grace_part_ && lm->grace_part_)
+       dist *= 0.7;
     }
+#endif
+  
+  return dist;
 }
+
index 227761a82dd1f95a8df0bb21b7125e660478f7a6..b725b64a4b010b9aa2a2f2d5cf3003027ea475a3 100644 (file)
@@ -8,39 +8,40 @@
  */
 
 #include "command-request.hh"
-#include "rhythmic-head.hh"
 #include "musical-request.hh"
 #include "tie.hh"
 #include "translator-group.hh"
 #include "spanner.hh"
 #include "tie-column.hh"
-#include "pqueue.hh"
 #include "engraver.hh"
 #include "item.hh"
 #include "grob-pitch-tuple.hh"
-
+#include "note-head.hh"
 
 /**
    Manufacture ties.  Acknowledge noteheads, and put them into a
    priority queue. If we have a Tie_req, connect the notes that finish
    just at this time, and note that start at this time.
 
-   TODO: junk the pq; the PQ is overkill if we assume that no
-   different durations occur in parallel.
-
    TODO: Remove the dependency on musical info. We should tie on the
    basis of position and duration-log of the heads (not of the reqs).
 
+
+   TODO: figure this out: currently, this engravers ties note heads
+   that have the same Y-position (and does not look at pitch). This
+   means that we will fuck up with a clef-change. How should
+   clef-changes during ties be handled, or should they not?
+
+   
 */
 class Tie_engraver : public Engraver
 {
-  PQueue<Grob_pitch_tuple> past_notes_pq_;
   Moment end_mom_;
   Moment next_end_mom_;
 
   Tie_req *req_l_;
-  Array<Grob_pitch_tuple> now_heads_;
-  Array<Grob_pitch_tuple> stopped_heads_;
+  Link_array<Grob> now_heads_;
+  Link_array<Grob> stopped_heads_;
   Link_array<Grob> tie_p_arr_;
 
   Spanner * tie_column_p_;
@@ -96,23 +97,26 @@ Tie_engraver::set_melisma (bool m)
 void
 Tie_engraver::acknowledge_grob (Grob_info i)
 {
-  if (Rhythmic_head::has_interface (i.grob_l_))
+  if (Note_head::has_interface (i.grob_l_))
     {
-      Note_req * m = dynamic_cast<Note_req* > (i.music_cause ());
-      if (!m)
-       return;
-      now_heads_.push (Grob_pitch_tuple (i.grob_l_, m, now_mom () + m->length_mom ()));
+      now_heads_.push (i.grob_l_);
     }
 }
 
+int
+head_position_compare (Grob  *const&a,Grob  *const&b)
+{
+  return sign (gh_scm2double (a->get_grob_property ("staff-position"))
+              - gh_scm2double (b->get_grob_property ("staff-position")));
+}
 
 void
 Tie_engraver::create_grobs ()
 {
   if (req_l_)
     {
-      now_heads_.sort (Grob_pitch_tuple::pitch_compare);
-      stopped_heads_.sort (Grob_pitch_tuple::pitch_compare);
+      now_heads_.sort (&head_position_compare);
+      stopped_heads_.sort (&head_position_compare);
 
       SCM head_list = SCM_EOL;
       
@@ -122,21 +126,19 @@ Tie_engraver::create_grobs ()
       while (i >= 0 && j >=0)
        {
          int comp
-           = Pitch::compare (now_heads_[i].pitch_,
-                             stopped_heads_[j].pitch_);
+           = head_position_compare (now_heads_[i], stopped_heads_[j]);
 
          if (comp)
            {
- (comp < 0) ? j -- : i--;
            (comp < 0) ? j -- : i--;
              continue;
            }
          else
            {
-             head_list  = gh_cons (gh_cons (stopped_heads_[j].head_l_->self_scm (),
-                                            now_heads_[i].head_l_->self_scm ()),
+             head_list  = gh_cons (gh_cons (stopped_heads_[j]->self_scm (),
+                                            now_heads_[i]->self_scm ()),
                                    head_list);
 
-             past_notes_pq_. insert (now_heads_[i]);
              now_heads_.del (i);
              stopped_heads_.del (j);
              i--;
@@ -192,10 +194,7 @@ void
 Tie_engraver::stop_translation_timestep ()
 {
   req_l_ = 0;
-  for (int i=0; i < now_heads_.size (); i++)
-    {
-      past_notes_pq_.insert (now_heads_[i]);
-    }
+
   now_heads_.clear ();
 
   /*
@@ -244,16 +243,24 @@ Tie_engraver::start_translation_timestep ()
       set_melisma (false);
     }
 
-  Moment now = now_mom ();
-  while (past_notes_pq_.size () && past_notes_pq_.front ().end_ < now)
-    past_notes_pq_.delmin ();
-
-
+  SCM grobs = get_property ("busyGrobs");
+  Moment now = now_mom();
   stopped_heads_.clear ();
-  while (past_notes_pq_.size ()
-        && past_notes_pq_.front ().end_ == now)
-    stopped_heads_.push (past_notes_pq_.get ());
-
+  
+  for (; gh_pair_p (grobs); grobs = gh_cdr (grobs))
+    {
+      Grob * grob  = unsmob_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)
+       break;
+      else if (end == now
+              && Note_head::has_interface (grob))
+       stopped_heads_.push (grob);
+    }
 }
 
 
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 57c60489d6c439113d3541d93d5142c4def237ba..eefc34282eba1bef6ec49feaa271b8e81feea74f 100644 (file)
@@ -85,6 +85,11 @@ in LilyPond-include-path."
   (and process
        (eq (process-status process) 'run))))
 
+(defun Midi-running ()
+  (let ((process (get-process "midi")))
+  (and process
+       (eq (process-status process) 'run))))
+
 (defun LilyPond-kill-job ()
   "Kill the currently running LilyPond job."
   (interactive)
@@ -281,6 +286,12 @@ Must be the car of an entry in `LilyPond-command-alist'."
   (LilyPond-command (LilyPond-command-query (LilyPond-master-file))
                    'LilyPond-master-file))
 
+(defun LilyPond-command-lilypond ()
+  "Run lilypond for the current document."
+  (interactive)
+  (LilyPond-command (LilyPond-command-menu "LilyPond") 'LilyPond-master-file)
+)
+
 (defun LilyPond-command-formatdvi ()
   "Format the dvi output of the current document."
   (interactive)
@@ -339,20 +350,20 @@ Must be the car of an entry in `LilyPond-command-alist'."
 (defun LilyPond-command-next-midi ()
   "Play next midi score of the current document."
   (interactive)
-  (LilyPond-compile-file 
-   (let ((allscores (count-midi-words))
-        (scores (count-midi-words-backwards))
-        (fname (LilyPond-master-file)))
-     (let ((count (string-to-number (substring scores 0 (+ (length scores) -12)))))
+  (if (Midi-running)
+      (quit-process (get-process "midi") t)
+    (LilyPond-compile-file 
+     (let ((fname (LilyPond-master-file))
+          (allcount (string-to-number (substring (count-midi-words) 0 -12)))
+          (count (string-to-number (substring (count-midi-words-backwards) 0 -12))))
        (concat  LilyPond-midi-command " "
-               (substring fname 0 (+ (length fname) -3)) ; suppose ".ly"
-               (if (not (string= "1 occurrences" allscores)) ; only one score
-                   (if (not (eq count 0))                    ; first score
-                       (if (string= scores allscores)        ; last score
-                           (concat "-" (number-to-string (+ count -1)))
-                         (concat "-" (number-to-string count)))))
-               ".midi")))
-   "Midi"))
+               (substring fname 0 -3) ; suppose ".ly"
+               (if (and (> allcount 1) (> count 0)) ; not first score
+                   (if (eq count allcount)          ; last score
+                       (concat "-" (number-to-string (+ count -1)))
+                     (concat "-" (number-to-string count))))
+               ".midi"))
+     "Midi")))
 
 ;; FIXME, this is broken
 (defun LilyPond-region-file (begin end)
@@ -459,6 +470,7 @@ command."
 (if LilyPond-mode-map
     ()
   (setq LilyPond-mode-map (make-sparse-keymap))
+  (define-key LilyPond-mode-map "\C-c\C-l" 'LilyPond-command-lilypond)
   (define-key LilyPond-mode-map "\C-c\C-r" 'LilyPond-command-region)
   (define-key LilyPond-mode-map "\C-c\C-b" 'LilyPond-command-buffer)
   (define-key LilyPond-mode-map "\C-c\C-k" 'LilyPond-kill-job)
@@ -540,7 +552,7 @@ command."
 ;        (let ((file 'LilyPond-command-on-current))
 ;          (mapcar 'LilyPond-command-menu-entry LilyPond-command-alist))
 ;;; Some kind of mapping which includes :keys might be more elegant
-         '([ "LilyPond" (LilyPond-command (LilyPond-command-menu "ViewPS") 'LilyPond-master-file) ])
+         '([ "LilyPond" (LilyPond-command (LilyPond-command-menu "LilyPond") 'LilyPond-master-file) :keys "C-c C-l"])
          '([ "TeX" (LilyPond-command (LilyPond-command-menu "TeX") 'LilyPond-master-file) ])
          '([ "2Dvi" (LilyPond-command (LilyPond-command-menu "2Dvi") 'LilyPond-master-file) :keys "C-c C-d"])
          '([ "2PS" (LilyPond-command (LilyPond-command-menu "2PS") 'LilyPond-master-file) :keys "C-c C-f"])
@@ -549,7 +561,7 @@ command."
          '([ "SmartView" (LilyPond-command (LilyPond-command-menu "SmartView") 'LilyPond-master-file) :keys "C-c C-s"])
          '([ "View" (LilyPond-command (LilyPond-command-menu "View") 'LilyPond-master-file) :keys "C-c C-v"])
          '([ "ViewPS" (LilyPond-command (LilyPond-command-menu "ViewPS") 'LilyPond-master-file) :keys "C-c C-p"])
-         '([ "Midi" (LilyPond-command-next-midi) :keys "C-c C-m"])
+         '([ "Midi (off)" (LilyPond-command-next-midi) :keys "C-c C-m"])
          ))
 
 (defconst LilyPond-imenu-generic-re "^\\([a-zA-Z_][a-zA-Z0-9_]*\\) *="
index 211246f0817c013bbd1cba98fb4adcc63f001896..c70b18e0fea90c9117b133f98dfb9130334e541b 100644 (file)
 #(define timbales `(
        (losidestick      cross         ,#f       ,(make-pitch -1 6 0))
        (lotimbale        default       ,#f       ,(make-pitch -1 6 0))
-       (cowbell          triangle      ,#f       ,(make-pitch 0 0 0))
+       (cowbell          triangle      ,#f       ,(make-pitch 0 2 0))
        (hisidestick      cross         ,#f       ,(make-pitch 0 1 0))
        (hitimbale        default       ,#f       ,(make-pitch 0 1 0))
  ))
        (hibongo          default       ,#f       ,(make-pitch 0 1 0))
  ))
 
-#(define guiro `(
-       (shortguiro       default       "staccato",(make-pitch 0 0 0))
-       (longguiro        default       "tenuto"  ,(make-pitch 0 0 0))
-       (guiro            default       ,#f       ,(make-pitch 0 0 0))
- ))
 
-#(define triangle `(
+#(define percussion `(
        (opentriangle     cross         "open"    ,(make-pitch 0 0 0))
        (mutetriangle     cross         "stopped" ,(make-pitch 0 0 0))
        (triangle         cross         ,#f       ,(make-pitch 0 0 0))
+       (shortguiro       default       "staccato",(make-pitch 0 0 0))
+       (longguiro        default       "tenuto"  ,(make-pitch 0 0 0))
+       (guiro            default       ,#f       ,(make-pitch 0 0 0))
+       (cowbell          triangle      ,#f       ,(make-pitch 0 0 0))
+       (claves           default       ,#f       ,(make-pitch 0 0 0))
+       (tambourine       default       ,#f       ,(make-pitch 0 0 0))
+       (cabasa           cross         ,#f       ,(make-pitch 0 0 0))
+       (maracas          default       ,#f       ,(make-pitch 0 0 0))
+       (handclap         default       ,#f       ,(make-pitch 0 0 0))
  ))
 
 
-
 \pitchnames
 #(append (map (lambda (x) (cons (car x) (caddr x))) drum-pitch-names)
         (map (lambda (x) (cons (cadr x) (caddr x))) drum-pitch-names)
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 1489a8cc53e0eb1a0950e6768bc7614c15fed27e..c75f25b10f3961b5277d63ed9ff6422db19d3ea4 100644 (file)
@@ -54,7 +54,7 @@ make web-doc top-web
 rm -rf $RPM_BUILD_ROOT
 mkdir -p $RPM_BUILD_ROOT/tmp/lilypond-rpm-doc
 
-strip lily/out/lilypond midi2ly/out/midi2ly
+strip lily/out/lilypond 
 make prefix="$RPM_BUILD_ROOT%{_prefix}" install
 
 %if info=="yes"
index 4c3253f95b89fda31867f5ea446417b49e0aba49..1eec5b418ba8eb10877b43840dba69ba29d94a07 100644 (file)
@@ -118,7 +118,7 @@ cp tex/titledefs.tex scripts/share/lilypond/tex
 ## end of hack
 
 
-strip lily/out/lilypond midi2ly/out/midi2ly
+strip lily/out/lilypond 
 make prefix="$RPM_BUILD_ROOT%{_prefix}" install
 
 %{INSTALL_DIR} $RPM_BUILD_ROOT/usr/share/texmf/fonts/source/public/lilypond
index e9bc7e9f71bcf3f19b90324f51dd47827e1bd73d..7a3ad6a10d39f6c705f7e44e371ae911610411b8 100644 (file)
@@ -1,15 +1,15 @@
 Begin3
 Title: LilyPond
-Version: 1.5.26
-Entered-date: 14DEC01
+Version: 1.5.27
+Entered-date: 24DEC01
 Description: @BLURB@
 Keywords: music notation typesetting midi fonts engraving
 Author: hanwen@cs.uu.nl (Han-Wen Nienhuys)
        janneke@gnu.org (Jan Nieuwenhuizen)
 Maintained-by: hanwen@stack.nl (Han-Wen Nienhuys)
 Primary-site: sunsite.unc.edu /pub/Linux/apps/sound/convert
-       1000k lilypond-1.5.26.tar.gz 
+       1000k lilypond-1.5.27.tar.gz 
 Original-site: ftp.cs.uu.nl /pub/GNU/LilyPond/development/
-       1000k lilypond-1.5.26.tar.gz 
+       1000k lilypond-1.5.27.tar.gz 
 Copying-policy: GPL
 End
index 0bfd6726321fab6986308ffebb096d24e08410b7..b8784354e32e68ca674ef3e6c90d9cad453ae9bb 100644 (file)
@@ -1,5 +1,5 @@
 %define name lilypond
-%define version 1.5.26
+%define version 1.5.27
 %define release 1mdk
 
 Name: %{name}
index 3f62515f6896b5def912919e3e7aed852062ad77..7d16d85b7d353deca287b6fb3c0b9fe4d4fcca89 100644 (file)
@@ -1,11 +1,11 @@
 %define info yes
 
 Name: lilypond
-Version: 1.5.26
+Version: 1.5.27
 Release: 1
 License: GPL
 Group: Applications/Publishing
-Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.26.tar.gz
+Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.27.tar.gz
 Summary: Create and print music notation 
 URL: http://www.lilypond.org/
 BuildRoot: /tmp/lilypond-install
@@ -54,7 +54,7 @@ make web-doc top-web
 rm -rf $RPM_BUILD_ROOT
 mkdir -p $RPM_BUILD_ROOT/tmp/lilypond-rpm-doc
 
-strip lily/out/lilypond midi2ly/out/midi2ly
+strip lily/out/lilypond 
 make prefix="$RPM_BUILD_ROOT%{_prefix}" install
 
 %if info=="yes"
index 35b61fe56bd95595193f0b9d5135331922ba16f9..afe1711f6a4c5f865b7dbca20e57ff97c8b25e70 100644 (file)
 
 Distribution: SuSE Linux 7.0 (i386)
 Name: lilypond
-Version: 1.5.26
+Version: 1.5.27
 Release: 2
 Copyright:    GPL
 Group: Applications/Publishing
-Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.26.tar.gz
+Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.27.tar.gz
 # music notation software for.. ?
 Summary: A program for printing sheet music.
 URL: http://www.lilypond.org/
@@ -118,7 +118,7 @@ cp tex/titledefs.tex scripts/share/lilypond/tex
 ## end of hack
 
 
-strip lily/out/lilypond midi2ly/out/midi2ly
+strip lily/out/lilypond 
 make prefix="$RPM_BUILD_ROOT%{_prefix}" install
 
 %{INSTALL_DIR} $RPM_BUILD_ROOT/usr/share/texmf/fonts/source/public/lilypond
index d1813de9a1d12c6569e622a3e593eae2db77aaf1..ffdae61043eb1ca7b7c5dc60a2e77760c1925ba2 100644 (file)
        (tuplet . ((font-family . roman) (font-shape . italic) (font-relative-size . -1)))
 
        (timesig . ((font-family . number) ))
-       (timesig-symbol . ((font-family . music) (font-relative-size . 0)))
+       (timesig-symbol . ((font-family . music) ))
        
-       (mmrest . ((font-family . number) (font-relative-size . 1)))
-       (mmrest-symbol . ((font-family . music) (font-relative-size . 0)))
+       (mmrest . ((font-family . number) ))
+       (mmrest-symbol . ((font-family . music) ))
 
        (mark . ((font-family . number) (font-relative-size . 1)))
        (script . ((font-family . roman) (font-relative-size . -1)))
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?")
index 8befc79dae9c62f39ab1e8ac4a9c4e7ee07076c7..4e431b030fd3897c2914897e81767e8b5e0726df 100644 (file)
@@ -468,8 +468,10 @@ re_dict = {
                 'lilypond-file': '(?m)^(?!@c)(?P<match>@lilypondfile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
                 'lilypond' : '(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
 # pyton2.2b2 barfs on this
-#               'lilypond-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s))""",
-                'lilypond-block': r"""(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s)""",
+                'lilypond-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s))""",
+
+# 1.5.2 barfs on this. 
+# 'lilypond-block': r"""(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s)""",
                  'option-sep' : ',\s*',
                  'intertext': r',?\s*intertext=\".*?\"',
                  'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
index bc30d5403992e4508e9902a36b5b8c49ebc06ebd..c47267cead9fb9e7586fc7ab9ef42f6d2bd8ec4c 100644 (file)
@@ -46,6 +46,8 @@
 \fi
 \ifundefined{lilypondpaperinterscorelinefill}
         \def\lilypondpaperinterscorelinefill{0}
+\else
+        \def\lilypondpaperinterscorelinefill{1}
 \fi
 
 \def\interscoreline{\vskip\lilypondpaperinterscoreline pt plus %