]> git.donarmstrong.com Git - lilypond.git/blob - lily/simultaneous-music-iterator.cc
3e42ed96c07dd99685af09aa148df16b77485f1a
[lilypond.git] / lily / simultaneous-music-iterator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "simultaneous-music-iterator.hh"
21 #include "music.hh"
22 #include "context.hh"
23 #include "warn.hh"
24 #include "context-def.hh"
25
26 Simultaneous_music_iterator::Simultaneous_music_iterator ()
27 {
28   create_separate_contexts_ = false;
29   children_list_ = SCM_EOL;
30 }
31
32 void
33 Simultaneous_music_iterator::derived_mark () const
34 {
35   scm_gc_mark (children_list_);
36 }
37
38 void
39 Simultaneous_music_iterator::derived_substitute (Context *f, Context *t)
40 {
41   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
42     Music_iterator::unsmob (scm_car (s))->substitute_outlet (f, t);
43 }
44
45 void
46 Simultaneous_music_iterator::construct_children ()
47 {
48   int j = 0;
49
50   SCM i = get_music ()->get_property ("elements");
51
52   children_list_ = SCM_EOL;
53   SCM *tail = &children_list_;
54   for (; scm_is_pair (i); i = scm_cdr (i), j++)
55     {
56       Music *mus = Music::unsmob (scm_car (i));
57
58       SCM scm_iter = get_static_get_iterator (mus);
59       Music_iterator *mi = Music_iterator::unsmob (scm_iter);
60
61       /* if create_separate_contexts_ is set, create a new context with the
62          number number as name */
63
64       SCM name = ly_symbol2scm (get_outlet ()->context_name ().c_str ());
65       Context *c = (j && create_separate_contexts_)
66                    ? get_outlet ()->find_create_context (name, ::to_string (j), SCM_EOL)
67                    : get_outlet ();
68
69       if (!c)
70         c = get_outlet ();
71
72       mi->init_context (mus, c);
73       mi->construct_children ();
74
75       if (mi->ok ())
76         {
77           *tail = scm_cons (scm_iter, *tail);
78           tail = SCM_CDRLOC (*tail);
79         }
80       else
81         mi->quit ();
82     }
83 }
84
85 // If there are non-run-always iterators and all of them die, take the
86 // rest of them along.
87 void
88 Simultaneous_music_iterator::process (Moment until)
89 {
90   bool had_good = false;
91   bool had_bad = false;
92   SCM *proc = &children_list_;
93   while (scm_is_pair (*proc))
94     {
95       Music_iterator *i = Music_iterator::unsmob (scm_car (*proc));
96       bool run_always = i->run_always ();
97       if (run_always || i->pending_moment () == until)
98         i->process (until);
99       if (!i->ok ())
100         {
101           if (!run_always)
102             had_bad = true;
103           i->quit ();
104           *proc = scm_cdr (*proc);
105         }
106       else
107         {
108           if (!run_always)
109             had_good = true;
110           proc = SCM_CDRLOC (*proc);
111         }
112     }
113   // If there were non-run-always iterators and all of them died, take
114   // the rest of the run-always iterators along with them.  They have
115   // likely lost their reference iterators.  Basing this on the actual
116   // music contexts is not reliable since something like
117   // \new Voice = blah {
118   //    << \context Voice = blah { c4 d }
119   //       \addlyrics { oh no }
120   //    >> e f
121   // }
122   // cannot wait for the death of context blah before ending the
123   // simultaneous iterator.
124   if (had_bad && !had_good)
125     {
126       for (SCM p = children_list_; scm_is_pair (p); p = scm_cdr (p))
127         Music_iterator::unsmob (scm_car (p))->quit ();
128       children_list_ = SCM_EOL;
129     }
130 }
131
132 Moment
133 Simultaneous_music_iterator::pending_moment () const
134 {
135   Moment next;
136   next.set_infinite (1);
137
138   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
139     {
140       Music_iterator *it = Music_iterator::unsmob (scm_car (s));
141       next = min (next, it->pending_moment ());
142     }
143
144   return next;
145 }
146
147 bool
148 Simultaneous_music_iterator::ok () const
149 {
150   bool run_always_ok = false;
151   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
152     {
153       Music_iterator *it = Music_iterator::unsmob (scm_car (s));
154       if (!it->run_always ())
155         return true;
156       else
157         run_always_ok = run_always_ok || it->ok ();
158     }
159   return run_always_ok;
160 }
161
162 bool
163 Simultaneous_music_iterator::run_always () const
164 {
165   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
166     {
167       Music_iterator *it = Music_iterator::unsmob (scm_car (s));
168       if (it->run_always ())
169         return true;
170     }
171   return false;
172 }
173
174 void
175 Simultaneous_music_iterator::do_quit ()
176 {
177   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
178     Music_iterator::unsmob (scm_car (s))->quit ();
179 }
180
181 IMPLEMENT_CTOR_CALLBACK (Simultaneous_music_iterator);