Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(219)

Delta Between Two Patch Sets: lily/slur-engraver.cc

Issue 6498077: Approximates cross-staff slurs in VerticalAxisGroup vertical-skylines. Base URL: http://git.savannah.gnu.org/gitweb/?p=lilypond.git/trunk/
Left Patch Set: Builds cross-staff-stub skylines directly into VerticalAxisGroup skylines Created 12 years, 7 months ago
Right Patch Set: Better approximations Created 12 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
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
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 <map> 33 #include <algorithm>
34 34
35 /* 35 /*
36 NOTE NOTE NOTE 36 NOTE NOTE NOTE
37 37
38 This is largely similar to Phrasing_slur_engraver. Check if fixes 38 This is largely similar to Phrasing_slur_engraver. Check if fixes
39 apply there too. 39 apply there too.
40 40
41 (on principle, engravers don't use inheritance for code sharing) 41 (on principle, engravers don't use inheritance for code sharing)
42 42
43 */ 43 */
44 44
45 /* 45 /*
46 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
47 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
48 ending of a phrase. 48 ending of a phrase.
49 */ 49 */
50
51 Slur_info::Slur_info (Grob *slur)
52 {
53 slur_ = slur;
54 }
55
50 class Slur_engraver : public Engraver 56 class Slur_engraver : public Engraver
51 { 57 {
52 vector<Stream_event *> start_events_; 58 vector<Stream_event *> start_events_;
53 vector<Stream_event *> stop_events_; 59 vector<Stream_event *> stop_events_;
54 vector<Grob *> slurs_; 60 vector<Slur_info> slur_infos_;
55 vector<Grob *> end_slurs_; 61 vector<Slur_info> end_slur_infos_;
56 map<Grob *, vector<Grob *> > slur_stubs_;
dak 2012/09/02 15:59:00 see comments in phrasing slur engraver.
57 vector<Grob_info> objects_to_acknowledge_; 62 vector<Grob_info> objects_to_acknowledge_;
58 63
59 void set_melisma (bool); 64 void set_melisma (bool);
60 65
61 protected: 66 protected:
62 DECLARE_TRANSLATOR_LISTENER (slur); 67 DECLARE_TRANSLATOR_LISTENER (slur);
63 DECLARE_ACKNOWLEDGER (inline_accidental); 68 DECLARE_ACKNOWLEDGER (inline_accidental);
64 DECLARE_ACKNOWLEDGER (fingering); 69 DECLARE_ACKNOWLEDGER (fingering);
65 DECLARE_ACKNOWLEDGER (note_column); 70 DECLARE_ACKNOWLEDGER (note_column);
66 DECLARE_ACKNOWLEDGER (script); 71 DECLARE_ACKNOWLEDGER (script);
67 DECLARE_ACKNOWLEDGER (dots); 72 DECLARE_ACKNOWLEDGER (dots);
68 DECLARE_ACKNOWLEDGER (text_script); 73 DECLARE_ACKNOWLEDGER (text_script);
69 DECLARE_ACKNOWLEDGER (tie); 74 DECLARE_END_ACKNOWLEDGER (tie);
70 DECLARE_ACKNOWLEDGER (tuplet_number); 75 DECLARE_ACKNOWLEDGER (tuplet_number);
71 76
72 void acknowledge_extra_object (Grob_info); 77 void acknowledge_extra_object (Grob_info);
73 void stop_translation_timestep (); 78 void stop_translation_timestep ();
74 void process_music (); 79 void process_music ();
75 80
76 virtual void finalize (); 81 virtual void finalize ();
77 virtual void derived_mark () const; 82 virtual void derived_mark () const;
78 83
79 public: 84 public:
(...skipping 28 matching lines...) Expand all
108 113
109 void 114 void
110 Slur_engraver::set_melisma (bool m) 115 Slur_engraver::set_melisma (bool m)
111 { 116 {
112 context ()->set_property ("slurMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F); 117 context ()->set_property ("slurMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F);
113 } 118 }
114 119
115 void 120 void
116 Slur_engraver::acknowledge_note_column (Grob_info info) 121 Slur_engraver::acknowledge_note_column (Grob_info info)
117 { 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 ··
118 Grob *e = info.grob (); 132 Grob *e = info.grob ();
119 for (vsize i = slurs_.size (); i--;) 133 for (vsize i = slur_infos_.size (); i--;)
120 Slur::add_column (slurs_[i], e); 134 {
121 for (vsize i = end_slurs_.size (); i--;) 135 Slur::add_column (slur_infos_[i].slur_, e);
122 Slur::add_column (end_slurs_[i], e); 136 Grob *stub = make_spanner ("SlurStub", slur_infos_[i].slur_->self_scm ());
123 137 slur_infos_[i].stubs_.push_back (stub);
124 for (vsize j = 0; j < slurs_.size (); j++) 138 }
125 { 139 for (vsize i = end_slur_infos_.size (); i--;)
126 if (slur_stubs_.find (slurs_[j]) == slur_stubs_.end ()) 140 {
127 slur_stubs_[slurs_[j]] = vector<Grob *> (); 141 Slur::add_column (end_slur_infos_[i].slur_, e);
128 142 Grob *stub = make_spanner ("SlurStub", slur_infos_[i].slur_->self_scm ());
129 Grob *stub = make_spanner ("SlurStub", info.grob ()->self_scm ()); 143 end_slur_infos_[i].stubs_.push_back (stub);
130 slur_stubs_[slurs_[j]].push_back (stub);
131 }
132
133 for (vsize j = 0; j < end_slurs_.size (); j++)
134 {
135 if (slur_stubs_.find (end_slurs_[j]) == slur_stubs_.end ())
136 slur_stubs_[end_slurs_[j]] = vector<Grob *> ();
137
138 Grob *stub = make_spanner ("SlurStub", info.grob ()->self_scm ());
139 slur_stubs_[end_slurs_[j]].push_back (stub);
140 } 144 }
141 } 145 }
142 146
143 void 147 void
144 Slur_engraver::acknowledge_extra_object (Grob_info info) 148 Slur_engraver::acknowledge_extra_object (Grob_info info)
145 { 149 {
146 objects_to_acknowledge_.push_back (info); 150 objects_to_acknowledge_.push_back (info);
147 } 151 }
148 152
149 void 153 void
(...skipping 27 matching lines...) Expand all
177 acknowledge_extra_object (info); 181 acknowledge_extra_object (info);
178 } 182 }
179 183
180 void 184 void
181 Slur_engraver::acknowledge_text_script (Grob_info info) 185 Slur_engraver::acknowledge_text_script (Grob_info info)
182 { 186 {
183 acknowledge_extra_object (info); 187 acknowledge_extra_object (info);
184 } 188 }
185 189
186 void 190 void
187 Slur_engraver::acknowledge_tie (Grob_info info) 191 Slur_engraver::acknowledge_end_tie (Grob_info info)
188 { 192 {
189 acknowledge_extra_object (info); 193 acknowledge_extra_object (info);
190 } 194 }
191 195
192 void 196 void
193 Slur_engraver::finalize () 197 Slur_engraver::finalize ()
194 { 198 {
195 for (vsize i = 0; i < slurs_.size (); i++) 199 for (vsize i = 0; i < slur_infos_.size (); i++)
196 { 200 {
197 slurs_[i]->warning (_ ("unterminated slur")); 201 slur_infos_[i].slur_->warning (_ ("unterminated slur"));
198 slurs_[i]->suicide (); 202 slur_infos_[i].slur_->suicide ();
199 } 203 for (vsize j = 0; j < slur_infos_[i].stubs_.size (); j++)
200 slurs_.clear (); 204 slur_infos_[i].stubs_[j]->suicide ();
201 slur_stubs_.clear (); 205 }
206
207 slur_infos_.clear ();
202 } 208 }
203 209
204 void 210 void
205 Slur_engraver::process_music () 211 Slur_engraver::process_music ()
206 { 212 {
207 for (vsize i = 0; i < stop_events_.size (); i++) 213 for (vsize i = 0; i < stop_events_.size (); i++)
208 { 214 {
209 Stream_event *ev = stop_events_[i]; 215 Stream_event *ev = stop_events_[i];
210 string id = robust_scm2string (ev->get_property ("spanner-id"), ""); 216 string id = robust_scm2string (ev->get_property ("spanner-id"), "");
211 217
212 // 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)
213 bool ended = false; 219 bool ended = false;
214 for (vsize j = slurs_.size (); j--;) 220 for (vsize j = slur_infos_.size (); j--;)
215 { 221 {
216 if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), " ")) 222 if (id == robust_scm2string (slur_infos_[j].slur_->get_property ("span ner-id"), ""))
217 { 223 {
218 ended = true; 224 ended = true;
219 end_slurs_.push_back (slurs_[j]); 225 end_slur_infos_.push_back (slur_infos_[j]);
220 slurs_.erase (slurs_.begin () + j); 226 slur_infos_.erase (slur_infos_.begin () + j);
221 } 227 }
222 } 228 }
223 if (ended) 229 if (ended)
224 { 230 {
225 // Ignore redundant stop events for this id 231 // Ignore redundant stop events for this id
226 for (vsize j = stop_events_.size (); --j > i;) 232 for (vsize j = stop_events_.size (); --j > i;)
227 { 233 {
228 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"), ""))
229 stop_events_.erase (stop_events_.begin () + j); 235 stop_events_.erase (stop_events_.begin () + j);
230 } 236 }
231 } 237 }
232 else 238 else
233 ev->origin ()->warning (_ ("cannot end slur")); 239 ev->origin ()->warning (_ ("cannot end slur"));
234 } 240 }
235 241
236 vsize old_slurs = slurs_.size (); 242 vsize old_slurs = slur_infos_.size ();
237 for (vsize i = start_events_.size (); i--;) 243 for (vsize i = start_events_.size (); i--;)
238 { 244 {
239 Stream_event *ev = start_events_[i]; 245 Stream_event *ev = start_events_[i];
240 string id = robust_scm2string (ev->get_property ("spanner-id"), ""); 246 string id = robust_scm2string (ev->get_property ("spanner-id"), "");
241 Direction updown = to_dir (ev->get_property ("direction")); 247 Direction updown = to_dir (ev->get_property ("direction"));
242 248
243 bool completed; 249 bool completed;
244 for (vsize j = slurs_.size (); !(completed = (j-- == 0));) 250 for (vsize j = slur_infos_.size (); !(completed = (j-- == 0));)
245 { 251 {
246 // 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.
247 if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), " ")) 253 if (id == robust_scm2string (slur_infos_[j].slur_->get_property ("span ner-id"), ""))
248 { 254 {
249 if (j < old_slurs) 255 if (j < old_slurs)
250 { 256 {
251 // We already have an old slur, so give a warning 257 // We already have an old slur, so give a warning
252 // and completely ignore the new slur. 258 // and completely ignore the new slur.
253 ev->origin ()->warning (_ ("already have slur")); 259 ev->origin ()->warning (_ ("already have slur"));
254 start_events_.erase (start_events_.begin () + i); 260 start_events_.erase (start_events_.begin () + i);
255 break; 261 break;
256 } 262 }
257 263
258 // If this slur event has no direction, it will not 264 // If this slur event has no direction, it will not
259 // contribute anything new to the existing slur(s), so 265 // contribute anything new to the existing slur(s), so
260 // we can ignore it. 266 // we can ignore it.
261 267
262 if (!updown) 268 if (!updown)
263 break; 269 break;
264 270
265 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"));
266 272
267 if (!c) 273 if (!c)
268 { 274 {
269 slurs_[j]->programming_error ("slur without a cause"); 275 slur_infos_[j].slur_->programming_error ("slur without a cause ");
270 continue; 276 continue;
271 } 277 }
272 278
273 Direction slur_dir = to_dir (c->get_property ("direction")); 279 Direction slur_dir = to_dir (c->get_property ("direction"));
274 280
275 // If the existing slur does not have a direction yet, 281 // If the existing slur does not have a direction yet,
276 // we'd rather take the new one. 282 // we'd rather take the new one.
277 283
278 if (!slur_dir) 284 if (!slur_dir)
279 { 285 {
280 slurs_[j]->suicide (); 286 slur_infos_[j].slur_->suicide ();
281 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);
282 continue; 290 continue;
283 } 291 }
284 292
285 // 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
286 294
287 if (slur_dir == updown) 295 if (slur_dir == updown)
288 break; 296 break;
289 } 297 }
290 } 298 }
291 // If the loop completed, our slur is new 299 // If the loop completed, our slur is new
292 if (completed) 300 if (completed)
293 { 301 {
294 Grob *slur = make_spanner ("Slur", ev->self_scm ()); 302 Grob *slur = make_spanner ("Slur", ev->self_scm ());
295 slur->set_property ("spanner-id", ly_string2scm (id)); 303 slur->set_property ("spanner-id", ly_string2scm (id));
296 if (updown) 304 if (updown)
297 set_grob_direction (slur, updown); 305 set_grob_direction (slur, updown);
298 slurs_.push_back (slur); 306 slur_infos_.push_back (Slur_info (slur));
299 307
300 if (to_boolean (get_property ("doubleSlurs"))) 308 if (to_boolean (get_property ("doubleSlurs")))
301 { 309 {
302 set_grob_direction (slur, DOWN); 310 set_grob_direction (slur, DOWN);
303 slur = make_spanner ("Slur", ev->self_scm ()); 311 slur = make_spanner ("Slur", ev->self_scm ());
304 slur->set_property ("spanner-id", ly_string2scm (id)); 312 slur->set_property ("spanner-id", ly_string2scm (id));
305 set_grob_direction (slur, UP); 313 set_grob_direction (slur, UP);
306 slurs_.push_back (slur); 314 slur_infos_.push_back (Slur_info (slur));
307 } 315 }
308 } 316 }
309 } 317 }
310 set_melisma (slurs_.size ()); 318 set_melisma (slur_infos_.size ());
311 } 319 }
312 320
313 void 321 void
314 Slur_engraver::stop_translation_timestep () 322 Slur_engraver::stop_translation_timestep ()
315 { 323 {
316 if (Grob *g = unsmob_grob (get_property ("currentCommandColumn"))) 324 if (Grob *g = unsmob_grob (get_property ("currentCommandColumn")))
317 { 325 {
318 for (vsize i = 0; i < end_slurs_.size (); i++) 326 for (vsize i = 0; i < end_slur_infos_.size (); i++)
319 Slur::add_extra_encompass (end_slurs_[i], g); 327 Slur::add_extra_encompass (end_slur_infos_[i].slur_, g);
320 328
321 if (!start_events_.size ()) 329 if (!start_events_.size ())
322 for (vsize i = 0; i < slurs_.size (); i++) 330 for (vsize i = 0; i < slur_infos_.size (); i++)
323 Slur::add_extra_encompass (slurs_[i], g); 331 Slur::add_extra_encompass (slur_infos_[i].slur_, g);
324 } 332 }
325 333
326 for (vsize i = 0; i < end_slurs_.size (); i++) 334 for (vsize i = 0; i < end_slur_infos_.size (); i++)
327 { 335 {
328 Spanner *s = dynamic_cast<Spanner *> (end_slurs_[i]); 336 Spanner *s = dynamic_cast<Spanner *> (end_slur_infos_[i].slur_);
329 if (!s->get_bound (RIGHT)) 337 if (!s->get_bound (RIGHT))
330 s->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")) ); 338 s->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")) );
331 announce_end_grob (s, SCM_EOL); 339 announce_end_grob (s, SCM_EOL);
332 } 340 }
333 341
334 for (vsize i = 0; i < objects_to_acknowledge_.size (); i++) 342 for (vsize i = 0; i < objects_to_acknowledge_.size (); i++)
335 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_);
336 344
337 for (vsize i = 0; i < end_slurs_.size (); i++) 345 for (vsize i = 0; i < end_slur_infos_.size (); i++)
338 if (slur_stubs_.find (end_slurs_[i]) != slur_stubs_.end ()) 346 {
339 { 347 // There are likely SlurStubs we don't need. Get rid of them
340 // We likely SlurStubs we don't need. Get rid of them. 348 // and only keep one per VerticalAxisGroup.
341 map<Grob *, Grob *> vag_to_slur; 349 vector<Grob *> vags;
342 for (vsize j = 0; j < slur_stubs_[end_slurs_[i]].size (); j++) 350 vector<Grob *> stubs;
343 { 351 for (vsize j = 0; j < end_slur_infos_[i].stubs_.size (); j++)
344 Grob *vag = Grob::get_vertical_axis_group (slur_stubs_[end_slurs_[i] ][j]); 352 {
345 if (vag) 353 Grob *stub = end_slur_infos_[i].stubs_[j];
346 { 354 Grob *vag = Grob::get_vertical_axis_group (stub);
347 if (vag_to_slur.find (vag) != vag_to_slur.end ()) 355 if (vag)
348 slur_stubs_[end_slurs_[i]][j]->suicide (); 356 {
349 else 357 vector<Grob *>::const_iterator it =
350 vag_to_slur[vag] = slur_stubs_[end_slurs_[i]][j]; 358 find (vags.begin (), vags.end (), vag);
351 } 359 if (it != vags.end ())
352 else 360 stub->suicide ();
353 { 361 else
354 end_slurs_[i]->programming_error ("Cannot find vertical axis gro up for NoteColumn."); 362 {
355 slur_stubs_[end_slurs_[i]][j]->suicide (); 363 vags.push_back (vag);
356 } 364 stubs.push_back (stub);
357 } 365 }
358 map<Grob *, Grob *>::const_iterator it; 366 }
359 for (it = vag_to_slur.begin (); 367 else
360 it != vag_to_slur.end (); 368 {
361 it++) 369 end_slur_infos_[i].slur_->programming_error ("Cannot find vertical axis group for NoteColumn.");
362 Slur::main_to_stub (end_slurs_[i], it->second); 370 stub->suicide ();
363 371 }
364 slur_stubs_.erase (end_slurs_[i]); 372 }
365 } 373 for (vsize j = 0; j < stubs.size (); j++)
374 Slur::main_to_stub (end_slur_infos_[i].slur_, stubs[j]);
375 }
366 376
367 objects_to_acknowledge_.clear (); 377 objects_to_acknowledge_.clear ();
368 end_slurs_.clear (); 378 end_slur_infos_.clear ();
369 start_events_.clear (); 379 start_events_.clear ();
370 stop_events_.clear (); 380 stop_events_.clear ();
371 } 381 }
372 382
373 ADD_ACKNOWLEDGER (Slur_engraver, inline_accidental); 383 ADD_ACKNOWLEDGER (Slur_engraver, inline_accidental);
374 ADD_ACKNOWLEDGER (Slur_engraver, fingering); 384 ADD_ACKNOWLEDGER (Slur_engraver, fingering);
375 ADD_ACKNOWLEDGER (Slur_engraver, note_column); 385 ADD_ACKNOWLEDGER (Slur_engraver, note_column);
376 ADD_ACKNOWLEDGER (Slur_engraver, script); 386 ADD_ACKNOWLEDGER (Slur_engraver, script);
377 ADD_ACKNOWLEDGER (Slur_engraver, text_script); 387 ADD_ACKNOWLEDGER (Slur_engraver, text_script);
378 ADD_ACKNOWLEDGER (Slur_engraver, dots); 388 ADD_ACKNOWLEDGER (Slur_engraver, dots);
379 ADD_ACKNOWLEDGER (Slur_engraver, tie); 389 ADD_END_ACKNOWLEDGER (Slur_engraver, tie);
380 ADD_ACKNOWLEDGER (Slur_engraver, tuplet_number); 390 ADD_ACKNOWLEDGER (Slur_engraver, tuplet_number);
381 ADD_TRANSLATOR (Slur_engraver, 391 ADD_TRANSLATOR (Slur_engraver,
382 /* doc */ 392 /* doc */
383 "Build slur grobs from slur events.", 393 "Build slur grobs from slur events.",
384 394
385 /* create */ 395 /* create */
386 "Slur ", 396 "Slur ",
387 397
388 /* read */ 398 /* read */
389 "slurMelismaBusy " 399 "slurMelismaBusy "
390 "doubleSlurs ", 400 "doubleSlurs ",
391 401
392 /* write */ 402 /* write */
393 "" 403 ""
394 ); 404 );
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b