From b12ee555e33d483eed0832d8502ad7a282ef9796 Mon Sep 17 00:00:00 2001 From: David Kastrup Date: Mon, 6 Oct 2014 00:31:58 +0200 Subject: [PATCH] Issue 2010: \lyricsto may turn into a voice-mangling zombie The problem here was that the simultaneous iterator might keep rerhythmed lyrics around when the associated voice has died already, blocking the simultaneous iterator. The solution is that when removing the last regular iterator to remove all remaining lyric-combined iterators at the same time. --- lily/simultaneous-music-iterator.cc | 33 ++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/lily/simultaneous-music-iterator.cc b/lily/simultaneous-music-iterator.cc index 92bf91b25a..3e42ed96c0 100644 --- a/lily/simultaneous-music-iterator.cc +++ b/lily/simultaneous-music-iterator.cc @@ -82,23 +82,50 @@ Simultaneous_music_iterator::construct_children () } } +// If there are non-run-always iterators and all of them die, take the +// rest of them along. void Simultaneous_music_iterator::process (Moment until) { + bool had_good = false; + bool had_bad = false; SCM *proc = &children_list_; while (scm_is_pair (*proc)) { Music_iterator *i = Music_iterator::unsmob (scm_car (*proc)); - if (i->run_always () - || i->pending_moment () == until) + bool run_always = i->run_always (); + if (run_always || i->pending_moment () == until) i->process (until); if (!i->ok ()) { + if (!run_always) + had_bad = true; i->quit (); *proc = scm_cdr (*proc); } else - proc = SCM_CDRLOC (*proc); + { + if (!run_always) + had_good = true; + proc = SCM_CDRLOC (*proc); + } + } + // If there were non-run-always iterators and all of them died, take + // the rest of the run-always iterators along with them. They have + // likely lost their reference iterators. Basing this on the actual + // music contexts is not reliable since something like + // \new Voice = blah { + // << \context Voice = blah { c4 d } + // \addlyrics { oh no } + // >> e f + // } + // cannot wait for the death of context blah before ending the + // simultaneous iterator. + if (had_bad && !had_good) + { + for (SCM p = children_list_; scm_is_pair (p); p = scm_cdr (p)) + Music_iterator::unsmob (scm_car (p))->quit (); + children_list_ = SCM_EOL; } } -- 2.39.5