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