]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-combine-music-iterator.cc
* stepmake/aclocal.m4 (depth): fix bashism.
[lilypond.git] / lily / lyric-combine-music-iterator.cc
1 /*
2   new-lyric-combine-iterator.cc -- implement Lyric_combine_music_iterator
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2004--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "context.hh"
10 #include "grob.hh"
11 #include "input.hh"
12 #include "international.hh"
13 #include "music-iterator.hh"
14 #include "music.hh"
15
16 class Lyric_combine_music_iterator : public Music_iterator
17 {
18 public:
19   Lyric_combine_music_iterator ();
20   Lyric_combine_music_iterator (Lyric_combine_music_iterator const &src);
21   DECLARE_SCHEME_CALLBACK (constructor, ());
22 protected:
23   virtual void construct_children ();
24   virtual Moment pending_moment () const;
25   virtual void do_quit ();
26   virtual void process (Moment);
27   virtual Music_iterator *try_music_in_children (Music *) const;
28   virtual bool run_always ()const;
29   virtual bool ok () const;
30   virtual void derived_mark () const;
31   virtual void derived_substitute (Context *, Context *);
32 private:
33   bool start_new_syllable ();
34   void find_voice ();
35
36   bool pending_grace_lyric_;
37   bool music_found_;
38   bool made_association_;
39   Context *lyrics_context_;
40   Context *music_context_;
41   SCM lyricsto_voice_name_;
42
43   Music_iterator *lyric_iter_;
44 };
45
46 /*
47   Ugh; this is a hack, let's not export this hack, so static.
48 */
49 static Music *busy_ev;
50 static Music *start_ev;
51 static Music *melisma_playing_ev;
52
53 Lyric_combine_music_iterator::Lyric_combine_music_iterator ()
54 {
55   music_found_ = false;
56   made_association_ = false;
57   pending_grace_lyric_ = false;
58   lyric_iter_ = 0;
59   music_context_ = 0;
60   lyrics_context_ = 0;
61
62   /*
63     Ugh. out of place here.
64   */
65   if (!busy_ev)
66     {
67       busy_ev
68         = make_music_by_name (ly_symbol2scm ("BusyPlayingEvent"));
69       start_ev
70         = make_music_by_name (ly_symbol2scm ("StartPlayingEvent"));
71       melisma_playing_ev
72         = make_music_by_name (ly_symbol2scm ("MelismaPlayingEvent"));
73     }
74 }
75
76 bool
77 Lyric_combine_music_iterator::start_new_syllable ()
78 {
79   bool b = music_context_->try_music (busy_ev);
80
81   if (!b)
82     return false;
83
84   if (!lyrics_context_)
85     return false;
86
87   if (!to_boolean (lyrics_context_->get_property ("ignoreMelismata")))
88     {
89       bool m = music_context_->try_music (melisma_playing_ev);
90       if (m)
91         return false;
92     }
93
94   return true;
95 }
96
97 Moment
98 Lyric_combine_music_iterator::pending_moment () const
99 {
100   Moment m;
101
102   m.set_infinite (1);
103
104   return m;
105 }
106
107 bool
108 Lyric_combine_music_iterator::run_always () const
109 {
110   return true;
111 }
112
113 bool
114 Lyric_combine_music_iterator::ok () const
115 {
116   return lyric_iter_ && lyric_iter_->ok ();
117 }
118
119 void
120 Lyric_combine_music_iterator::derived_mark ()const
121 {
122   if (lyric_iter_)
123     scm_gc_mark (lyric_iter_->self_scm ());
124   if (lyrics_context_)
125     scm_gc_mark (lyrics_context_->self_scm ());
126   if (music_context_)
127     scm_gc_mark (music_context_->self_scm ());
128 }
129
130 void
131 Lyric_combine_music_iterator::derived_substitute (Context *f, Context *t)
132 {
133   if (lyric_iter_)
134     lyric_iter_->substitute_outlet (f, t);
135   if (lyrics_context_ && lyrics_context_ == f)
136     lyrics_context_ = t;
137   if (music_context_ && music_context_ == f)
138     music_context_ = t;
139 }
140
141 void
142 Lyric_combine_music_iterator::construct_children ()
143 {
144   Music *m = unsmob_music (get_music ()->get_property ("element"));
145   lyric_iter_ = unsmob_iterator (get_iterator (m));
146
147   lyricsto_voice_name_ = get_music ()->get_property ("associated-context");
148
149   find_voice ();
150
151   if (lyric_iter_)
152     lyrics_context_ = find_context_below (lyric_iter_->get_outlet (),
153                                           ly_symbol2scm ("Lyrics"), "");
154
155   /*
156     We do not create a Lyrics context, because the user might
157     create one with a different name, and then we will not find that
158     one.
159   */
160 }
161
162 void
163 Lyric_combine_music_iterator::find_voice ()
164 {
165   SCM voice_name = lyricsto_voice_name_;
166   SCM running = lyrics_context_
167     ? lyrics_context_->get_property ("associatedVoice")
168     : SCM_EOL;
169
170   if (scm_is_string (running))
171     voice_name = running;
172
173   if (scm_is_string (voice_name)
174       && (!music_context_ || ly_scm2string (voice_name) != music_context_->id_string ()))
175     {
176       /*
177         (spaghettini).
178
179         Need to set associatedVoiceContext again
180       */
181       if (music_context_)
182         made_association_ = false;
183
184       Context *t = get_outlet ();
185       while (t && t->get_parent_context ())
186         t = t->get_parent_context ();
187
188       string name = ly_scm2string (voice_name);
189       Context *voice = find_context_below (t, ly_symbol2scm ("Voice"), name);
190
191       if (voice)
192         music_context_ = voice;
193     }
194
195   if (lyrics_context_ && music_context_)
196     {
197       if (!made_association_)
198         {
199           made_association_ = true;
200           lyrics_context_->set_property ("associatedVoiceContext",
201                                          music_context_->self_scm ());
202         }
203     }
204 }
205
206 void
207 Lyric_combine_music_iterator::process (Moment mom)
208 {
209   (void) mom;
210   find_voice ();
211   if (!music_context_)
212     return;
213
214   if (!music_context_->get_parent_context ())
215     {
216       /*
217         The melody has died.
218         We die too.
219       */
220       if (lyrics_context_)
221         lyrics_context_->unset_property (ly_symbol2scm ("associatedVoiceContext"));
222       lyric_iter_ = 0;
223       music_context_ = 0;
224     }
225
226   if (music_context_
227       && (start_new_syllable () || pending_grace_lyric_)
228       && lyric_iter_->ok ())
229     {
230       if (music_context_->now_mom ().grace_part_)
231         {
232           pending_grace_lyric_ = true;
233           return;
234         }
235       else
236         pending_grace_lyric_ = false;
237       
238       Moment m = lyric_iter_->pending_moment ();
239       lyric_iter_->process (m);
240
241       music_found_ = true;
242     }
243 }
244
245 void
246 Lyric_combine_music_iterator::do_quit ()
247 {
248   if (!music_found_)
249     {
250       SCM voice_name = get_music ()->get_property ("associated-context");
251
252       string name;
253       if (scm_is_string (voice_name))
254         name = ly_scm2string (voice_name);
255
256       get_music ()->origin ()->warning (_f ("cannot find Voice `%s'",
257                                             name.c_str ()) + "\n");
258     }
259
260   if (lyric_iter_)
261     lyric_iter_->quit ();
262 }
263
264 Music_iterator *
265 Lyric_combine_music_iterator::try_music_in_children (Music *m) const
266 {
267   return lyric_iter_->try_music (m);
268 }
269
270 IMPLEMENT_CTOR_CALLBACK (Lyric_combine_music_iterator);