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