]> git.donarmstrong.com Git - lilypond.git/blob - lily/quote-iterator.cc
Update source file headers. Fixes using standard GNU package conventions.
[lilypond.git] / lily / quote-iterator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2004--2009 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 "music-wrapper-iterator.hh"
21
22 #include "context.hh"
23 #include "dispatcher.hh"
24 #include "input.hh"
25 #include "international.hh"
26 #include "lily-guile.hh"
27 #include "music-sequence.hh"
28 #include "music.hh"
29 #include "warn.hh"
30
31 class Quote_iterator : public Music_wrapper_iterator
32 {
33 public:
34   Quote_iterator ();
35   Moment vector_moment (int idx) const;
36   Context_handle quote_outlet_;
37
38   Moment start_moment_;
39   Moment stop_moment_;
40   SCM event_vector_;
41   int event_idx_;
42   int end_idx_;
43   
44   SCM transposed_musics_;
45
46   DECLARE_SCHEME_CALLBACK (constructor, ());
47   bool quote_ok () const;
48   bool accept_music_type (Stream_event *) const;
49
50 protected:
51   virtual void derived_mark () const;
52   virtual void construct_children ();
53   virtual Moment pending_moment () const;
54   virtual void process (Moment);
55   virtual void do_quit ();
56   virtual bool ok () const;
57 };
58
59 void
60 Quote_iterator::do_quit ()
61 {
62   Music_wrapper_iterator::do_quit ();
63   quote_outlet_.set_context (0);
64 }
65
66 bool
67 Quote_iterator::accept_music_type (Stream_event *ev) const
68 {
69   for (SCM accept = get_outlet ()->get_property ("quotedEventTypes");
70        scm_is_pair (accept); accept = scm_cdr (accept))
71     {
72       if (ev->internal_in_event_class (scm_car (accept)))
73         return true;
74     }
75   return false;
76 }
77
78 void
79 Quote_iterator::derived_mark () const
80 {
81   Music_wrapper_iterator::derived_mark ();
82   scm_gc_mark (transposed_musics_);
83 }
84
85 Quote_iterator::Quote_iterator ()
86 {
87   transposed_musics_ = SCM_EOL;
88   event_vector_ = SCM_EOL;
89   event_idx_ = 0;
90   end_idx_ = 0;
91 }
92
93 int
94 binsearch_scm_vector (SCM vec, SCM key, bool (*is_less) (SCM a, SCM b))
95 {
96   int lo = 0;
97   int hi = scm_c_vector_length (vec);
98
99   /* binary search */
100   do
101     {
102       int cmp = (lo + hi) / 2;
103
104       SCM when = scm_caar (scm_c_vector_ref (vec, cmp));
105       bool result = (*is_less) (key, when);
106       if (result)
107         hi = cmp;
108       else
109         lo = cmp;
110     }
111   while (hi - lo > 1);
112
113   return lo;
114 }
115
116 void
117 Quote_iterator::construct_children ()
118 {
119   Music_wrapper_iterator::construct_children ();
120       
121   SCM name = get_music ()->get_property ("quoted-context-type");
122   SCM id = get_music ()->get_property ("quoted-context-id");
123
124   if (scm_is_string (id)
125       && scm_is_symbol (name))
126     {
127       Context *cue_context = get_outlet ()->find_create_context (name,
128                                                                  ly_scm2string (id), SCM_EOL);
129       quote_outlet_.set_context (cue_context);
130     }
131   else
132     quote_outlet_.set_context (get_outlet ());
133
134   event_vector_ = get_music ()->get_property ("quoted-events");
135
136   /*
137     We have to delay initting event_idx_ , since we have to
138     take starting grace notes into account. Those may offset
139     event_idx_.
140   */
141   event_idx_ = -1;
142 }
143
144 bool
145 Quote_iterator::ok () const
146 {
147   return
148     Music_wrapper_iterator::ok ()
149     || quote_ok ();
150 }
151
152 bool
153 Quote_iterator::quote_ok () const
154 {
155   return (event_idx_ >= 0
156           && scm_is_vector (event_vector_)
157           && event_idx_ <= end_idx_
158
159           /*
160             Don't quote the grace notes leading to an unquoted note.
161           */
162           && vector_moment (event_idx_).main_part_ < stop_moment_.main_part_);
163 }
164
165 Moment
166 Quote_iterator::pending_moment () const
167 {
168   Rational infty;
169   infty.set_infinite (1);
170   Moment m (infty);
171
172   if (Music_wrapper_iterator::ok ())
173     m = min (m, Music_wrapper_iterator::pending_moment ());
174
175   /*
176     In case event_idx_ < 0, we're not initted yet, and the wrapped
177     music expression determines the starting moment.
178   */
179   if (quote_ok ())
180     m = min (m, vector_moment (event_idx_) - start_moment_);
181
182   return m;
183 }
184
185 Moment
186 Quote_iterator::vector_moment (int idx) const
187 {
188   SCM entry = scm_c_vector_ref (event_vector_, idx);
189   return *unsmob_moment (scm_caar (entry));
190 }
191
192 void
193 Quote_iterator::process (Moment m)
194 {
195   if (Music_wrapper_iterator::ok ())
196     Music_wrapper_iterator::process (m);
197
198   if (!scm_is_vector (event_vector_))
199     return;
200
201   if (event_idx_ < 0)
202     {
203       event_idx_ = binsearch_scm_vector (event_vector_,
204                                          get_outlet ()->now_mom ().smobbed_copy (),
205                                          &moment_less);
206       start_moment_ = get_outlet ()->now_mom () - music_start_mom ();
207       stop_moment_ = start_moment_ + get_music ()->get_length ();
208
209       end_idx_ = binsearch_scm_vector (event_vector_,
210                                        stop_moment_.smobbed_copy (),
211                                        &moment_less);
212     }
213
214   m += start_moment_;
215   while (event_idx_ <= end_idx_)
216     {
217       Moment em = vector_moment (event_idx_);
218       if (em > m)
219         return;
220
221       if (em == m)
222         break;
223
224       event_idx_++;
225     }
226
227   if (quote_ok ())
228     {
229       SCM entry = scm_c_vector_ref (event_vector_, event_idx_);
230       Pitch *quote_pitch = unsmob_pitch (scm_cdar (entry));
231
232       /*
233         The pitch that sounds like central C
234       */
235       Pitch *me_pitch = unsmob_pitch (get_music ()->get_property ("quoted-transposition"));
236       if (!me_pitch)
237         me_pitch = unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
238
239       for (SCM s = scm_cdr (entry); scm_is_pair (s); s = scm_cdr (s))
240         {
241           SCM ev_acc = scm_car (s);
242
243           Stream_event *ev = unsmob_stream_event (scm_car (ev_acc));
244           if (!ev)
245             programming_error ("no music found in quote");
246           else if (accept_music_type (ev))
247             {
248               /* create a transposed copy if necessary */
249               if (quote_pitch || me_pitch)
250                 {
251                   Pitch qp, mp;
252                   if (quote_pitch)
253                     qp = *quote_pitch;
254                   if (me_pitch)
255                     mp = *me_pitch;
256
257                   Pitch diff = pitch_interval (qp, mp);
258                   ev = ev->clone ();
259                   
260                   transpose_mutable (ev->get_property_alist (true), diff);
261                   transposed_musics_ = scm_cons (ev->unprotect (), transposed_musics_);
262                 }
263               quote_outlet_.get_outlet ()->event_source ()->broadcast (ev);
264             }
265         }
266
267       event_idx_++;
268     }
269 }
270
271 IMPLEMENT_CTOR_CALLBACK (Quote_iterator);