OLD | NEW |
1 /* | 1 /* |
2 This file is part of LilyPond, the GNU music typesetter. | 2 This file is part of LilyPond, the GNU music typesetter. |
3 | 3 |
4 Copyright (C) 1997--2012 Han-Wen Nienhuys <hanwen@xs4all.nl> | 4 Copyright (C) 1997--2012 Han-Wen Nienhuys <hanwen@xs4all.nl> |
5 | 5 |
6 LilyPond is free software: you can redistribute it and/or modify | 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 | 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 | 8 the Free Software Foundation, either version 3 of the License, or |
9 (at your option) any later version. | 9 (at your option) any later version. |
10 | 10 |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "directional-element-interface.hh" | 23 #include "directional-element-interface.hh" |
24 #include "international.hh" | 24 #include "international.hh" |
25 #include "note-column.hh" | 25 #include "note-column.hh" |
26 #include "slur.hh" | 26 #include "slur.hh" |
27 #include "spanner.hh" | 27 #include "spanner.hh" |
28 #include "stream-event.hh" | 28 #include "stream-event.hh" |
29 #include "warn.hh" | 29 #include "warn.hh" |
30 | 30 |
31 #include "translator.icc" | 31 #include "translator.icc" |
32 | 32 |
| 33 #include <algorithm> |
| 34 |
33 /* | 35 /* |
34 NOTE NOTE NOTE | 36 NOTE NOTE NOTE |
35 | 37 |
36 This is largely similar to Phrasing_slur_engraver. Check if fixes | 38 This is largely similar to Phrasing_slur_engraver. Check if fixes |
37 apply there too. | 39 apply there too. |
38 | 40 |
39 (on principle, engravers don't use inheritance for code sharing) | 41 (on principle, engravers don't use inheritance for code sharing) |
40 | 42 |
41 */ | 43 */ |
42 | 44 |
43 /* | 45 /* |
44 It is possible that a slur starts and ends on the same note. At | 46 It is possible that a slur starts and ends on the same note. At |
45 least, it is for phrasing slurs: a note can be both beginning and | 47 least, it is for phrasing slurs: a note can be both beginning and |
46 ending of a phrase. | 48 ending of a phrase. |
47 */ | 49 */ |
| 50 |
| 51 Slur_info::Slur_info (Grob *slur) |
| 52 { |
| 53 slur_ = slur; |
| 54 } |
| 55 |
48 class Slur_engraver : public Engraver | 56 class Slur_engraver : public Engraver |
49 { | 57 { |
50 vector<Stream_event *> start_events_; | 58 vector<Stream_event *> start_events_; |
51 vector<Stream_event *> stop_events_; | 59 vector<Stream_event *> stop_events_; |
52 vector<Grob *> slurs_; | 60 vector<Slur_info> slur_infos_; |
53 vector<Grob *> end_slurs_; | 61 vector<Slur_info> end_slur_infos_; |
54 vector<Grob_info> objects_to_acknowledge_; | 62 vector<Grob_info> objects_to_acknowledge_; |
55 | 63 |
56 void set_melisma (bool); | 64 void set_melisma (bool); |
57 | 65 |
58 protected: | 66 protected: |
59 DECLARE_TRANSLATOR_LISTENER (slur); | 67 DECLARE_TRANSLATOR_LISTENER (slur); |
60 DECLARE_ACKNOWLEDGER (inline_accidental); | 68 DECLARE_ACKNOWLEDGER (inline_accidental); |
61 DECLARE_ACKNOWLEDGER (fingering); | 69 DECLARE_ACKNOWLEDGER (fingering); |
62 DECLARE_ACKNOWLEDGER (note_column); | 70 DECLARE_ACKNOWLEDGER (note_column); |
63 DECLARE_ACKNOWLEDGER (script); | 71 DECLARE_ACKNOWLEDGER (script); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 | 113 |
106 void | 114 void |
107 Slur_engraver::set_melisma (bool m) | 115 Slur_engraver::set_melisma (bool m) |
108 { | 116 { |
109 context ()->set_property ("slurMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F); | 117 context ()->set_property ("slurMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F); |
110 } | 118 } |
111 | 119 |
112 void | 120 void |
113 Slur_engraver::acknowledge_note_column (Grob_info info) | 121 Slur_engraver::acknowledge_note_column (Grob_info info) |
114 { | 122 { |
| 123 /* |
| 124 * For every active slur, we create a slur stub. |
| 125 * As we do not yet know what vertical axis groups note columns belong to, |
| 126 * we create a stub for each note and then suicide duplicate stubs on |
| 127 * axis groups. |
| 128 * These slurs should be used ONLY to approximate cross-staff slurs |
| 129 * in vertical skylines. |
| 130 */ |
| 131 ·· |
115 Grob *e = info.grob (); | 132 Grob *e = info.grob (); |
116 for (vsize i = slurs_.size (); i--;) | 133 for (vsize i = slur_infos_.size (); i--;) |
117 Slur::add_column (slurs_[i], e); | 134 { |
118 for (vsize i = end_slurs_.size (); i--;) | 135 Slur::add_column (slur_infos_[i].slur_, e); |
119 Slur::add_column (end_slurs_[i], e); | 136 Grob *stub = make_spanner ("SlurStub", info.grob ()->self_scm ()); |
| 137 slur_infos_[i].stubs_.push_back (stub); |
| 138 } |
| 139 for (vsize i = end_slur_infos_.size (); i--;) |
| 140 { |
| 141 Slur::add_column (end_slur_infos_[i].slur_, e); |
| 142 Grob *stub = make_spanner ("SlurStub", info.grob ()->self_scm ()); |
| 143 end_slur_infos_[i].stubs_.push_back (stub); |
| 144 } |
120 } | 145 } |
121 | 146 |
122 void | 147 void |
123 Slur_engraver::acknowledge_extra_object (Grob_info info) | 148 Slur_engraver::acknowledge_extra_object (Grob_info info) |
124 { | 149 { |
125 objects_to_acknowledge_.push_back (info); | 150 objects_to_acknowledge_.push_back (info); |
126 } | 151 } |
127 | 152 |
128 void | 153 void |
129 Slur_engraver::acknowledge_inline_accidental (Grob_info info) | 154 Slur_engraver::acknowledge_inline_accidental (Grob_info info) |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 | 189 |
165 void | 190 void |
166 Slur_engraver::acknowledge_end_tie (Grob_info info) | 191 Slur_engraver::acknowledge_end_tie (Grob_info info) |
167 { | 192 { |
168 acknowledge_extra_object (info); | 193 acknowledge_extra_object (info); |
169 } | 194 } |
170 | 195 |
171 void | 196 void |
172 Slur_engraver::finalize () | 197 Slur_engraver::finalize () |
173 { | 198 { |
174 for (vsize i = 0; i < slurs_.size (); i++) | 199 for (vsize i = 0; i < slur_infos_.size (); i++) |
175 { | 200 { |
176 slurs_[i]->warning (_ ("unterminated slur")); | 201 slur_infos_[i].slur_->warning (_ ("unterminated slur")); |
177 slurs_[i]->suicide (); | 202 slur_infos_[i].slur_->suicide (); |
| 203 for (vsize j = 0; j < slur_infos_[i].stubs_.size (); j++) |
| 204 slur_infos_[i].stubs_[j]->suicide (); |
178 } | 205 } |
179 slurs_.clear (); | 206 |
| 207 slur_infos_.clear (); |
180 } | 208 } |
181 | 209 |
182 void | 210 void |
183 Slur_engraver::process_music () | 211 Slur_engraver::process_music () |
184 { | 212 { |
185 for (vsize i = 0; i < stop_events_.size (); i++) | 213 for (vsize i = 0; i < stop_events_.size (); i++) |
186 { | 214 { |
187 Stream_event *ev = stop_events_[i]; | 215 Stream_event *ev = stop_events_[i]; |
188 string id = robust_scm2string (ev->get_property ("spanner-id"), ""); | 216 string id = robust_scm2string (ev->get_property ("spanner-id"), ""); |
189 | 217 |
190 // Find the slurs that are ended with this event (by checking the spanner-
id) | 218 // Find the slurs that are ended with this event (by checking the spanner-
id) |
191 bool ended = false; | 219 bool ended = false; |
192 for (vsize j = slurs_.size (); j--;) | 220 for (vsize j = slur_infos_.size (); j--;) |
193 { | 221 { |
194 if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), "
")) | 222 if (id == robust_scm2string (slur_infos_[j].slur_->get_property ("span
ner-id"), "")) |
195 { | 223 { |
196 ended = true; | 224 ended = true; |
197 end_slurs_.push_back (slurs_[j]); | 225 end_slur_infos_.push_back (slur_infos_[j]); |
198 slurs_.erase (slurs_.begin () + j); | 226 slur_infos_.erase (slur_infos_.begin () + j); |
199 } | 227 } |
200 } | 228 } |
201 if (ended) | 229 if (ended) |
202 { | 230 { |
203 // Ignore redundant stop events for this id | 231 // Ignore redundant stop events for this id |
204 for (vsize j = stop_events_.size (); --j > i;) | 232 for (vsize j = stop_events_.size (); --j > i;) |
205 { | 233 { |
206 if (id == robust_scm2string (stop_events_[j]->get_property ("spann
er-id"), "")) | 234 if (id == robust_scm2string (stop_events_[j]->get_property ("spann
er-id"), "")) |
207 stop_events_.erase (stop_events_.begin () + j); | 235 stop_events_.erase (stop_events_.begin () + j); |
208 } | 236 } |
209 } | 237 } |
210 else | 238 else |
211 ev->origin ()->warning (_ ("cannot end slur")); | 239 ev->origin ()->warning (_ ("cannot end slur")); |
212 } | 240 } |
213 | 241 |
214 vsize old_slurs = slurs_.size (); | 242 vsize old_slurs = slur_infos_.size (); |
215 for (vsize i = start_events_.size (); i--;) | 243 for (vsize i = start_events_.size (); i--;) |
216 { | 244 { |
217 Stream_event *ev = start_events_[i]; | 245 Stream_event *ev = start_events_[i]; |
218 string id = robust_scm2string (ev->get_property ("spanner-id"), ""); | 246 string id = robust_scm2string (ev->get_property ("spanner-id"), ""); |
219 Direction updown = to_dir (ev->get_property ("direction")); | 247 Direction updown = to_dir (ev->get_property ("direction")); |
220 | 248 |
221 bool completed; | 249 bool completed; |
222 for (vsize j = slurs_.size (); !(completed = (j-- == 0));) | 250 for (vsize j = slur_infos_.size (); !(completed = (j-- == 0));) |
223 { | 251 { |
224 // Check if we already have a slur with the same spanner-id. | 252 // Check if we already have a slur with the same spanner-id. |
225 if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), "
")) | 253 if (id == robust_scm2string (slur_infos_[j].slur_->get_property ("span
ner-id"), "")) |
226 { | 254 { |
227 if (j < old_slurs) | 255 if (j < old_slurs) |
228 { | 256 { |
229 // We already have an old slur, so give a warning | 257 // We already have an old slur, so give a warning |
230 // and completely ignore the new slur. | 258 // and completely ignore the new slur. |
231 ev->origin ()->warning (_ ("already have slur")); | 259 ev->origin ()->warning (_ ("already have slur")); |
232 start_events_.erase (start_events_.begin () + i); | 260 start_events_.erase (start_events_.begin () + i); |
233 break; | 261 break; |
234 } | 262 } |
235 | 263 |
236 // If this slur event has no direction, it will not | 264 // If this slur event has no direction, it will not |
237 // contribute anything new to the existing slur(s), so | 265 // contribute anything new to the existing slur(s), so |
238 // we can ignore it. | 266 // we can ignore it. |
239 | 267 |
240 if (!updown) | 268 if (!updown) |
241 break; | 269 break; |
242 | 270 |
243 Stream_event *c = unsmob_stream_event (slurs_[j]->get_property ("c
ause")); | 271 Stream_event *c = unsmob_stream_event (slur_infos_[j].slur_->get_p
roperty ("cause")); |
244 | 272 |
245 if (!c) | 273 if (!c) |
246 { | 274 { |
247 slurs_[j]->programming_error ("slur without a cause"); | 275 slur_infos_[j].slur_->programming_error ("slur without a cause
"); |
248 continue; | 276 continue; |
249 } | 277 } |
250 | 278 |
251 Direction slur_dir = to_dir (c->get_property ("direction")); | 279 Direction slur_dir = to_dir (c->get_property ("direction")); |
252 | 280 |
253 // If the existing slur does not have a direction yet, | 281 // If the existing slur does not have a direction yet, |
254 // we'd rather take the new one. | 282 // we'd rather take the new one. |
255 | 283 |
256 if (!slur_dir) | 284 if (!slur_dir) |
257 { | 285 { |
258 slurs_[j]->suicide (); | 286 slur_infos_[j].slur_->suicide (); |
259 slurs_.erase (slurs_.begin () + j); | 287 for (vsize k = 0; k < slur_infos_[j].stubs_.size (); k++) |
| 288 slur_infos_[j].stubs_[k]->suicide (); |
| 289 slur_infos_.erase (slur_infos_.begin () + j); |
260 continue; | 290 continue; |
261 } | 291 } |
262 | 292 |
263 // If the existing slur has the same direction as ours, drop ours | 293 // If the existing slur has the same direction as ours, drop ours |
264 | 294 |
265 if (slur_dir == updown) | 295 if (slur_dir == updown) |
266 break; | 296 break; |
267 } | 297 } |
268 } | 298 } |
269 // If the loop completed, our slur is new | 299 // If the loop completed, our slur is new |
270 if (completed) | 300 if (completed) |
271 { | 301 { |
272 Grob *slur = make_spanner ("Slur", ev->self_scm ()); | 302 Grob *slur = make_spanner ("Slur", ev->self_scm ()); |
273 slur->set_property ("spanner-id", ly_string2scm (id)); | 303 slur->set_property ("spanner-id", ly_string2scm (id)); |
274 if (updown) | 304 if (updown) |
275 set_grob_direction (slur, updown); | 305 set_grob_direction (slur, updown); |
276 slurs_.push_back (slur); | 306 slur_infos_.push_back (Slur_info (slur)); |
277 | 307 |
278 if (to_boolean (get_property ("doubleSlurs"))) | 308 if (to_boolean (get_property ("doubleSlurs"))) |
279 { | 309 { |
280 set_grob_direction (slur, DOWN); | 310 set_grob_direction (slur, DOWN); |
281 slur = make_spanner ("Slur", ev->self_scm ()); | 311 slur = make_spanner ("Slur", ev->self_scm ()); |
282 slur->set_property ("spanner-id", ly_string2scm (id)); | 312 slur->set_property ("spanner-id", ly_string2scm (id)); |
283 set_grob_direction (slur, UP); | 313 set_grob_direction (slur, UP); |
284 slurs_.push_back (slur); | 314 slur_infos_.push_back (Slur_info (slur)); |
285 } | 315 } |
286 } | 316 } |
287 } | 317 } |
288 set_melisma (slurs_.size ()); | 318 set_melisma (slur_infos_.size ()); |
289 } | 319 } |
290 | 320 |
291 void | 321 void |
292 Slur_engraver::stop_translation_timestep () | 322 Slur_engraver::stop_translation_timestep () |
293 { | 323 { |
294 if (Grob *g = unsmob_grob (get_property ("currentCommandColumn"))) | 324 if (Grob *g = unsmob_grob (get_property ("currentCommandColumn"))) |
295 { | 325 { |
296 for (vsize i = 0; i < end_slurs_.size (); i++) | 326 for (vsize i = 0; i < end_slur_infos_.size (); i++) |
297 Slur::add_extra_encompass (end_slurs_[i], g); | 327 Slur::add_extra_encompass (end_slur_infos_[i].slur_, g); |
298 | 328 |
299 if (!start_events_.size ()) | 329 if (!start_events_.size ()) |
300 for (vsize i = 0; i < slurs_.size (); i++) | 330 for (vsize i = 0; i < slur_infos_.size (); i++) |
301 Slur::add_extra_encompass (slurs_[i], g); | 331 Slur::add_extra_encompass (slur_infos_[i].slur_, g); |
302 } | 332 } |
303 | 333 |
304 for (vsize i = 0; i < end_slurs_.size (); i++) | 334 for (vsize i = 0; i < end_slur_infos_.size (); i++) |
305 { | 335 { |
306 Spanner *s = dynamic_cast<Spanner *> (end_slurs_[i]); | 336 Spanner *s = dynamic_cast<Spanner *> (end_slur_infos_[i].slur_); |
307 if (!s->get_bound (RIGHT)) | 337 if (!s->get_bound (RIGHT)) |
308 s->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn"))
); | 338 s->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn"))
); |
309 announce_end_grob (s, SCM_EOL); | 339 announce_end_grob (s, SCM_EOL); |
310 } | 340 } |
311 | 341 |
312 for (vsize i = 0; i < objects_to_acknowledge_.size (); i++) | 342 for (vsize i = 0; i < objects_to_acknowledge_.size (); i++) |
313 Slur::auxiliary_acknowledge_extra_object (objects_to_acknowledge_[i], slurs_
, end_slurs_); | 343 Slur::auxiliary_acknowledge_extra_object (objects_to_acknowledge_[i], slur_i
nfos_, end_slur_infos_); |
| 344 |
| 345 for (vsize i = 0; i < end_slur_infos_.size (); i++) |
| 346 { |
| 347 // There are likely SlurStubs we don't need. Get rid of them |
| 348 // and only keep one per VerticalAxisGroup. |
| 349 vector<Grob *> vags; |
| 350 vector<Grob *> stubs; |
| 351 for (vsize j = 0; j < end_slur_infos_[i].stubs_.size (); j++) |
| 352 { |
| 353 Grob *stub = end_slur_infos_[i].stubs_[j]; |
| 354 Grob *vag = Grob::get_vertical_axis_group (stub); |
| 355 if (vag) |
| 356 { |
| 357 vector<Grob *>::const_iterator it = |
| 358 find (vags.begin (), vags.end (), vag); |
| 359 if (it != vags.end ()) |
| 360 stub->suicide (); |
| 361 else |
| 362 { |
| 363 vags.push_back (vag); |
| 364 stubs.push_back (stub); |
| 365 } |
| 366 } |
| 367 else |
| 368 { |
| 369 end_slur_infos_[i].slur_->programming_error ("Cannot find vertical
axis group for NoteColumn."); |
| 370 stub->suicide (); |
| 371 } |
| 372 } |
| 373 for (vsize j = 0; j < stubs.size (); j++) |
| 374 Slur::main_to_stub (end_slur_infos_[i].slur_, stubs[j]); |
| 375 } |
314 | 376 |
315 objects_to_acknowledge_.clear (); | 377 objects_to_acknowledge_.clear (); |
316 end_slurs_.clear (); | 378 end_slur_infos_.clear (); |
317 start_events_.clear (); | 379 start_events_.clear (); |
318 stop_events_.clear (); | 380 stop_events_.clear (); |
319 } | 381 } |
320 | 382 |
321 ADD_ACKNOWLEDGER (Slur_engraver, inline_accidental); | 383 ADD_ACKNOWLEDGER (Slur_engraver, inline_accidental); |
322 ADD_ACKNOWLEDGER (Slur_engraver, fingering); | 384 ADD_ACKNOWLEDGER (Slur_engraver, fingering); |
323 ADD_ACKNOWLEDGER (Slur_engraver, note_column); | 385 ADD_ACKNOWLEDGER (Slur_engraver, note_column); |
324 ADD_ACKNOWLEDGER (Slur_engraver, script); | 386 ADD_ACKNOWLEDGER (Slur_engraver, script); |
325 ADD_ACKNOWLEDGER (Slur_engraver, text_script); | 387 ADD_ACKNOWLEDGER (Slur_engraver, text_script); |
326 ADD_ACKNOWLEDGER (Slur_engraver, dots); | 388 ADD_ACKNOWLEDGER (Slur_engraver, dots); |
327 ADD_END_ACKNOWLEDGER (Slur_engraver, tie); | 389 ADD_END_ACKNOWLEDGER (Slur_engraver, tie); |
328 ADD_ACKNOWLEDGER (Slur_engraver, tuplet_number); | 390 ADD_ACKNOWLEDGER (Slur_engraver, tuplet_number); |
329 ADD_TRANSLATOR (Slur_engraver, | 391 ADD_TRANSLATOR (Slur_engraver, |
330 /* doc */ | 392 /* doc */ |
331 "Build slur grobs from slur events.", | 393 "Build slur grobs from slur events.", |
332 | 394 |
333 /* create */ | 395 /* create */ |
334 "Slur ", | 396 "Slur ", |
335 | 397 |
336 /* read */ | 398 /* read */ |
337 "slurMelismaBusy " | 399 "slurMelismaBusy " |
338 "doubleSlurs ", | 400 "doubleSlurs ", |
339 | 401 |
340 /* write */ | 402 /* write */ |
341 "" | 403 "" |
342 ); | 404 ); |
OLD | NEW |