]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-combine-music-iterator.cc
*** empty log message ***
[lilypond.git] / lily / lyric-combine-music-iterator.cc
1 /*
2   lyric-combine-music-iterator.cc -- implement Lyric_combine_music_iterator
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1999--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "context.hh"
10 #include "event.hh"
11 #include "note-head.hh"
12 #include "grob.hh"
13 #include "music-iterator.hh"
14
15 class Lyric_combine_music_iterator : public Music_iterator
16 {
17 public:
18   Lyric_combine_music_iterator ();
19   Lyric_combine_music_iterator (Lyric_combine_music_iterator const &src);
20   DECLARE_SCHEME_CALLBACK (constructor, ());
21 protected:
22   virtual void construct_children ();
23   virtual Moment pending_moment () const;
24   virtual void do_quit ();
25   virtual void process (Moment);
26   virtual Music_iterator *try_music_in_children (Music *) const;
27
28   virtual bool ok () const;
29   virtual void derived_mark () const;
30   virtual void derived_substitute (Context *, Context *);
31 private:
32   bool get_busy_status ()const;
33   bool melisma_busy ();
34   Music *get_combine_lyrics () const;
35   Music *get_combine_music () const;
36
37   Music_iterator *music_iter_;
38   Music_iterator *lyric_iter_;
39 };
40
41 bool
42 melisma_busy (Context *tr)
43 {
44   SCM melisma_properties = tr->get_property ("melismaBusyProperties");
45   bool busy = false;
46
47   for (; scm_is_pair (melisma_properties);
48        melisma_properties = scm_cdr (melisma_properties))
49     busy = busy || to_boolean (tr->internal_get_property (scm_car (melisma_properties)));
50
51   return busy;
52 }
53
54 /*
55   Ugh, why static?
56 */
57 Music *busy_req;
58 Music *melisma_playing_req;
59
60 Lyric_combine_music_iterator::Lyric_combine_music_iterator ()
61 {
62   music_iter_ = 0;
63   lyric_iter_ = 0;
64
65   if (!busy_req)
66     {
67       busy_req
68         = make_music_by_name (ly_symbol2scm ("BusyPlayingEvent"));
69       melisma_playing_req
70         = make_music_by_name (ly_symbol2scm ("MelismaPlayingEvent"));
71     }
72 }
73
74 Moment
75 Lyric_combine_music_iterator::pending_moment () const
76 {
77   Moment musnext = music_iter_->pending_moment ();
78   return musnext;
79 }
80
81 bool
82 Lyric_combine_music_iterator::ok () const
83 {
84   return music_iter_->ok ();
85 }
86
87 void
88 Lyric_combine_music_iterator::derived_mark ()const
89 {
90   if (music_iter_)
91     scm_gc_mark (music_iter_->self_scm ());
92   if (lyric_iter_)
93     scm_gc_mark (lyric_iter_->self_scm ());
94 }
95
96 void
97 Lyric_combine_music_iterator::derived_substitute (Context *f, Context *t)
98 {
99   if (music_iter_)
100     music_iter_->substitute_outlet (f, t);
101   if (lyric_iter_)
102     lyric_iter_->substitute_outlet (f, t);
103 }
104
105 Music *
106 Lyric_combine_music_iterator::get_combine_music () const
107 {
108   SCM l = get_music ()->get_property ("elements");
109   if (!scm_is_pair (l))
110     return 0;
111   return unsmob_music (scm_car (l));
112 }
113
114 Music *
115 Lyric_combine_music_iterator::get_combine_lyrics () const
116 {
117   SCM l = get_music ()->get_property ("elements");
118   if (!scm_is_pair (l))
119     return 0;
120   l = scm_cdr (l);
121   if (!scm_is_pair (l))
122     return 0;
123   return unsmob_music (scm_car (l));
124 }
125
126 void
127 Lyric_combine_music_iterator::construct_children ()
128 {
129   music_iter_ = unsmob_iterator (get_iterator (get_combine_music ()));
130   lyric_iter_ = unsmob_iterator (get_iterator (get_combine_lyrics ()));
131 }
132
133 bool
134 Lyric_combine_music_iterator::get_busy_status () const
135 {
136   /*
137     We have to use both the event and the busyGrobs queue.  The
138     busyGrobs queue doesn't contain any notes that have started this
139     instant.  */
140   if (try_music (busy_req))
141     return true;
142
143   Context *tr = music_iter_->get_outlet ();
144
145   SCM grobs = tr->get_property ("busyGrobs");
146   Moment now = tr->now_mom ();
147   for (; scm_is_pair (grobs); grobs = scm_cdr (grobs))
148     {
149       SCM grob = scm_cdar (grobs);
150       Moment end = *unsmob_moment (scm_caar (grobs));
151
152       /*
153         This is slightly ugh: we are now confunding the frontend
154         (iterators) and the backend (note heads) */
155       if (end > now
156           && Note_head::has_interface (unsmob_grob (grob)))
157         return true;
158     }
159
160   return false;
161 }
162
163 bool
164 Lyric_combine_music_iterator::melisma_busy ()
165 {
166   /* We cannot read the property, since music_iter_->get_outlet () might
167      not be the context that sets the melisma properties, but rather a
168      parent context.  */
169   return music_iter_->try_music (melisma_playing_req);
170 }
171
172 void
173 Lyric_combine_music_iterator::process (Moment m)
174 {
175   Moment my_next = music_iter_->pending_moment ();
176   if (my_next > m)
177     return;
178
179   music_iter_->process (m);
180
181   if (get_busy_status () && !melisma_busy () && lyric_iter_->ok ())
182     {
183       Moment m = lyric_iter_->pending_moment ();
184       lyric_iter_->process (m);
185     }
186 }
187
188 void
189 Lyric_combine_music_iterator::do_quit ()
190 {
191   if (music_iter_)
192     music_iter_->quit ();
193   if (lyric_iter_)
194     lyric_iter_->quit ();
195 }
196
197 Music_iterator *
198 Lyric_combine_music_iterator::try_music_in_children (Music *m) const
199 {
200   Music_iterator *i = music_iter_->try_music (m);
201   if (i)
202     return i;
203   else
204     return lyric_iter_->try_music (m);
205 }
206
207 IMPLEMENT_CTOR_CALLBACK (Lyric_combine_music_iterator);