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