Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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) 1998--2011 Han-Wen Nienhuys <hanwen@xs4all.nl> | 4 Copyright (C) 1998--2011 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
60 tie_definition_ = SCM_EOL; | 60 tie_definition_ = SCM_EOL; |
61 tie_event_ = 0; | 61 tie_event_ = 0; |
62 tie_stream_event_ = 0; | 62 tie_stream_event_ = 0; |
63 tie_from_chord_created = false; | 63 tie_from_chord_created = false; |
64 } | 64 } |
65 }; | 65 }; |
66 | 66 |
67 class Tie_engraver : public Engraver | 67 class Tie_engraver : public Engraver |
68 { | 68 { |
69 Stream_event *event_; | 69 Stream_event *event_; |
70 vector<Grob*> now_heads_; | 70 vector<Grob *> now_heads_; |
71 vector<Head_event_tuple> heads_to_tie_; | 71 vector<Head_event_tuple> heads_to_tie_; |
72 vector<Grob*> ties_; | 72 vector<Grob *> ties_; |
73 | 73 |
74 Spanner *tie_column_; | 74 Spanner *tie_column_; |
75 | 75 |
76 protected: | 76 protected: |
77 void stop_translation_timestep (); | 77 void stop_translation_timestep (); |
78 virtual void derived_mark () const; | 78 virtual void derived_mark () const; |
79 void start_translation_timestep (); | 79 void start_translation_timestep (); |
80 DECLARE_ACKNOWLEDGER (note_head); | 80 DECLARE_ACKNOWLEDGER (note_head); |
81 DECLARE_TRANSLATOR_LISTENER (tie); | 81 DECLARE_TRANSLATOR_LISTENER (tie); |
82 void process_music (); | 82 void process_music (); |
(...skipping 24 matching lines...) Expand all Loading... | |
107 { | 107 { |
108 ASSIGN_EVENT_ONCE (event_, ev); | 108 ASSIGN_EVENT_ONCE (event_, ev); |
109 } | 109 } |
110 | 110 |
111 void Tie_engraver::report_unterminated_tie (Head_event_tuple const &tie_start) | 111 void Tie_engraver::report_unterminated_tie (Head_event_tuple const &tie_start) |
112 { | 112 { |
113 // If tie_from_chord_created is set, we have another note at the same | 113 // If tie_from_chord_created is set, we have another note at the same |
114 // moment that created a tie, so this is not necessarily an unterminated | 114 // moment that created a tie, so this is not necessarily an unterminated |
115 // tie. Happens e.g. for <c e g>~ g | 115 // tie. Happens e.g. for <c e g>~ g |
116 if (!tie_start.tie_from_chord_created) | 116 if (!tie_start.tie_from_chord_created) |
117 tie_start.head_->warning (_("unterminated tie")); | 117 tie_start.head_->warning (_ ("unterminated tie")); |
118 } | 118 } |
119 | 119 |
120 /* | 120 /* |
121 Determines whether the end of an event was created by | 121 Determines whether the end of an event was created by |
122 a split in Completion_heads_engraver or by user input. | 122 a split in Completion_heads_engraver or by user input. |
123 */ | 123 */ |
124 bool | 124 bool |
125 Tie_engraver::has_autosplit_end (Stream_event *event) | 125 Tie_engraver::has_autosplit_end (Stream_event *event) |
126 { | 126 { |
127 if (event) | 127 if (event) |
128 return to_boolean (event->get_property ("autosplit-end")); | 128 return to_boolean (event->get_property ("autosplit-end")); |
129 return false; | 129 return false; |
130 } | 130 } |
131 | 131 |
132 void | 132 void |
133 Tie_engraver::process_music () | 133 Tie_engraver::process_music () |
134 { | 134 { |
135 bool busy = event_; | 135 bool busy = event_; |
136 for (vsize i = 0; !busy && i < heads_to_tie_.size (); i++) | 136 for (vsize i = 0; !busy && i < heads_to_tie_.size (); i++) |
137 busy |= (heads_to_tie_[i].tie_event_ | 137 busy |= (heads_to_tie_[i].tie_event_ |
138 » || heads_to_tie_[i].tie_stream_event_); | 138 » || heads_to_tie_[i].tie_stream_event_); |
139 | 139 |
140 if (busy) | 140 if (busy) |
141 context ()->set_property ("tieMelismaBusy", SCM_BOOL_T); | 141 context ()->set_property ("tieMelismaBusy", SCM_BOOL_T); |
142 } | 142 } |
143 | 143 |
144 void | 144 void |
145 Tie_engraver::acknowledge_note_head (Grob_info i) | 145 Tie_engraver::acknowledge_note_head (Grob_info i) |
146 { | 146 { |
147 Grob *h = i.grob (); | 147 Grob *h = i.grob (); |
148 | 148 |
149 now_heads_.push_back (h); | 149 now_heads_.push_back (h); |
150 for (vsize i = heads_to_tie_.size (); i--;) | 150 for (vsize i = heads_to_tie_.size (); i--;) |
151 { | 151 { |
152 Grob *th = heads_to_tie_[i].head_; | 152 Grob *th = heads_to_tie_[i].head_; |
153 Stream_event *right_ev = unsmob_stream_event (h->get_property ("cause")); | 153 Stream_event *right_ev = unsmob_stream_event (h->get_property ("cause")); |
154 Stream_event *left_ev = unsmob_stream_event (th->get_property ("cause")); | 154 Stream_event *left_ev = unsmob_stream_event (th->get_property ("cause")); |
155 | 155 |
156 /* | 156 /* |
157 maybe should check positions too. | 157 maybe should check positions too. |
Graham Percival (old account)
2011/06/15 09:29:00
this should be indented with:
1 tab
| |
158 */ | 158 */ |
159 if (!right_ev || !left_ev) | 159 if (!right_ev || !left_ev) |
160 continue; | 160 » continue; |
161 | |
162 | 161 |
163 /* | 162 /* |
164 Make a tie only if pitches are equal or if event end was not generated b y | 163 Make a tie only if pitches are equal or if event end was not generated b y |
165 Completion_heads_engraver. | 164 Completion_heads_engraver. |
166 */ | 165 */ |
167 if (ly_is_equal (right_ev->get_property ("pitch"), left_ev->get_property ( "pitch")) | 166 if (ly_is_equal (right_ev->get_property ("pitch"), left_ev->get_property ( "pitch")) |
168 && (!Tie_engraver::has_autosplit_end (left_ev))) | 167 » && (!Tie_engraver::has_autosplit_end (left_ev))) |
169 { | 168 » { |
170 Grob *p = new Spanner (heads_to_tie_[i].tie_definition_); | 169 » Grob *p = new Spanner (heads_to_tie_[i].tie_definition_); |
171 Moment end = heads_to_tie_[i].end_moment_; | 170 » Moment end = heads_to_tie_[i].end_moment_; |
172 | 171 |
173 SCM cause = heads_to_tie_[i].tie_event_ | 172 » SCM cause = heads_to_tie_[i].tie_event_ |
174 ? heads_to_tie_[i].tie_event_->self_scm () | 173 » ? heads_to_tie_[i].tie_event_->self_scm () |
175 » : heads_to_tie_[i].tie_stream_event_->self_scm (); | 174 » : heads_to_tie_[i].tie_stream_event_->self_scm (); |
176 | 175 |
177 announce_grob (p, cause); | 176 » announce_grob (p, cause); |
178 Tie::set_head (p, LEFT, th); | 177 » Tie::set_head (p, LEFT, th); |
179 Tie::set_head (p, RIGHT, h); | 178 » Tie::set_head (p, RIGHT, h); |
180 | 179 |
181 | 180 » if (is_direction (unsmob_stream_event (cause)->get_property ("directio n"))) |
182 if (is_direction (unsmob_stream_event (cause)->get_property ("directio n"))) | 181 » { |
183 { | 182 » Direction d = to_dir (unsmob_stream_event (cause)->get_property (" direction")); |
184 Direction d = to_dir (unsmob_stream_event (cause)->get_property (" direction")); | 183 » p->set_property ("direction", scm_from_int (d)); |
185 p->set_property ("direction", scm_from_int (d)); | 184 » } |
186 } | 185 |
187 | 186 » ties_.push_back (p); |
188 ties_.push_back (p); | 187 » heads_to_tie_.erase (heads_to_tie_.begin () + i); |
189 heads_to_tie_.erase (heads_to_tie_.begin () + i); | 188 |
190 | 189 /* |
Graham Percival (old account)
2011/06/15 09:29:00
this should be indented with:
1 tab
| |
191 /* | 190 Prevent all other tied notes ending at the same moment (assume |
Graham Percival (old account)
2011/06/15 09:29:00
this should be indented with:
1 tab + 2 spaces
| |
192 Prevent all other tied notes ending at the same moment (assume | 191 implicitly the notes have also started at the same moment!) |
193 implicitly the notes have also started at the same moment!) | 192 from triggering an "unterminated tie" warning. Needed e.g. for |
194 from triggering an "unterminated tie" warning. Needed e.g. for | 193 <c e g>~ g |
195 <c e g>~ g | 194 */ |
196 */ | 195 » for (vsize j = heads_to_tie_.size (); j--;) |
197 for (vsize j = heads_to_tie_.size (); j--;) | 196 » { |
198 { | 197 » if (heads_to_tie_[j].end_moment_ == end) |
199 if (heads_to_tie_[j].end_moment_ == end) | 198 » heads_to_tie_[j].tie_from_chord_created = true; |
200 heads_to_tie_[j].tie_from_chord_created = true; | 199 » } |
201 } | 200 » } |
202 } | 201 } |
203 } | 202 |
204 | 203 if (ties_.size () && !tie_column_) |
205 if (ties_.size () && ! tie_column_) | |
206 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ()); | 204 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ()); |
207 | 205 |
208 if (tie_column_) | 206 if (tie_column_) |
209 for (vsize i = ties_.size (); i--;) | 207 for (vsize i = ties_.size (); i--;) |
210 Tie_column::add_tie (tie_column_, ties_[i]); | 208 Tie_column::add_tie (tie_column_, ties_[i]); |
211 } | 209 } |
212 | 210 |
213 void | 211 void |
214 Tie_engraver::start_translation_timestep () | 212 Tie_engraver::start_translation_timestep () |
215 { | 213 { |
216 if (heads_to_tie_.size () && !to_boolean (get_property ("tieWaitForNote"))) | 214 if (heads_to_tie_.size () && !to_boolean (get_property ("tieWaitForNote"))) |
217 { | 215 { |
218 Moment now = now_mom (); | 216 Moment now = now_mom (); |
219 for (vsize i = heads_to_tie_.size (); i--; ) | 217 for (vsize i = heads_to_tie_.size (); i--;) |
220 { | 218 { |
221 if (now > heads_to_tie_[i].end_moment_) | 219 if (now > heads_to_tie_[i].end_moment_) |
222 { | 220 { |
223 report_unterminated_tie (heads_to_tie_[i]); | 221 report_unterminated_tie (heads_to_tie_[i]); |
224 heads_to_tie_.erase (heads_to_tie_.begin () + i); | 222 heads_to_tie_.erase (heads_to_tie_.begin () + i); |
225 } | 223 } |
226 } | 224 } |
227 } | 225 } |
228 | 226 |
229 context ()->set_property ("tieMelismaBusy", | 227 context ()->set_property ("tieMelismaBusy", |
230 ly_bool2scm (heads_to_tie_.size ())); | 228 ly_bool2scm (heads_to_tie_.size ())); |
231 } | 229 } |
232 | 230 |
233 void | 231 void |
234 Tie_engraver::stop_translation_timestep () | 232 Tie_engraver::stop_translation_timestep () |
235 { | 233 { |
236 bool wait = to_boolean (get_property ("tieWaitForNote")); | 234 bool wait = to_boolean (get_property ("tieWaitForNote")); |
237 if (ties_.size ()) | 235 if (ties_.size ()) |
238 { | 236 { |
239 if (!wait) | 237 if (!wait) |
240 { | 238 » { |
Graham Percival (old account)
2011/06/15 09:29:00
heh, wow, the original file was wrong. Go figure.
| |
241 vector<Head_event_tuple>::iterator it = heads_to_tie_.begin (); | 239 vector<Head_event_tuple>::iterator it = heads_to_tie_.begin (); |
242 for (; it < heads_to_tie_.end (); it++) | 240 for (; it < heads_to_tie_.end (); it++) |
243 report_unterminated_tie (*it); | 241 report_unterminated_tie (*it); |
244 heads_to_tie_.clear (); | 242 heads_to_tie_.clear (); |
245 } | 243 » } |
246 | 244 |
247 for (vsize i = 0; i < ties_.size (); i++) | 245 for (vsize i = 0; i < ties_.size (); i++) |
248 » typeset_tie (ties_[i]); | 246 » typeset_tie (ties_[i]); |
249 | 247 |
250 ties_.clear (); | 248 ties_.clear (); |
251 tie_column_ = 0; | 249 tie_column_ = 0; |
252 } | 250 } |
253 | 251 |
254 vector<Head_event_tuple> new_heads_to_tie; | 252 vector<Head_event_tuple> new_heads_to_tie; |
255 | 253 |
256 /* | 254 /* |
257 Whether tie event has been processed and can be deleted or should | 255 Whether tie event has been processed and can be deleted or should |
258 be kept for later portions of a split note. | 256 be kept for later portions of a split note. |
259 */ | 257 */ |
260 bool event_processed = false; | 258 bool event_processed = false; |
261 | 259 |
262 for (vsize i = 0; i < now_heads_.size (); i++) | 260 for (vsize i = 0; i < now_heads_.size (); i++) |
263 { | 261 { |
264 Grob *head = now_heads_[i]; | 262 Grob *head = now_heads_[i]; |
265 Stream_event *left_ev | 263 Stream_event *left_ev |
266 = unsmob_stream_event (head->get_property ("cause")); | 264 = unsmob_stream_event (head->get_property ("cause")); |
267 | 265 |
268 if (!left_ev) | 266 if (!left_ev) |
269 { | 267 { |
270 // may happen for ambitus | 268 // may happen for ambitus |
271 continue; | 269 continue; |
272 } | 270 } |
273 | 271 |
274 | |
275 SCM left_articulations = left_ev->get_property ("articulations"); | 272 SCM left_articulations = left_ev->get_property ("articulations"); |
276 | 273 |
277 Stream_event *tie_event = 0; | 274 Stream_event *tie_event = 0; |
278 Stream_event *tie_stream_event = event_; | 275 Stream_event *tie_stream_event = event_; |
279 for (SCM s = left_articulations; | 276 for (SCM s = left_articulations; |
280 !tie_event && !tie_stream_event && scm_is_pair (s); | 277 !tie_event && !tie_stream_event && scm_is_pair (s); |
281 s = scm_cdr (s)) | 278 s = scm_cdr (s)) |
282 { | 279 { |
283 Stream_event *ev = unsmob_stream_event (scm_car (s)); | 280 Stream_event *ev = unsmob_stream_event (scm_car (s)); |
284 if (!ev) | 281 if (!ev) |
285 continue; | 282 continue; |
286 | 283 |
287 if (ev->in_event_class ("tie-event")) | 284 if (ev->in_event_class ("tie-event")) |
288 tie_event = ev; | 285 tie_event = ev; |
289 } | 286 } |
290 | 287 |
291 if (left_ev && (tie_event || tie_stream_event) | 288 if (left_ev && (tie_event || tie_stream_event) |
292 && (!Tie_engraver::has_autosplit_end (left_ev))) | 289 » && (!Tie_engraver::has_autosplit_end (left_ev))) |
293 { | 290 » { |
294 event_processed = true; | 291 » event_processed = true; |
295 | 292 |
296 » Head_event_tuple event_tup; | 293 » Head_event_tuple event_tup; |
297 | 294 |
298 » SCM start_definition | 295 » SCM start_definition |
299 » = updated_grob_properties (context (), ly_symbol2scm ("Tie")); | 296 » = updated_grob_properties (context (), ly_symbol2scm ("Tie")); |
300 | 297 |
301 » event_tup.head_ = head; | 298 » event_tup.head_ = head; |
302 » event_tup.tie_definition_ = start_definition; | 299 » event_tup.tie_definition_ = start_definition; |
303 » event_tup.tie_event_ = tie_event; | 300 » event_tup.tie_event_ = tie_event; |
304 » event_tup.tie_stream_event_ = tie_stream_event; | 301 » event_tup.tie_stream_event_ = tie_stream_event; |
305 | 302 |
306 » Moment end = now_mom (); | 303 » Moment end = now_mom (); |
307 » if (end.grace_part_) | 304 » if (end.grace_part_) |
308 » { | 305 » { |
309 » end.grace_part_ += get_event_length (left_ev).main_part_; | 306 » end.grace_part_ += get_event_length (left_ev).main_part_; |
310 » } | 307 » } |
311 » else | 308 » else |
312 » { | 309 » { |
313 » end += get_event_length (left_ev); | 310 » end += get_event_length (left_ev); |
314 » } | 311 » } |
315 » event_tup.end_moment_ = end; | 312 » event_tup.end_moment_ = end; |
316 | 313 |
317 » new_heads_to_tie.push_back (event_tup); | 314 » new_heads_to_tie.push_back (event_tup); |
318 » } | 315 » } |
319 } | 316 } |
320 | 317 |
321 if (!wait && new_heads_to_tie.size ()) | 318 if (!wait && new_heads_to_tie.size ()) |
322 { | 319 { |
323 vector<Head_event_tuple>::iterator it=heads_to_tie_.begin (); | 320 vector<Head_event_tuple>::iterator it = heads_to_tie_.begin (); |
324 for (; it < heads_to_tie_.end (); it++) | 321 for (; it < heads_to_tie_.end (); it++) |
325 report_unterminated_tie (*it); | 322 » report_unterminated_tie (*it); |
326 heads_to_tie_.clear (); | 323 heads_to_tie_.clear (); |
327 } | 324 } |
328 | 325 |
329 // hmmm, how to do with copy () ? | 326 // hmmm, how to do with copy () ? |
330 for (vsize i = 0; i < new_heads_to_tie.size (); i++) | 327 for (vsize i = 0; i < new_heads_to_tie.size (); i++) |
331 heads_to_tie_.push_back (new_heads_to_tie[i]); | 328 heads_to_tie_.push_back (new_heads_to_tie[i]); |
332 | 329 |
333 /* | 330 /* |
334 Discard event only if it has been processed with at least one | 331 Discard event only if it has been processed with at least one |
335 appropriate note. | 332 appropriate note. |
(...skipping 14 matching lines...) Expand all Loading... | |
350 Drul_array<Grob *> new_head_drul; | 347 Drul_array<Grob *> new_head_drul; |
351 new_head_drul[LEFT] = Tie::head (her, LEFT); | 348 new_head_drul[LEFT] = Tie::head (her, LEFT); |
352 new_head_drul[RIGHT] = Tie::head (her, RIGHT); | 349 new_head_drul[RIGHT] = Tie::head (her, RIGHT); |
353 do | 350 do |
354 { | 351 { |
355 if (!Tie::head (her, d)) | 352 if (!Tie::head (her, d)) |
356 new_head_drul[d] = Tie::head (her, (Direction) - d); | 353 new_head_drul[d] = Tie::head (her, (Direction) - d); |
357 } | 354 } |
358 while (flip (&d) != LEFT); | 355 while (flip (&d) != LEFT); |
359 | 356 |
360 Spanner *sp = dynamic_cast<Spanner*> (her); | 357 Spanner *sp = dynamic_cast<Spanner *> (her); |
361 sp->set_bound (LEFT, new_head_drul[LEFT]); | 358 sp->set_bound (LEFT, new_head_drul[LEFT]); |
362 sp->set_bound (RIGHT, new_head_drul[RIGHT]); | 359 sp->set_bound (RIGHT, new_head_drul[RIGHT]); |
363 } | 360 } |
364 | 361 |
365 ADD_ACKNOWLEDGER (Tie_engraver, note_head); | 362 ADD_ACKNOWLEDGER (Tie_engraver, note_head); |
366 ADD_TRANSLATOR (Tie_engraver, | 363 ADD_TRANSLATOR (Tie_engraver, |
367 /* doc */ | 364 /* doc */ |
368 "Generate ties between note heads of equal pitch.", | 365 "Generate ties between note heads of equal pitch.", |
369 | 366 |
370 /* create */ | 367 /* create */ |
371 "Tie " | 368 "Tie " |
372 "TieColumn ", | 369 "TieColumn ", |
373 | 370 |
374 /* read */ | 371 /* read */ |
375 "tieWaitForNote ", | 372 "tieWaitForNote ", |
376 | 373 |
377 /* write */ | 374 /* write */ |
378 "tieMelismaBusy " | 375 "tieMelismaBusy " |
379 ); | 376 ); |
LEFT | RIGHT |