1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7 See the AUTHORS file for more details.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #define RG_MODULE_STRING "[SegmentNotationHelper]"
17 // Turn off all debugging here.
18 #define RG_NO_DEBUG_PRINT
19
20 #include "SegmentNotationHelper.h"
21 #include "base/NotationTypes.h"
22 #include "Quantizer.h"
23 #include "BasicQuantizer.h"
24 #include "NotationQuantizer.h"
25 #include "base/BaseProperties.h"
26 #include "Composition.h"
27
28 #include <iostream>
29 #include <algorithm>
30 #include <iterator>
31 #include <list>
32
33 //#define DEBUG_DECOUNTERPOINT
34
35 namespace Rosegarden
36 {
37 using std::string;
38 using std::list;
39
40 using namespace BaseProperties;
41
42
~SegmentNotationHelper()43 SegmentNotationHelper::~SegmentNotationHelper() { }
44
45
46 const Quantizer &
basicQuantizer()47 SegmentNotationHelper::basicQuantizer() {
48 return *(segment().getComposition()->getBasicQuantizer());
49 }
50
51 const Quantizer &
notationQuantizer()52 SegmentNotationHelper::notationQuantizer() {
53 return *(segment().getComposition()->getNotationQuantizer());
54 }
55
56
57 //!!! we need to go very carefully through this file and check calls
58 //to getAbsoluteTime/getDuration -- the vast majority should almost
59 //certainly now be using getNotationAbsoluteTime/getNotationDuration
60
61 Segment::iterator
findNotationAbsoluteTime(timeT t)62 SegmentNotationHelper::findNotationAbsoluteTime(timeT t)
63 {
64 iterator i(segment().findTime(t));
65
66 // We don't know whether the notation absolute time t will appear
67 // before or after the real absolute time t. First scan backwards
68 // until we find a notation absolute time prior to (or equal to)
69 // t, and then scan forwards until we find the first one that
70 // isn't prior to t
71
72 while (i != begin() &&
73 ((i == end() ? t + 1 : (*i)->getNotationAbsoluteTime()) > t))
74 --i;
75
76 while (i != end() &&
77 ((*i)->getNotationAbsoluteTime() < t))
78 ++i;
79
80 return i;
81 }
82
83 Segment::iterator
findNearestNotationAbsoluteTime(timeT t)84 SegmentNotationHelper::findNearestNotationAbsoluteTime(timeT t)
85 {
86 iterator i(segment().findTime(t));
87
88 // Exactly findNotationAbsoluteTime, only with the two scan loops
89 // in the other order
90
91 while (i != end() &&
92 ((*i)->getNotationAbsoluteTime() < t))
93 ++i;
94
95 while (i != begin() &&
96 ((i == end() ? t + 1 : (*i)->getNotationAbsoluteTime()) > t))
97 --i;
98
99 return i;
100 }
101
102 void
setNotationProperties(timeT startTime,timeT endTime)103 SegmentNotationHelper::setNotationProperties(timeT startTime, timeT endTime)
104 {
105 Segment::iterator from = begin();
106 Segment::iterator to = end();
107
108 if (startTime != endTime) {
109 from = segment().findTime(startTime);
110 to = segment().findTime(endTime);
111 }
112 /*!!!
113 bool justSeenGraceNote = false;
114 timeT graceNoteStart = 0;
115 */
116 for (Segment::iterator i = from;
117 i != to && segment().isBeforeEndMarker(i); ++i) {
118
119 if ((*i)->has(NOTE_TYPE) /*!!! && !(*i)->has(IS_GRACE_NOTE) */) continue;
120
121 timeT duration = (*i)->getNotationDuration();
122
123 if ((*i)->has(BEAMED_GROUP_TUPLET_BASE)) {
124 int tcount = (*i)->get<Int>(BEAMED_GROUP_TUPLED_COUNT);
125 int ucount = (*i)->get<Int>(BEAMED_GROUP_UNTUPLED_COUNT);
126
127 if (tcount == 0) {
128 RG_DEBUG << "WARNING: SegmentNotationHelper::setNotationProperties: zero tuplet count:";
129 RG_DEBUG << (**i);
130 } else {
131 // nominal duration is longer than actual (sounding) duration
132 duration = (duration / tcount) * ucount;
133 }
134 }
135
136 if ((*i)->isa(Note::EventType) || (*i)->isa(Note::EventRestType)) {
137
138 if ((*i)->isa(Note::EventType)) {
139 /*!!!
140 if ((*i)->has(IS_GRACE_NOTE) &&
141 (*i)->get<Bool>(IS_GRACE_NOTE)) {
142
143 if (!justSeenGraceNote) {
144 graceNoteStart = (*i)->getNotationAbsoluteTime();
145 justSeenGraceNote = true;
146 }
147
148 } else if (justSeenGraceNote) {
149
150 duration += (*i)->getNotationAbsoluteTime() - graceNoteStart;
151 justSeenGraceNote = false;
152 }
153 */
154 }
155
156 Note n(Note::getNearestNote(duration));
157
158 (*i)->setMaybe<Int>(NOTE_TYPE, n.getNoteType());
159 (*i)->setMaybe<Int>(NOTE_DOTS, n.getDots());
160 }
161 }
162 }
163
164 timeT
getNotationEndTime(Event * e)165 SegmentNotationHelper::getNotationEndTime(Event *e)
166 {
167 return e->getNotationAbsoluteTime() + e->getNotationDuration();
168 }
169
170
171 Segment::iterator
getNextAdjacentNote(iterator i,bool matchPitch,bool allowOverlap)172 SegmentNotationHelper::getNextAdjacentNote(iterator i,
173 bool matchPitch,
174 bool allowOverlap)
175 {
176 iterator j(i);
177 if (!isBeforeEndMarker(i)) return i;
178 if (!(*i)->isa(Note::EventType)) return end();
179
180 timeT iEnd = getNotationEndTime(*i);
181 long ip = 0, jp = 0;
182 if (!(*i)->get<Int>(PITCH, ip) && matchPitch) return end();
183
184 while (true) {
185 if (!isBeforeEndMarker(j) || !isBeforeEndMarker(++j)) return end();
186 if (!(*j)->isa(Note::EventType)) continue;
187
188 timeT jStart = (*j)->getNotationAbsoluteTime();
189 if (jStart > iEnd) return end();
190
191 if (matchPitch) {
192 if (!(*j)->get<Int>(PITCH, jp) || (jp != ip)) continue;
193 }
194
195 if (allowOverlap || (jStart == iEnd)) return j;
196 }
197 }
198
199
200 Segment::iterator
getPreviousAdjacentNote(iterator i,timeT rangeStart,bool matchPitch,bool allowOverlap)201 SegmentNotationHelper::getPreviousAdjacentNote(iterator i,
202 timeT rangeStart,
203 bool matchPitch,
204 bool allowOverlap)
205 {
206 iterator j(i);
207 if (!isBeforeEndMarker(i)) return i;
208 if (!(*i)->isa(Note::EventType)) return end();
209
210 timeT iStart = (*i)->getNotationAbsoluteTime();
211 timeT iEnd = getNotationEndTime(*i);
212 long ip = 0, jp = 0;
213 if (!(*i)->get<Int>(PITCH, ip) && matchPitch) return end();
214
215 while (true) {
216 if (j == begin()) return end(); else --j;
217 if (!(*j)->isa(Note::EventType)) continue;
218 if ((*j)->getAbsoluteTime() < rangeStart) return end();
219
220 timeT jEnd = getNotationEndTime(*j);
221
222 // don't consider notes that end after i ends or before i begins
223
224 if (jEnd > iEnd || jEnd < iStart) continue;
225
226 if (matchPitch) {
227 if (!(*j)->get<Int>(PITCH, jp) || (jp != ip)) continue;
228 }
229
230 if (allowOverlap || (jEnd == iStart)) return j;
231 }
232 }
233
234
235 Segment::iterator
findContiguousNext(iterator el)236 SegmentNotationHelper::findContiguousNext(iterator el)
237 {
238 std::string elType = (*el)->getType(),
239 reject, accept;
240
241 if (elType == Note::EventType) {
242 accept = Note::EventType;
243 reject = Note::EventRestType;
244 } else if (elType == Note::EventRestType) {
245 accept = Note::EventRestType;
246 reject = Note::EventType;
247 } else {
248 accept = elType;
249 reject = "";
250 }
251
252 bool success = false;
253
254 iterator i = ++el;
255
256 for(; isBeforeEndMarker(i); ++i) {
257 std::string iType = (*i)->getType();
258
259 if (iType == reject) {
260 success = false;
261 break;
262 }
263 if (iType == accept) {
264 success = true;
265 break;
266 }
267 }
268
269 if (success) return i;
270 else return end();
271
272 }
273
274 Segment::iterator
findContiguousPrevious(iterator el)275 SegmentNotationHelper::findContiguousPrevious(iterator el)
276 {
277 if (el == begin()) return end();
278
279 std::string elType = (*el)->getType(),
280 reject, accept;
281
282 if (elType == Note::EventType) {
283 accept = Note::EventType;
284 reject = Note::EventRestType;
285 } else if (elType == Note::EventRestType) {
286 accept = Note::EventRestType;
287 reject = Note::EventType;
288 } else {
289 accept = elType;
290 reject = "";
291 }
292
293 bool success = false;
294
295 iterator i = --el;
296
297 while (true) {
298 std::string iType = (*i)->getType();
299
300 if (iType == reject) {
301 success = false;
302 break;
303 }
304 if (iType == accept) {
305 success = true;
306 break;
307 }
308 if (i == begin()) break;
309 --i;
310 }
311
312 if (success) return i;
313 else return end();
314 }
315
316
317 bool
noteIsInChord(Event * note)318 SegmentNotationHelper::noteIsInChord(Event *note)
319 {
320 iterator i = segment().findSingle(note);
321 timeT t = note->getNotationAbsoluteTime();
322
323 for (iterator j = i; j != end(); ++j) { // not isBeforeEndMarker, unnecessary here
324 if (j == i) continue;
325 if ((*j)->isa(Note::EventType)) {
326 timeT tj = (*j)->getNotationAbsoluteTime();
327 if (tj == t) return true;
328 else if (tj > t) break;
329 }
330 }
331
332 for (iterator j = i; ; ) {
333 if (j == begin()) break;
334 --j;
335 if ((*j)->isa(Note::EventType)) {
336 timeT tj = (*j)->getNotationAbsoluteTime();
337 if (tj == t) return true;
338 else if (tj < t) break;
339 }
340 }
341
342 return false;
343
344 /*!!!
345 iterator first, second;
346 segment().getTimeSlice(note->getAbsoluteTime(), first, second);
347
348 int noteCount = 0;
349 for (iterator i = first; i != second; ++i) {
350 if ((*i)->isa(Note::EventType)) ++noteCount;
351 }
352
353 return noteCount > 1;
354 */
355 }
356
357
358 //!!! This doesn't appear to be used any more and may well not work.
359 // Ties are calculated in several different places, and it's odd that
360 // we don't have a decent API for them
361 Segment::iterator
getNoteTiedWith(Event * note,bool forwards)362 SegmentNotationHelper::getNoteTiedWith(Event *note, bool forwards)
363 {
364 bool tied = false;
365
366 if (!note->get<Bool>(forwards ?
367 BaseProperties::TIED_FORWARD :
368 BaseProperties::TIED_BACKWARD, tied) || !tied) {
369 return end();
370 }
371
372 timeT myTime = note->getAbsoluteTime();
373 timeT myDuration = note->getDuration();
374 int myPitch = note->get<Int>(BaseProperties::PITCH);
375
376 iterator i = segment().findSingle(note);
377 if (!isBeforeEndMarker(i)) return end();
378
379 for (;;) {
380 i = forwards ? findContiguousNext(i) : findContiguousPrevious(i);
381
382 if (!isBeforeEndMarker(i)) return end();
383 if ((*i)->getAbsoluteTime() == myTime) continue;
384
385 if (forwards && ((*i)->getAbsoluteTime() != myTime + myDuration)) {
386 return end();
387 }
388 if (!forwards &&
389 (((*i)->getAbsoluteTime() + (*i)->getDuration()) != myTime)) {
390 return end();
391 }
392
393 if (!(*i)->get<Bool>(forwards ?
394 BaseProperties::TIED_BACKWARD :
395 BaseProperties::TIED_FORWARD, tied) || !tied) {
396 continue;
397 }
398
399 if ((*i)->get<Int>(BaseProperties::PITCH) == myPitch) return i;
400 }
401
402 return end();
403 }
404
405
406 bool
collapseRestsIfValid(Event * e,bool & collapseForward)407 SegmentNotationHelper::collapseRestsIfValid(Event* e, bool& collapseForward)
408 {
409 iterator elPos = segment().findSingle(e);
410 if (elPos == end()) return false;
411
412 timeT myDuration = (*elPos)->getNotationDuration();
413
414 // findContiguousNext won't return an iterator beyond the end marker
415 iterator nextEvent = findContiguousNext(elPos),
416 previousEvent = findContiguousPrevious(elPos);
417
418 // Remark: findContiguousXXX is inadequate for notes, we would
419 // need to check adjacency using e.g. getNextAdjacentNote if this
420 // method were to work for notes as well as rests.
421
422 // collapse to right if (a) not at end...
423 if (nextEvent != end() &&
424 // ...(b) rests can be merged to a single, valid unit
425 isCollapseValid((*nextEvent)->getNotationDuration(), myDuration) &&
426 // ...(c) event is in same bar (no cross-bar collapsing)
427 (*nextEvent)->getAbsoluteTime() <
428 segment().getBarEndForTime(e->getAbsoluteTime())) {
429
430 // collapse right is OK; collapse e with nextEvent
431 Event *e1(new Event(*e, e->getAbsoluteTime(),
432 e->getDuration() + (*nextEvent)->getDuration()));
433
434 collapseForward = true;
435 erase(elPos);
436 erase(nextEvent);
437 insert(e1);
438 return true;
439 }
440
441 // logic is exactly backwards from collapse to right logic above
442 if (previousEvent != end() &&
443 isCollapseValid((*previousEvent)->getNotationDuration(), myDuration) &&
444 (*previousEvent)->getAbsoluteTime() >
445 segment().getBarStartForTime(e->getAbsoluteTime())) {
446
447 // collapse left is OK; collapse e with previousEvent
448 Event *e1(new Event(**previousEvent,
449 (*previousEvent)->getAbsoluteTime(),
450 e->getDuration() +
451 (*previousEvent)->getDuration()));
452
453 collapseForward = false;
454 erase(elPos);
455 erase(previousEvent);
456 insert(e1);
457 return true;
458 }
459
460 return false;
461 }
462
463
464 bool
isCollapseValid(timeT a,timeT b)465 SegmentNotationHelper::isCollapseValid(timeT a, timeT b)
466 {
467 return (isViable(a + b));
468 }
469
470
471 bool
isSplitValid(timeT a,timeT b)472 SegmentNotationHelper::isSplitValid(timeT a, timeT b)
473 {
474 return (isViable(a) && isViable(b));
475 }
476
477 Segment::iterator
splitIntoTie(iterator & i,timeT baseDuration)478 SegmentNotationHelper::splitIntoTie(iterator &i, timeT baseDuration)
479 {
480 if (i == end()) return end();
481 iterator i2;
482 segment().getTimeSlice((*i)->getAbsoluteTime(), i, i2);
483 return splitIntoTie(i, i2, baseDuration);
484 }
485
486 Segment::iterator
splitIntoTie(iterator & from,iterator to,timeT baseDuration)487 SegmentNotationHelper::splitIntoTie(iterator &from, iterator to,
488 timeT baseDuration)
489 {
490 // so long as we do the quantization checks for validity before
491 // calling this method, we should be fine splitting precise times
492 // in this method. only problem is deciding not to split something
493 // if its duration is very close to requested duration, but that's
494 // probably not a task for this function
495
496 timeT eventDuration = (*from)->getDuration();
497 timeT baseTime = (*from)->getAbsoluteTime();
498
499 long firstGroupId = -1;
500 (*from)->get<Int>(BEAMED_GROUP_ID, firstGroupId);
501
502 long nextGroupId = -1;
503 iterator ni(to);
504
505 if (segment().isBeforeEndMarker(ni) && segment().isBeforeEndMarker(++ni)) {
506 (*ni)->get<Int>(BEAMED_GROUP_ID, nextGroupId);
507 }
508
509 list<Event *> toInsert;
510 list<iterator> toErase;
511
512 // Split all the note and rest events in range [from, to[
513 //
514 for (iterator i = from; i != to; ++i) {
515
516 if (!(*i)->isa(Note::EventType) &&
517 !(*i)->isa(Note::EventRestType)) continue;
518
519 if ((*i)->getAbsoluteTime() != baseTime) {
520 // no way to really cope with an error, because at this
521 // point we may already have splut some events. Best to
522 // skip this event
523 RG_DEBUG << "WARNING: SegmentNotationHelper::splitIntoTie(): (*i)->getAbsoluteTime() != baseTime (" << (*i)->getAbsoluteTime() << " vs " << baseTime << "), ignoring this event\n";
524 continue;
525 }
526
527 if ((*i)->getDuration() != eventDuration) {
528 if ((*i)->getDuration() == 0) continue;
529 RG_DEBUG << "WARNING: SegmentNotationHelper::splitIntoTie(): (*i)->getDuration() != eventDuration (" << (*i)->getDuration() << " vs " << eventDuration << "), changing eventDuration to match\n";
530 eventDuration = (*i)->getDuration();
531 }
532
533 if (baseDuration >= eventDuration) {
534 // RG_DEBUG << "SegmentNotationHelper::splitIntoTie() : baseDuration >= eventDuration, ignoring event\n";
535 continue;
536 }
537
538 std::pair<Event *, Event *> split =
539 splitPreservingPerformanceTimes(*i, baseDuration);
540
541 Event *eva = split.first;
542 Event *evb = split.second;
543
544 if (!eva || !evb) {
545 RG_DEBUG << "WARNING: SegmentNotationHelper::splitIntoTie(): No valid split for event of duration " << eventDuration << " at " << baseTime << " (baseDuration " << baseDuration << "), ignoring this event\n";
546 continue;
547 }
548
549 // we only want to tie Note events:
550
551 if (eva->isa(Note::EventType)) {
552
553 // if the first event was already tied forward, the
554 // second one will now be marked as tied forward
555 // (which is good). set up the relationship between
556 // the original (now shorter) event and the new one.
557
558 evb->set<Bool>(TIED_BACKWARD, true);
559 eva->set<Bool>(TIED_FORWARD, true);
560 }
561
562 // we may also need to change some group information: if
563 // the first event is in a beamed group but the event
564 // following the insertion is not or is in a different
565 // group, then the new second event should not be in a
566 // group. otherwise, it should inherit the grouping info
567 // from the first event (as it already does, because it
568 // was created using the copy constructor).
569
570 // (this doesn't apply to tupled groups, which we want
571 // to persist wherever possible.)
572
573 if (firstGroupId != -1 &&
574 nextGroupId != firstGroupId &&
575 !evb->has(BEAMED_GROUP_TUPLET_BASE)) {
576 evb->unset(BEAMED_GROUP_ID);
577 evb->unset(BEAMED_GROUP_TYPE);
578 }
579
580 toInsert.push_back(eva);
581 toInsert.push_back(evb);
582 toErase.push_back(i);
583 }
584
585 // erase the old events
586 for (list<iterator>::iterator i = toErase.begin();
587 i != toErase.end(); ++i) {
588 segment().erase(*i);
589 }
590
591 from = end();
592 iterator last = end();
593
594 // now insert the new events
595 for (list<Event *>::iterator i = toInsert.begin();
596 i != toInsert.end(); ++i) {
597 last = insert(*i);
598 if (from == end()) from = last;
599 }
600
601 return last;
602 }
603
604 bool
isViable(timeT duration,int dots)605 SegmentNotationHelper::isViable(timeT duration, int dots)
606 {
607 bool viable;
608
609 /*!!!
610 duration = basicQuantizer().quantizeDuration(duration);
611
612 if (dots >= 0) {
613 viable = (duration == Quantizer(Quantizer::RawEventData,
614 Quantizer::DefaultTarget,
615 Quantizer::NoteQuantize, 1, dots).
616 quantizeDuration(duration));
617 } else {
618 viable = (duration == notationQuantizer().quantizeDuration(duration));
619 }
620 */
621
622 //!!! what to do about this?
623
624 timeT nearestDuration =
625 Note::getNearestNote(duration, dots >= 0 ? dots : 2).getDuration();
626
627 // RG_DEBUG << "SegmentNotationHelper::isViable: nearestDuration is " << nearestDuration << ", duration is " << duration;
628 viable = (nearestDuration == duration);
629
630 return viable;
631 }
632
633
634 void
makeRestViable(iterator i)635 SegmentNotationHelper::makeRestViable(iterator i)
636 {
637 timeT absTime = (*i)->getAbsoluteTime();
638 timeT duration = (*i)->getDuration();
639 erase(i);
640 segment().fillWithRests(absTime, absTime + duration);
641 }
642
643
644 Event *
makeThisNoteViable(iterator noteItr,bool splitAtBars)645 SegmentNotationHelper::makeThisNoteViable(iterator noteItr, bool splitAtBars)
646 {
647 // We don't use quantized values here; we want a precise division.
648 // Even if it doesn't look precise on the score (because the score
649 // is quantized), we want any playback to produce exactly the same
650 // duration of note as was originally recorded
651
652 // Holds the events we will add once an event is split.
653 std::vector<Event *> toInsert;
654
655 Segment::iterator i = noteItr;
656
657 if (!(*i)->isa(Note::EventType) && !(*i)->isa(Note::EventRestType)) {
658 return *noteItr;
659 }
660
661 if ((*i)->has(BEAMED_GROUP_TUPLET_BASE)) {
662 return *noteItr;
663 }
664
665 // A list of durations that will satisfactorily break up this event.
666 DurationList dl;
667
668 // Behaviour differs from TimeSignature::getDurationListForInterval
669
670 timeT acc = 0;
671 timeT qt = (*i)->getNotationAbsoluteTime();
672 timeT required = (*i)->getNotationDuration();
673 timeT maxdur = (*i)->getAbsoluteTime() + (*i)->getDuration() - qt;
674
675 if (maxdur <= 0) {
676 return *noteItr;
677 }
678
679 // While we've not yet accumulated the required amount of time, build
680 // the duration list (dl).
681 while (acc < required) {
682 timeT remaining = required - acc;
683 if (splitAtBars) {
684 timeT thisNoteStart = qt + acc;
685 timeT toNextBar =
686 segment().getBarEndForTime(thisNoteStart) - thisNoteStart;
687 if (toNextBar > 0 && remaining > toNextBar)
688 remaining = toNextBar;
689 }
690 timeT component = Note::getNearestNote(remaining).getDuration();
691 timeT dur = (component > (required - acc) ? (required - acc) : component);
692
693 // #1517: In the scenario where there is a whole note (4 beats) in a
694 // single measure of 2/2, maxdur == dur and this is exactly as it should
695 // be. I dug around in here and all the numbers were perfect for that
696 // case, and the only fault was the <= test condition was kicking this
697 // out when the two values were ==. I changed the test to a < and fixed
698 // the bug. The most obvious consequence of this change is that it is
699 // no longer possible to put a semibreve into a single measure of 4/4
700 // time. It splits into two tied whole notes. This seems perfectly
701 // acceptable and reasonable to me (dmm) so I decided to just go with
702 // this and move along.
703 if (maxdur < dur) {
704 // Split point doesn't preseve performance time
705 break;
706 }
707 dl.push_back(dur);
708 acc += component;
709 maxdur -= dur;
710 }
711
712 if (dl.size() < 2) {
713 // event is already of the correct duration
714 return *noteItr;
715 }
716
717 acc = (*i)->getNotationAbsoluteTime();
718 Event *e = new Event(*(*i));
719
720 bool lastTiedForward = false;
721 e->get<Bool>(TIED_FORWARD, lastTiedForward);
722
723 e->set<Bool>(TIED_FORWARD, true);
724 erase(i);
725
726 // For each duration
727 for (DurationList::iterator dli = dl.begin(); dli != dl.end(); ++dli) {
728
729 DurationList::iterator dlj(dli);
730 if (++dlj == dl.end()) {
731 // end of duration list
732 if (!lastTiedForward)
733 e->unset(TIED_FORWARD);
734 toInsert.push_back(e);
735 e = nullptr;
736 break;
737 }
738
739 std::pair<Event *, Event *> splits =
740 splitPreservingPerformanceTimes(e, *dli);
741
742 if (!splits.first || !splits.second) {
743 RG_DEBUG
744 << "WARNING: SegmentNotationHelper::makeThisNoteViable(): No valid split for event of duration "
745 << e->getDuration() << " at " << e->getAbsoluteTime()
746 << " (split duration " << *dli << "), ignoring remainder\n";
747 RG_DEBUG << "WARNING: This is probably a bug; fix required";
748
749 // Bug #3466912
750 // There's a situation where an event might be unsplittable, and
751 // it could cause an endless loop because its notation duration
752 // is longer than the event duration. The following check will
753 // make sure the notation duration is truncated to the event
754 // duration thus preventing the endless loop.
755
756 // Bug #1419
757 //
758 // The above referenced check obviously didn't work correctly. The
759 // following code block used to be inside a test to see if
760 // performance and notation duration were the same, which is
761 // antithetical to the above stated goal of the following code
762 // block. Without doing any thinking on the greater picture here, I
763 // decided to try removing the test entirely. The thought was if
764 // we're in this "no valid split" code block anyway, then let's just
765 // hit it with a hammer in every case and try to avoid infinite
766 // loops!
767 //
768 // It successfully addresses the infinite loop in #1419 with no
769 // immediately obvious consequences, although I'm sure there are
770 // hidden consequences.
771
772 // Create a new event with the notation abs time and duration
773 // set to the event abs time and duration.
774 Event *e1 = new Event(*e,
775 e->getAbsoluteTime(), e->getDuration(), // event
776 e->getSubOrdering(),
777 e->getAbsoluteTime(), e->getDuration()); // notation
778 toInsert.push_back(e1);
779 break;
780
781 // Add in the remaining time.
782 toInsert.push_back(e);
783 e = nullptr;
784 break;
785 }
786
787 toInsert.push_back(splits.first);
788 delete e;
789 e = splits.second;
790
791 acc += *dli;
792
793 e->set<Bool>(TIED_BACKWARD, true);
794 }
795
796 delete e;
797
798 // Insert new events into segment
799 for (std::vector<Event *>::iterator ei = toInsert.begin();
800 ei != toInsert.end(); ++ei) {
801 insert(*ei);
802 }
803
804 // Make assumption that toInsert.begin() != toInsert.end()
805 return *(toInsert.begin());
806
807 }
808
809 void
makeNotesViable(iterator from,iterator to,bool splitAtBars)810 SegmentNotationHelper::makeNotesViable(iterator from, iterator to,
811 bool splitAtBars)
812 {
813 // std::vector<Event *> toInsert;
814
815 // For each Event in the range
816 for (Segment::iterator i = from, j = i;
817 segment().isBeforeEndMarker(i) && i != to;
818 i = j) {
819
820 // We keep a second iterator to make sure we aren't modifying the
821 // event that our iterator points to.
822 ++j;
823
824 makeThisNoteViable(i, splitAtBars);
825 }
826
827 }
828
829 void
makeNotesViable(timeT startTime,timeT endTime,bool splitAtBars)830 SegmentNotationHelper::makeNotesViable(timeT startTime, timeT endTime,
831 bool splitAtBars)
832 {
833 Segment::iterator from = segment().findTime(startTime);
834 Segment::iterator to = segment().findTime(endTime);
835
836 makeNotesViable(from, to, splitAtBars);
837 }
838
839
840 Segment::iterator
insertNote(timeT absoluteTime,Note note,int pitch,Accidental explicitAccidental)841 SegmentNotationHelper::insertNote(timeT absoluteTime, Note note, int pitch,
842 Accidental explicitAccidental)
843 {
844 Event *e = new Event(Note::EventType, absoluteTime, note.getDuration());
845 e->set<Int>(PITCH, pitch);
846 e->set<String>(ACCIDENTAL, explicitAccidental);
847 iterator i = insertNote(e);
848 delete e;
849 return i;
850 }
851
852 Segment::iterator
insertNote(Event * modelEvent)853 SegmentNotationHelper::insertNote(Event *modelEvent)
854 {
855 RG_DEBUG << "insertNote";
856 RG_DEBUG << *modelEvent;
857
858 timeT absoluteTime = modelEvent->getAbsoluteTime();
859 iterator i = segment().findNearestTime(absoluteTime);
860
861 RG_DEBUG << "absoluteTime" << absoluteTime;
862
863 // If our insertion time doesn't match up precisely with any
864 // existing event, and if we're inserting over a rest, split the
865 // rest at the insertion time first.
866
867 if (i != end() &&
868 (*i)->getAbsoluteTime() < absoluteTime &&
869 (*i)->getAbsoluteTime() + (*i)->getDuration() > absoluteTime &&
870 (*i)->isa(Note::EventRestType)) {
871 i = splitIntoTie(i, absoluteTime - (*i)->getAbsoluteTime());
872 }
873
874 timeT duration = modelEvent->getDuration();
875
876 if (i != end() && (*i)->has(BEAMED_GROUP_TUPLET_BASE)) {
877 duration = duration * (*i)->get<Int>(BEAMED_GROUP_TUPLED_COUNT) /
878 (*i)->get<Int>(BEAMED_GROUP_UNTUPLED_COUNT);
879 }
880
881 RG_DEBUG << "duration" << duration;
882 //!!! Deal with end-of-bar issues!
883
884 return insertSomething(i, duration, modelEvent, false);
885 }
886
887
888 Segment::iterator
insertRest(timeT absoluteTime,Note note)889 SegmentNotationHelper::insertRest(timeT absoluteTime, Note note)
890 {
891 iterator i, j;
892 segment().getTimeSlice(absoluteTime, i, j);
893
894 //!!! Deal with end-of-bar issues!
895
896 timeT duration(note.getDuration());
897
898 if (i != end() && (*i)->has(BEAMED_GROUP_TUPLET_BASE)) {
899 duration = duration * (*i)->get<Int>(BEAMED_GROUP_TUPLED_COUNT) /
900 (*i)->get<Int>(BEAMED_GROUP_UNTUPLED_COUNT);
901 }
902
903 Event *modelEvent = new Event(Note::EventRestType, absoluteTime,
904 note.getDuration(),
905 Note::EventRestSubOrdering);
906
907 i = insertSomething(i, duration, modelEvent, false);
908 delete modelEvent;
909 return i;
910 }
911
912
913 // return an iterator pointing to the "same" event as the original
914 // iterator (which will have been replaced)
915
916 Segment::iterator
collapseRestsForInsert(iterator i,timeT desiredDuration)917 SegmentNotationHelper::collapseRestsForInsert(iterator i,
918 timeT desiredDuration)
919 {
920 // collapse at most once, then recurse
921
922 if (!segment().isBeforeEndMarker(i) ||
923 !(*i)->isa(Note::EventRestType)) return i;
924
925 timeT d = (*i)->getDuration();
926 iterator j = findContiguousNext(i); // won't return itr after end marker
927 if (d >= desiredDuration || j == end()) return i;
928
929 Event *e(new Event(**i, (*i)->getAbsoluteTime(), d + (*j)->getDuration()));
930 iterator ii(insert(e));
931 erase(i);
932 erase(j);
933
934 return collapseRestsForInsert(ii, desiredDuration);
935 }
936
937
938 Segment::iterator
insertSomething(iterator i,int duration,Event * modelEvent,bool tiedBack)939 SegmentNotationHelper::insertSomething(iterator i, int duration,
940 Event *modelEvent, bool tiedBack)
941 {
942 // Rules:
943 //
944 // 1. If we hit a bar line in the course of the intended inserted
945 // note, we should split the note rather than make the bar the
946 // wrong length. (Not implemented yet)
947 // [NB. This is now implemented, but not here -- see end of
948 // NoteInsertionCommand::modifySegment --cc, 20110428]
949 //
950 // 2. If there's nothing at the insertion point but rests (and
951 // enough of them to cover the entire duration of the new note),
952 // then we should insert the new note/rest literally and remove
953 // rests as appropriate. Rests should never prevent us from
954 // inserting what the user asked for.
955 //
956 // 3. If there are notes in the way of an inserted note, however,
957 // we split whenever "reasonable" and truncate our user's note if
958 // not reasonable to split. We can't always give users the Right
959 // Thing here, so to hell with them.
960
961 while (i != end() &&
962 ((*i)->getDuration() == 0 ||
963 !((*i)->isa(Note::EventType) || (*i)->isa(Note::EventRestType))))
964 ++i;
965
966 if (i == end()) {
967 return insertSingleSomething(i, duration, modelEvent, tiedBack);
968 }
969
970 // If there's a rest at the insertion position, merge it with any
971 // following rests, if available, until we have at least the
972 // duration of the new note.
973 i = collapseRestsForInsert(i, duration);
974
975 timeT existingDuration = (*i)->getNotationDuration();
976
977 // RG_DEBUG << "SegmentNotationHelper::insertSomething: asked to insert duration " << duration
978 // << " over event of duration " << existingDuration << ":";
979 RG_DEBUG << (**i);
980
981 if (duration == existingDuration) {
982
983 // 1. If the new note or rest is the same length as an
984 // existing note or rest at that position, chord the existing
985 // note or delete the existing rest and insert.
986
987 // RG_DEBUG << "Durations match; doing simple insert";
988
989 return insertSingleSomething(i, duration, modelEvent, tiedBack);
990
991 } else if (duration < existingDuration) {
992
993 // 2. If the new note or rest is shorter than an existing one,
994 // split the existing one and chord or replace the first part.
995
996 if ((*i)->isa(Note::EventType)) {
997
998 if (!isSplitValid(duration, existingDuration - duration)) {
999
1000 // RG_DEBUG << "Bad split, coercing new note";
1001
1002 // not reasonable to split existing note, so force new one
1003 // to same duration instead
1004 duration = (*i)->getNotationDuration();
1005
1006 } else {
1007 // RG_DEBUG << "Good split, splitting old event";
1008 splitIntoTie(i, duration);
1009 }
1010 } else if ((*i)->isa(Note::EventRestType)) {
1011
1012 // RG_DEBUG << "Found rest, splitting";
1013 iterator last = splitIntoTie(i, duration);
1014
1015 // Recover viability for the second half of any split rest
1016 // (we duck out of this if we find we're in a tupleted zone)
1017
1018 if (last != end() && !(*last)->has(BEAMED_GROUP_TUPLET_BASE)) {
1019 makeRestViable(last);
1020 }
1021 }
1022
1023 return insertSingleSomething(i, duration, modelEvent, tiedBack);
1024
1025 } else { // duration > existingDuration
1026
1027 // 3. If the new note is longer, split the new note so that
1028 // the first part is the same duration as the existing note or
1029 // rest, and recurse to step 1 with both the first and the
1030 // second part in turn.
1031
1032 bool needToSplit = true;
1033
1034 // special case: existing event is a rest, and it's at the end
1035 // of the segment
1036
1037 if ((*i)->isa(Note::EventRestType)) {
1038 iterator j;
1039 for (j = i; j != end(); ++j) {
1040 if ((*j)->isa(Note::EventType)) break;
1041 }
1042 if (j == end()) needToSplit = false;
1043 }
1044
1045 if (needToSplit) {
1046
1047 //!!! This is not quite right for rests. Because they
1048 //replace (rather than chording with) any events already
1049 //present, they don't need to be split in the case where
1050 //their duration spans several note-events. Worry about
1051 //that later, I guess. We're actually getting enough
1052 //is-note/is-rest decisions here to make it possibly worth
1053 //splitting this method into note and rest versions again
1054
1055 // RG_DEBUG << "Need to split new note";
1056
1057 i = insertSingleSomething
1058 (i, existingDuration, modelEvent, tiedBack);
1059
1060 if (modelEvent->isa(Note::EventType))
1061 (*i)->set<Bool>(TIED_FORWARD, true);
1062
1063 timeT insertedTime = (*i)->getAbsoluteTime();
1064 while (i != end() &&
1065 ((*i)->getNotationAbsoluteTime() <
1066 (insertedTime + existingDuration))) ++i;
1067
1068 return insertSomething
1069 (i, duration - existingDuration, modelEvent, true);
1070
1071 } else {
1072 // RG_DEBUG << "No need to split new note";
1073 return insertSingleSomething(i, duration, modelEvent, tiedBack);
1074 }
1075 }
1076 }
1077
1078 Segment::iterator
insertSingleSomething(iterator i,int duration,Event * modelEvent,bool tiedBack)1079 SegmentNotationHelper::insertSingleSomething(iterator i, int duration,
1080 Event *modelEvent, bool tiedBack)
1081 {
1082 timeT time;
1083 timeT notationTime;
1084 bool eraseI = false;
1085 timeT effectiveDuration(duration);
1086
1087 if (i == end()) {
1088 time = segment().getEndTime();
1089 notationTime = time;
1090 } else {
1091 time = (*i)->getAbsoluteTime();
1092 notationTime = (*i)->getNotationAbsoluteTime();
1093 if (modelEvent->isa(Note::EventRestType) ||
1094 (*i)->isa(Note::EventRestType)) eraseI = true;
1095 }
1096
1097 Event *e = new Event(*modelEvent, time, effectiveDuration,
1098 modelEvent->getSubOrdering(), notationTime);
1099
1100 // If the model event already has group info, I guess we'd better use it!
1101 if (!e->has(BEAMED_GROUP_ID)) {
1102 setInsertedNoteGroup(e, i);
1103 }
1104
1105 if (tiedBack && e->isa(Note::EventType)) {
1106 e->set<Bool>(TIED_BACKWARD, true);
1107 }
1108
1109 if (eraseI) {
1110 // erase i and all subsequent events with the same type and
1111 // absolute time
1112 timeT time((*i)->getAbsoluteTime());
1113 std::string type((*i)->getType());
1114 iterator j(i);
1115 while (j != end() && (*j)->getAbsoluteTime() == time) {
1116 ++j;
1117 if ((*i)->isa(type)) erase(i);
1118 i = j;
1119 }
1120 }
1121
1122 return insert(e);
1123 }
1124
1125 void
setInsertedNoteGroup(Event * e,iterator i)1126 SegmentNotationHelper::setInsertedNoteGroup(Event *e, iterator i)
1127 {
1128 // Formerly this was posited on the note being inserted between
1129 // two notes in the same group, but that's quite wrong-headed: we
1130 // want to place it in the same group as any existing note at the
1131 // same time, and otherwise leave it alone.
1132
1133 e->unset(BEAMED_GROUP_ID);
1134 e->unset(BEAMED_GROUP_TYPE);
1135
1136 while (isBeforeEndMarker(i) &&
1137 (!((*i)->isa(Note::EventRestType)) ||
1138 (*i)->has(BEAMED_GROUP_TUPLET_BASE)) &&
1139 (*i)->getNotationAbsoluteTime() == e->getAbsoluteTime()) {
1140
1141 if ((*i)->has(BEAMED_GROUP_ID)) {
1142
1143 string type = (*i)->get<String>(BEAMED_GROUP_TYPE);
1144 if (type != GROUP_TYPE_TUPLED && !(*i)->isa(Note::EventType)) {
1145 if ((*i)->isa(Note::EventRestType)) return;
1146 else {
1147 ++i;
1148 continue;
1149 }
1150 }
1151
1152 e->set<Int>(BEAMED_GROUP_ID, (*i)->get<Int>(BEAMED_GROUP_ID));
1153 e->set<String>(BEAMED_GROUP_TYPE, type);
1154
1155 if ((*i)->has(BEAMED_GROUP_TUPLET_BASE)) {
1156
1157 e->set<Int>(BEAMED_GROUP_TUPLET_BASE,
1158 (*i)->get<Int>(BEAMED_GROUP_TUPLET_BASE));
1159 e->set<Int>(BEAMED_GROUP_TUPLED_COUNT,
1160 (*i)->get<Int>(BEAMED_GROUP_TUPLED_COUNT));
1161 e->set<Int>(BEAMED_GROUP_UNTUPLED_COUNT,
1162 (*i)->get<Int>(BEAMED_GROUP_UNTUPLED_COUNT));
1163 }
1164
1165 return;
1166 }
1167
1168 ++i;
1169 }
1170 }
1171
1172
1173 Segment::iterator
insertClef(timeT absoluteTime,Clef clef)1174 SegmentNotationHelper::insertClef(timeT absoluteTime, Clef clef)
1175 {
1176 return insert(clef.getAsEvent(absoluteTime));
1177 }
1178
1179
1180 Segment::iterator
insertSymbol(timeT absoluteTime,Symbol symbol)1181 SegmentNotationHelper::insertSymbol(timeT absoluteTime, Symbol symbol)
1182 {
1183 return insert(symbol.getAsEvent(absoluteTime));
1184 }
1185
1186
1187 Segment::iterator
insertKey(timeT absoluteTime,Key key)1188 SegmentNotationHelper::insertKey(timeT absoluteTime, Key key)
1189 {
1190 return insert(key.getAsEvent(absoluteTime));
1191 }
1192
1193
1194 Segment::iterator
insertText(timeT absoluteTime,Text text)1195 SegmentNotationHelper::insertText(timeT absoluteTime, Text text)
1196 {
1197 Segment::iterator i = insert(text.getAsEvent(absoluteTime));
1198
1199 // If text is lyric, invalidateVerseCount() have to be called to avoid a
1200 // crash when opening the lyric editor if the lyric is on a still
1201 // non-existent verse(fix bug #1598)
1202 if (text.getTextType() == Text::Lyric) segment().invalidateVerseCount();
1203
1204 return i;
1205 }
1206
1207
1208 void
deleteNote(Event * e,bool collapseRest)1209 SegmentNotationHelper::deleteNote(Event *e, bool collapseRest)
1210 {
1211 iterator i = segment().findSingle(e);
1212
1213 if (i == end()) return;
1214
1215 if ((*i)->has(TIED_BACKWARD) && (*i)->get<Bool>(TIED_BACKWARD)) {
1216 iterator j = getPreviousAdjacentNote(i, segment().getStartTime(),
1217 true, false);
1218 if (j != end()) {
1219 (*j)->unset(TIED_FORWARD); // don't even check if it has it set
1220 }
1221 }
1222
1223 if ((*i)->has(TIED_FORWARD) && (*i)->get<Bool>(TIED_FORWARD)) {
1224 iterator j = getNextAdjacentNote(i, true, false);
1225 if (j != end()) {
1226 (*j)->unset(TIED_BACKWARD); // don't even check if it has it set
1227 }
1228 }
1229
1230 // If any notes start at the same time as this one but end first,
1231 // or start after this one starts but before it ends, then we go
1232 // for the delete-event-and-normalize-rests option. Otherwise
1233 // (the notationally simpler case) we go for the
1234 // replace-note-by-rest option. We still lose in the case where
1235 // another note starts before this one, overlaps it, but then also
1236 // ends before it does -- but I think we can live with that.
1237
1238 iterator j = i;
1239 timeT dur = (*i)->getGreaterDuration();
1240 timeT endTime = (*i)->getAbsoluteTime() + dur;
1241
1242 while (j != end() && (*j)->getAbsoluteTime() < endTime) {
1243
1244 bool complicatedOverlap = false;
1245
1246 if ((*j)->getAbsoluteTime() != (*i)->getAbsoluteTime()) {
1247 complicatedOverlap = true;
1248 } else if (((*j)->getAbsoluteTime() + (*j)->getDuration()) < endTime) {
1249 complicatedOverlap = true;
1250 }
1251
1252 if (complicatedOverlap) {
1253 timeT startTime = (*i)->getAbsoluteTime();
1254 segment().erase(i);
1255 segment().normalizeRests(startTime, endTime);
1256 return;
1257 }
1258
1259 ++j;
1260 }
1261
1262 if (noteIsInChord(e)) {
1263
1264 erase(i);
1265
1266 } else {
1267 if (e->has(BEAMED_GROUP_TUPLET_BASE)==false){
1268 // replace with a rest
1269 Event *newRest = new Event(Note::EventRestType,
1270 e->getAbsoluteTime(), dur,
1271 Note::EventRestSubOrdering);
1272 insert(newRest);
1273 erase(i);
1274 // collapse the new rest
1275 if (collapseRest) {
1276 bool dummy;
1277 collapseRestsIfValid(newRest, dummy);
1278 }
1279
1280 }else{
1281 int untupled = e->get<Int>(BEAMED_GROUP_UNTUPLED_COUNT);
1282 iterator begin, end;
1283 int count = findBorderTuplet(i, begin, end);
1284 if (count>1){
1285 // insert rest instead of note
1286 string type = (*i)->getType();
1287 int note_type = (*i)->get<Int>(NOTE_TYPE);
1288 insertRest((*i)->getAbsoluteTime(), Note(note_type,0));
1289 }else {
1290 // replace with a rest
1291 timeT time = (*begin)->getAbsoluteTime();
1292 Event *newRest = new Event(Note::EventRestType,
1293 (*begin)->getAbsoluteTime(),
1294 (*begin)->getDuration()*untupled,
1295 Note::EventRestSubOrdering);
1296 segment().erase(begin, end);
1297 insert(newRest);
1298 timeT startTime = segment().getStartTime();
1299 if (time==startTime){
1300 begin=segment().findTime(startTime);
1301 (*begin)->unset(BEAMED_GROUP_ID);
1302 (*begin)->unset(BEAMED_GROUP_TYPE);
1303 (*begin)->unset(BEAMED_GROUP_TUPLET_BASE);
1304 (*begin)->unset(BEAMED_GROUP_TUPLED_COUNT);
1305 (*begin)->unset(BEAMED_GROUP_UNTUPLED_COUNT);
1306 }
1307
1308 // collapse the new rest
1309 if (collapseRest) {
1310 bool dummy;
1311 collapseRestsIfValid(newRest, dummy);
1312 }
1313 }
1314 }
1315 }
1316 }
1317
1318 bool
deleteRest(Event * e)1319 SegmentNotationHelper::deleteRest(Event *e)
1320 {
1321 bool collapseForward;
1322 return collapseRestsIfValid(e, collapseForward);
1323 }
1324
1325 bool
deleteEvent(Event * e,bool collapseRest)1326 SegmentNotationHelper::deleteEvent(Event *e, bool collapseRest)
1327 {
1328 bool res = true;
1329
1330 if (e->isa(Note::EventType)) deleteNote(e, collapseRest);
1331 else if (e->isa(Note::EventRestType)) res = deleteRest(e);
1332 else {
1333 // just plain delete
1334 iterator i = segment().findSingle(e);
1335 if (i != end()) erase(i);
1336 }
1337
1338 return res;
1339 }
1340
1341
1342 bool
hasEffectiveDuration(iterator i)1343 SegmentNotationHelper::hasEffectiveDuration(iterator i)
1344 {
1345 bool hasDuration = ((*i)->getDuration() > 0);
1346
1347 if ((*i)->isa(Note::EventType)) {
1348 iterator i0(i);
1349 if (++i0 != end() &&
1350 (*i0)->isa(Note::EventType) &&
1351 (*i0)->getNotationAbsoluteTime() ==
1352 (*i)->getNotationAbsoluteTime()) {
1353 // we're in a chord or something
1354 hasDuration = false;
1355 }
1356 }
1357
1358 return hasDuration;
1359 }
1360
1361
1362 void
makeBeamedGroup(timeT from,timeT to,string type)1363 SegmentNotationHelper::makeBeamedGroup(timeT from, timeT to, string type)
1364 {
1365 makeBeamedGroupAux(segment().findTime(from), segment().findTime(to),
1366 type, false);
1367 }
1368
1369 void
makeBeamedGroup(iterator from,iterator to,string type)1370 SegmentNotationHelper::makeBeamedGroup(iterator from, iterator to, string type)
1371 {
1372 makeBeamedGroupAux
1373 ((from == end()) ? from : segment().findTime((*from)->getAbsoluteTime()),
1374 (to == end()) ? to : segment().findTime((*to )->getAbsoluteTime()),
1375 type, false);
1376 }
1377
1378 void
makeBeamedGroupExact(iterator from,iterator to,string type)1379 SegmentNotationHelper::makeBeamedGroupExact(iterator from, iterator to, string type)
1380 {
1381 makeBeamedGroupAux(from, to, type, true);
1382 }
1383
1384 void
makeBeamedGroupAux(iterator from,iterator to,string type,bool groupGraces)1385 SegmentNotationHelper::makeBeamedGroupAux(iterator from, iterator to,
1386 string type, bool groupGraces)
1387 {
1388 // RG_DEBUG << "SegmentNotationHelper::makeBeamedGroupAux: type " << type;
1389 // if (from == to) RG_DEBUG << "from == to";
1390
1391 int groupId = segment().getNextId();
1392 bool beamedSomething = false;
1393
1394 for (iterator i = from; i != to; ++i) {
1395 // RG_DEBUG << "looking at " << (*i)->getType() << " at " << (*i)->getAbsoluteTime();
1396
1397 // don't permit ourselves to change the type of an
1398 // already-grouped event here
1399 if ((*i)->has(BEAMED_GROUP_TYPE) &&
1400 (*i)->get<String>(BEAMED_GROUP_TYPE) != GROUP_TYPE_BEAMED) {
1401 continue;
1402 }
1403
1404 if (!groupGraces) {
1405 if ((*i)->has(IS_GRACE_NOTE) &&
1406 (*i)->get<Bool>(IS_GRACE_NOTE)) {
1407 continue;
1408 }
1409 }
1410
1411 // don't beam anything longer than a quaver unless it's
1412 // between beamed quavers -- in which case marking it as
1413 // beamed will ensure that it gets re-stemmed appropriately
1414
1415 if ((*i)->isa(Note::EventType) &&
1416 (*i)->getNotationDuration() >= Note(Note::Crotchet).getDuration()) {
1417 // RG_DEBUG << "too long";
1418 if (!beamedSomething) continue;
1419 iterator j = i;
1420 bool somethingLeft = false;
1421 while (++j != to) {
1422 if ((*j)->getType() == Note::EventType &&
1423 (*j)->getNotationAbsoluteTime() > (*i)->getNotationAbsoluteTime() &&
1424 (*j)->getNotationDuration() < Note(Note::Crotchet).getDuration()) {
1425 somethingLeft = true;
1426 break;
1427 }
1428 }
1429 if (!somethingLeft) continue;
1430 }
1431
1432 // RG_DEBUG << "beaming it";
1433 (*i)->set<Int>(BEAMED_GROUP_ID, groupId);
1434 (*i)->set<String>(BEAMED_GROUP_TYPE, type);
1435 }
1436 }
1437
1438 void
makeTupletGroup(timeT t,int untupled,int tupled,timeT unit)1439 SegmentNotationHelper::makeTupletGroup(timeT t, int untupled, int tupled,
1440 timeT unit)
1441 {
1442 int groupId = segment().getNextId();
1443
1444 RG_DEBUG << "SegmentNotationHelper::makeTupletGroup: time " << t << ", unit "<< unit << ", params " << untupled << "/" << tupled << ", id " << groupId;
1445
1446 list<Event *> toInsert;
1447 list<iterator> toErase;
1448 timeT notationTime = t;
1449 timeT fillWithRestsTo = t;
1450 bool haveStartNotationTime = false;
1451
1452 for (iterator i = segment().findTime(t); i != end(); ++i) {
1453
1454 if (!haveStartNotationTime) {
1455 notationTime = (*i)->getNotationAbsoluteTime();
1456 fillWithRestsTo = notationTime + (untupled * unit);
1457 haveStartNotationTime = true;
1458 }
1459
1460 if ((*i)->getNotationAbsoluteTime() >=
1461 notationTime + (untupled * unit)) break;
1462
1463 timeT offset = (*i)->getNotationAbsoluteTime() - notationTime;
1464 timeT duration = (*i)->getNotationDuration();
1465
1466 if ((*i)->isa(Note::EventRestType) &&
1467 ((offset + duration) > (untupled * unit))) {
1468 fillWithRestsTo = std::max(fillWithRestsTo,
1469 notationTime + offset + duration);
1470 duration = (untupled * unit) - offset;
1471 if (duration <= 0) {
1472 toErase.push_back(i);
1473 continue;
1474 }
1475 }
1476
1477 Event *e = new Event(**i,
1478 notationTime + (offset * tupled / untupled),
1479 duration * tupled / untupled);
1480
1481 RG_DEBUG << "SegmentNotationHelper::makeTupletGroup: made event at time " << e->getAbsoluteTime() << ", duration " << e->getDuration();
1482
1483 e->set<Int>(BEAMED_GROUP_ID, groupId);
1484 e->set<String>(BEAMED_GROUP_TYPE, GROUP_TYPE_TUPLED);
1485
1486 e->set<Int>(BEAMED_GROUP_TUPLET_BASE, unit);
1487 e->set<Int>(BEAMED_GROUP_TUPLED_COUNT, tupled);
1488 e->set<Int>(BEAMED_GROUP_UNTUPLED_COUNT, untupled);
1489
1490 toInsert.push_back(e);
1491 toErase.push_back(i);
1492 }
1493
1494 for (list<iterator>::iterator i = toErase.begin();
1495 i != toErase.end(); ++i) {
1496 segment().erase(*i);
1497 }
1498
1499 for (list<Event *>::iterator i = toInsert.begin();
1500 i != toInsert.end(); ++i) {
1501 segment().insert(*i);
1502 }
1503
1504 if (haveStartNotationTime) {
1505 segment().fillWithRests(notationTime + (tupled * unit),
1506 fillWithRestsTo);
1507 }
1508 }
1509
1510
1511
1512
1513 void
unbeam(timeT from,timeT to)1514 SegmentNotationHelper::unbeam(timeT from, timeT to)
1515 {
1516 unbeamAux(segment().findTime(from), segment().findTime(to));
1517 }
1518
1519 void
unbeam(iterator from,iterator to)1520 SegmentNotationHelper::unbeam(iterator from, iterator to)
1521 {
1522 unbeamAux
1523 ((from == end()) ? from : segment().findTime((*from)->getAbsoluteTime()),
1524 (to == end()) ? to : segment().findTime((*to )->getAbsoluteTime()));
1525 }
1526
1527 void
unbeamAux(iterator from,iterator to)1528 SegmentNotationHelper::unbeamAux(iterator from, iterator to)
1529 {
1530 for (iterator i = from; i != to; ++i) {
1531 (*i)->unset(BEAMED_GROUP_ID);
1532 (*i)->unset(BEAMED_GROUP_TYPE);
1533 (*i)->clearNonPersistentProperties();
1534 }
1535 }
1536
1537
1538
1539 /*
1540
1541 Auto-beaming code derived from X11 Rosegarden's ItemListAutoBeam
1542 and ItemListAutoBeamSub in editor/src/ItemList.c.
1543
1544 */
1545
1546 void
autoBeam(timeT from,timeT to,string type)1547 SegmentNotationHelper::autoBeam(timeT from, timeT to, string type)
1548 {
1549 /*
1550 RG_DEBUG << "autoBeam from " << from << " to " << to << " on segment start time " << segment().getStartTime() << ", end time " << segment().getEndTime() << ", end marker " << segment().getEndMarkerTime();
1551 */
1552
1553 autoBeam(segment().findTime(from), segment().findTime(to), type);
1554 }
1555
1556 void
autoBeam(iterator from,iterator to,string type)1557 SegmentNotationHelper::autoBeam(iterator from, iterator to, string type)
1558 {
1559 // This can only manage whole bars at a time, and it will split
1560 // the from-to range out to encompass the whole bars in which they
1561 // each occur
1562
1563 if (!segment().getComposition()) {
1564 RG_DEBUG << "WARNING: SegmentNotationHelper::autoBeam requires Segment be in a Composition";
1565 return;
1566 }
1567
1568 if (!segment().isBeforeEndMarker(from)) return;
1569
1570 unbeam(from, to);
1571
1572 Composition *comp = segment().getComposition();
1573
1574 // Get bar range for selection. Since this is inclusive, we subtract 1 from
1575 // the "to" time to ensure we don't get an additional bar (bug #703).
1576
1577 int fromBar = comp->getBarNumber((*from)->getAbsoluteTime());
1578 int toBar = comp->getBarNumber(segment().isBeforeEndMarker(to) ?
1579 (*to)->getAbsoluteTime() - 1 :
1580 segment().getEndMarkerTime() - 1);
1581
1582 for (int barNo = fromBar; barNo <= toBar; ++barNo) {
1583
1584 std::pair<timeT, timeT> barRange = comp->getBarRange(barNo);
1585 iterator barStart = segment().findTime(barRange.first);
1586 iterator barEnd = segment().findTime(barRange.second);
1587
1588 // Make sure we're examining the notes defined to be within
1589 // the bar in notation terms rather than raw terms
1590
1591 while (barStart != segment().end() &&
1592 (*barStart)->getNotationAbsoluteTime() < barRange.first) ++barStart;
1593
1594 iterator scooter = barStart;
1595 if (barStart != segment().end()) {
1596 while (scooter != segment().begin()) {
1597 --scooter;
1598 if ((*scooter)->getNotationAbsoluteTime() < barRange.first) break;
1599 barStart = scooter;
1600 }
1601 }
1602
1603 while (barEnd != segment().end() &&
1604 (*barEnd)->getNotationAbsoluteTime() < barRange.second) ++barEnd;
1605
1606 scooter = barEnd;
1607 if (barEnd != segment().end()) {
1608 while (scooter != segment().begin()) {
1609 --scooter;
1610 if ((*scooter)->getNotationAbsoluteTime() < barRange.second) break;
1611 barEnd = scooter;
1612 }
1613 }
1614
1615 TimeSignature timeSig =
1616 segment().getComposition()->getTimeSignatureAt(barRange.first);
1617
1618 autoBeamBar(barStart, barEnd, timeSig, type);
1619 }
1620 }
1621
1622
1623 /*
1624
1625 Derived from (and no less mystifying than) X11 Rosegarden's
1626 ItemListAutoBeamSub in editor/src/ItemList.c.
1627
1628 "Today I want to celebrate "Montreal" by Autechre, because of
1629 its sleep-disturbing aura, because it sounds like the sort of music
1630 which would be going around in the gunman's head as he trains a laser
1631 sight into your bedroom through the narrow gap in your curtains and
1632 dances the little red dot around nervously on your wall."
1633
1634 */
1635
1636 void
autoBeamBar(iterator from,iterator to,TimeSignature tsig,string type)1637 SegmentNotationHelper::autoBeamBar(iterator from, iterator to,
1638 TimeSignature tsig, string type)
1639 {
1640 int num = tsig.getNumerator();
1641 int denom = tsig.getDenominator();
1642
1643 timeT average;
1644 timeT minimum = 0;
1645
1646 // If the denominator is 2 or 4, beam in twos (3/4, 6/2 etc).
1647
1648 if (denom == 2 || denom == 4) {
1649
1650 if (num % 3) {
1651 average = Note(Note::Quaver).getDuration();
1652 } else {
1653 average = Note(Note::Semiquaver).getDuration();
1654 minimum = average;
1655 }
1656
1657 } else {
1658
1659 if (num % 3 == 0 && denom == 8) { // special hack for 6/8, 12/8 etc...
1660 average = 3 * Note(Note::Quaver).getDuration();
1661
1662 } else {
1663 // find a divisor (at least 2) for the numerator
1664 int n = 2;
1665 while (num >= n && num % n != 0) ++n;
1666 average = n * Note(Note::Semiquaver).getDuration();
1667 }
1668 }
1669
1670 if (minimum == 0) minimum = average / 2;
1671 if (denom > 4) average /= 2;
1672
1673 autoBeamBar(from, to, average, minimum, average * 4, type);
1674 }
1675
1676
1677 void
autoBeamBar(iterator from,iterator to,timeT average,timeT minimum,timeT maximum,string type)1678 SegmentNotationHelper::autoBeamBar(iterator from, iterator to,
1679 timeT average, timeT minimum,
1680 timeT maximum, string type)
1681 {
1682 timeT accumulator = 0;
1683 timeT crotchet = Note(Note::Crotchet).getDuration();
1684 timeT semiquaver = Note(Note::Semiquaver).getDuration();
1685
1686 iterator e = end();
1687
1688 for (iterator i = from; i != to && i != e; ++i) {
1689
1690 // only look at one note in each chord, and at rests
1691 if (!hasEffectiveDuration(i)) continue;
1692 timeT idur = (*i)->getNotationDuration();
1693
1694 if (accumulator % average == 0 && // "beamable duration" threshold
1695 idur < crotchet) {
1696
1697 // This could be the start of a beamed group. We maintain
1698 // two sorts of state as we scan along here: data about
1699 // the best group we've found so far (beamDuration,
1700 // prospective, k etc), and data about the items we're
1701 // looking at (count, beamable, longerThanDemi etc) just
1702 // in case we find a better candidate group before the
1703 // eight-line conditional further down makes us give up
1704 // the search, beam our best shot, and start again.
1705
1706 // I hope this is clear.
1707
1708 iterator k = end(); // best-so-far last item in group;
1709 // end() indicates that we've found nothing
1710
1711 timeT tmin = minimum;
1712 timeT count = 0;
1713 timeT prospective = 0;
1714 timeT beamDuration = 0;
1715
1716 int beamable = 0;
1717 int longerThanDemi = 0;
1718
1719 for (iterator j = i; j != to; ++j) {
1720
1721 if (!hasEffectiveDuration(j)) continue;
1722 timeT jdur = (*j)->getNotationDuration();
1723
1724 if ((*j)->isa(Note::EventType)) {
1725 if (jdur < crotchet) ++beamable;
1726 if (jdur >= semiquaver) ++longerThanDemi;
1727 }
1728
1729 count += jdur;
1730
1731 if (count % tmin == 0) {
1732
1733 k = j;
1734 beamDuration = count;
1735 prospective = accumulator + count;
1736
1737 // found a group; now accept only double this
1738 // group's length for a better one
1739 tmin *= 2;
1740 }
1741
1742 // Stop scanning and make the group if our scan has
1743 // reached the maximum length of beamed group, we have
1744 // more than 4 semis or quavers, we're at the end of
1745 // our run, the next chord is longer than the current
1746 // one, or there's a rest ahead. (We used to check
1747 // that the rest had non-zero duration, but the new
1748 // quantization regime should ensure that this doesn't
1749 // happen unless we really are displaying completely
1750 // unquantized data in which case anything goes.)
1751
1752 iterator jnext(j);
1753
1754 if ((count > maximum)
1755 || (longerThanDemi > 4)
1756 || (++jnext == to)
1757 || ((*j )->isa(Note::EventType) &&
1758 (*jnext)->isa(Note::EventType) &&
1759 (*jnext)->getNotationDuration() > jdur)
1760 || ((*jnext)->isa(Note::EventRestType))) {
1761
1762 if (k != end() && beamable >= 2) {
1763
1764 iterator knext(k);
1765 ++knext;
1766
1767 makeBeamedGroup(i, knext, type);
1768 }
1769
1770 // If this group is at least as long as the check
1771 // threshold ("average"), its length must be a
1772 // multiple of the threshold and hence we can
1773 // continue scanning from the end of the group
1774 // without losing the modulo properties of the
1775 // accumulator.
1776
1777 if (k != end() && beamDuration >= average) {
1778
1779 i = k;
1780 accumulator = prospective;
1781
1782 } else {
1783
1784 // Otherwise, we continue from where we were.
1785 // (This must be safe because we can't get
1786 // another group starting half-way through, as
1787 // we know the last group is shorter than the
1788 // check threshold.)
1789
1790 accumulator += idur;
1791 }
1792
1793 break;
1794 }
1795 }
1796 } else {
1797
1798 accumulator += idur;
1799 }
1800 }
1801 }
1802
1803
1804 // based on X11 Rosegarden's GuessItemListClef in editor/src/MidiIn.c
1805
1806 Clef
guessClef(iterator from,iterator to)1807 SegmentNotationHelper::guessClef(iterator from, iterator to)
1808 {
1809 long totalHeight = 0;
1810 int noteCount = 0;
1811
1812 // just the defaults:
1813 Clef clef;
1814 Key key;
1815
1816 for (iterator i = from; i != to; ++i) {
1817 if ((*i)->isa(Note::EventType)) {
1818 //!!! NotationDisplayPitch p((*i)->get<Int>(PITCH), clef, key);
1819 try {
1820 Pitch p(**i);
1821 totalHeight += p.getHeightOnStaff(clef, key);
1822 ++noteCount;
1823 } catch (const Exception &e) {
1824 // no pitch in note
1825 }
1826 }
1827 }
1828
1829 if (noteCount == 0) return Clef(Clef::Treble);
1830
1831 int average = totalHeight / noteCount;
1832
1833 // Let's try these new extents and see how the fare. Ideally these should
1834 // pick plain treble and bass clefs a reasonable amount of the time, and not
1835 // be too prone to picking transposed clefs, while picking transposed clefs
1836 // when really necessary.
1837 if (average < -12) return Clef(Clef::Bass, -2);
1838 else if (average < - 9) return Clef(Clef::Bass, -1);
1839 else if (average < -6) return Clef(Clef::Bass);
1840 else if (average < -3) return Clef(Clef::Tenor);
1841 else if (average < 1) return Clef(Clef::Alto);
1842 else if (average < 12) return Clef(Clef::Treble);
1843 else if (average < 24) return Clef(Clef::Treble, 1);
1844 else if (average < 48) return Clef(Clef::Treble, 2);
1845 else return Clef(Clef::Treble);
1846 }
1847
1848
1849 bool
removeRests(timeT time,timeT & duration,bool testOnly)1850 SegmentNotationHelper::removeRests(timeT time, timeT &duration, bool testOnly)
1851 {
1852 Event dummy("dummy", time, 0, MIN_SUBORDERING);
1853
1854 RG_DEBUG << "SegmentNotationHelper::removeRests(" << time
1855 << ", " << duration << ")";
1856
1857 iterator from = segment().lower_bound(&dummy);
1858
1859 // ignore any number of zero-duration events at the start
1860 while (from != segment().end() &&
1861 (*from)->getAbsoluteTime() == time &&
1862 (*from)->getDuration() == 0) ++from;
1863 if (from == segment().end()) return false;
1864
1865 iterator to = from;
1866
1867 timeT eventTime = time;
1868 timeT finalTime = time + duration;
1869
1870 //!!! We should probably not use an accumulator, but instead
1871 // calculate based on each event's absolute time + duration --
1872 // in case we've somehow ended up with overlapping rests
1873
1874 // Iterate on events, checking if all are rests
1875 //
1876 while ((eventTime < finalTime) && (to != end())) {
1877
1878 if (!(*to)->isa(Note::EventRestType)) {
1879 // a non-rest was found
1880 duration = (*to)->getAbsoluteTime() - time;
1881 return false;
1882 }
1883
1884 timeT nextEventDuration = (*to)->getDuration();
1885
1886 if ((eventTime + nextEventDuration) <= finalTime) {
1887 eventTime += nextEventDuration;
1888 duration = eventTime - time;
1889 } else break;
1890
1891 ++to;
1892 }
1893
1894 bool checkLastRest = false;
1895 iterator lastEvent = to;
1896
1897 if (eventTime < finalTime) {
1898 // shorten last event's duration, if possible
1899
1900
1901 if (lastEvent == end()) {
1902 duration = segment().getEndTime() - time;
1903 return false;
1904 }
1905
1906 if (!testOnly) {
1907 // can't safely change the absolute time of an event in a segment
1908 Event *newEvent = new Event(**lastEvent, finalTime,
1909 (*lastEvent)->getDuration() -
1910 (finalTime - eventTime));
1911 duration = finalTime + (*lastEvent)->getDuration() - time;
1912 bool same = (from == to);
1913 segment().erase(lastEvent);
1914 to = lastEvent = segment().insert(newEvent);
1915 if (same) from = to;
1916 checkLastRest = true;
1917 }
1918 }
1919
1920 if (testOnly) return true;
1921
1922 segment().erase(from, to);
1923
1924 // we must defer calling makeRestViable() until after erase,
1925 // because it will invalidate 'to'
1926 //
1927 if (checkLastRest) makeRestViable(lastEvent);
1928
1929 return true;
1930 }
1931
1932
1933 void
collapseRestsAggressively(timeT startTime,timeT endTime)1934 SegmentNotationHelper::collapseRestsAggressively(timeT startTime,
1935 timeT endTime)
1936 {
1937 reorganizeRests(startTime, endTime,
1938 &SegmentNotationHelper::mergeContiguousRests);
1939 }
1940
1941
1942 void
reorganizeRests(timeT startTime,timeT endTime,Reorganizer reorganizer)1943 SegmentNotationHelper::reorganizeRests(timeT startTime, timeT endTime,
1944 Reorganizer reorganizer)
1945 {
1946 iterator ia = segment().findTime(startTime);
1947 iterator ib = segment().findTime(endTime);
1948
1949 if (ia == end()) return;
1950
1951 std::vector<iterator> erasable;
1952 std::vector<Event *> insertable;
1953
1954 // RG_DEBUG << "SegmentNotationHelper::reorganizeRests (" << startTime << ","
1955 // << endTime << ")";
1956
1957 for (iterator i = ia; i != ib; ++i) {
1958
1959 if ((*i)->isa(Note::EventRestType)) {
1960
1961 timeT startTime = (*i)->getAbsoluteTime();
1962 timeT duration = 0;
1963 iterator j = i;
1964
1965 for ( ; j != ib; ++j) {
1966
1967 if ((*j)->isa(Note::EventRestType)) {
1968 duration += (*j)->getDuration();
1969 erasable.push_back(j);
1970 } else break;
1971 }
1972
1973 (this->*reorganizer)(startTime, duration, insertable);
1974 if (j == ib) break;
1975 i = j;
1976 }
1977 }
1978
1979 for (size_t ei = 0; ei < erasable.size(); ++ei)
1980 segment().erase(erasable[ei]);
1981
1982 for (size_t ii = 0; ii < insertable.size(); ++ii)
1983 segment().insert(insertable[ii]);
1984 }
1985
1986
1987 void
normalizeContiguousRests(timeT startTime,timeT duration,std::vector<Event * > & toInsert)1988 SegmentNotationHelper::normalizeContiguousRests(timeT startTime,
1989 timeT duration,
1990 std::vector<Event *> &toInsert)
1991 {
1992 TimeSignature ts;
1993 timeT sigTime =
1994 segment().getComposition()->getTimeSignatureAt(startTime, ts);
1995
1996 // RG_DEBUG << "SegmentNotationHelper::normalizeContiguousRests:"
1997 // << " startTime = " << startTime << ", duration = "
1998 // << duration;
1999
2000 DurationList dl;
2001 ts.getDurationListForInterval(dl, duration, startTime - sigTime);
2002
2003 timeT acc = startTime;
2004
2005 for (DurationList::iterator i = dl.begin(); i != dl.end(); ++i) {
2006 Event *e = new Event(Note::EventRestType, acc, *i,
2007 Note::EventRestSubOrdering);
2008 toInsert.push_back(e);
2009 acc += *i;
2010 }
2011 }
2012
2013
2014 void
mergeContiguousRests(timeT startTime,timeT duration,std::vector<Event * > & toInsert)2015 SegmentNotationHelper::mergeContiguousRests(timeT startTime,
2016 timeT duration,
2017 std::vector<Event *> &toInsert)
2018 {
2019 while (duration > 0) {
2020
2021 timeT d = Note::getNearestNote(duration).getDuration();
2022
2023 Event *e = new Event(Note::EventRestType, startTime, d,
2024 Note::EventRestSubOrdering);
2025 toInsert.push_back(e);
2026
2027 startTime += d;
2028 duration -= d;
2029 }
2030 }
2031
2032
2033 Segment::iterator
collapseNoteAggressively(Event * note,timeT rangeEnd)2034 SegmentNotationHelper::collapseNoteAggressively(Event *note,
2035 timeT rangeEnd)
2036 {
2037 iterator i = segment().findSingle(note);
2038 if (i == end()) return end();
2039
2040 iterator j = getNextAdjacentNote(i, true, true);
2041
2042 if (j == end() || (*j)->getNotationAbsoluteTime() >= rangeEnd) return end();
2043 if ((*i)->maskedInTrigger() != (*j)->maskedInTrigger()) {
2044 // They should be just tied, just not merged.
2045 (*i)->set<Bool>(TIED_FORWARD, true);
2046 (*j)->set<Bool>(TIED_BACKWARD, true);
2047 return end();
2048 }
2049
2050 timeT iEnd = (*i)->getNotationAbsoluteTime() + (*i)->getNotationDuration();
2051 timeT jEnd = (*j)->getNotationAbsoluteTime() + (*j)->getNotationDuration();
2052
2053 Event *newEvent = new Event
2054 (**i, (*i)->getNotationAbsoluteTime(),
2055 (std::max(iEnd, jEnd) - (*i)->getNotationAbsoluteTime()));
2056
2057 newEvent->unset(TIED_BACKWARD);
2058 newEvent->unset(TIED_FORWARD);
2059
2060 // Unset any tied notes for these since this will trigger extra
2061 // deselecting fro mthe selection set.
2062 (*i)->unset(TIED_BACKWARD);
2063 (*i)->unset(TIED_FORWARD);
2064
2065 (*j)->unset(TIED_BACKWARD);
2066 (*j)->unset(TIED_FORWARD);
2067
2068 segment().erase(i);
2069 segment().erase(j);
2070 return segment().insert(newEvent);
2071 }
2072
2073 std::pair<Event *, Event *>
splitPreservingPerformanceTimes(Event * e,timeT q1)2074 SegmentNotationHelper::splitPreservingPerformanceTimes(Event *e, timeT q1)
2075 {
2076 timeT ut = e->getAbsoluteTime();
2077 timeT ud = e->getDuration();
2078 timeT qt = e->getNotationAbsoluteTime();
2079 timeT qd = e->getNotationDuration();
2080
2081 timeT u1 = (qt + q1) - ut;
2082 timeT u2 = (ut + ud) - (qt + q1);
2083
2084 RG_DEBUG << "splitPreservingPerformanceTimes: (ut,ud) (" << ut << "," << ud << "), (qt,qd) (" << qt << "," << qd << ") q1 " << q1 << ", u1 " << u1 << ", u2 " << u2;
2085
2086 if (u1 <= 0 || u2 <= 0) { // can't do a meaningful split
2087 return std::pair<Event *, Event *>(0, nullptr);
2088 }
2089
2090 Event *e1 = new Event(*e, ut, u1, e->getSubOrdering(), qt, q1);
2091 Event *e2 = new Event(*e, ut + u1, u2, e->getSubOrdering(), qt + q1, qd - q1);
2092
2093 e1->set<Bool>(TIED_FORWARD, true);
2094 e2->set<Bool>(TIED_BACKWARD, true);
2095
2096 return std::pair<Event *, Event *>(e1, e2);
2097 }
2098
2099 void
deCounterpoint(timeT startTime,timeT endTime)2100 SegmentNotationHelper::deCounterpoint(timeT startTime, timeT endTime)
2101 {
2102 // How this should work: scan through the range and, for each
2103 // note "n" found, if the next following note "m" not at the same
2104 // absolute time as n starts before n ends, then split n at m-n.
2105
2106 // also, if m starts at the same time as n but has a different
2107 // duration, we should split the longer of n and m at the shorter
2108 // one's duration.
2109
2110 for (Segment::iterator i = segment().findTime(startTime);
2111 segment().isBeforeEndMarker(i); ) {
2112
2113 timeT t = (*i)->getAbsoluteTime();
2114 if (t >= endTime) break;
2115
2116 #ifdef DEBUG_DECOUNTERPOINT
2117 RG_DEBUG << "SegmentNotationHelper::deCounterpoint: event at " << (*i)->getAbsoluteTime() << " notation " << (*i)->getNotationAbsoluteTime() << ", duration " << (*i)->getNotationDuration() << ", type " << (*i)->getType();
2118 #endif
2119
2120 if (!(*i)->isa(Note::EventType)) { ++i; continue; }
2121
2122 timeT ti = (*i)->getNotationAbsoluteTime();
2123 timeT di = (*i)->getNotationDuration();
2124
2125 #ifdef DEBUG_DECOUNTERPOINT
2126 RG_DEBUG<<"looking for k";
2127 #endif
2128
2129 // find next event that's either at a different time or (if a
2130 // note) has a different duration
2131 Segment::iterator k = i;
2132 while (segment().isBeforeEndMarker(k)) {
2133 if ((*k)->isa(Note::EventType)) {
2134 #ifdef DEBUG_DECOUNTERPOINT
2135 RG_DEBUG<<"abstime "<<(*k)->getAbsoluteTime();
2136 #endif
2137 if ((*k)->getNotationAbsoluteTime() > ti ||
2138 (*k)->getNotationDuration() != di) break;
2139 }
2140 ++k;
2141 }
2142
2143 if (!segment().isBeforeEndMarker(k)) break; // no split, no more notes
2144
2145 #ifdef DEBUG_DECOUNTERPOINT
2146 RG_DEBUG << "k is at " << (k == segment().end() ? -1 : (*k)->getAbsoluteTime()) << ", notation " << (*k)->getNotationAbsoluteTime() << ", duration " << (*k)->getNotationDuration();
2147 #endif
2148
2149 timeT tk = (*k)->getNotationAbsoluteTime();
2150 timeT dk = (*k)->getNotationDuration();
2151
2152 Event *e1 = nullptr, *e2 = nullptr;
2153 std::pair<Event *, Event *> splits;
2154 Segment::iterator toGo = segment().end();
2155
2156 if (tk == ti && dk != di) {
2157 // do the same-time-different-durations case
2158 if (di > dk) { // split *i
2159 #ifdef DEBUG_DECOUNTERPOINT
2160 RG_DEBUG << "splitting i into " << dk << " and "<< (di-dk);
2161 #endif
2162 splits = splitPreservingPerformanceTimes(*i, dk);
2163
2164 toGo = i;
2165 } else { // split *k
2166 #ifdef DEBUG_DECOUNTERPOINT
2167 RG_DEBUG << "splitting k into " << di << " and "<< (dk-di);
2168 #endif
2169 splits = splitPreservingPerformanceTimes(*k, di);
2170
2171 toGo = k;
2172 }
2173 } else if (tk - ti > 0 && tk - ti < di) { // split *i
2174 #ifdef DEBUG_DECOUNTERPOINT
2175 RG_DEBUG << "splitting i[*] into " << (tk-ti) << " and "<< (di-(tk-ti));
2176 #endif
2177 splits = splitPreservingPerformanceTimes(*i, tk - ti);
2178
2179 toGo = i;
2180 }
2181
2182 e1 = splits.first;
2183 e2 = splits.second;
2184
2185 if (e1 && e2) { // e2 is the new note
2186
2187 e1->set<Bool>(TIED_FORWARD, true);
2188 e2->set<Bool>(TIED_BACKWARD, true);
2189
2190 #ifdef DEBUG_DECOUNTERPOINT
2191 RG_DEBUG<<"Erasing:";
2192 RG_DEBUG << (**toGo);
2193 #endif
2194
2195 segment().erase(toGo);
2196
2197 #ifdef DEBUG_DECOUNTERPOINT
2198 RG_DEBUG<<"Inserting:";
2199 RG_DEBUG << *e1;
2200 #endif
2201
2202 segment().insert(e1);
2203
2204 #ifdef DEBUG_DECOUNTERPOINT
2205 RG_DEBUG<<"Inserting:";
2206 RG_DEBUG << *e2;
2207 #endif
2208
2209 segment().insert(e2);
2210
2211 i = segment().findTime(t);
2212
2213 #ifdef DEBUG_DECOUNTERPOINT
2214 RG_DEBUG<<"resync at " << t << ":";
2215 if (i != segment().end()) RG_DEBUG << (**i);
2216 else RG_DEBUG << "(end)";
2217 #endif
2218
2219 } else {
2220
2221 // no split here
2222
2223 #ifdef DEBUG_DECOUNTERPOINT
2224 RG_DEBUG<<"no split";
2225 #endif
2226 ++i;
2227 }
2228 }
2229
2230 segment().normalizeRests(startTime, endTime);
2231 }
2232
2233
2234 void
autoSlur(timeT startTime,timeT endTime,bool legatoOnly)2235 SegmentNotationHelper::autoSlur(timeT startTime, timeT endTime, bool legatoOnly)
2236 {
2237 iterator from = segment().findTime(startTime);
2238 iterator to = segment().findTime(endTime);
2239
2240 timeT potentialStart = segment().getEndTime();
2241 long groupId = -1;
2242 timeT prevTime = startTime;
2243 int count = 0;
2244 bool thisLegato = false, prevLegato = false;
2245
2246 for (iterator i = from; i != to && segment().isBeforeEndMarker(i); ++i) {
2247
2248 timeT t = (*i)->getNotationAbsoluteTime();
2249
2250 long newGroupId = -1;
2251 if ((*i)->get<Int>(BEAMED_GROUP_ID, newGroupId)) {
2252 if (groupId == newGroupId) { // group continuing
2253 if (t > prevTime) {
2254 ++count;
2255 prevLegato = thisLegato;
2256 thisLegato = Marks::hasMark(**i, Marks::Tenuto);
2257 }
2258 prevTime = t;
2259 continue;
2260 }
2261 } else {
2262 if (groupId == -1) continue; // no group
2263 }
2264
2265 // a group has ended (and a new one might have begun)
2266
2267 if (groupId >= 0 && count > 1 && (!legatoOnly || prevLegato)) {
2268 Indication ind(Indication::Slur, t - potentialStart);
2269 segment().insert(ind.getAsEvent(potentialStart));
2270 if (legatoOnly) {
2271 for (iterator j = segment().findTime(potentialStart); j != i; ++j) {
2272 Marks::removeMark(**j, Marks::Tenuto);
2273 }
2274 }
2275 }
2276
2277 potentialStart = t;
2278 groupId = newGroupId;
2279 prevTime = t;
2280 count = 0;
2281 thisLegato = false;
2282 prevLegato = false;
2283 }
2284
2285 if (groupId >= 0 && count > 1 && (!legatoOnly || prevLegato)) {
2286 Indication ind(Indication::Slur, endTime - potentialStart);
2287 segment().insert(ind.getAsEvent(potentialStart));
2288 if (legatoOnly) {
2289 for (iterator j = segment().findTime(potentialStart);
2290 segment().isBeforeEndMarker(j) && j != to; ++j) {
2291 Marks::removeMark(**j, Marks::Tenuto);
2292 }
2293 }
2294 }
2295 }
2296
findBorderTuplet(iterator it,iterator & start,iterator & end)2297 int SegmentNotationHelper::findBorderTuplet(iterator it, iterator &start, iterator &end){
2298 iterator beginB = segment().findTime(segment().getBarStartForTime((*it)->getAbsoluteTime()));
2299 iterator endB = segment().findTime(segment().getBarEndForTime((*it)->getAbsoluteTime()));
2300 int maxcount = 0;
2301 int count = 0;
2302 int index = 0;
2303 bool ourTuplet = false;
2304 bool newTuplet = true;
2305
2306 if ((*beginB)->getType()=="clefchange"){
2307 ++beginB;
2308 }
2309
2310 for ( ;beginB!=endB; ++beginB){
2311 index++;
2312 if (index>maxcount){
2313 index=1;
2314 count = 0;
2315 newTuplet=true;
2316 }
2317 if ((*beginB)->has(BEAMED_GROUP_TUPLET_BASE)==true){
2318 maxcount = (*beginB)->get<Int>(BEAMED_GROUP_UNTUPLED_COUNT);
2319 if ((*beginB)->getType() == "note"){
2320 count++;
2321 }
2322 if (it == beginB) ourTuplet = true;
2323 if (newTuplet){
2324 start = beginB;
2325 newTuplet=false;
2326 }
2327 if (ourTuplet && index==maxcount){
2328 end = ++beginB;
2329 return count;
2330 }
2331 continue;
2332 }else maxcount=0;
2333 if (ourTuplet == true){
2334 end = beginB;
2335 return count;
2336 }
2337 newTuplet = true;
2338 count = 0;
2339 }
2340 end=endB;
2341 return count;
2342 }
2343 } // end of namespace
2344
2345