2004-02-04 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ * lily/parser.yy (part_combined_music): remove old PC cruft.
+
+ * ly/engraver-init.ly: remove old
+ PC cruft.
+
+ * Documentation/user/refman.itely (The Lyrics context): note about
+ extender lines.
-
* lily/multi-measure-rest-engraver.cc (process_music): extra check
to allow 0-length mmrest events.
@refbugs
-The definition of lyrics mode is too complex.
+The definition of lyrics mode is too complex.
+
+
@node The Lyrics context
@subsection The Lyrics context
inserted by hand.
+For proper processing of extender lines, the
+@internalsref{LyricsVoice} and @internalsref{Voice} should be
+linked. This can be achieved either by using @code{\lyricsto} or by
+setting corresponding names for both contexts. The latter is explained
+in @ref{More stanzas}.
+
@node More stanzas
@subsection More stanzas
The lyrics should be aligned with the note heads of the melody. To
achieve this, each line of lyrics should be marked to correspond with
-the melodic line.
+the melodic line. This is done automatically when @code{\lyricsto},
+but it can also be done manually.
To this end, give the @internalsref{Voice} context an identity:
@example
PACKAGE_NAME=LilyPond
MAJOR_VERSION=2
MINOR_VERSION=1
-PATCH_LEVEL=17
-MY_PATCH_LEVEL=hwn1
+PATCH_LEVEL=18
+MY_PATCH_LEVEL=
+++ /dev/null
-
-\header {
- texidoc ="The a2 string is only printed on notes, not on rests,
-and only after chords, solo or polyphony."
- }
-
-vone = \notes \relative a' { R1*2 g2 r2 g2 r2 a4 r4 g
- }
-vtwo = \notes \relative a' { R1*2 g2 r2 g2 r2 f4 r4 g }
-
-\score {
- << \property Score.skipBars = ##t
- \newpartcombine \vone \vtwo
- >>
-}
-
+++ /dev/null
-
-\header { texidoc = "Solo/Solo2 also is global: In this example, solo1
- should not printed over the 1st note, because the voice
- switch would kill the slur."
-
-}
-
-
-\score {
- \new Staff
- \newpartcombine \notes \relative c'' {
- bes2(
- a4)
- }
- \notes \relative c' {
- r2 cis4
- }
-}
+++ /dev/null
-
-\header { texidoc =
-
- "A solo string can only be printed when a note
- starts. Hence, in this example, there is no Solo-2 although the
- 2nd voice has a dotted quarter, while the first voice has a rest.
-
-A Solo indication is only printed once; (shared) rests do not require
-reprinting a solo indication.
-
-Solo 1/2 can not be used when a spanner is active, so there is no solo
- over any of the tied notes.
-
-"
- }
-
-vone = \notes \relative a' { g4 r8 g8 g8 r8 g8 r8 g2 ~ g2 ~ g4 }
-vtwo = \notes \relative g' { e4. e8 r2 e4 r4 r2 e4 }
-
-\score {
-
- << \property Score.skipBars = ##t
- \newpartcombine \vone \vtwo
- >>
-}
-
+++ /dev/null
-
-\header {
- texidoc ="The new part combiner:
-
-Detect a2, solo1, solo2 and print texts accordingly.
-
-"
-
-
- }
-
-
-vone = \notes \relative a' { R1 a2 r4 r a a a a }
-vtwo = \notes \relative a' { R1 f4 f4 f4 f f f a a }
-
-\score {
- \newpartcombine \vone \vtwo
-}
-
+++ /dev/null
-
-\header {
- texidoc ="The new part combiner.
-Apart for:
-@itemize @bullet
-@item different durations (start points)
-@item different articulations (only slur/beam/tie work)
-@item wide pitch ranges
-@end itemize
-"
- }
-
-vone = \notes \relative a' { g2 g g g4 g f' c c( c) c c c ~ c
- c2. c4 c
- }
-vtwo = \notes \relative a' { f2 f4 f f2 g4 g c, f f f f f~ f ~ f
- f4 f2. ~ f4
-
- }
-
-\score {
- \newpartcombine \vone \vtwo
-}
-
--- /dev/null
+
+\header {
+ texidoc ="The a2 string is only printed on notes, not on rests,
+and only after chords, solo or polyphony."
+ }
+
+vone = \notes \relative a' { R1*2 g2 r2 g2 r2 a4 r4 g
+ }
+vtwo = \notes \relative a' { R1*2 g2 r2 g2 r2 f4 r4 g }
+
+\score {
+ << \property Score.skipBars = ##t
+ \newpartcombine \vone \vtwo
+ >>
+}
+
--- /dev/null
+
+\header { texidoc = "Solo/Solo2 also is global: In this example, solo1
+ should not printed over the 1st note, because the voice
+ switch would kill the slur."
+
+}
+
+
+\score {
+ \new Staff
+ \newpartcombine \notes \relative c'' {
+ bes2(
+ a4)
+ }
+ \notes \relative c' {
+ r2 cis4
+ }
+}
--- /dev/null
+
+\header { texidoc =
+
+ "A solo string can only be printed when a note
+ starts. Hence, in this example, there is no Solo-2 although the
+ 2nd voice has a dotted quarter, while the first voice has a rest.
+
+A Solo indication is only printed once; (shared) rests do not require
+reprinting a solo indication.
+
+Solo 1/2 can not be used when a spanner is active, so there is no solo
+ over any of the tied notes.
+
+"
+ }
+
+vone = \notes \relative a' { g4 r8 g8 g8 r8 g8 r8 g2 ~ g2 ~ g4 }
+vtwo = \notes \relative g' { e4. e8 r2 e4 r4 r2 e4 }
+
+\score {
+
+ << \property Score.skipBars = ##t
+ \newpartcombine \vone \vtwo
+ >>
+}
+
--- /dev/null
+
+\header {
+ texidoc ="The new part combiner:
+
+Detect a2, solo1, solo2 and print texts accordingly.
+
+"
+
+
+ }
+
+
+vone = \notes \relative a' { R1 a2 r4 r a a a a }
+vtwo = \notes \relative a' { R1 f4 f4 f4 f f f a a }
+
+\score {
+ \newpartcombine \vone \vtwo
+}
+
--- /dev/null
+
+\header {
+ texidoc ="The new part combiner.
+Apart for:
+@itemize @bullet
+@item different durations (start points)
+@item different articulations (only slur/beam/tie work)
+@item wide pitch ranges
+@end itemize
+"
+ }
+
+vone = \notes \relative a' { g2 g g g4 g f' c c( c) c c c ~ c
+ c2. c4 c
+ }
+vtwo = \notes \relative a' { f2 f4 f f2 g4 g c, f f f f f~ f ~ f
+ f4 f2. ~ f4
+
+ }
+
+\score {
+ \newpartcombine \vone \vtwo
+}
+
+++ /dev/null
-/*
- a2-engraver.cc -- implement A2_engraver
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
-*/
-
-#include "engraver.hh"
-#include "item.hh"
-#include "note-head.hh"
-#include "stem.hh"
-#include "slur.hh"
-#include "translator-group.hh"
-#include "side-position-interface.hh"
-#include "directional-element-interface.hh"
-#include "multi-measure-rest.hh"
-#include "tie.hh"
-
-class A2_engraver : public Engraver
-{
- TRANSLATOR_DECLARATIONS(A2_engraver);
-
-protected:
- virtual void acknowledge_grob (Grob_info);
- virtual void process_acknowledged_grobs ();
- virtual void stop_translation_timestep ();
-private:
- Item* text_;
- enum State { SOLO, SPLIT_INTERVAL, UNIRHYTHM, UNISILENCE, UNISON } state_;
-};
-
-
-
-A2_engraver::A2_engraver ()
-{
- text_ = 0;
- state_ = UNISILENCE;
-}
-
-void
-A2_engraver::process_acknowledged_grobs ()
-{
- if (!to_boolean (get_property ("combineParts")))
- return ;
- if (!text_)
- {
- SCM unison = get_property ("unison");
- SCM solo = get_property ("solo");
- SCM solo_adue = get_property ("soloADue");
-
- if (solo_adue == SCM_BOOL_T
- && ((solo == SCM_BOOL_T && state_ != SOLO)
- || (unison == SCM_BOOL_T && state_ != UNISON
- && daddy_trans_->id_string_.left_string (3) == "one")))
- {
- text_ = make_item ("TextScript");
- Side_position_interface::set_axis (text_, Y_AXIS);
- announce_grob(text_, SCM_EOL);
-
- Direction dir = UP;
- SCM text = SCM_EOL;
- if (solo == SCM_BOOL_T)
- {
- state_ = SOLO;
- if (daddy_trans_->id_string_.left_string (3) == "one")
- {
- text = get_property ("soloText");
- }
- else
- {
- text = get_property ("soloIIText");
- dir = DOWN;
- }
- }
- else if (unison == SCM_BOOL_T)
- {
- state_ = UNISON;
- if (daddy_trans_->id_string_.left_string (3) == "one")
- text = get_property ("aDueText");
- }
-
- set_grob_direction (text_, dir);
- text_->set_grob_property ("text", text);
- }
- }
-}
-
-void
-A2_engraver::acknowledge_grob (Grob_info i)
-{
- if (!to_boolean (get_property ("combineParts")))
- return ;
-
- if (text_)
- {
- if (Note_head::has_interface (i.grob_))
- {
- Grob*t = text_;
- Side_position_interface::add_support (t, i.grob_);
- if (Side_position_interface::get_axis (t) == X_AXIS
- && !t->get_parent (Y_AXIS))
- t->set_parent (i.grob_, Y_AXIS);
- }
- if (Stem::has_interface (i.grob_))
- {
- Side_position_interface::add_support (text_, i.grob_);
- }
- }
-
- SCM unisilence = get_property ("unisilence");
- SCM unison = get_property ("unison");
- SCM unirhythm = get_property ("unirhythm");
- SCM solo = get_property ("solo");
- SCM split_interval = get_property ("split-interval");
- SCM solo_adue = get_property ("soloADue");
-
- State previous_state = state_;
- if (unisilence == SCM_BOOL_T)
- /*
- state_ = UNISILENCE;
- */
- ;
- else if (solo == SCM_BOOL_T)
- state_ = SOLO;
- else if (unison == SCM_BOOL_T)
- state_ = UNISON;
- else if (unirhythm == SCM_BOOL_T && split_interval == SCM_BOOL_T)
- state_ = SPLIT_INTERVAL;
- else if (unirhythm)
- state_ = UNIRHYTHM;
-
- Direction d = CENTER;
- if (daddy_trans_->id_string_.left_string (3) == "one")
- d = UP;
- else if (daddy_trans_->id_string_.left_string (3) == "two")
- d = DOWN;
-
- /* Must only set direction for VoiceCombines, not for StaffCombines:
- we can't detect that here, so we use yet another property */
- if (!to_boolean (get_property ("noDirection"))
- && (Stem::has_interface (i.grob_)
- || Slur::has_interface (i.grob_)
- || Tie::has_interface (i.grob_)
- /* Usually, dynamics are removed by *_devnull_engravers for
- the second voice. On the one hand, we don't want all
- dynamics for the first voice to be placed above the
- staff. On the other hand, colliding of scripts may be
- worse. So, we don't set directions for these when we're
- playing solo. */
- || (i.grob_->internal_has_interface (ly_symbol2scm
- ("dynamic-interface"))
- && state_ != SOLO)
- || (i.grob_->internal_has_interface (ly_symbol2scm
- ("text-interface"))
- && state_ != SOLO)
- ))
- {
- /* When in solo a due mode, and we have solo, every grob in
- other thread gets annihilated, so we don't set dir.
-
- Maybe that should be optional? */
- if ((solo != SCM_BOOL_T && solo_adue == SCM_BOOL_T)
-
- /* When not same rhythm, we set dir */
- && (unirhythm != SCM_BOOL_T
- /* When both have rests, but previously played something
- different, we set dir */
- || ((unisilence == SCM_BOOL_T && previous_state != UNISON))
- /* When same rhythm, and split stems, but not same pitch
- or not solo a du mode, we set dir */
- || (unirhythm == SCM_BOOL_T && split_interval == SCM_BOOL_T
- && (unison != SCM_BOOL_T || solo_adue != SCM_BOOL_T))))
- {
-
- /* Blunt axe method: every grob gets a propertysetting. */
- i.grob_->set_grob_property ("direction", scm_int2num (d));
- }
- }
-
- /* Should we have separate state variable for being "rest
- while other has solo?" */
- if (Multi_measure_rest::has_interface (i.grob_) && d)
- if (state_ == UNIRHYTHM
- && unisilence != SCM_BOOL_T)
- {
- i.grob_->set_grob_property ("staff-position", scm_int2num (d * 6));
- }
-}
-
-void
-A2_engraver::stop_translation_timestep ()
-{
- if (text_)
- {
- typeset_grob (text_);
- text_ = 0;
- }
-}
-
-ENTER_DESCRIPTION(A2_engraver,
-/* descr */ "Part combine engraver for orchestral scores. "
-"The markings @emph{a2}, @emph{Solo} and @emph{Solo II}, are "
-"created by this engraver. It also acts upon instructions of the part "
-"combiner. Another thing that the this engraver, is forcing of stem, "
-"slur and tie directions, always when both threads are not identical; "
-"up for the musicexpr called @code{one}, down for the musicexpr called "
-"@code{two}. "
-,
-/* creats*/ "TextScript",
-/* accepts */ "",
-/* acks */ "multi-measure-rest-interface "
-"slur-interface stem-interface tie-interface note-head-interface dynamic-interface text-interface"
-,/* reads */ "combineParts noDirection soloADue soloText soloIIText aDueText split-interval unison solo unisilence unirhythm",
-/* write */ "");
{"midi", MIDI},
{"name", NAME},
{"new", NEWCONTEXT},
- {"newpartcombine", NEWPARTCOMBINE},
{"notes", NOTES},
{"octave", OCTAVE},
{"once", ONCE},
(c) 2004 Han-Wen Nienhuys
*/
-#include "part-combine-music-iterator.hh"
#include "translator-group.hh"
#include "event.hh"
#include "music-sequence.hh"
%token OVERRIDE SET REVERT
%token PAPER
%token PARTCOMBINE
-%token NEWPARTCOMBINE
%token PARTIAL
%token PITCHNAMES
%token PROPERTY
;
part_combined_music:
- PARTCOMBINE STRING Music Music {
- Music * p= MY_MAKE_MUSIC("PartCombineMusic");
- p->set_mus_property ("what", scm_string_to_symbol ($2));
- p->set_mus_property ("elements", gh_list ($3->self_scm (),$4->self_scm (), SCM_UNDEFINED));
-
- scm_gc_unprotect_object ($3->self_scm ());
- scm_gc_unprotect_object ($4->self_scm ());
-
- $$ = p;
- }
- | NEWPARTCOMBINE Music Music {
+ PARTCOMBINE Music Music {
static SCM proc;
if (!proc)
- proc = scm_c_eval_string ("make-new-part-combine-music");
+ proc = scm_c_eval_string ("make-part-combine-music");
SCM res = scm_call_1 (proc, gh_list ($2->self_scm (),
$3->self_scm (), SCM_UNDEFINED));
+++ /dev/null
-/*
- part-combine-music-iterator.cc -- implement Part_combine_music_iterator
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
- */
-
-#include "part-combine-music-iterator.hh"
-#include "translator-group.hh"
-#include "event.hh"
-#include "music-sequence.hh"
-#include "lily-guile.hh"
-#include "warn.hh"
-#include "music-iterator.hh"
-
-class Part_combine_music_iterator : public Music_iterator
-{
-public:
- VIRTUAL_COPY_CONS (Music_iterator);
- Part_combine_music_iterator ();
-
- enum State { UNKNOWN, UNRELATED=1, SOLO1=2, SOLO2=4, UNIRHYTHM=8, UNISON=16, UNISILENCE=32, SPLIT_INTERVAL=64 };
- DECLARE_SCHEME_CALLBACK(constructor, ());
-protected:
- virtual void derived_substitute (Translator_group*f, Translator_group*t) ;
-
- virtual void derived_mark () const;
- Part_combine_music_iterator (Part_combine_music_iterator const &);
- virtual void construct_children ();
- virtual Moment pending_moment () const;
- virtual void do_quit();
- virtual void process (Moment);
- virtual SCM get_pending_events (Moment)const;
- virtual Music_iterator *try_music_in_children (Music *) const;
- virtual bool ok () const;
-
-private:
- void change_to (Music_iterator*, SCM, String);
- int get_state (Moment m);
-
- Music_iterator * first_iter_;
- Music_iterator * second_iter_;
- Moment first_until_;
- Moment second_until_;
- int state_;
- String suffix_;
-};
-
-
-Part_combine_music_iterator::Part_combine_music_iterator ()
-{
- first_iter_ = 0;
- second_iter_ = 0;
- first_until_ = 0;
- second_until_ = 0;
- state_ = 0;
-}
-
-void
-Part_combine_music_iterator::derived_mark () const
-{
- if (first_iter_)
- scm_gc_mark (first_iter_->self_scm());
- if (second_iter_)
- scm_gc_mark(second_iter_->self_scm());
-}
-
-void
-Part_combine_music_iterator::derived_substitute (Translator_group*f,
- Translator_group*t)
-{
- if (first_iter_)
- first_iter_->substitute_outlet (f,t);
- if (second_iter_)
- second_iter_->substitute_outlet (f,t);
-}
-
-void
-Part_combine_music_iterator::do_quit ()
-{
- if (first_iter_)
- first_iter_->quit();
- if (second_iter_)
- second_iter_->quit();
-}
-
-Part_combine_music_iterator::Part_combine_music_iterator (Part_combine_music_iterator const &src)
- : Music_iterator (src)
-{
- first_iter_ = 0;
- second_iter_ = 0;
-
- if(src.first_iter_)
- first_iter_ = src.first_iter_->clone ();
- if (src.second_iter_)
- second_iter_ = src.second_iter_->clone ();
-
- first_until_ = src.first_until_;
- second_until_ = src.second_until_;
- state_ = src.state_;
- suffix_ = src.suffix_;
-
- if (first_iter_)
- scm_gc_unprotect_object (first_iter_->self_scm());
- if (second_iter_)
- scm_gc_unprotect_object (second_iter_->self_scm());
-}
-
-Moment
-Part_combine_music_iterator::pending_moment () const
-{
- Moment p;
- p.set_infinite (1);
- if (first_iter_->ok ())
- p = p <? first_iter_->pending_moment ();
-
- if (second_iter_->ok ())
- p = p <? second_iter_->pending_moment ();
- return p;
-}
-
-bool
-Part_combine_music_iterator::ok () const
-{
- return first_iter_->ok () || second_iter_->ok ();
-}
-
-
-void
-Part_combine_music_iterator::construct_children ()
-{
- SCM lst = get_music ()->get_mus_property ("elements");
-
- first_iter_ = unsmob_iterator (get_iterator (unsmob_music (gh_car (lst))));
- second_iter_ = unsmob_iterator (get_iterator (unsmob_music (gh_cadr (lst))));
-}
-
-void
-Part_combine_music_iterator::change_to (Music_iterator *it, SCM to_type,
- String to_id)
-{
- Translator_group * current = it->report_to ();
- Translator_group * last = 0;
-
- /*
- Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
-
- TODO: abstract this function
- */
-
- /* find the type of translator that we're changing.
-
- If \translator Staff = bass, then look for Staff = *
- */
- while (current && !current->is_alias (to_type))
- {
- last = current;
- current = current->daddy_trans_;
- }
-
- if (current && current->id_string_ == to_id)
- {
- String msg;
- msg += _ ("Can't switch translators, I'm there already");
- }
-
- if (current)
- if (last)
- {
- Translator_group * dest =
- it->report_to ()->find_create_translator (to_type, to_id, SCM_EOL);
- current->remove_translator (last);
- dest->add_used_group_translator (last);
- }
- else
- {
- /*
- We could change the current translator's id, but that would make
- errors hard to catch
-
- last->translator_id_string_ = get_change ()->change_to_id_string_;
- */
- error (_f ("I'm one myself: `%s'", ly_symbol2string (to_type).to_str0 ()));
- }
- else
- error (_f ("none of these in my family: `%s'", to_id.to_str0 ()));
-}
-
-
-// SCM*, moet / kan dat niet met set_x ofzo?
-static void
-get_music_info (Moment m, Music_iterator* iter, SCM *pitches, SCM *durations)
-{
- if (iter->ok ())
- {
- for (SCM i = iter->get_pending_events (m); gh_pair_p (i); i = ly_cdr (i))
- {
- Music *m = unsmob_music (ly_car (i));
- SCM p = m->get_mus_property ("pitch");
- SCM d = m->get_mus_property ("duration");
- if (unsmob_pitch (p))
- *pitches = gh_cons (p, *pitches);
- if (unsmob_duration (d))
- *durations = gh_cons (d, *durations);
- }
- }
-}
-
-int
-Part_combine_music_iterator::get_state (Moment)
-{
- int state = UNKNOWN;
-
- Music *p = get_music ();
-
- SCM w = p->get_mus_property ("what");
-
-
- Translator_group *first_translator = first_iter_->report_to ()->find_create_translator (w, "one" + suffix_, SCM_EOL);
-
- SCM s = first_translator->get_property ("changeMoment");
- if (!gh_pair_p (s))
- return state;
-
- Moment change_mom = *unsmob_moment (ly_car (s));
- Moment diff_mom = *unsmob_moment (ly_cdr (s));
-
- Moment now = pending_moment ();
-
- if (!now.main_part_.mod_rat (change_mom.main_part_))
- {
- SCM interval = SCM_BOOL_F;
- if (first_until_ < now)
- first_until_ = now;
- if (second_until_ < now)
- second_until_ = now;
-
- Moment first_mom = first_until_;
- Moment second_mom = second_until_;
- Moment diff_until = diff_mom + now;
-
-
- bool first = true;
- Music_iterator *first_iter = first_iter_->clone ();
- Music_iterator *second_iter = second_iter_->clone ();
-
- Moment last_pending (-1);
- Moment pending = now;
- while (now < diff_until
- && (first_iter->ok () || second_iter->ok ())
-
- // urg, this is a hack, haven't caught this case yet
- && (pending != last_pending))
- {
- if (!second_iter->ok ())
- pending = first_iter->pending_moment ();
- else if (!first_iter->ok ())
- pending = second_iter->pending_moment ();
- else
- pending = first_iter->pending_moment () <? second_iter->pending_moment ();
- last_pending = pending;
-
- SCM first_pitches = SCM_EOL;
- SCM first_durations = SCM_EOL;
- get_music_info (pending, first_iter,
- &first_pitches, &first_durations);
-
- SCM second_pitches = SCM_EOL;
- SCM second_durations = SCM_EOL;
- get_music_info (pending, second_iter,
- &second_pitches, &second_durations);
-
- if (first_pitches != SCM_EOL && second_pitches != SCM_EOL)
- {
- scm_sort_list_x (first_pitches, Pitch::less_p_proc);
- scm_sort_list_x (second_pitches, Pitch::less_p_proc);
-
- interval = gh_int2scm (unsmob_pitch (ly_car (first_pitches))->steps ()
- - unsmob_pitch (ly_car (scm_last_pair (second_pitches)))->steps ());
- }
-
- if (first_durations != SCM_EOL)
- {
- scm_sort_list_x (first_durations,
- Duration::less_p_proc);
- first_mom += unsmob_duration (ly_car (first_durations))->get_length ();
- }
-
- if (second_durations != SCM_EOL)
- {
- scm_sort_list_x (second_durations,
- Duration::less_p_proc);
- second_mom += unsmob_duration (ly_car (second_durations))->get_length ();
- }
-
- if (first_pitches != SCM_EOL && second_pitches == SCM_EOL
- && ! (second_until_ > now))
- {
- state |= UNRELATED;
- state &= ~UNISILENCE;
- if (! (state & ~ (UNRELATED | SOLO1 | UNISILENCE)))
- state |= SOLO1;
- }
- else
- state &= ~SOLO1;
-
- if (first_pitches == SCM_EOL && second_pitches != SCM_EOL
- && ! (first_until_ > now))
- {
- state |= UNRELATED;
- state &= ~UNISILENCE;
- if (! (state & ~ (UNRELATED | SOLO2 | UNISILENCE)))
- state |= SOLO2;
- }
- else
- state &= ~SOLO2;
-
- if (gh_equal_p (first_durations, second_durations))
- {
- state &= ~UNISILENCE;
- if (! (state & ~ (UNIRHYTHM | UNISON)))
- state |= UNIRHYTHM;
- }
- else
- state &= ~ (UNIRHYTHM | UNISILENCE);
-
- if (first_pitches != SCM_EOL
- && gh_equal_p (first_pitches, second_pitches))
- {
- state &= ~UNISILENCE;
- if (! (state & ~ (UNIRHYTHM | UNISON)))
- state |= UNISON;
- }
- else
- state &= ~ (UNISON);
-
- if (first_pitches == SCM_EOL && second_pitches == SCM_EOL)
- {
- if (! (state & ~ (UNIRHYTHM | UNISILENCE)))
- state |= UNISILENCE;
- }
- else if (!state)
- state |= UNRELATED;
- else
- state &= ~ (UNISILENCE);
-
- if (gh_number_p (interval))
- {
- SCM s = first_translator->get_property ("splitInterval");
- int i = gh_scm2int (interval);
- if (gh_pair_p (s)
- && gh_number_p (ly_car (s))
- && gh_number_p (ly_cdr (s))
- && i >= gh_scm2int (ly_car (s))
- && i <= gh_scm2int (ly_cdr (s)))
- {
- if (! (state & ~ (SPLIT_INTERVAL | UNIRHYTHM | UNISON)))
- state |= SPLIT_INTERVAL;
- }
- else
- state &= ~ (SPLIT_INTERVAL);
- }
-
- if (first && first_pitches != SCM_EOL)
- first_until_ = first_mom;
- if (first && second_pitches != SCM_EOL)
- second_until_ = second_mom;
- first = false;
-
- if (first_iter->ok ())
- first_iter->skip (pending);
- if (second_iter->ok ())
- second_iter->skip (pending);
- now = pending;
- }
- scm_gc_unprotect_object (first_iter->self_scm ());
- scm_gc_unprotect_object (second_iter->self_scm ());
- }
-
- return state;
-}
-
-static Music* abort_req = NULL;
-
-void
-Part_combine_music_iterator::process (Moment m)
-{
-
- /*
- TODO:
- - Use three named contexts (be it Thread or Voice): one, two, solo.
- Let user pre-set (pushproperty) stem direction, remove
- dynamic-engraver, and such.
-
- **** Tried this, but won't work:
-
-s Consider thread switching: threads "one", "two" and "both".
- User can't pre-set the (most important) stem direction at
- thread level!
- */
-
- if (suffix_.is_empty ())
- suffix_ = first_iter_->report_to ()
- ->daddy_trans_->id_string_.cut_string (3, INT_MAX);
-
- int state = get_state (m);
- if (state)
- state_ = state;
- else
- state = state_;
-
- Music *p =get_music ();
-
-
- bool previously_combined_b = first_iter_->report_to ()->daddy_trans_
- == second_iter_->report_to ()->daddy_trans_;
-
- bool combine_b = previously_combined_b;
-
- if (! (state & UNIRHYTHM)
- || (state & SPLIT_INTERVAL)
- || (state & (SOLO1 | SOLO2)))
- combine_b = false;
- else if (state & (UNIRHYTHM | UNISILENCE))
- combine_b = true;
-
- /*
- When combining, abort all running spanners
- */
-
- if (!abort_req)
- {
- abort_req = make_music_by_name (ly_symbol2scm ("AbortEvent"));
- }
-
- if (combine_b && combine_b != previously_combined_b)
- {
- if (second_iter_ && second_iter_->ok ())
- second_iter_->try_music (abort_req);
- }
- SCM w = p->get_mus_property ("what");
- if (combine_b != previously_combined_b)
- change_to (second_iter_, w, (combine_b ? "one" : "two")
- + suffix_);
-
- Translator_group *first_translator = first_iter_->report_to ()->find_create_translator (w, "one" + suffix_, SCM_EOL);
- Translator_group *second_translator = second_iter_->report_to ()->find_create_translator (w, "two" + suffix_, SCM_EOL);
-
-
- /* Hmm */
- first_translator->set_property ("combineParts", SCM_BOOL_T);
- second_translator ->set_property ("combineParts", SCM_BOOL_T);
-
-
- /* hmm */
- SCM b = (state & UNIRHYTHM) ? SCM_BOOL_T : SCM_BOOL_F;
- first_translator->set_property ("unirhythm", b);
- second_translator->set_property ("unirhythm", b);
-
- b = (state & SPLIT_INTERVAL) ? SCM_BOOL_T : SCM_BOOL_F;
- first_translator->set_property ("split-interval", b);
- second_translator->set_property ("split-interval", b);
-
- b = (state & UNISILENCE) ? SCM_BOOL_T : SCM_BOOL_F;
- first_translator->set_property ("unisilence", b);
- second_translator->set_property ("unisilence", b);
-
- // difference in definition...
- //b = ((state & UNISON) ? SCM_BOOL_T : SCM_BOOL_F;
- b = ((state & UNISON) && (state & UNIRHYTHM)) ? SCM_BOOL_T : SCM_BOOL_F;
- first_translator->set_property ("unison", b);
- second_translator->set_property ("unison", b);
-
- SCM b1 = (state & SOLO1) ? SCM_BOOL_T : SCM_BOOL_F;
- SCM b2 = (state & SOLO2) ? SCM_BOOL_T : SCM_BOOL_F;
- first_translator->set_property ("solo", b1);
- second_translator->set_property ("solo", b2);
-
- /* Can't these be computed? */
- first_translator->set_property ("othersolo", b2);
- second_translator->set_property ("othersolo", b1);
-
- if (first_iter_->ok ())
- first_iter_->process (m);
-
- if (second_iter_->ok ())
- second_iter_->process (m);
-}
-
-Music_iterator*
-Part_combine_music_iterator::try_music_in_children (Music *m) const
-{
- Music_iterator * i = first_iter_->try_music (m);
- if (i)
- return i;
- else
- return second_iter_->try_music (m);
-}
-
-
-SCM
-Part_combine_music_iterator::get_pending_events (Moment m)const
-{
- SCM s = SCM_EOL;
- if (first_iter_)
- s = gh_append2 (s,first_iter_->get_pending_events (m));
- if (second_iter_)
- s = gh_append2 (second_iter_->get_pending_events (m),s);
- return s;
-}
-
-IMPLEMENT_CTOR_CALLBACK (Part_combine_music_iterator);
+++ /dev/null
-/*
- thread-devnull-engraver.cc -- implement Thread_devnull_engraver
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
-*/
-
-#include "engraver.hh"
-#include "item.hh"
-#include "event.hh"
-#include "translator-group.hh"
-
-class Thread_devnull_engraver : public Engraver
-{
-public:
- TRANSLATOR_DECLARATIONS(Thread_devnull_engraver);
-
-protected:
- virtual void acknowledge_grob (Grob_info);
-};
-
-
-
-void
-Thread_devnull_engraver::acknowledge_grob (Grob_info i)
-{
- SCM s = get_property ("devNullThread");
-
- if (s == ly_symbol2scm ("always")
- || (s == SCM_EOL
- && to_boolean (get_property ("soloADue"))
- && ((daddy_trans_->id_string_.left_string (3) == "two"
- && (to_boolean (get_property ("unison"))
- || to_boolean (get_property ("unisilence"))))
-
- /* Maybe this should be optional? */
- || to_boolean (get_property ("othersolo")))))
- {
- i.grob_->suicide ();
- }
-}
-Thread_devnull_engraver::Thread_devnull_engraver(){}
-
-ENTER_DESCRIPTION(Thread_devnull_engraver,
-/* descr */ "Kill elements whenever we are Voice called `two' and either "
-"unison, unisilence or soloADue is set.@footnote{On unix systems, the "
-"file @file{/dev/null} is special device: anything written to it is "
-"discarded.}. This engraver works closely together with the part "
-"combiner. When the part combiner notices that two threads are "
-"identical, it tells the @code{Thread_devnull_engraver} to discard "
-"everything in the second thread. "
-,
-/* creats*/ "",
-/* accepts */ "",
-/* acks */ "grob-interface",
-/* reads */ "",
-/* write */ "");
+++ /dev/null
-/*
- voice-devnull-engraver.cc -- implement Voice_devnull_engraver
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
-*/
-
-#include "engraver.hh"
-#include "item.hh"
-#include "event.hh"
-#include "translator-group.hh"
-
-class Voice_devnull_engraver : public Engraver
-{
-public:
- TRANSLATOR_DECLARATIONS(Voice_devnull_engraver);
-
-protected:
- virtual bool try_music (Music *m);
- virtual void acknowledge_grob (Grob_info);
-};
-
-
-/*
-
-ARGH .
-
-
-This really sucks.
-
- */
-static char const *eat_spanners[] = {
- "beam",
- "crescendo",
- "decrescendo",
- "rest",
- "slur",
- 0
-};
-
-bool
-Voice_devnull_engraver::try_music (Music *m)
-{
- SCM s = get_property ("devNullVoice");
-
- if (gh_equal_p (s, ly_symbol2scm ("always"))
- || (s == SCM_EOL
- && daddy_trans_->id_string_.left_string (3) == "two"
- && (to_boolean (get_property ("unison"))
- || to_boolean (get_property ("unisilence")))))
- {
- if (m->is_mus_type ("span-event"))
- {
- SCM t = m->get_mus_property ("span-type");
-
- for (char const **p = eat_spanners; *p; p++)
- {
- if (t == scm_makfrom0str (*p))
- return true;
- }
- }
- /* Ugh. Should eat other events, script etc. too. */
- else if (m->is_mus_type ("tie-event"))
- return true;
- }
- return false;
-}
-
-static char const *junk_interfaces[] = {
- "beam-interface",
- "dynamic-interface",
- "hairpin-interface",
- "multi-measure-rest-interface",
- "script-interface",
- "slur-interface",
- "text-interface",
- "text-item-interface",
- "text-script-interface",
- "text-spanner-interface",
- "tie-interface",
- 0
-};
-
-void
-Voice_devnull_engraver::acknowledge_grob (Grob_info i)
-{
- SCM s = get_property ("devNullVoice");
-
- if (s == ly_symbol2scm ("always")
- || (s == SCM_EOL
- && to_boolean (get_property ("soloADue"))
- && ((daddy_trans_->id_string_.left_string (3) == "two"
- && (to_boolean (get_property ("unison"))
- || to_boolean (get_property ("unisilence"))))
-
- /* Maybe this should be optional? */
- || to_boolean (get_property ("othersolo")))))
-
- for (char const **p = junk_interfaces; *p; p++)
- if (i.grob_->internal_has_interface (ly_symbol2scm (*p)))
- {
- i.grob_->suicide ();
- return;
- }
-}
-
-Voice_devnull_engraver::Voice_devnull_engraver(){}
-
-ENTER_DESCRIPTION(Voice_devnull_engraver,
-/* descr */ "Kill off certain items and spanners if we're Voice `two' and unison or unisilence is set.",
-/* creats*/ "",
-/* accepts */ "general-music", /*UGH.*/
-/* acks */ "grob-interface",
-/* reads */ "",
-/* write */ "");
localKeySignature = #'()
\consists "Font_size_engraver"
- % must come before all
- \consists "Voice_devnull_engraver"
\consists "Output_property_engraver"
\consists "Arpeggio_engraver"
\consists "Multi_measure_rest_engraver"
\consists "Slur_engraver"
\consists "Tie_engraver"
\consists "Tuplet_engraver"
- \consists "A2_engraver"
\consists "Skip_event_swallow_translator"
\accepts Thread % bug if you leave out this!
style of individual note heads.
"
\consists "Font_size_engraver"
- \consists "Thread_devnull_engraver"
\consists "Note_heads_engraver"
\consists "Rest_engraver"
soloIIText = #"Solo II"
aDueText = #"a2"
soloADue = ##t
- splitInterval = #'(0 . 1)
- changeMoment = #`(,(ly:make-moment 0 0) . ,(ly:make-moment 1 512))
systemStartDelimiter =#'SystemStartBar
melismaBusyProperties = #default-melisma-properties
(types . (general-music layout-instruction))
(iterator-ctor . , Push_property_iterator::constructor)
))
-
(PartCombineMusic
. (
(description . "Combine two parts on a staff, either merged or
as separate voices.")
- (internal-class-name . "Simultaneous_music")
- (types . (general-music part-combine-music))
- (iterator-ctor . ,Part_combine_music_iterator::constructor)
- ))
- (NewPartCombineMusic
- . (
- (description . "Combine two parts on a staff, either merged or
-as separate voices.")
-
(internal-class-name . "Simultaneous_music")
(types . (general-music part-combine-music))
(iterator-ctor . ,New_pc_iterator::constructor)
the central C, measured in half staffspaces. 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
'chordNameFunction procedure?
"The function that converts lists of pitches to chord names.")
positive value shifts it up, a negative value shifts it down. The
unit of this distance is the half staff space.")
-(translator-property-description 'combineParts boolean? "try to combine parts?")
(translator-property-description 'connectArpeggios boolean? " If
set, connect all arpeggios that are found. In this way, you can make
arpeggios that cross staves.
Staff.defaultBarType will have no effect.
")
-(translator-property-description 'devNullThread symbol? "User control of Thread_devnull_engraver: one of
-@table @samp
-@item (), or unset
-Behave in normal way: remove one set of grobs when in unisolo.
-@item always:
-Remove any grob that comes along.
-@item never:
-Do nothing.
-@end table
-")
-(translator-property-description 'devNullVoice symbol? "User control of Voice_devnull_engraver: one of
-@table @samp
-@item (), or unset
-Behave in normal way: remove spanners when in unisolo.
-@item always:
-Remove any spanners that come along.
-@item never:
-Do nothing.
-@end table
-")
+
(translator-property-description 'decrescendoSpanner symbol? "Type of spanner to be used for decrescendi. One of: @samp{hairpin}, @samp{line}, @samp{dashed-line}, @samp{dotted-line}. If unset, hairpin type is used.")
(translator-property-description 'dynamicAbsoluteVolumeFunction procedure? "
objects. The list of contains entries with start times, music objects
and whether they're processed in this context.")
-(translator-property-description 'noDirection boolean? "Don't set directions by a2-engraver when part-combining.")
(translator-property-description
'originalCentralCPosition integer?
"Used for temporary overriding central C in octavation brackets. ")
(translator-property-description 'soloIIText string? "text for begin of solo for voice ``two'' when part-combining.")
(translator-property-description 'soloText string? "text for begin of solo when part-combining.")
(translator-property-description 'sparseTies boolean? "only create one tie per chord.")
-(translator-property-description 'splitInterval number-pair? "part-combiner will separate its two voices (or threads) when interval between the two voices is contained in this range.")
-(translator-property-description 'split-interval boolean? "set if part-combiner separated voices based on splitInterval.")
(translator-property-description 'squashedPosition integer? " Vertical position of
squashing for Pitch_squash_engraver.")
(translator-property-description 'stringOneTopmost boolean? "Whether the 1st string is printed on the
@@end lilypond
@end example
.")
-(translator-property-description 'unirhythm boolean? "set if unirhythm is detected by the part combiner.")
-(translator-property-description 'unisilence boolean? "set if unisilence is detected by the part combiner.")
-(translator-property-description 'unison boolean? "set if unisono is detected by the part combiner. .")
(translator-property-description 'verticalAlignmentChildCallback
procedure? "what callback to add to children of a vertical alignment.
It determines what alignment procedure is used on the alignment
(define-public (make-new-part-combine-music music-list)
(let*
- ((m (make-music-by-name 'NewPartCombineMusic))
+ ((m (make-music-by-name 'PartCombineMusic))
(m1 (context-spec-music (car music-list) 'Voice "one"))
(m2 (context-spec-music (cadr music-list) 'Voice "two"))
(props '((denies Thread)