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