X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fpart-combine-iterator.cc;h=fdbb0b1b9135b64d9c47d5330196f277012f4ebf;hb=5b4b0d6e9a197e8f9eb085b7c2ad78b8be3e5cfc;hp=95542d3c303c984a040f52f51cefabd1833b92a3;hpb=5758fa63add68276fd012fac73a240f40332a320;p=lilypond.git diff --git a/lily/part-combine-iterator.cc b/lily/part-combine-iterator.cc index 95542d3c30..fdbb0b1b91 100644 --- a/lily/part-combine-iterator.cc +++ b/lily/part-combine-iterator.cc @@ -1,75 +1,92 @@ -/* - new-part-combine-music-iterator.cc -- implement Part_combine_iterator +/* + new-part-combine-music-iterator.cc -- implement Part_combine_iterator - source file of the GNU LilyPond music typesetter - - (c) 2004 Han-Wen Nienhuys + source file of the GNU LilyPond music typesetter + + (c) 2004--2008 Han-Wen Nienhuys */ #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" + +typedef enum Outlet_type + { + CONTEXT_ONE, CONTEXT_TWO, + CONTEXT_SHARED, CONTEXT_SOLO, + CONTEXT_NULL, NUM_OUTLETS + }; + +static const char *outlet_names_[NUM_OUTLETS] = + {"one", "two", "shared", "solo", "null"}; 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_; + /* used by try_process */ + DECLARE_LISTENER (set_busy); + bool busy_; + bool notice_busy_; + + bool try_process (Music_iterator *i, Moment m); + Music_iterator *first_iter_; + Music_iterator *second_iter_; + Moment start_moment_; + SCM split_list_; - enum Status { - APART, - TOGETHER, - SOLO1, - SOLO2, - UNISONO, - UNISILENCE, - }; + Stream_event *unisono_event_; + Stream_event *solo_one_event_; + Stream_event *solo_two_event_; + Stream_event *mmrest_event_; + + enum Status + { + APART, + TOGETHER, + SOLO1, + SOLO2, + UNISONO, + UNISILENCE, + }; Status state_; Status playing_state_; /* Should be SOLO1 or SOLO2 - */ + */ Status last_playing_; /* - 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); + TODO: this is getting of hand... + */ + Context_handle handles_[NUM_OUTLETS]; - void kill_mmrest (Context *); + void substitute_both (Outlet_type to1, + Outlet_type to2); + + /* parameter is really Outlet_type */ + void kill_mmrest (int in); void chords_together (); void solo1 (); void solo2 (); @@ -77,9 +94,6 @@ private: void unisono (bool silent); }; - -static Music *busy_playing_event; - void Part_combine_iterator::do_quit () { @@ -88,27 +102,28 @@ Part_combine_iterator::do_quit () if (second_iter_) second_iter_->quit (); - null_.set_context (0); - one_ .set_context (0); - two_.set_context (0); - shared_.set_context (0); - solo_.set_context (0); - + // Add listeners to all contexts except Devnull. + for (int i = 0; i < NUM_OUTLETS; i++) + { + Context *c = handles_[i].get_outlet (); + if (c->is_alias (ly_symbol2scm ("Voice"))) + c->event_source ()->remove_listener (GET_LISTENER (set_busy), ly_symbol2scm ("music-event")); + handles_[i].set_context (0); + } } Part_combine_iterator::Part_combine_iterator () { + mmrest_event_ = 0; + unisono_event_ = 0; + solo_two_event_ = 0; + solo_one_event_= 0; + first_iter_ = 0; second_iter_ = 0; split_list_ = SCM_EOL; state_ = APART; playing_state_ = APART; - - if (!busy_playing_event) - { - busy_playing_event - = make_music_by_name (ly_symbol2scm ("BusyPlayingEvent")); - } } void @@ -118,15 +133,25 @@ Part_combine_iterator::derived_mark () const scm_gc_mark (first_iter_->self_scm ()); if (second_iter_) scm_gc_mark (second_iter_->self_scm ()); + + Stream_event *ptrs[] = { + unisono_event_, + mmrest_event_, + solo_two_event_, + solo_one_event_, + 0 + }; + for (int i = 0; ptrs[i]; i++) + if (ptrs[i]) + scm_gc_mark (ptrs[i]->self_scm ()); } void Part_combine_iterator::derived_substitute (Context *f, - Context *t) + Context *t) { if (first_iter_) - first_iter_->substitute_outlet (f,t); - + first_iter_->substitute_outlet (f, t); } Moment @@ -135,10 +160,10 @@ Part_combine_iterator::pending_moment () const Moment p; p.set_infinite (1); if (first_iter_->ok ()) - p = p pending_moment (); + p = min (p, first_iter_->pending_moment ()); if (second_iter_->ok ()) - p = p pending_moment (); + p = min (p, second_iter_->pending_moment ()); return p; } @@ -158,22 +183,22 @@ Part_combine_iterator::chords_together () playing_state_ = TOGETHER; state_ = TOGETHER; - substitute_both (shared_.get_outlet (), shared_.get_outlet ()); + substitute_both (CONTEXT_SHARED, CONTEXT_SHARED); } } - void -Part_combine_iterator::kill_mmrest (Context * tg) +Part_combine_iterator::kill_mmrest (int in) { - static Music * mmrest; - if (!mmrest) + + if (!mmrest_event_) { - mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent")); - mmrest->set_property ("duration", SCM_EOL); + mmrest_event_ = new Stream_event (ly_symbol2scm ("multi-measure-rest-event")); + mmrest_event_->set_property ("duration", SCM_EOL); + mmrest_event_->unprotect (); } - tg->try_music (mmrest); + handles_[in].get_outlet ()->event_source ()->broadcast (mmrest_event_); } void @@ -184,83 +209,81 @@ Part_combine_iterator::solo1 () else { state_ = SOLO1; - substitute_both (solo_.get_outlet (), - null_.get_outlet ()); - - kill_mmrest (two_.get_outlet ()); - kill_mmrest (shared_.get_outlet ()); + substitute_both (CONTEXT_SOLO, CONTEXT_NULL); + + kill_mmrest (CONTEXT_TWO); + kill_mmrest (CONTEXT_SHARED); if (playing_state_ != SOLO1) { - static Music* event; - if (!event) - event = make_music_by_name (ly_symbol2scm ("SoloOneEvent")); + if (!solo_one_event_) + { + solo_one_event_ = new Stream_event (ly_symbol2scm ("solo-one-event")); + solo_one_event_->unprotect (); + } - first_iter_-> try_music_in_children (event); + first_iter_->get_outlet ()->event_source ()->broadcast (solo_one_event_); } playing_state_ = SOLO1; } } void -Part_combine_iterator::substitute_both (Context * to1, - Context * to2) +Part_combine_iterator::substitute_both (Outlet_type to1, + Outlet_type to2) { - 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++) + Outlet_type tos[] = {to1, to2}; + + Music_iterator *mis[] = {first_iter_, second_iter_}; + + 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; j < NUM_OUTLETS; j++) + if (j != tos[i]) + mis[i]->substitute_outlet (handles_[j].get_outlet (), handles_[tos[i]].get_outlet ()); } - for (int j = 0; hs[j]; j++) + for (int j = 0; j < NUM_OUTLETS; j++) { - Context * t = hs[j]->get_outlet (); - if (t != to1 && t != to2) - kill_mmrest (t); + if (j != to1 && j != to2) + kill_mmrest (j); } } - void Part_combine_iterator::unisono (bool silent) { Status newstate = (silent) ? UNISILENCE : UNISONO; - + if (newstate == state_) - return; + 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 + in the 1st voice, so in that case, we use the second voice as a basis for events. - */ - Context *c1 = (last_playing_ == SOLO2) ? null_.get_outlet() : shared_.get_outlet(); - Context *c2 = (last_playing_ == SOLO2) ? shared_.get_outlet() : null_.get_outlet(); + */ + Outlet_type c1 = (last_playing_ == SOLO2) ? CONTEXT_NULL : CONTEXT_SHARED; + Outlet_type c2 = (last_playing_ == SOLO2) ? CONTEXT_SHARED : CONTEXT_NULL; substitute_both (c1, c2); kill_mmrest ((last_playing_ == SOLO2) - ? one_.get_outlet () : two_.get_outlet ()); - kill_mmrest (shared_.get_outlet ()); + ? CONTEXT_ONE : CONTEXT_TWO); + kill_mmrest (CONTEXT_SHARED); if (playing_state_ != UNISONO && newstate == UNISONO) { - static Music* event; - if (!event) - event = make_music_by_name (ly_symbol2scm ("UnisonoEvent")); - - (last_playing_ == SOLO2 ? second_iter_ : first_iter_) - ->try_music_in_children (event); + if (!unisono_event_) + { + unisono_event_ = new Stream_event (ly_symbol2scm ("unisono-event")); + unisono_event_->unprotect (); + } + + + Context *out = (last_playing_ == SOLO2 ? second_iter_ : first_iter_) + ->get_outlet (); + out->event_source ()->broadcast (unisono_event_); playing_state_ = UNISONO; } state_ = newstate; @@ -275,16 +298,18 @@ Part_combine_iterator::solo2 () else { state_ = SOLO2; - - substitute_both (null_.get_outlet (), solo_.get_outlet ()); - + + substitute_both (CONTEXT_NULL, CONTEXT_SOLO); + if (playing_state_ != SOLO2) { - static Music* event; - if (!event) - event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent")); - - second_iter_-> try_music_in_children (event); + if (!solo_two_event_) + { + solo_two_event_ = new Stream_event (ly_symbol2scm ("solo-two-event")); + solo_two_event_->unprotect (); + } + + second_iter_->get_outlet ()->event_source ()->broadcast (solo_two_event_); playing_state_ = SOLO2; } } @@ -301,70 +326,38 @@ Part_combine_iterator::apart (bool silent) else { state_ = APART; - substitute_both (one_.get_outlet (), two_.get_outlet ()); + substitute_both (CONTEXT_ONE, CONTEXT_TWO); } } - 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_context (tr); + split_list_ = get_music ()->get_property ("split-list"); - /* - If we don't, we get a new staff for every Voice. - */ - set_context (tr); - - Context *solo_tr - = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"), - "solo",props); - - solo_ .set_context (solo_tr); - - Context *null - = get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"), - "", SCM_EOL); - - if (!null) - programming_error ("No Devnull found?"); - - null_.set_context (null); + Context *c = get_outlet (); - Context *one = tr->find_create_context (ly_symbol2scm ("Voice"), - "one", props); - - one_.set_context (one); + for (int i = 0; i < NUM_OUTLETS; i++) + { + SCM type = (i == CONTEXT_NULL) ? ly_symbol2scm ("Devnull") : ly_symbol2scm ("Voice"); + /* find context below c: otherwise we may create new staff for each voice */ + c = c->find_create_context (type, outlet_names_[i], SCM_EOL); + handles_[i].set_context (c); + if (c->is_alias (ly_symbol2scm ("Voice"))) + c->event_source ()->add_listener (GET_LISTENER (set_busy), ly_symbol2scm ("music-event")); + } + SCM lst = get_music ()->get_property ("elements"); + Context *one = handles_[CONTEXT_ONE].get_outlet (); set_context (one); first_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (lst)))); - - - Context *two = tr->find_create_context (ly_symbol2scm ("Voice"), - "two", props); - two_.set_context (two); + Context *two = handles_[CONTEXT_TWO].get_outlet (); set_context (two); second_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_cadr (lst)))); - - set_context (tr); - - - char const * syms[] = { + char const *syms[] + = { "Stem", "DynamicLineSpanner", "Tie", @@ -375,17 +368,45 @@ Part_combine_iterator::construct_children () "Script", 0 }; - - for (char const**p = syms; *p; p++) + + for (char const **p = syms; *p; p++) { SCM sym = ly_symbol2scm (*p); execute_pushpop_property (one, sym, - ly_symbol2scm ("direction"), scm_int2num (1)); + ly_symbol2scm ("direction"), scm_from_int (1)); execute_pushpop_property (two, sym, - ly_symbol2scm ("direction"), scm_int2num (-1)); + ly_symbol2scm ("direction"), scm_from_int (-1)); } +} +IMPLEMENT_LISTENER (Part_combine_iterator, set_busy); +void +Part_combine_iterator::set_busy (SCM se) +{ + if (!notice_busy_) + return; + + Stream_event *e = unsmob_stream_event (se); + + if (e->in_event_class ("note-event") || e->in_event_class ("cluster-note-event")) + busy_ = true; +} + +/* + Processes a moment in an iterator, and returns whether any new music + was reported. +*/ +bool +Part_combine_iterator::try_process (Music_iterator *i, Moment m) +{ + busy_ = false; + notice_busy_ = true; + + i->process (m); + + notice_busy_ = false; + return busy_; } void @@ -393,15 +414,20 @@ Part_combine_iterator::process (Moment m) { Moment now = get_outlet ()->now_mom (); Moment *splitm = 0; - + + /* This is needed if construct_children was called before iteration + started */ + if (start_moment_.main_part_.is_infinity () && start_moment_ < 0) + start_moment_ = now; + for (; scm_is_pair (split_list_); split_list_ = scm_cdr (split_list_)) { splitm = unsmob_moment (scm_caar (split_list_)); if (splitm && *splitm + start_moment_ > now) - break ; + break; SCM tag = scm_cdar (split_list_); - + if (tag == ly_symbol2scm ("chords")) chords_together (); else if (tag == ly_symbol2scm ("apart") @@ -418,35 +444,23 @@ Part_combine_iterator::process (Moment m) solo2 (); else if (scm_is_symbol (tag)) { - String s = "Unknown split directive: " - + (scm_is_symbol (tag) ? ly_symbol2string (tag) : String ("not a symbol")); + string s = "Unknown split directive: " + + (scm_is_symbol (tag) ? ly_symbol2string (tag) : string ("not a symbol")); programming_error (s); } } if (first_iter_->ok ()) { - first_iter_->process (m); - if (first_iter_->try_music_in_children (busy_playing_event)) - last_playing_ = SOLO1; + if (try_process (first_iter_, m)) + last_playing_ = SOLO1; } - + if (second_iter_->ok ()) { - second_iter_->process (m); - if (first_iter_->try_music_in_children (busy_playing_event)) + if (try_process (second_iter_, m)) last_playing_ = SOLO2; } } -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);