From 8dbb0048c1ac59125562d5adc1c68512eab8541b Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Mon, 24 Dec 2001 14:50:08 +0100 Subject: [PATCH] release: 1.5.27 --- ChangeLog | 48 +- Documentation/regression-test.tely | 2 + Documentation/user/converters.itely | 19 + Documentation/user/refman.itely | 18 +- INSTALL.txt | 34 +- VERSION | 4 +- input/regression/spacing-accidental-staffs.ly | 7 +- input/regression/tie-busy-grobs.ly | 16 + input/test/staff-size.ly | 11 +- lily/accidental-engraver.cc | 34 +- lily/chord-name.cc | 5 - lily/completion-note-heads-engraver.cc | 20 +- lily/grob-pq-engraver.cc | 159 +++++ lily/include/grob-info.hh | 1 - lily/include/lily-guile.hh | 10 +- lily/include/lyric-combine-music-iterator.hh | 3 +- lily/include/note-column.hh | 1 + lily/include/note-spacing.hh | 6 +- lily/include/paper-column.hh | 6 +- lily/line-of-score.cc | 29 +- lily/lyric-combine-music-iterator.cc | 39 +- lily/music-iterator.cc | 6 + lily/note-column.cc | 19 +- lily/note-heads-engraver.cc | 7 +- lily/note-spacing-engraver.cc | 99 ++++ lily/note-spacing.cc | 79 ++- lily/paper-column.cc | 47 ++ lily/rhythmic-column-engraver.cc | 9 - lily/separating-line-group-engraver.cc | 101 +++- lily/spacing-wish.cc | 1 + lily/staff-spacing.cc | 1 + lily/stem-engraver.cc | 4 + lily/text-item.cc | 11 +- lily/third-try.cc | 550 ++++++++++++++++-- lily/tie-engraver.cc | 77 +-- lily/translator-group.cc | 2 +- lilypond-mode.el | 42 +- ly/drumpitch-init.ly | 19 +- ly/engraver-init.ly | 3 +- make/lilypond.redhat.spec.in | 2 +- make/lilypond.suse.spec.in | 2 +- make/out/lilypond.lsm | 8 +- make/out/lilypond.mandrake.spec | 2 +- make/out/lilypond.redhat.spec | 6 +- make/out/lilypond.suse.spec | 6 +- scm/font.scm | 6 +- scm/grob-description.scm | 4 +- scm/grob-property-description.scm | 3 +- scm/interface-description.scm | 1 + scm/translator-property-description.scm | 4 + scripts/lilypond-book.py | 6 +- tex/lilyponddefs.tex | 2 + 52 files changed, 1354 insertions(+), 247 deletions(-) create mode 100644 input/regression/tie-busy-grobs.ly create mode 100644 lily/grob-pq-engraver.cc create mode 100644 lily/note-spacing-engraver.cc create mode 100644 lily/spacing-wish.cc diff --git a/ChangeLog b/ChangeLog index ca802f93a5..ded1e51b59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,16 +1,56 @@ -2001-12-16 Jan Nieuwenhuizen +2001-12-24 Han-Wen Nienhuys + + * 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 + + * 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 + + * 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 + * 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 + + * lilypond-mode.el (LilyPond-command-next-midi): Make + possible to kill midi-process (using "C-c C-m"). 2001-12-14 Han-Wen diff --git a/Documentation/regression-test.tely b/Documentation/regression-test.tely index 0f7791c577..42f5aad17e 100644 --- a/Documentation/regression-test.tely +++ b/Documentation/regression-test.tely @@ -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} diff --git a/Documentation/user/converters.itely b/Documentation/user/converters.itely index 1d1e75b1b9..dceade2638 100644 --- a/Documentation/user/converters.itely +++ b/Documentation/user/converters.itely @@ -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 diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely index 12adf9a8c4..2dbad10f96 100644 --- a/Documentation/user/refman.itely +++ b/Documentation/user/refman.itely @@ -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 diff --git a/INSTALL.txt b/INSTALL.txt index 176a50e062..058e0d97e7 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -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 8c2c4cc485..c939db38f5 100644 --- 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. diff --git a/input/regression/spacing-accidental-staffs.ly b/input/regression/spacing-accidental-staffs.ly index 58d1ecf1c9..175be7bade 100644 --- a/input/regression/spacing-accidental-staffs.ly +++ b/input/regression/spacing-accidental-staffs.ly @@ -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 index 0000000000..719d196f2c --- /dev/null +++ b/input/regression/tie-busy-grobs.ly @@ -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 }} + > +} diff --git a/input/test/staff-size.ly b/input/test/staff-size.ly index 854d6cc4ab..3dbe63ee08 100644 --- a/input/test/staff-size.ly +++ b/input/test/staff-size.ly @@ -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. } diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc index 015b515e66..0f9b126eb3 100644 --- a/lily/accidental-engraver.cc +++ b/lily/accidental-engraver.cc @@ -54,7 +54,7 @@ public: Link_array arpeggios_; Link_array mel_l_arr_; - Link_array support_l_arr_; + Link_array head_l_arr_; Link_array forced_l_arr_; Link_array 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_)) { diff --git a/lily/chord-name.cc b/lily/chord-name.cc index 5595759236..2c0e717a89 100644 --- a/lily/chord-name.cc +++ b/lily/chord-name.cc @@ -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 (); } diff --git a/lily/completion-note-heads-engraver.cc b/lily/completion-note-heads-engraver.cc index 85609c295a..6d1157560d 100644 --- a/lily/completion-note-heads-engraver.cc +++ b/lily/completion-note-heads-engraver.cc @@ -16,9 +16,22 @@ #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 note_p_arr_; @@ -72,8 +85,9 @@ Completion_heads_engraver::try_music (Music *m) } else if (dynamic_cast (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 index 0000000000..fad29ac48d --- /dev/null +++ b/lily/grob-pq-engraver.cc @@ -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 +*/ + +#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 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"); diff --git a/lily/include/grob-info.hh b/lily/include/grob-info.hh index 6d8868214c..578c20730a 100644 --- a/lily/include/grob-info.hh +++ b/lily/include/grob-info.hh @@ -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 origin_trans_l_arr (Translator*) const; diff --git a/lily/include/lily-guile.hh b/lily/include/lily-guile.hh index 26c2a8a300..7788833f4b 100644 --- a/lily/include/lily-guile.hh +++ b/lily/include/lily-guile.hh @@ -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 diff --git a/lily/include/lyric-combine-music-iterator.hh b/lily/include/lyric-combine-music-iterator.hh index dae14c81dc..8544673a21 100644 --- a/lily/include/lyric-combine-music-iterator.hh +++ b/lily/include/lyric-combine-music-iterator.hh @@ -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_; }; diff --git a/lily/include/note-column.hh b/lily/include/note-column.hh index 5f24f7284e..647ac34cb7 100644 --- a/lily/include/note-column.hh +++ b/lily/include/note-column.hh @@ -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*); diff --git a/lily/include/note-spacing.hh b/lily/include/note-spacing.hh index ed92e06519..1905c72e85 100644 --- a/lily/include/note-spacing.hh +++ b/lily/include/note-spacing.hh @@ -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 */ diff --git a/lily/include/paper-column.hh b/lily/include/paper-column.hh index 507ba6f0fe..4a21edaffc 100644 --- a/lily/include/paper-column.hh +++ b/lily/include/paper-column.hh @@ -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*); diff --git a/lily/line-of-score.cc b/lily/line-of-score.cc index 96f00ce5ba..eaadc08fa5 100644 --- a/lily/line-of-score.cc +++ b/lily/line-of-score.cc @@ -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; iloose_cols_.size (); i++) + for (int i = 0; i < posns->loose_cols_.size (); i++) { int divide_over = 1; Item *loose = dynamic_cast (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 (unsmob_grob (ly_car (between))); + Item * r=dynamic_cast (unsmob_grob (ly_cdr (between))); + + if (!(l && r)) + break ; + + if (!left && l) { - left = dynamic_cast (unsmob_grob (ly_car (between))); - left = left->column_l (); + left = l->column_l (); } - divide_over ++; - loose = dynamic_cast (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); diff --git a/lily/lyric-combine-music-iterator.cc b/lily/lyric-combine-music-iterator.cc index 6052b89ffd..e7e7901e87 100644 --- a/lily/lyric-combine-music-iterator.cc +++ b/lily/lyric-combine-music-iterator.cc @@ -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 { diff --git a/lily/music-iterator.cc b/lily/music-iterator.cc index f27f2f0d77..4135a6c988 100644 --- a/lily/music-iterator.cc +++ b/lily/music-iterator.cc @@ -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 { diff --git a/lily/note-column.cc b/lily/note-column.cc index 56a29d08a3..95b2cd67ed 100644 --- a/lily/note-column.cc +++ b/lily/note-column.cc @@ -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; +} diff --git a/lily/note-heads-engraver.cc b/lily/note-heads-engraver.cc index 2a9b5e49e4..96938212e4 100644 --- a/lily/note-heads-engraver.cc +++ b/lily/note-heads-engraver.cc @@ -24,7 +24,7 @@ class Note_heads_engraver : public Engraver Link_array dot_p_arr_; Link_array 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 (m)) { note_req_l_arr_.push (n); - note_end_mom_ = note_end_mom_ >? now_mom () + m->length_mom (); - return true; } else if (dynamic_cast (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 index 0000000000..47b11ae5ac --- /dev/null +++ b/lily/note-spacing-engraver.cc @@ -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 + +*/ + +#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 current_heads_; + Link_array 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 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 diff --git a/lily/note-spacing.cc b/lily/note-spacing.cc index 81eb2aa03b..0628ffab82 100644 --- a/lily/note-spacing.cc +++ b/lily/note-spacing.cc @@ -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 + (c) 2001 Han-Wen Nienhuys +*/ - */ +#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 props(me->get_grob_property ("left-items"), + me->get_grob_property ("right-items")); + Direction d = LEFT; + Drul_array extents; + do + { + for (SCM s = props[d]; gh_pair_p (s); s = gh_cdr (s)) + { + Item * it= dynamic_cast (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 (right_grob); + if (!ri) + { + int r = Paper_column::rank_i (dynamic_cast(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; +} diff --git a/lily/paper-column.cc b/lily/paper-column.cc index 14774ed651..789a9cfa73 100644 --- a/lily/paper-column.cc +++ b/lily/paper-column.cc @@ -5,12 +5,32 @@ (c) 1997--2001 Han-Wen Nienhuys */ + #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 (); +} + diff --git a/lily/rhythmic-column-engraver.cc b/lily/rhythmic-column-engraver.cc index c87409c450..84bd2ae16c 100644 --- a/lily/rhythmic-column-engraver.cc +++ b/lily/rhythmic-column-engraver.cc @@ -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++) diff --git a/lily/separating-line-group-engraver.cc b/lily/separating-line-group-engraver.cc index fc8679494f..57100c952e 100644 --- a/lily/separating-line-group-engraver.cc +++ b/lily/separating-line-group-engraver.cc @@ -15,6 +15,27 @@ #include "axis-group-interface.hh" #include "note-spacing.hh" + +struct Spacings +{ + Item * staff_spacing_; + Link_array 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 index 0000000000..8b13789179 --- /dev/null +++ b/lily/spacing-wish.cc @@ -0,0 +1 @@ + diff --git a/lily/staff-spacing.cc b/lily/staff-spacing.cc index 771760ca52..a662f54133 100644 --- a/lily/staff-spacing.cc +++ b/lily/staff-spacing.cc @@ -15,3 +15,4 @@ Staff_spacing::has_interface (Grob* g) { return g && g->has_interface (ly_symbol2scm ("staff-spacing-interface")); } + diff --git a/lily/stem-engraver.cc b/lily/stem-engraver.cc index 5ab49f9227..aba73c027f 100644 --- a/lily/stem-engraver.cc +++ b/lily/stem-engraver.cc @@ -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 ()); } diff --git a/lily/text-item.cc b/lily/text-item.cc index e4320a3daf..1f83982d06 100644 --- a/lily/text-item.cc +++ b/lily/text-item.cc @@ -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)); diff --git a/lily/third-try.cc b/lily/third-try.cc index b66e5f6129..bfc1a34ac8 100644 --- a/lily/third-try.cc +++ b/lily/third-try.cc @@ -6,103 +6,545 @@ (c) 1999--2001 Han-Wen Nienhuys */ +#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 *cols); - void find_loose_columns (Link_array 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 *cols); + static void find_loose_columns (Link_array cols); + static void set_explicit_neighbor_columns (Link_array cols); + static void set_implicit_neighbor_columns (Link_array cols); + static void do_measure (Grob*me,Link_array *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 (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 (unsmob_grob (gh_car (lns))); + Item * r_neighbor = dynamic_cast (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 *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 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 cols) +Third_spacing_spanner::set_explicit_neighbor_columns (Link_array 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 (left); - Item * ri = dynamic_cast (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 (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 (right); - SCM neighbors = rc->get_grob_property ("left-neighbors"); - Item * left_neighbor = gh_pair_p (neighbors) - ? dynamic_cast (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 (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 cols) +{ + for (int i = 0; i < cols.size (); i++) + { + Item * it = dynamic_cast(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 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 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 *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 springs; + + for (int i= 0; i < cols->size () - 1; i++) + { + Item * l = dynamic_cast (cols->elem (i)); + Item * r = dynamic_cast (cols->elem (i+1)); + + Paper_column * lc = dynamic_cast (l); + Paper_column * rc = dynamic_cast (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 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; } + diff --git a/lily/tie-engraver.cc b/lily/tie-engraver.cc index 227761a82d..b725b64a4b 100644 --- a/lily/tie-engraver.cc +++ b/lily/tie-engraver.cc @@ -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 past_notes_pq_; Moment end_mom_; Moment next_end_mom_; Tie_req *req_l_; - Array now_heads_; - Array stopped_heads_; + Link_array now_heads_; + Link_array stopped_heads_; Link_array 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 (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); + } } diff --git a/lily/translator-group.cc b/lily/translator-group.cc index aac575c38b..34e8d0c63e 100644 --- a/lily/translator-group.cc +++ b/lily/translator-group.cc @@ -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) (); } diff --git a/lilypond-mode.el b/lilypond-mode.el index 57c60489d6..eefc34282e 100644 --- a/lilypond-mode.el +++ b/lilypond-mode.el @@ -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_]*\\) *=" diff --git a/ly/drumpitch-init.ly b/ly/drumpitch-init.ly index 211246f081..c70b18e0fe 100644 --- a/ly/drumpitch-init.ly +++ b/ly/drumpitch-init.ly @@ -116,7 +116,7 @@ #(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)) )) @@ -137,20 +137,23 @@ (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) diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 003d380d3f..0e1f1e7181 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -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) diff --git a/make/lilypond.redhat.spec.in b/make/lilypond.redhat.spec.in index 1489a8cc53..c75f25b10f 100644 --- a/make/lilypond.redhat.spec.in +++ b/make/lilypond.redhat.spec.in @@ -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" diff --git a/make/lilypond.suse.spec.in b/make/lilypond.suse.spec.in index 4c3253f95b..1eec5b418b 100644 --- a/make/lilypond.suse.spec.in +++ b/make/lilypond.suse.spec.in @@ -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 diff --git a/make/out/lilypond.lsm b/make/out/lilypond.lsm index e9bc7e9f71..7a3ad6a10d 100644 --- a/make/out/lilypond.lsm +++ b/make/out/lilypond.lsm @@ -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 diff --git a/make/out/lilypond.mandrake.spec b/make/out/lilypond.mandrake.spec index 0bfd672632..b8784354e3 100644 --- a/make/out/lilypond.mandrake.spec +++ b/make/out/lilypond.mandrake.spec @@ -1,5 +1,5 @@ %define name lilypond -%define version 1.5.26 +%define version 1.5.27 %define release 1mdk Name: %{name} diff --git a/make/out/lilypond.redhat.spec b/make/out/lilypond.redhat.spec index 3f62515f68..7d16d85b7d 100644 --- a/make/out/lilypond.redhat.spec +++ b/make/out/lilypond.redhat.spec @@ -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" diff --git a/make/out/lilypond.suse.spec b/make/out/lilypond.suse.spec index 35b61fe56b..afe1711f6a 100644 --- a/make/out/lilypond.suse.spec +++ b/make/out/lilypond.suse.spec @@ -14,11 +14,11 @@ 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 diff --git a/scm/font.scm b/scm/font.scm index d1813de9a1..ffdae61043 100644 --- a/scm/font.scm +++ b/scm/font.scm @@ -205,10 +205,10 @@ (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))) diff --git a/scm/grob-description.scm b/scm/grob-description.scm index fd68506d0d..3938da7413 100644 --- a/scm/grob-description.scm +++ b/scm/grob-description.scm @@ -529,7 +529,9 @@ )) (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) diff --git a/scm/grob-property-description.scm b/scm/grob-property-description.scm index 0df5480c15..0d018c3d97 100644 --- a/scm/grob-property-description.scm +++ b/scm/grob-property-description.scm @@ -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 diff --git a/scm/interface-description.scm b/scm/interface-description.scm index 1e2fda7b37..ce5f960c3f 100644 --- a/scm/interface-description.scm +++ b/scm/interface-description.scm @@ -122,6 +122,7 @@ 'note-column-interface "Stem and noteheads combined" '( + note-heads horizontal-shift force-hshift )) diff --git a/scm/translator-property-description.scm b/scm/translator-property-description.scm index f5b1adaf40..93aabd8cdd 100644 --- a/scm/translator-property-description.scm +++ b/scm/translator-property-description.scm @@ -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?") diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index 8befc79dae..4e431b030f 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -468,8 +468,10 @@ re_dict = { 'lilypond-file': '(?m)^(?!@c)(?P@lilypondfile(\[(?P.*?)\])?{(?P[^}]+)})', 'lilypond' : '(?m)^(?!@c)(?P@lilypond(\[(?P.*?)\])?{(?P.*?)})', # pyton2.2b2 barfs on this -# 'lilypond-block': r"""(?m)^(?!@c)(?P(?s)(?P@lilypond(\[(?P.*?)\])?\s(?P.*?)@end lilypond\s))""", - 'lilypond-block': r"""(?m)^(?!@c)(?P@lilypond(\[(?P.*?)\])?\s(?P.*?)@end lilypond\s)""", + 'lilypond-block': r"""(?m)^(?!@c)(?P(?s)(?P@lilypond(\[(?P.*?)\])?\s(?P.*?)@end lilypond\s))""", + +# 1.5.2 barfs on this. +# 'lilypond-block': r"""(?m)^(?!@c)(?P@lilypond(\[(?P.*?)\])?\s(?P.*?)@end lilypond\s)""", 'option-sep' : ',\s*', 'intertext': r',?\s*intertext=\".*?\"', 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P@ignore\s.*?@end ignore)\s", diff --git a/tex/lilyponddefs.tex b/tex/lilyponddefs.tex index bc30d54039..c47267cead 100644 --- a/tex/lilyponddefs.tex +++ b/tex/lilyponddefs.tex @@ -46,6 +46,8 @@ \fi \ifundefined{lilypondpaperinterscorelinefill} \def\lilypondpaperinterscorelinefill{0} +\else + \def\lilypondpaperinterscorelinefill{1} \fi \def\interscoreline{\vskip\lilypondpaperinterscoreline pt plus % -- 2.39.2