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