-/*
- new-part-combine-music-iterator.cc -- implement Part_combine_iterator
+/*
+ This file is part of LilyPond, the GNU music typesetter.
- source file of the GNU LilyPond music typesetter
-
- (c) 2004 Han-Wen Nienhuys
+ Copyright (C) 2004--2015 Han-Wen Nienhuys
+
+ LilyPond is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ LilyPond is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
#include "context.hh"
-#include "event.hh"
-#include "music-sequence.hh"
+#include "dispatcher.hh"
#include "lily-guile.hh"
-#include "warn.hh"
+#include "music.hh"
#include "music-iterator.hh"
-#include "interpretation-context-handle.hh"
+#include "music-sequence.hh"
+#include "warn.hh"
+#include "lily-imports.hh"
class Part_combine_iterator : public Music_iterator
{
public:
Part_combine_iterator ();
- DECLARE_SCHEME_CALLBACK (constructor, ());
+ DECLARE_SCHEME_CALLBACK (constructor, ());
protected:
- virtual void derived_substitute (Context *f, Context *t) ;
+ virtual void derived_substitute (Context *f, Context *t);
virtual void derived_mark () const;
- Part_combine_iterator (Part_combine_iterator const &);
virtual void construct_children ();
virtual Moment pending_moment () const;
- virtual void do_quit ();
+ virtual void do_quit ();
virtual void process (Moment);
- virtual Music_iterator *try_music_in_children (Music *) const;
-
virtual bool ok () const;
private:
- Music_iterator * first_iter_;
- Music_iterator * second_iter_;
- Moment start_moment_;
-
- SCM split_list_;
-
- enum Status {
- APART, TOGETHER,
- SOLO1, SOLO2,
- UNISONO, UNISILENCE,
- };
- Status state_;
- Status playing_state_;
-
- /*
- TODO: this is getting of hand...
- */
- Interpretation_context_handle one_;
- Interpretation_context_handle two_;
- Interpretation_context_handle null_;
- Interpretation_context_handle shared_;
- Interpretation_context_handle solo_;
-
- void substitute_both (Context * to1,
- Context * to2);
-
- void kill_mmrest (Context *);
- void chords_together ();
- void solo1 ();
- void solo2 ();
- void apart (bool silent);
- void unisono (bool silent);
+ static const size_t NUM_PARTS = 2;
+ Music_iterator *iterators_[NUM_PARTS];
+
+ Stream_event *mmrest_event_;
+
+ bool is_active_outlet (const Context *c) const;
+ void kill_mmrest (Context *c);
};
+const size_t Part_combine_iterator::NUM_PARTS;
-Part_combine_iterator::Part_combine_iterator ()
+void
+Part_combine_iterator::do_quit ()
{
- first_iter_ = 0;
- second_iter_ = 0;
- split_list_ = SCM_EOL;
- state_ = APART;
- playing_state_ = APART;
+ for (size_t i = 0; i < NUM_PARTS; i++)
+ if (iterators_[i])
+ iterators_[i]->quit ();
}
-void
-Part_combine_iterator::derived_mark () const
+Part_combine_iterator::Part_combine_iterator ()
{
- if (first_iter_)
- scm_gc_mark (first_iter_->self_scm ());
- if (second_iter_)
- scm_gc_mark (second_iter_->self_scm ());
+ mmrest_event_ = 0;
+
+ for (size_t i = 0; i < NUM_PARTS; i++)
+ iterators_[i] = 0;
}
void
-Part_combine_iterator::derived_substitute (Context *f,
- Context *t)
+Part_combine_iterator::derived_mark () const
{
- if (first_iter_)
- first_iter_->substitute_outlet (f,t);
- if (second_iter_)
- second_iter_->substitute_outlet (f,t);
+ for (size_t i = 0; i < NUM_PARTS; i++)
+ if (iterators_[i])
+ scm_gc_mark (iterators_[i]->self_scm ());
+
+ if (mmrest_event_)
+ scm_gc_mark (mmrest_event_->self_scm ());
}
void
-Part_combine_iterator::do_quit ()
+Part_combine_iterator::derived_substitute (Context *f,
+ Context *t)
{
- if (first_iter_)
- first_iter_->quit ();
- if (second_iter_)
- second_iter_->quit ();
-
- null_.set_translator (0);
- one_ .set_translator (0);
- two_.set_translator (0);
- shared_.set_translator (0);
- solo_.set_translator (0);
+ // (Explain why just iterators_[0].)
+ if (iterators_[0])
+ iterators_[0]->substitute_outlet (f, t);
}
Moment
{
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 ();
+ for (size_t i = 0; i < NUM_PARTS; i++)
+ if (iterators_[i]->ok ())
+ p = min (p, iterators_[i]->pending_moment ());
+
return p;
}
bool
Part_combine_iterator::ok () const
{
- return first_iter_->ok () || second_iter_->ok ();
-}
+ for (size_t i = 0; i < NUM_PARTS; i++)
+ if (iterators_[i]->ok ())
+ return true;
-void
-Part_combine_iterator::chords_together ()
-{
- if (state_ == TOGETHER)
- return;
- else
- {
- playing_state_ = TOGETHER;
- state_ = TOGETHER;
-
- substitute_both (shared_.get_outlet (), shared_.get_outlet ());
- }
+ return false;
}
-
-void
-Part_combine_iterator::kill_mmrest (Context * tg)
+bool Part_combine_iterator::is_active_outlet (const Context *c) const
{
- static Music * mmrest;
- if (!mmrest)
- {
- mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent"));
- mmrest->set_property ("duration", SCM_EOL);
- }
-
- tg->try_music (mmrest);
-}
+ for (size_t i = 0; i < NUM_PARTS; i++)
+ if (iterators_[i] && (iterators_[i]->get_outlet () == c))
+ return true;
-void
-Part_combine_iterator::solo1 ()
-{
- if (state_ == SOLO1)
- return;
- else
- {
- state_ = SOLO1;
- substitute_both (solo_.get_outlet (),
- null_.get_outlet ());
-
- kill_mmrest (two_.get_outlet ());
- kill_mmrest (shared_.get_outlet ());
-
- if (playing_state_ != SOLO1)
- {
- static Music* event;
- if (!event)
- event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
-
- first_iter_-> try_music_in_children (event);
- }
- playing_state_ = SOLO1;
- }
+ return false;
}
void
-Part_combine_iterator::substitute_both (Context * to1,
- Context * to2)
+Part_combine_iterator::kill_mmrest (Context *c)
{
- Context *tos[] = {to1,to2};
- Music_iterator *mis[] = {first_iter_, second_iter_};
- Interpretation_context_handle *hs[] = {
- &null_,
- &one_, &two_,
- &shared_, &solo_,
- 0
- };
-
- for (int i = 0; i < 2 ; i++)
- {
- for (int j = 0; hs[j]; j++)
- if (hs[j]->get_outlet () != tos[i])
- mis[i]->substitute_outlet (hs[j]->get_outlet (), tos[i]);
- }
- for (int j = 0; hs[j]; j++)
+ if (!mmrest_event_)
{
- Context * t = hs[j]->get_outlet ();
- if (t != to1 && t != to2)
- kill_mmrest (t);
+ mmrest_event_ = new Stream_event
+ (Lily::ly_make_event_class (ly_symbol2scm ("multi-measure-rest-event")));
+ mmrest_event_->set_property ("duration", SCM_EOL);
+ mmrest_event_->unprotect ();
}
-}
-
-void
-Part_combine_iterator::unisono (bool silent)
-{
- Status newstate = (silent) ? UNISILENCE : UNISONO;
-
- if (newstate == state_)
- return;
- else
- {
- /*
- If we're coming from SOLO2 state, we might have kill mmrests
- in the 1st voice, so in that case, we use the second voice
- as a basis for events.
- */
- Context *c1 = (state_ == SOLO2) ? null_.get_outlet() : shared_.get_outlet();
- Context *c2 = (state_ == SOLO2) ? shared_.get_outlet() : null_.get_outlet();
-
- substitute_both (c1, c2);
-
-
- kill_mmrest ((state_ == SOLO2)
- ? one_.get_outlet () : two_.get_outlet ());
- kill_mmrest (shared_.get_outlet ());
-
- if (playing_state_ != UNISONO
- && newstate == UNISONO)
- {
- static Music* event;
- if (!event)
- event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
-
- (state_ == SOLO2 ? second_iter_ : first_iter_)
- ->try_music_in_children (event);
- playing_state_ = UNISONO;
- }
- state_ = newstate;
- }
+ c->event_source ()->broadcast (mmrest_event_);
}
void
-Part_combine_iterator::solo2 ()
+Part_combine_iterator::construct_children ()
{
- if (state_ == SOLO2)
- return;
- else
- {
- state_ = SOLO2;
-
- substitute_both (null_.get_outlet (), solo_.get_outlet ());
-
- if (playing_state_ != SOLO2)
- {
- static Music* event;
- if (!event)
- event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
-
- second_iter_-> try_music_in_children (event);
- playing_state_ = SOLO2;
- }
- }
+ SCM lst = get_music ()->get_property ("elements");
+ iterators_[0] = unsmob<Music_iterator> (get_iterator (unsmob<Music> (scm_car (lst))));
+ iterators_[1] = unsmob<Music_iterator> (get_iterator (unsmob<Music> (scm_cadr (lst))));
}
void
-Part_combine_iterator::apart (bool silent)
+Part_combine_iterator::process (Moment m)
{
- if (!silent)
- playing_state_ = APART;
-
- if (state_ == APART)
- return;
- else
+ Context *prev_active_outlets[NUM_PARTS];
+ bool any_outlet_changed = false;
+ for (size_t i = 0; i < NUM_PARTS; i++)
{
- state_ = APART;
- substitute_both (one_.get_outlet (), two_.get_outlet ());
- }
-}
-
-
-void
-Part_combine_iterator::construct_children ()
-{
- start_moment_ = get_outlet ()->now_mom ();
- split_list_ = get_music ()->get_property ("split-list");
- SCM lst = get_music ()->get_property ("elements");
-
- SCM props = scm_list_n (/*
- used to have tweaks here.
- */
-
- SCM_UNDEFINED);
-
- Context *tr
- = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
- "shared",props);
-
- shared_.set_translator (tr);
-
- /*
- If we don't, we get a new staff for every Voice.
- */
- set_translator (tr);
+ prev_active_outlets[i] = iterators_[i]->get_outlet ();
- Context *solo_tr
- = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
- "solo",props);
+ if (iterators_[i]->ok ())
+ iterators_[i]->process (m);
- solo_ .set_translator (solo_tr);
-
- Context *null
- = get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"),
- "", SCM_EOL);
-
- if (!null)
- programming_error ("No Devnull found?");
-
- null_.set_translator (null);
-
- Context *one = tr->find_create_context (ly_symbol2scm ("Voice"),
- "one", props);
-
- one_.set_translator (one);
-
- set_translator (one);
- first_iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_car (lst))));
-
-
- Context *two = tr->find_create_context (ly_symbol2scm ("Voice"),
- "two", props);
- two_.set_translator (two);
- set_translator (two);
- second_iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_cadr (lst))));
-
-
- set_translator (tr);
-
-
- char const * syms[] = {
- "Stem",
- "DynamicLineSpanner",
- "Tie",
- "Dots",
- "Rest",
- "Slur",
- "TextScript",
- "Script",
- 0
- };
-
- for (char const**p = syms; *p; p++)
- {
- SCM sym = ly_symbol2scm (*p);
- execute_pushpop_property (one, sym,
- ly_symbol2scm ("direction"), scm_int2num (1));
-
- execute_pushpop_property (two, sym,
- ly_symbol2scm ("direction"), scm_int2num (-1));
+ if (prev_active_outlets[i] != iterators_[i]->get_outlet ())
+ any_outlet_changed = true;
}
-}
-
-void
-Part_combine_iterator::process (Moment m)
-{
- Moment now = get_outlet ()->now_mom ();
- Moment *splitm = 0;
-
- for (; ly_c_pair_p (split_list_); split_list_ = ly_cdr (split_list_))
+ if (any_outlet_changed)
{
- splitm = unsmob_moment (ly_caar (split_list_));
- if (splitm && *splitm + start_moment_ > now)
- break ;
-
- SCM tag = ly_cdar (split_list_);
-
- if (tag == ly_symbol2scm ("chords"))
- chords_together ();
- else if (tag == ly_symbol2scm ("apart")
- || tag == ly_symbol2scm ("apart-silence")
- || tag == ly_symbol2scm ("apart-spanner"))
- apart (tag == ly_symbol2scm ("apart-silence"));
- else if (tag == ly_symbol2scm ("unisono"))
- unisono (false);
- else if (tag == ly_symbol2scm ("unisilence"))
- unisono (true);
- else if (tag == ly_symbol2scm ("solo1"))
- solo1 ();
- else if (tag == ly_symbol2scm ("solo2"))
- solo2 ();
- else if (scm_is_symbol (tag))
- {
- String s = "Unknown split directive: "
- + (scm_is_symbol (tag) ? ly_symbol2string (tag) : String ("not a symbol"));
- programming_error (s);
- }
+ // Kill multi-measure rests in outlets that were previously active and
+ // are no longer active.
+ for (size_t i = 0; i < NUM_PARTS; i++)
+ {
+ Context *c = prev_active_outlets[i];
+ if (c && !is_active_outlet (c))
+ kill_mmrest (c);
+ }
}
-
- if (first_iter_->ok ())
- first_iter_->process (m);
-
- if (second_iter_->ok ())
- second_iter_->process (m);
-}
-
-Music_iterator*
-Part_combine_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);
}
IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);