]> git.donarmstrong.com Git - lilypond.git/blob - lily/quote-iterator.cc
* lily/include/event.hh: remove file.
[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--2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "context.hh"
10 #include "music.hh"
11 #include "music-sequence.hh"
12 #include "lily-guile.hh"
13 #include "music-wrapper-iterator.hh"
14 #include "warn.hh"
15 #include "input.hh"
16
17 class Quote_iterator : public Music_wrapper_iterator
18 {
19 public:
20   Quote_iterator ();
21   Moment vector_moment (int idx) const;
22   Context_handle quote_outlet_;
23
24   Moment start_moment_;
25   Moment stop_moment_;
26   SCM event_vector_;
27   int event_idx_;
28   int end_idx_;
29
30   SCM transposed_musics_;
31
32   DECLARE_SCHEME_CALLBACK (constructor, ());
33   bool quote_ok () const;
34   bool accept_music_type (Music *) const;
35
36 protected:
37   virtual void derived_mark () const;
38   virtual void construct_children ();
39   virtual Moment pending_moment () const;
40   virtual void process (Moment);
41   virtual void do_quit ();
42   virtual bool ok () const;
43 };
44
45 void
46 Quote_iterator::do_quit ()
47 {
48   Music_wrapper_iterator::do_quit ();
49   quote_outlet_.set_context (0);
50 }
51
52 bool
53 Quote_iterator::accept_music_type (Music *mus) const
54 {
55   SCM accept = get_outlet ()->get_property ("quotedEventTypes");
56   for (SCM s = mus->get_property ("types");
57        scm_is_pair (s); s = scm_cdr (s))
58     {
59       if (scm_memq (scm_car (s), accept) != SCM_BOOL_F)
60         return true;
61     }
62
63   return false;
64 }
65
66 void
67 Quote_iterator::derived_mark () const
68 {
69   Music_wrapper_iterator::derived_mark ();
70   scm_gc_mark (transposed_musics_);
71 }
72
73 Quote_iterator::Quote_iterator ()
74 {
75   transposed_musics_ = SCM_EOL;
76   event_vector_ = SCM_EOL;
77   event_idx_ = 0;
78   end_idx_ = 0;
79 }
80
81 int
82 binsearch_scm_vector (SCM vec, SCM key, bool (*is_less) (SCM a, SCM b))
83 {
84   int lo = 0;
85   int hi = scm_c_vector_length (vec);
86
87   /* binary search */
88   do
89     {
90       int cmp = (lo + hi) / 2;
91
92       SCM when = scm_caar (scm_c_vector_ref (vec, cmp));
93       bool result = (*is_less) (key, when);
94       if (result)
95         hi = cmp;
96       else
97         lo = cmp;
98     }
99   while (hi - lo > 1);
100
101   return lo;
102 }
103
104 void
105 Quote_iterator::construct_children ()
106 {
107   Music_wrapper_iterator::construct_children ();
108
109   SCM name = get_music ()->get_property ("quoted-context-type");
110   SCM id = get_music ()->get_property ("quoted-context-id");
111
112   if (scm_is_string (id)
113       && scm_is_symbol (name))
114     {
115       Context *cue_context = get_outlet ()->find_create_context (name,
116                                                                  ly_scm2string (id), SCM_EOL);
117       quote_outlet_.set_context (cue_context);
118     }
119   else
120     {
121       quote_outlet_.set_context (get_outlet ());
122     }
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);