X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Flyric-combine-music-iterator.cc;h=bf5d02d8b2876a2b1d154c2064cbab0f9d17bff9;hb=fc273c71061c4859cebc95bb91d86c9373d94f64;hp=f812d1c952768d0a46f25f4448f44139d1112265;hpb=6e200203e9d8067e9211dd93b7e4a47099aae949;p=lilypond.git diff --git a/lily/lyric-combine-music-iterator.cc b/lily/lyric-combine-music-iterator.cc index f812d1c952..bf5d02d8b2 100644 --- a/lily/lyric-combine-music-iterator.cc +++ b/lily/lyric-combine-music-iterator.cc @@ -3,16 +3,32 @@ source file of the GNU LilyPond music typesetter - (c) 2004--2006 Han-Wen Nienhuys + (c) 2004--2007 Han-Wen Nienhuys */ -#include "context.hh" +#include "dispatcher.hh" +#include "global-context.hh" #include "grob.hh" #include "input.hh" #include "international.hh" +#include "listener.hh" #include "music-iterator.hh" #include "music.hh" +/* + This iterator is hairy. It tracks both lyric and melody contexts, + and has a complicated communication route, reading/writing + properties in both. + + In the future, this should rather be done with + + \interpretAsMelodyFor { MUSIC } { LYRICS LYRICS LYRICS } + + This can run an interpret step on MUSIC, generating a stream. Then + the stream can be perused at leisure to apply durations to all of + the LYRICS. +*/ + class Lyric_combine_music_iterator : public Music_iterator { public: @@ -24,61 +40,77 @@ protected: virtual Moment pending_moment () const; virtual void do_quit (); virtual void process (Moment); - virtual Music_iterator *try_music_in_children (Music *) const; virtual bool run_always ()const; virtual bool ok () const; virtual void derived_mark () const; virtual void derived_substitute (Context *, Context *); + void set_music_context (Context *to); private: - bool start_new_syllable (); - void find_voice (); + bool start_new_syllable () const; + Context *find_voice (); + DECLARE_LISTENER (set_busy); + DECLARE_LISTENER (check_new_context); - bool pending_grace_lyric_; bool music_found_; - bool made_association_; Context *lyrics_context_; Context *music_context_; SCM lyricsto_voice_name_; + Moment busy_moment_; + Moment pending_grace_moment_; + Music_iterator *lyric_iter_; }; -/* - Ugh; this is a hack, let's not export this hack, so static. -*/ -static Music *busy_ev; -static Music *start_ev; -static Music *melisma_playing_ev; - Lyric_combine_music_iterator::Lyric_combine_music_iterator () { music_found_ = false; - made_association_ = false; - pending_grace_lyric_ = false; + pending_grace_moment_.set_infinite (1); lyric_iter_ = 0; music_context_ = 0; lyrics_context_ = 0; + busy_moment_.set_infinite (-1); +} - /* - Ugh. out of place here. - */ - if (!busy_ev) + +/* + It's dubious whether we can ever make this fully work. Due to + associatedVoice switching, this routine may be triggered for + the wrong music_context_ + */ +IMPLEMENT_LISTENER (Lyric_combine_music_iterator, set_busy) +void +Lyric_combine_music_iterator::set_busy (SCM se) +{ + Stream_event *e = unsmob_stream_event (se); + + if ((e->in_event_class ("note-event") || e->in_event_class ("cluster-note-event")) + && music_context_) + + busy_moment_ = max (music_context_->now_mom (), + busy_moment_); + +} + +void +Lyric_combine_music_iterator::set_music_context (Context *to) +{ + if (music_context_) + { + music_context_->event_source ()->remove_listener (GET_LISTENER (set_busy), ly_symbol2scm ("music-event")); + } + + music_context_ = to; + if (to) { - busy_ev - = make_music_by_name (ly_symbol2scm ("BusyPlayingEvent")); - start_ev - = make_music_by_name (ly_symbol2scm ("StartPlayingEvent")); - melisma_playing_ev - = make_music_by_name (ly_symbol2scm ("MelismaPlayingEvent")); + to->event_source ()->add_listener (GET_LISTENER (set_busy), ly_symbol2scm ("music-event")); } } bool -Lyric_combine_music_iterator::start_new_syllable () +Lyric_combine_music_iterator::start_new_syllable () const { - bool b = music_context_->try_music (busy_ev); - - if (!b) + if (busy_moment_ < music_context_->now_mom ()) return false; if (!lyrics_context_) @@ -86,7 +118,7 @@ Lyric_combine_music_iterator::start_new_syllable () if (!to_boolean (lyrics_context_->get_property ("ignoreMelismata"))) { - bool m = music_context_->try_music (melisma_playing_ev); + bool m = melisma_busy (music_context_); if (m) return false; } @@ -135,7 +167,7 @@ Lyric_combine_music_iterator::derived_substitute (Context *f, Context *t) if (lyrics_context_ && lyrics_context_ == f) lyrics_context_ = t; if (music_context_ && music_context_ == f) - music_context_ = t; + set_music_context (t); } void @@ -143,14 +175,28 @@ Lyric_combine_music_iterator::construct_children () { Music *m = unsmob_music (get_music ()->get_property ("element")); lyric_iter_ = unsmob_iterator (get_iterator (m)); + if (!lyric_iter_) + return; + lyrics_context_ = find_context_below (lyric_iter_->get_outlet (), + ly_symbol2scm ("Lyrics"), ""); + if (!lyrics_context_) + { + m->origin ()->warning ("argument of \\lyricsto should contain Lyrics context"); + } + lyricsto_voice_name_ = get_music ()->get_property ("associated-context"); - find_voice (); + Context *voice = find_voice (); + if (voice) + set_music_context (voice); - if (lyric_iter_) - lyrics_context_ = find_context_below (lyric_iter_->get_outlet (), - ly_symbol2scm ("Lyrics"), ""); + /* + Wait for a Create_context event. If this isn't done, lyrics can be + delayed when voices are created implicitly. + */ + Global_context *g = get_outlet ()->get_global_context (); + g->events_below ()->add_listener (GET_LISTENER (check_new_context), ly_symbol2scm ("CreateContext")); /* We do not create a Lyrics context, because the user might @@ -159,7 +205,34 @@ Lyric_combine_music_iterator::construct_children () */ } +IMPLEMENT_LISTENER (Lyric_combine_music_iterator, check_new_context) void +Lyric_combine_music_iterator::check_new_context (SCM sev) +{ + if (!ok ()) + return ; + + // TODO: Check first if type=Voice and if id matches + Stream_event * ev = unsmob_stream_event (sev); + if (ev->get_property ("type") != ly_symbol2scm ("Voice")) + return ; + + Context *voice = find_voice (); + + if (voice) + { + set_music_context (voice); + } +} + +/* + Look for a suitable voice to align lyrics to. + + Returns 0 if nothing should change; i.e., if we already listen to the + right voice, or if we don't yet listen to a voice but no appropriate + voice could be found. +*/ +Context * Lyric_combine_music_iterator::find_voice () { SCM voice_name = lyricsto_voice_name_; @@ -173,41 +246,27 @@ Lyric_combine_music_iterator::find_voice () if (scm_is_string (voice_name) && (!music_context_ || ly_scm2string (voice_name) != music_context_->id_string ())) { - /* - (spaghettini). - - Need to set associatedVoiceContext again - */ - if (music_context_) - made_association_ = false; - Context *t = get_outlet (); while (t && t->get_parent_context ()) t = t->get_parent_context (); string name = ly_scm2string (voice_name); - Context *voice = find_context_below (t, ly_symbol2scm ("Voice"), name); - - if (voice) - music_context_ = voice; + return find_context_below (t, ly_symbol2scm ("Voice"), name); } - if (lyrics_context_ && music_context_) - { - if (!made_association_) - { - made_association_ = true; - lyrics_context_->set_property ("associatedVoiceContext", - music_context_->self_scm ()); - } - } + return 0; } void -Lyric_combine_music_iterator::process (Moment mom) +Lyric_combine_music_iterator::process (Moment when) { - (void) mom; - find_voice (); + (void) when; + + /* see if associatedVoice has been changed */ + Context *new_voice = find_voice (); + if (new_voice) + set_music_context (new_voice); + if (!music_context_) return; @@ -220,26 +279,38 @@ Lyric_combine_music_iterator::process (Moment mom) if (lyrics_context_) lyrics_context_->unset_property (ly_symbol2scm ("associatedVoiceContext")); lyric_iter_ = 0; - music_context_ = 0; + set_music_context (0); } + if (music_context_ - && (start_new_syllable () || pending_grace_lyric_) + && (start_new_syllable () || + (busy_moment_ >= pending_grace_moment_)) && lyric_iter_->ok ()) { - if (music_context_->now_mom ().grace_part_) + Moment now = music_context_->now_mom (); + if (now.grace_part_) { - pending_grace_lyric_ = true; + pending_grace_moment_ = now; + pending_grace_moment_.grace_part_ = Rational (0); return; } else - pending_grace_lyric_ = false; + { + pending_grace_moment_.set_infinite (1); + } Moment m = lyric_iter_->pending_moment (); + lyrics_context_->set_property (ly_symbol2scm ("associatedVoiceContext"), + music_context_->self_scm ()); lyric_iter_->process (m); music_found_ = true; } + + new_voice = find_voice (); + if (new_voice) + set_music_context (new_voice); } void @@ -261,10 +332,4 @@ Lyric_combine_music_iterator::do_quit () lyric_iter_->quit (); } -Music_iterator * -Lyric_combine_music_iterator::try_music_in_children (Music *m) const -{ - return lyric_iter_->try_music (m); -} - IMPLEMENT_CTOR_CALLBACK (Lyric_combine_music_iterator);