]> git.donarmstrong.com Git - lilypond.git/blob - lily/quote-iterator.cc
Nitpick run.
[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     quote_outlet_.set_context (get_outlet ());
121
122   event_vector_ = get_music ()->get_property ("quoted-events");
123
124   /*
125     We have to delay initting event_idx_ , since we have to
126     take starting grace notes into account. Those may offset
127     event_idx_.
128   */
129   event_idx_ = -1;
130 }
131
132 bool
133 Quote_iterator::ok () const
134 {
135   return
136     Music_wrapper_iterator::ok ()
137     || quote_ok ();
138 }
139
140 bool
141 Quote_iterator::quote_ok () const
142 {
143   return (event_idx_ >= 0
144           && scm_is_vector (event_vector_)
145           && event_idx_ <= end_idx_
146
147           /*
148             Don't quote the grace notes leading to an unquoted note.
149           */
150           && vector_moment (event_idx_).main_part_ < stop_moment_.main_part_);
151 }
152
153 Moment
154 Quote_iterator::pending_moment () const
155 {
156   Rational infty;
157   infty.set_infinite (1);
158   Moment m (infty);
159
160   if (Music_wrapper_iterator::ok ())
161     m = min (m, Music_wrapper_iterator::pending_moment ());
162
163   /*
164     In case event_idx_ < 0, we're not initted yet, and the wrapped
165     music expression determines the starting moment.
166   */
167   if (quote_ok ())
168     m = min (m, vector_moment (event_idx_) - start_moment_);
169
170   return m;
171 }
172
173 Moment
174 Quote_iterator::vector_moment (int idx) const
175 {
176   SCM entry = scm_c_vector_ref (event_vector_, idx);
177   return *unsmob_moment (scm_caar (entry));
178 }
179
180 void
181 Quote_iterator::process (Moment m)
182 {
183   if (Music_wrapper_iterator::ok ())
184     Music_wrapper_iterator::process (m);
185
186   if (!scm_is_vector (event_vector_))
187     return;
188
189   if (event_idx_ < 0)
190     {
191       event_idx_ = binsearch_scm_vector (event_vector_,
192                                          get_outlet ()->now_mom ().smobbed_copy (),
193                                          &moment_less);
194       start_moment_ = get_outlet ()->now_mom () - music_start_mom ();
195       stop_moment_ = start_moment_ + get_music ()->get_length ();
196
197       end_idx_ = binsearch_scm_vector (event_vector_,
198                                        stop_moment_.smobbed_copy (),
199                                        &moment_less);
200     }
201
202   m += start_moment_;
203   while (event_idx_ <= end_idx_)
204     {
205       Moment em = vector_moment (event_idx_);
206       if (em > m)
207         return;
208
209       if (em == m)
210         break;
211
212       event_idx_++;
213     }
214
215   if (quote_ok ())
216     {
217       SCM entry = scm_c_vector_ref (event_vector_, event_idx_);
218       Pitch *quote_pitch = unsmob_pitch (scm_cdar (entry));
219
220       /*
221         The pitch that sounds like central C
222       */
223       Pitch *me_pitch = unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
224
225       for (SCM s = scm_cdr (entry); scm_is_pair (s); s = scm_cdr (s))
226         {
227           SCM ev_acc = scm_car (s);
228
229           Music *mus = unsmob_music (scm_car (ev_acc));
230           if (!mus)
231             programming_error ("no music found in quote");
232           else if (accept_music_type (mus))
233             {
234               if (quote_pitch || me_pitch)
235                 {
236                   Pitch qp, mp;
237                   if (quote_pitch)
238                     qp = *quote_pitch;
239                   if (me_pitch)
240                     mp = *me_pitch;
241
242                   Pitch diff = pitch_interval (qp, mp);
243
244                   SCM copy = ly_music_deep_copy (mus->self_scm ());
245                   mus = unsmob_music (copy);
246
247                   transposed_musics_ = scm_cons (copy, transposed_musics_);
248                   mus->transpose (diff);
249                 }
250
251               bool b = quote_outlet_.get_outlet ()->try_music (mus);
252               if (!b)
253                 mus->origin ()->warning (_f ("in quotation: junking event %s",
254                                              mus->name ()));
255             }
256         }
257
258       event_idx_++;
259     }
260 }
261
262 IMPLEMENT_CTOR_CALLBACK (Quote_iterator);