Nitpick: ly:spanner-bound grob name slur -> spanner.
[lilypond.git] / lily / quote-iterator.cc
blob58d4378d2543a9a55cc65cec2d6250dd655e2f41
1 /*
2 quote-iterator.cc -- implement Quote_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 2004--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include "music-wrapper-iterator.hh"
11 #include "context.hh"
12 #include "dispatcher.hh"
13 #include "input.hh"
14 #include "international.hh"
15 #include "lily-guile.hh"
16 #include "music-sequence.hh"
17 #include "music.hh"
18 #include "warn.hh"
20 class Quote_iterator : public Music_wrapper_iterator
22 public:
23 Quote_iterator ();
24 Moment vector_moment (int idx) const;
25 Context_handle quote_outlet_;
27 Moment start_moment_;
28 Moment stop_moment_;
29 SCM event_vector_;
30 int event_idx_;
31 int end_idx_;
33 SCM transposed_musics_;
35 DECLARE_SCHEME_CALLBACK (constructor, ());
36 bool quote_ok () const;
37 bool accept_music_type (Stream_event *) const;
39 protected:
40 virtual void derived_mark () const;
41 virtual void construct_children ();
42 virtual Moment pending_moment () const;
43 virtual void process (Moment);
44 virtual void do_quit ();
45 virtual bool ok () const;
48 void
49 Quote_iterator::do_quit ()
51 Music_wrapper_iterator::do_quit ();
52 quote_outlet_.set_context (0);
55 bool
56 Quote_iterator::accept_music_type (Stream_event *ev) const
58 for (SCM accept = get_outlet ()->get_property ("quotedEventTypes");
59 scm_is_pair (accept); accept = scm_cdr (accept))
61 if (ev->internal_in_event_class (scm_car (accept)))
62 return true;
64 return false;
67 void
68 Quote_iterator::derived_mark () const
70 Music_wrapper_iterator::derived_mark ();
71 scm_gc_mark (transposed_musics_);
74 Quote_iterator::Quote_iterator ()
76 transposed_musics_ = SCM_EOL;
77 event_vector_ = SCM_EOL;
78 event_idx_ = 0;
79 end_idx_ = 0;
82 int
83 binsearch_scm_vector (SCM vec, SCM key, bool (*is_less) (SCM a, SCM b))
85 int lo = 0;
86 int hi = scm_c_vector_length (vec);
88 /* binary search */
91 int cmp = (lo + hi) / 2;
93 SCM when = scm_caar (scm_c_vector_ref (vec, cmp));
94 bool result = (*is_less) (key, when);
95 if (result)
96 hi = cmp;
97 else
98 lo = cmp;
100 while (hi - lo > 1);
102 return lo;
105 void
106 Quote_iterator::construct_children ()
108 Music_wrapper_iterator::construct_children ();
110 SCM name = get_music ()->get_property ("quoted-context-type");
111 SCM id = get_music ()->get_property ("quoted-context-id");
113 if (scm_is_string (id)
114 && scm_is_symbol (name))
116 Context *cue_context = get_outlet ()->find_create_context (name,
117 ly_scm2string (id), SCM_EOL);
118 quote_outlet_.set_context (cue_context);
120 else
121 quote_outlet_.set_context (get_outlet ());
123 event_vector_ = get_music ()->get_property ("quoted-events");
126 We have to delay initting event_idx_ , since we have to
127 take starting grace notes into account. Those may offset
128 event_idx_.
130 event_idx_ = -1;
133 bool
134 Quote_iterator::ok () const
136 return
137 Music_wrapper_iterator::ok ()
138 || quote_ok ();
141 bool
142 Quote_iterator::quote_ok () const
144 return (event_idx_ >= 0
145 && scm_is_vector (event_vector_)
146 && event_idx_ <= end_idx_
149 Don't quote the grace notes leading to an unquoted note.
151 && vector_moment (event_idx_).main_part_ < stop_moment_.main_part_);
154 Moment
155 Quote_iterator::pending_moment () const
157 Rational infty;
158 infty.set_infinite (1);
159 Moment m (infty);
161 if (Music_wrapper_iterator::ok ())
162 m = min (m, Music_wrapper_iterator::pending_moment ());
165 In case event_idx_ < 0, we're not initted yet, and the wrapped
166 music expression determines the starting moment.
168 if (quote_ok ())
169 m = min (m, vector_moment (event_idx_) - start_moment_);
171 return m;
174 Moment
175 Quote_iterator::vector_moment (int idx) const
177 SCM entry = scm_c_vector_ref (event_vector_, idx);
178 return *unsmob_moment (scm_caar (entry));
181 void
182 Quote_iterator::process (Moment m)
184 if (Music_wrapper_iterator::ok ())
185 Music_wrapper_iterator::process (m);
187 if (!scm_is_vector (event_vector_))
188 return;
190 if (event_idx_ < 0)
192 event_idx_ = binsearch_scm_vector (event_vector_,
193 get_outlet ()->now_mom ().smobbed_copy (),
194 &moment_less);
195 start_moment_ = get_outlet ()->now_mom () - music_start_mom ();
196 stop_moment_ = start_moment_ + get_music ()->get_length ();
198 end_idx_ = binsearch_scm_vector (event_vector_,
199 stop_moment_.smobbed_copy (),
200 &moment_less);
203 m += start_moment_;
204 while (event_idx_ <= end_idx_)
206 Moment em = vector_moment (event_idx_);
207 if (em > m)
208 return;
210 if (em == m)
211 break;
213 event_idx_++;
216 if (quote_ok ())
218 SCM entry = scm_c_vector_ref (event_vector_, event_idx_);
219 Pitch *quote_pitch = unsmob_pitch (scm_cdar (entry));
222 The pitch that sounds like central C
224 Pitch *me_pitch = unsmob_pitch (get_music ()->get_property ("quoted-transposition"));
225 if (!me_pitch)
226 me_pitch = unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
228 for (SCM s = scm_cdr (entry); scm_is_pair (s); s = scm_cdr (s))
230 SCM ev_acc = scm_car (s);
232 Stream_event *ev = unsmob_stream_event (scm_car (ev_acc));
233 if (!ev)
234 programming_error ("no music found in quote");
235 else if (accept_music_type (ev))
237 /* create a transposed copy if necessary */
238 if (quote_pitch || me_pitch)
240 Pitch qp, mp;
241 if (quote_pitch)
242 qp = *quote_pitch;
243 if (me_pitch)
244 mp = *me_pitch;
246 Pitch diff = pitch_interval (qp, mp);
247 ev = ev->clone ();
249 transpose_mutable (ev->get_property_alist (true), diff);
250 transposed_musics_ = scm_cons (ev->unprotect (), transposed_musics_);
252 quote_outlet_.get_outlet ()->event_source ()->broadcast (ev);
256 event_idx_++;
260 IMPLEMENT_CTOR_CALLBACK (Quote_iterator);