2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2004--2011 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_string (id
)
132 && scm_is_symbol (name
))
134 Context
*cue_context
= get_outlet ()->find_create_context (name
,
135 ly_scm2string (id
), SCM_EOL
);
136 quote_outlet_
.set_context (cue_context
);
139 quote_outlet_
.set_context (get_outlet ());
141 event_vector_
= get_music ()->get_property ("quoted-events");
144 We have to delay initting event_idx_ , since we have to
145 take starting grace notes into account. Those may offset
152 Quote_iterator::ok () const
155 Music_wrapper_iterator::ok ()
160 Quote_iterator::quote_ok () const
162 return (event_idx_
>= 0
163 && scm_is_vector (event_vector_
)
164 && event_idx_
<= end_idx_
167 Don't quote the grace notes leading to an unquoted note.
169 && vector_moment (event_idx_
).main_part_
< stop_moment_
.main_part_
);
173 Quote_iterator::pending_moment () const
176 infty
.set_infinite (1);
179 if (Music_wrapper_iterator::ok ())
180 m
= min (m
, Music_wrapper_iterator::pending_moment ());
183 In case event_idx_ < 0, we're not initted yet, and the wrapped
184 music expression determines the starting moment.
187 m
= min (m
, vector_moment (event_idx_
) - start_moment_
);
193 Quote_iterator::vector_moment (int idx
) const
195 SCM entry
= scm_c_vector_ref (event_vector_
, idx
);
196 return *unsmob_moment (scm_caar (entry
));
200 Quote_iterator::process (Moment m
)
202 if (Music_wrapper_iterator::ok ())
203 Music_wrapper_iterator::process (m
);
205 if (!scm_is_vector (event_vector_
))
210 event_idx_
= binsearch_scm_vector (event_vector_
,
211 get_outlet ()->now_mom ().smobbed_copy (),
213 start_moment_
= get_outlet ()->now_mom () - music_start_mom ();
214 stop_moment_
= start_moment_
+ get_music ()->get_length ();
216 end_idx_
= binsearch_scm_vector (event_vector_
,
217 stop_moment_
.smobbed_copy (),
222 while (event_idx_
<= end_idx_
)
224 Moment em
= vector_moment (event_idx_
);
236 SCM entry
= scm_c_vector_ref (event_vector_
, event_idx_
);
237 Pitch
*quote_pitch
= unsmob_pitch (scm_cdar (entry
));
240 The pitch that sounds like central C
242 Pitch
*me_pitch
= unsmob_pitch (get_music ()->get_property ("quoted-transposition"));
244 me_pitch
= unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
245 SCM cid
= get_music ()->get_property ("quoted-context-id");
246 bool is_cue
= scm_is_string (cid
) && (ly_scm2string (cid
) == "cue");
248 for (SCM s
= scm_cdr (entry
); scm_is_pair (s
); s
= scm_cdr (s
))
250 SCM ev_acc
= scm_car (s
);
252 Stream_event
*ev
= unsmob_stream_event (scm_car (ev_acc
));
254 programming_error ("no music found in quote");
255 else if (accept_music_type (ev
, is_cue
))
257 /* create a transposed copy if necessary */
258 if (quote_pitch
|| me_pitch
)
266 Pitch diff
= pitch_interval (qp
, mp
);
269 transpose_mutable (ev
->get_property_alist (true), diff
);
270 transposed_musics_
= scm_cons (ev
->unprotect (), transposed_musics_
);
272 quote_outlet_
.get_outlet ()->event_source ()->broadcast (ev
);
280 IMPLEMENT_CTOR_CALLBACK (Quote_iterator
);