]> git.donarmstrong.com Git - lilypond.git/blob - lily/simultaneous-music-iterator.cc
Release: bump VERSION_DEVEL.
[lilypond.git] / lily / simultaneous-music-iterator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2015 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     unsmob<Music_iterator> (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 = unsmob<Music> (scm_car (i));
57
58       SCM scm_iter = get_static_get_iterator (mus);
59       Music_iterator *mi = unsmob<Music_iterator> (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 we have some iterators with definite next moment and no of them
86 // remain after processing, we take the iterators with indefinite next
87 // moment along.  That makes sure that no Lyric_combine_music_iterator
88 // will outstay its welcome (issue 2010).
89
90 void
91 Simultaneous_music_iterator::process (Moment until)
92 {
93   SCM *proc = &children_list_;
94   bool finite = !pending_moment ().main_part_.is_infinity ();
95   while (scm_is_pair (*proc))
96     {
97       Music_iterator *i = unsmob<Music_iterator> (scm_car (*proc));
98       if (i->run_always () || i->pending_moment () == until)
99         i->process (until);
100       if (!i->ok ())
101         {
102           i->quit ();
103           *proc = scm_cdr (*proc);
104         }
105       else
106         {
107           proc = SCM_CDRLOC (*proc);
108         }
109     }
110   // If there were definite-ended iterators and all of them died, take
111   // the rest of the iterators along with them.  They have
112   // likely lost their reference iterators.  Basing this on the actual
113   // music contexts is not reliable since something like
114   // \new Voice = blah {
115   //    << \context Voice = blah { c4 d }
116   //       \addlyrics { oh no }
117   //    >> e f
118   // }
119   // cannot wait for the death of context blah before ending the
120   // simultaneous iterator.
121   if (finite && pending_moment ().main_part_.is_infinity ())
122     {
123       for (SCM p = children_list_; scm_is_pair (p); p = scm_cdr (p))
124         unsmob<Music_iterator> (scm_car (p))->quit ();
125       children_list_ = SCM_EOL;
126     }
127 }
128
129 Moment
130 Simultaneous_music_iterator::pending_moment () const
131 {
132   Moment next;
133   next.set_infinite (1);
134
135   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
136     {
137       Music_iterator *it = unsmob<Music_iterator> (scm_car (s));
138       next = min (next, it->pending_moment ());
139     }
140
141   return next;
142 }
143
144 bool
145 Simultaneous_music_iterator::ok () const
146 {
147   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
148     {
149       Music_iterator *it = unsmob<Music_iterator> (scm_car (s));
150       if (it->ok ())
151         return true;
152     }
153   return false;
154 }
155
156 bool
157 Simultaneous_music_iterator::run_always () const
158 {
159   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
160     {
161       Music_iterator *it = unsmob<Music_iterator> (scm_car (s));
162       if (it->run_always ())
163         return true;
164     }
165   return false;
166 }
167
168 void
169 Simultaneous_music_iterator::do_quit ()
170 {
171   for (SCM s = children_list_; scm_is_pair (s); s = scm_cdr (s))
172     unsmob<Music_iterator> (scm_car (s))->quit ();
173 }
174
175 IMPLEMENT_CTOR_CALLBACK (Simultaneous_music_iterator);