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