]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-iterator.cc
Web-ja: update introduction
[lilypond.git] / lily / part-combine-iterator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2004--2015 Han-Wen Nienhuys
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 "context.hh"
21 #include "dispatcher.hh"
22 #include "lily-guile.hh"
23 #include "music.hh"
24 #include "music-iterator.hh"
25 #include "music-sequence.hh"
26 #include "warn.hh"
27 #include "lily-imports.hh"
28
29 class Part_combine_iterator : public Music_iterator
30 {
31 public:
32   Part_combine_iterator ();
33
34   DECLARE_SCHEME_CALLBACK (constructor, ());
35 protected:
36   virtual void derived_substitute (Context *f, Context *t);
37   virtual void derived_mark () const;
38
39   virtual void construct_children ();
40   virtual Moment pending_moment () const;
41   virtual void do_quit ();
42   virtual void process (Moment);
43
44   virtual bool ok () const;
45
46 private:
47   static const size_t NUM_PARTS = 2;
48   Music_iterator *iterators_[NUM_PARTS];
49
50   Stream_event *mmrest_event_;
51
52   bool is_active_outlet (const Context *c) const;
53   void kill_mmrest (Context *c);
54 };
55
56 const size_t Part_combine_iterator::NUM_PARTS;
57
58 void
59 Part_combine_iterator::do_quit ()
60 {
61   for (size_t i = 0; i < NUM_PARTS; i++)
62     if (iterators_[i])
63       iterators_[i]->quit ();
64 }
65
66 Part_combine_iterator::Part_combine_iterator ()
67 {
68   mmrest_event_ = 0;
69
70   for (size_t i = 0; i < NUM_PARTS; i++)
71     iterators_[i] = 0;
72 }
73
74 void
75 Part_combine_iterator::derived_mark () const
76 {
77   for (size_t i = 0; i < NUM_PARTS; i++)
78     if (iterators_[i])
79       scm_gc_mark (iterators_[i]->self_scm ());
80
81   if (mmrest_event_)
82     scm_gc_mark (mmrest_event_->self_scm ());
83 }
84
85 void
86 Part_combine_iterator::derived_substitute (Context *f,
87                                            Context *t)
88 {
89   // (Explain why just iterators_[0].)
90   if (iterators_[0])
91     iterators_[0]->substitute_outlet (f, t);
92 }
93
94 Moment
95 Part_combine_iterator::pending_moment () const
96 {
97   Moment p;
98   p.set_infinite (1);
99
100   for (size_t i = 0; i < NUM_PARTS; i++)
101     if (iterators_[i]->ok ())
102       p = min (p, iterators_[i]->pending_moment ());
103
104   return p;
105 }
106
107 bool
108 Part_combine_iterator::ok () const
109 {
110   for (size_t i = 0; i < NUM_PARTS; i++)
111     if (iterators_[i]->ok ())
112       return true;
113
114   return false;
115 }
116
117 bool Part_combine_iterator::is_active_outlet (const Context *c) const
118 {
119   for (size_t i = 0; i < NUM_PARTS; i++)
120     if (iterators_[i] && (iterators_[i]->get_outlet () == c))
121       return true;
122
123   return false;
124 }
125
126 void
127 Part_combine_iterator::kill_mmrest (Context *c)
128 {
129
130   if (!mmrest_event_)
131     {
132       mmrest_event_ = new Stream_event
133         (Lily::ly_make_event_class (ly_symbol2scm ("multi-measure-rest-event")));
134       mmrest_event_->set_property ("duration", SCM_EOL);
135       mmrest_event_->unprotect ();
136     }
137
138   c->event_source ()->broadcast (mmrest_event_);
139 }
140
141 void
142 Part_combine_iterator::construct_children ()
143 {
144   SCM lst = get_music ()->get_property ("elements");
145   iterators_[0] = unsmob<Music_iterator> (get_iterator (unsmob<Music> (scm_car (lst))));
146   iterators_[1] = unsmob<Music_iterator> (get_iterator (unsmob<Music> (scm_cadr (lst))));
147 }
148
149 void
150 Part_combine_iterator::process (Moment m)
151 {
152   Context *prev_active_outlets[NUM_PARTS];
153   bool any_outlet_changed = false;
154   for (size_t i = 0; i < NUM_PARTS; i++)
155     {
156       prev_active_outlets[i] = iterators_[i]->get_outlet ();
157
158       if (iterators_[i]->ok ())
159         iterators_[i]->process (m);
160
161       if (prev_active_outlets[i] != iterators_[i]->get_outlet ())
162           any_outlet_changed = true;
163     }
164
165   if (any_outlet_changed)
166     {
167       // Kill multi-measure rests in outlets that were previously active and
168       // are no longer active.
169       for (size_t i = 0; i < NUM_PARTS; i++)
170         {
171           Context *c = prev_active_outlets[i];
172           if (c && !is_active_outlet (c))
173               kill_mmrest (c);
174         }
175     }
176 }
177
178 IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);