2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2004--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "music-wrapper-iterator.hh"
23 #include "dispatcher.hh"
25 #include "international.hh"
26 #include "lily-guile.hh"
27 #include "music-sequence.hh"
31 class Quote_iterator : public Music_wrapper_iterator
35 Moment vector_moment (int idx) const;
36 Context_handle quote_outlet_;
44 SCM transposed_musics_;
46 DECLARE_SCHEME_CALLBACK (constructor, ());
47 bool quote_ok () const;
48 bool accept_music_type (Stream_event *, bool is_cue = true) const;
51 virtual void derived_mark () const;
52 virtual void construct_children ();
53 virtual Moment pending_moment () const;
54 virtual void process (Moment);
55 virtual void do_quit ();
56 virtual bool ok () const;
60 Quote_iterator::do_quit ()
62 Music_wrapper_iterator::do_quit ();
63 quote_outlet_.set_context (0);
67 Quote_iterator::accept_music_type (Stream_event *ev, bool is_cue) const
70 // Cue notes use the quotedCueEventTypes property, otherwise (and as fallback
71 // for cue notes if quotedCueEventTypes is not set) use quotedEventTypes
73 accept = get_outlet ()->get_property ("quotedCueEventTypes");
74 if (accept == SCM_EOL)
75 accept = get_outlet ()->get_property ("quotedEventTypes");
77 for (; scm_is_pair (accept); accept = scm_cdr (accept))
79 if (ev->internal_in_event_class (scm_car (accept)))
86 Quote_iterator::derived_mark () const
88 Music_wrapper_iterator::derived_mark ();
89 scm_gc_mark (transposed_musics_);
92 Quote_iterator::Quote_iterator ()
94 transposed_musics_ = SCM_EOL;
95 event_vector_ = SCM_EOL;
101 binsearch_scm_vector (SCM vec, SCM key, bool (*is_less) (SCM a, SCM b))
104 int hi = scm_c_vector_length (vec);
109 int cmp = (lo + hi) / 2;
111 SCM when = scm_caar (scm_c_vector_ref (vec, cmp));
112 bool result = (*is_less) (key, when);
124 Quote_iterator::construct_children ()
126 Music_wrapper_iterator::construct_children ();
128 SCM name = get_music ()->get_property ("quoted-context-type");
129 SCM id = get_music ()->get_property ("quoted-context-id");
131 if (scm_is_symbol (name))
133 Context *cue_context =
134 get_outlet ()->find_create_context (name,
135 robust_scm2string (id, ""),
137 quote_outlet_.set_context (cue_context);
140 quote_outlet_.set_context (get_outlet ()->get_default_interpreter ());
142 event_vector_ = get_music ()->get_property ("quoted-events");
145 We have to delay initting event_idx_ , since we have to
146 take starting grace notes into account. Those may offset
153 Quote_iterator::ok () const
156 Music_wrapper_iterator::ok ()
161 Quote_iterator::quote_ok () const
163 return (event_idx_ >= 0
164 && scm_is_vector (event_vector_)
165 && event_idx_ <= end_idx_
168 Don't quote the grace notes leading to an unquoted note.
170 && vector_moment (event_idx_).main_part_ < stop_moment_.main_part_);
174 Quote_iterator::pending_moment () const
177 infty.set_infinite (1);
180 if (Music_wrapper_iterator::ok ())
181 m = min (m, Music_wrapper_iterator::pending_moment ());
184 In case event_idx_ < 0, we're not initted yet, and the wrapped
185 music expression determines the starting moment.
188 m = min (m, vector_moment (event_idx_) - start_moment_);
194 Quote_iterator::vector_moment (int idx) const
196 SCM entry = scm_c_vector_ref (event_vector_, idx);
197 return *unsmob_moment (scm_caar (entry));
201 Quote_iterator::process (Moment m)
203 if (Music_wrapper_iterator::ok ())
204 Music_wrapper_iterator::process (m);
206 if (!scm_is_vector (event_vector_))
211 event_idx_ = binsearch_scm_vector (event_vector_,
212 get_outlet ()->now_mom ().smobbed_copy (),
214 start_moment_ = get_outlet ()->now_mom () - music_start_mom ();
215 stop_moment_ = start_moment_ + get_music ()->get_length ();
217 end_idx_ = binsearch_scm_vector (event_vector_,
218 stop_moment_.smobbed_copy (),
223 while (event_idx_ <= end_idx_)
225 Moment em = vector_moment (event_idx_);
237 SCM entry = scm_c_vector_ref (event_vector_, event_idx_);
238 Pitch *quote_pitch = unsmob_pitch (scm_cdar (entry));
241 The pitch that sounds when written central C is played.
244 Pitch *me_pitch = unsmob_pitch (get_music ()->get_property ("quoted-transposition"));
246 me_pitch = unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
249 // We are not going to win a beauty contest with this one,
250 // but it is slated for replacement and touches little code.
251 // quoted-transposition currently has a different sign
252 // convention than instrumentTransposition
253 temp_pitch = me_pitch->negated ();
254 me_pitch = &temp_pitch;
256 SCM cid = get_music ()->get_property ("quoted-context-id");
257 bool is_cue = scm_is_string (cid) && (ly_scm2string (cid) == "cue");
259 for (SCM s = scm_cdr (entry); scm_is_pair (s); s = scm_cdr (s))
261 SCM ev_acc = scm_car (s);
263 Stream_event *ev = unsmob_stream_event (scm_car (ev_acc));
265 programming_error ("no music found in quote");
266 else if (accept_music_type (ev, is_cue))
268 /* create a transposed copy if necessary */
269 if (quote_pitch || me_pitch)
277 Pitch diff = pitch_interval (mp, qp);
279 ev->make_transposable ();
281 transpose_mutable (ev->get_property_alist (true), diff);
282 transposed_musics_ = scm_cons (ev->unprotect (), transposed_musics_);
284 quote_outlet_.get_context ()->event_source ()->broadcast (ev);
292 IMPLEMENT_CTOR_CALLBACK (Quote_iterator);