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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 14 matching lines...) Expand all Loading... |
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")); |
117 } | 118 } |
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; |
| 130 } |
| 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. |
145 */ | 158 */ |
146 if (!right_ev || !left_ev) | 159 if (!right_ev || !left_ev) |
147 » continue; | 160 continue; |
148 | |
149 if (ly_is_equal (right_ev->get_property ("pitch"), | |
150 » » left_ev->get_property ("pitch"))) | |
151 » { | |
152 » Grob *p = new Spanner (heads_to_tie_[i].tie_definition_); | |
153 » Moment end = heads_to_tie_[i].end_moment_; | |
154 | |
155 » SCM cause = heads_to_tie_[i].tie_event_ | |
156 » ? heads_to_tie_[i].tie_event_->self_scm () | |
157 » : heads_to_tie_[i].tie_stream_event_->self_scm (); | |
158 | |
159 » announce_grob (p, cause); | |
160 » Tie::set_head (p, LEFT, th); | |
161 » Tie::set_head (p, RIGHT, h); | |
162 | 161 |
163 | 162 |
164 » if (is_direction (unsmob_stream_event (cause)->get_property ("directio
n"))) | 163 /* |
165 » { | 164 Make a tie only if pitches are equal or if event end was not generated b
y |
166 » Direction d = to_dir (unsmob_stream_event (cause)->get_property ("
direction")); | 165 Completion_heads_engraver. |
167 » p->set_property ("direction", scm_from_int (d)); | 166 */ |
168 » } | 167 if (ly_is_equal (right_ev->get_property ("pitch"), left_ev->get_property (
"pitch")) |
| 168 && (!Tie_engraver::has_autosplit_end (left_ev))) |
| 169 { |
| 170 Grob *p = new Spanner (heads_to_tie_[i].tie_definition_); |
| 171 Moment end = heads_to_tie_[i].end_moment_; |
169 | 172 |
170 » ties_.push_back (p); | 173 SCM cause = heads_to_tie_[i].tie_event_ |
171 » heads_to_tie_.erase (heads_to_tie_.begin () + i); | 174 ? heads_to_tie_[i].tie_event_->self_scm () |
| 175 » : heads_to_tie_[i].tie_stream_event_->self_scm (); |
172 | 176 |
173 » // Prevent all other tied notes ending at the same moment (assume | 177 announce_grob (p, cause); |
174 » // implicitly the notes have also started at the same moment!) | 178 Tie::set_head (p, LEFT, th); |
175 » // from triggering an "unterminated tie" warning. Needed e.g. for | 179 Tie::set_head (p, RIGHT, h); |
176 » // <c e g>~ g | 180 |
177 » for (vsize j = heads_to_tie_.size (); j--;) | 181 |
178 » { | 182 if (is_direction (unsmob_stream_event (cause)->get_property ("directio
n"))) |
179 » if (heads_to_tie_[j].end_moment_ == end) | 183 { |
180 » heads_to_tie_[j].tie_from_chord_created = true; | 184 Direction d = to_dir (unsmob_stream_event (cause)->get_property ("
direction")); |
181 » } | 185 p->set_property ("direction", scm_from_int (d)); |
182 » } | 186 } |
| 187 |
| 188 ties_.push_back (p); |
| 189 heads_to_tie_.erase (heads_to_tie_.begin () + i); |
| 190 |
| 191 /* |
| 192 Prevent all other tied notes ending at the same moment (assume |
| 193 implicitly the notes have also started at the same moment!) |
| 194 from triggering an "unterminated tie" warning. Needed e.g. for |
| 195 <c e g>~ g |
| 196 */ |
| 197 for (vsize j = heads_to_tie_.size (); j--;) |
| 198 { |
| 199 if (heads_to_tie_[j].end_moment_ == end) |
| 200 heads_to_tie_[j].tie_from_chord_created = true; |
| 201 } |
| 202 } |
183 } | 203 } |
184 | 204 |
185 if (ties_.size () && ! tie_column_) | 205 if (ties_.size () && ! tie_column_) |
186 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ()); | 206 tie_column_ = make_spanner ("TieColumn", ties_[0]->self_scm ()); |
187 | 207 |
188 if (tie_column_) | 208 if (tie_column_) |
189 for (vsize i = ties_.size (); i--;) | 209 for (vsize i = ties_.size (); i--;) |
190 Tie_column::add_tie (tie_column_, ties_[i]); | 210 Tie_column::add_tie (tie_column_, ties_[i]); |
191 } | 211 } |
192 | 212 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 | 246 |
227 for (vsize i = 0; i < ties_.size (); i++) | 247 for (vsize i = 0; i < ties_.size (); i++) |
228 typeset_tie (ties_[i]); | 248 typeset_tie (ties_[i]); |
229 | 249 |
230 ties_.clear (); | 250 ties_.clear (); |
231 tie_column_ = 0; | 251 tie_column_ = 0; |
232 } | 252 } |
233 | 253 |
234 vector<Head_event_tuple> new_heads_to_tie; | 254 vector<Head_event_tuple> new_heads_to_tie; |
235 | 255 |
| 256 /* |
| 257 Whether tie event has been processed and can be deleted or should |
| 258 be kept for later portions of a split note. |
| 259 */ |
| 260 bool event_processed = false; |
| 261 |
236 for (vsize i = 0; i < now_heads_.size (); i++) | 262 for (vsize i = 0; i < now_heads_.size (); i++) |
237 { | 263 { |
238 Grob *head = now_heads_[i]; | 264 Grob *head = now_heads_[i]; |
239 Stream_event *left_ev | 265 Stream_event *left_ev |
240 = unsmob_stream_event (head->get_property ("cause")); | 266 = unsmob_stream_event (head->get_property ("cause")); |
241 | 267 |
242 if (!left_ev) | 268 if (!left_ev) |
243 { | 269 { |
244 // may happen for ambitus | 270 // may happen for ambitus |
245 continue; | 271 continue; |
246 } | 272 } |
247 | 273 |
248 | 274 |
249 SCM left_articulations = left_ev->get_property ("articulations"); | 275 SCM left_articulations = left_ev->get_property ("articulations"); |
250 | 276 |
251 Stream_event *tie_event = 0; | 277 Stream_event *tie_event = 0; |
252 Stream_event *tie_stream_event = event_; | 278 Stream_event *tie_stream_event = event_; |
253 for (SCM s = left_articulations; | 279 for (SCM s = left_articulations; |
254 !tie_event && !tie_stream_event && scm_is_pair (s); | 280 !tie_event && !tie_stream_event && scm_is_pair (s); |
255 s = scm_cdr (s)) | 281 s = scm_cdr (s)) |
256 { | 282 { |
257 Stream_event *ev = unsmob_stream_event (scm_car (s)); | 283 Stream_event *ev = unsmob_stream_event (scm_car (s)); |
258 if (!ev) | 284 if (!ev) |
259 continue; | 285 continue; |
260 | 286 |
261 if (ev->in_event_class ("tie-event")) | 287 if (ev->in_event_class ("tie-event")) |
262 tie_event = ev; | 288 tie_event = ev; |
263 } | 289 } |
264 | 290 |
265 if (left_ev && (tie_event || tie_stream_event)) | 291 if (left_ev && (tie_event || tie_stream_event) |
266 » { | 292 && (!Tie_engraver::has_autosplit_end (left_ev))) |
267 » Head_event_tuple event_tup; | 293 { |
| 294 event_processed = true; |
268 | 295 |
269 » SCM start_definition | 296 » Head_event_tuple event_tup; |
270 » = updated_grob_properties (context (), ly_symbol2scm ("Tie")); | |
271 | 297 |
272 » event_tup.head_ = head; | 298 » SCM start_definition |
273 » event_tup.tie_definition_ = start_definition; | 299 » = updated_grob_properties (context (), ly_symbol2scm ("Tie")); |
274 » event_tup.tie_event_ = tie_event; | |
275 » event_tup.tie_stream_event_ = tie_stream_event; | |
276 | 300 |
277 » Moment end = now_mom (); | 301 » event_tup.head_ = head; |
278 » if (end.grace_part_) | 302 » event_tup.tie_definition_ = start_definition; |
279 » { | 303 » event_tup.tie_event_ = tie_event; |
280 » end.grace_part_ += get_event_length (left_ev).main_part_; | 304 » event_tup.tie_stream_event_ = tie_stream_event; |
281 » } | |
282 » else | |
283 » { | |
284 » end += get_event_length (left_ev); | |
285 » } | |
286 » event_tup.end_moment_ = end; | |
287 | 305 |
288 » new_heads_to_tie.push_back (event_tup); | 306 » Moment end = now_mom (); |
289 » } | 307 » if (end.grace_part_) |
| 308 » { |
| 309 » end.grace_part_ += get_event_length (left_ev).main_part_; |
| 310 » } |
| 311 » else |
| 312 » { |
| 313 » end += get_event_length (left_ev); |
| 314 » } |
| 315 » event_tup.end_moment_ = end; |
| 316 |
| 317 » new_heads_to_tie.push_back (event_tup); |
| 318 » } |
290 } | 319 } |
291 | 320 |
292 if (!wait && new_heads_to_tie.size ()) | 321 if (!wait && new_heads_to_tie.size ()) |
293 { | 322 { |
294 vector<Head_event_tuple>::iterator it=heads_to_tie_.begin (); | 323 vector<Head_event_tuple>::iterator it=heads_to_tie_.begin (); |
295 for (; it < heads_to_tie_.end (); it++) | 324 for (; it < heads_to_tie_.end (); it++) |
296 report_unterminated_tie (*it); | 325 report_unterminated_tie (*it); |
297 heads_to_tie_.clear (); | 326 heads_to_tie_.clear (); |
298 } | 327 } |
299 | 328 |
300 // hmmm, how to do with copy () ? | 329 // hmmm, how to do with copy () ? |
301 for (vsize i = 0; i < new_heads_to_tie.size (); i++) | 330 for (vsize i = 0; i < new_heads_to_tie.size (); i++) |
302 heads_to_tie_.push_back (new_heads_to_tie[i]); | 331 heads_to_tie_.push_back (new_heads_to_tie[i]); |
303 | 332 |
304 event_ = 0; | 333 /* |
| 334 Discard event only if it has been processed with at least one |
| 335 appropriate note. |
| 336 */ |
| 337 if (event_processed) |
| 338 event_ = 0; |
| 339 |
305 now_heads_.clear (); | 340 now_heads_.clear (); |
306 } | 341 } |
307 | 342 |
308 void | 343 void |
309 Tie_engraver::typeset_tie (Grob *her) | 344 Tie_engraver::typeset_tie (Grob *her) |
310 { | 345 { |
311 if (! (Tie::head (her, LEFT) && Tie::head (her, RIGHT))) | 346 if (! (Tie::head (her, LEFT) && Tie::head (her, RIGHT))) |
312 warning (_ ("lonely tie")); | 347 warning (_ ("lonely tie")); |
313 | 348 |
314 Direction d = LEFT; | 349 Direction d = LEFT; |
(...skipping 20 matching lines...) Expand all Loading... |
335 /* create */ | 370 /* create */ |
336 "Tie " | 371 "Tie " |
337 "TieColumn ", | 372 "TieColumn ", |
338 | 373 |
339 /* read */ | 374 /* read */ |
340 "tieWaitForNote ", | 375 "tieWaitForNote ", |
341 | 376 |
342 /* write */ | 377 /* write */ |
343 "tieMelismaBusy " | 378 "tieMelismaBusy " |
344 ); | 379 ); |
OLD | NEW |