Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / quote-iterator.cc
blob749bc13407befb65449969c75e92190e248bcc6d
1 /*
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"
22 #include "context.hh"
23 #include "dispatcher.hh"
24 #include "input.hh"
25 #include "international.hh"
26 #include "lily-guile.hh"
27 #include "music-sequence.hh"
28 #include "music.hh"
29 #include "warn.hh"
31 class Quote_iterator : public Music_wrapper_iterator
33 public:
34 Quote_iterator ();
35 Moment vector_moment (int idx) const;
36 Context_handle quote_outlet_;
38 Moment start_moment_;
39 Moment stop_moment_;
40 SCM event_vector_;
41 int event_idx_;
42 int end_idx_;
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;
50 protected:
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;
59 void
60 Quote_iterator::do_quit ()
62 Music_wrapper_iterator::do_quit ();
63 quote_outlet_.set_context (0);
66 bool
67 Quote_iterator::accept_music_type (Stream_event *ev, bool is_cue) const
69 SCM accept = SCM_EOL;
70 // Cue notes use the quotedCueEventTypes property, otherwise (and as fallback
71 // for cue notes if quotedCueEventTypes is not set) use quotedEventTypes
72 if (is_cue)
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)))
80 return true;
82 return false;
85 void
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;
96 event_idx_ = 0;
97 end_idx_ = 0;
101 binsearch_scm_vector (SCM vec, SCM key, bool (*is_less) (SCM a, SCM b))
103 int lo = 0;
104 int hi = scm_c_vector_length (vec);
106 /* binary search */
109 int cmp = (lo + hi) / 2;
111 SCM when = scm_caar (scm_c_vector_ref (vec, cmp));
112 bool result = (*is_less) (key, when);
113 if (result)
114 hi = cmp;
115 else
116 lo = cmp;
118 while (hi - lo > 1);
120 return lo;
123 void
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);
138 else
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
146 event_idx_.
148 event_idx_ = -1;
151 bool
152 Quote_iterator::ok () const
154 return
155 Music_wrapper_iterator::ok ()
156 || quote_ok ();
159 bool
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_);
172 Moment
173 Quote_iterator::pending_moment () const
175 Rational infty;
176 infty.set_infinite (1);
177 Moment m (infty);
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.
186 if (quote_ok ())
187 m = min (m, vector_moment (event_idx_) - start_moment_);
189 return m;
192 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));
199 void
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_))
206 return;
208 if (event_idx_ < 0)
210 event_idx_ = binsearch_scm_vector (event_vector_,
211 get_outlet ()->now_mom ().smobbed_copy (),
212 &moment_less);
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 (),
218 &moment_less);
221 m += start_moment_;
222 while (event_idx_ <= end_idx_)
224 Moment em = vector_moment (event_idx_);
225 if (em > m)
226 return;
228 if (em == m)
229 break;
231 event_idx_++;
234 if (quote_ok ())
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"));
243 if (!me_pitch)
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));
253 if (!ev)
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)
260 Pitch qp, mp;
261 if (quote_pitch)
262 qp = *quote_pitch;
263 if (me_pitch)
264 mp = *me_pitch;
266 Pitch diff = pitch_interval (qp, mp);
267 ev = ev->clone ();
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);
276 event_idx_++;
280 IMPLEMENT_CTOR_CALLBACK (Quote_iterator);