1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: part.cpp,v 1.12.2.17 2009/06/25 05:13:02 terminator356 Exp $
5 //
6 // (C) Copyright 1999/2000 Werner Schweer (ws@seh.de)
7 // Additions, modifications (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net)
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
11 // as published by the Free Software Foundation; version 2 of
12 // the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=========================================================
24
25 #include <assert.h>
26 #include <stdio.h>
27 #include "muse_math.h"
28
29 #include "part.h"
30 #include "song.h"
31 #include "globals.h"
32 #include "audio.h"
33 #include "wave.h"
34 #include "midiport.h"
35 #include "drummap.h"
36 #include "midictrl.h"
37 #include "gconfig.h"
38 #include "config.h"
39
40 // Forwards from header:
41 #include "track.h"
42 #include "xml.h"
43
44 namespace MusECore {
45
46 int Part::snGen=0;
47
48 //---------------------------------------------------------
49 // MidiCtrlViewState::write
50 //---------------------------------------------------------
51
write(int level,Xml & xml) const52 void MidiCtrlViewState::write(int level, Xml& xml) const
53 {
54 xml.nput(level, "<ctrlViewState num=\"%d\"", _num);
55 if(_perNoteVel)
56 xml.nput(" perNoteVel=\"1\"");
57
58 xml.put(" />");
59 }
60
61 //---------------------------------------------------------
62 // MidiPartViewState::read
63 //---------------------------------------------------------
64
read(Xml & xml)65 void MidiCtrlViewState::read(Xml& xml)
66 {
67 for (;;) {
68 Xml::Token token = xml.parse();
69 const QString& tag = xml.s1();
70 switch (token) {
71 case Xml::Error:
72 case Xml::End:
73 return;
74 case Xml::Attribut:
75 if (tag == "num")
76 _num = xml.s2().toInt();
77 else if (tag == "perNoteVel")
78 _perNoteVel = xml.s2().toInt();
79 break;
80 case Xml::TagEnd:
81 if (xml.s1() == "ctrlViewState")
82 return;
83 default:
84 break;
85 }
86 }
87 }
88
89 //---------------------------------------------------------
90 // MidiPartViewState::write
91 //---------------------------------------------------------
92
write(int level,Xml & xml) const93 void MidiPartViewState::write(int level, Xml& xml) const
94 {
95 // Don't bother if it's an invalid state.
96 if(!isValid())
97 return;
98
99 xml.tag(level++, "viewState xscroll=\"%d\" yscroll=\"%d\" xscale=\"%d\" yscale=\"%d\"",
100 xscroll(), yscroll(), xscale(), yscale());
101
102 if(!_controllers.empty()) {
103 for (ciMidiCtrlViewState i = _controllers.cbegin();
104 i != _controllers.cend(); ++i) {
105 (*i).write(level, xml);
106 }
107 }
108
109 xml.tag(level, "/viewState");
110
111 }
112
113 //---------------------------------------------------------
114 // MidiPartViewState::read
115 //---------------------------------------------------------
116
read(Xml & xml)117 void MidiPartViewState::read(Xml& xml)
118 {
119 // Make sure to clear the controllers list first.
120 clearControllers();
121 for (;;) {
122 Xml::Token token = xml.parse();
123 const QString& tag = xml.s1();
124 switch (token) {
125 case Xml::Error:
126 case Xml::End:
127 return;
128 case MusECore::Xml::TagStart:
129 if (tag == "ctrlViewState") {
130 MidiCtrlViewState mcvs;
131 mcvs.read(xml);
132 addController(mcvs);
133 }
134 else
135 xml.unknown("MidiPartViewState");
136 break;
137 case Xml::Attribut:
138 if (tag == "xscroll")
139 setXScroll(xml.s2().toInt());
140 else if (tag == "yscroll")
141 setYScroll(xml.s2().toInt());
142 else if (tag == "xscale")
143 setXScale(xml.s2().toInt());
144 else if (tag == "yscale")
145 setYScale(xml.s2().toInt());
146 break;
147 case Xml::TagEnd:
148 if (xml.s1() == "viewState")
149 return;
150 default:
151 break;
152 }
153 }
154 }
155
156
157
unchainClone()158 void Part::unchainClone()
159 {
160 chainCheckErr(this); // FIXME proper assert!
161
162 if (_backupClone) printf("THIS SHOULD NEVER HAPPEN: Part::unchainClone() called, but _backupClone was non-NULL\n");
163
164 _backupClone=_prevClone;
165
166 // Unchain the part.
167 _prevClone->_nextClone = _nextClone;
168 _nextClone->_prevClone = _prevClone;
169
170 // Isolate the part.
171 _prevClone = this;
172 _nextClone = this;
173
174 _clonemaster_sn = this->_sn;
175 }
176
chainClone(Part * p)177 void Part::chainClone(Part* p)
178 {
179 // FIXME assertion
180 assert(p);
181
182 if (! (_prevClone==this && _nextClone==this)) // the part is still part of a clone chain!
183 {
184 printf("ERROR: THIS SHOULD NEVER HAPPEN: Part::chainClone() called, but part is already chained! I'll unchain for now, but better fix that!\n");
185 this->unchainClone();
186 }
187
188 // Make our links to the chain
189 this->_prevClone = p;
190 this->_nextClone = p->_nextClone;
191
192 // Make the chain's links to us
193 this->_nextClone->_prevClone = this;
194 p->_nextClone = this;
195
196 // we only chain clones. we must trust in the GUI thread that the eventlist is consistent.
197
198 this->_clonemaster_sn = p->_sn;
199 }
200
rechainClone()201 void Part::rechainClone()
202 {
203 if(_backupClone)
204 {
205 this->chainClone(_backupClone);
206 _backupClone = NULL;
207 }
208 }
209
isCloneOf(const Part * other) const210 bool Part::isCloneOf(const Part* other) const
211 {
212 return this->_clonemaster_sn == other->_clonemaster_sn;
213 }
214
nClones() const215 int Part::nClones() const
216 {
217 int n=1;
218
219 for(const Part* it = this->_nextClone; it!=this; it=it->_nextClone)
220 n++;
221
222 return n;
223 }
224
225
226 // FIXME FINDMICHJETZT TODO: weg damit!
227
228 //---------------------------------------------------------
229 // unchainTrackParts
230 //---------------------------------------------------------
231
unchainTrackParts(Track * t)232 void unchainTrackParts(Track* t)
233 {
234 PartList* pl = t->parts();
235 for(iPart ip = pl->begin(); ip != pl->end(); ++ip)
236 ip->second->unchainClone();
237 }
238
239 //---------------------------------------------------------
240 // chainTrackParts
241 //---------------------------------------------------------
242
chainTrackParts(Track * t)243 void chainTrackParts(Track* t)
244 {
245 PartList* pl = t->parts();
246 for(riPart ip = pl->rbegin(); ip != pl->rend(); ++ip) // walk through in opposite direction than we unchained them.
247 ip->second->rechainClone();
248 }
249
250 //---------------------------------------------------------
251 // chainCheckErr
252 //---------------------------------------------------------
253
chainCheckErr(Part * p)254 void chainCheckErr(Part* p)
255 {
256 // At all times these must be false...
257 if(p->nextClone()->prevClone() != p)
258 printf("chainCheckErr: Next clone:%s %p prev clone:%s %p != %s %p\n", p->nextClone()->name().toLatin1().constData(), p->nextClone(), p->nextClone()->prevClone()->name().toLatin1().constData(), p->nextClone()->prevClone(), p->name().toLatin1().constData(), p);
259 if(p->prevClone()->nextClone() != p)
260 printf("chainCheckErr: Prev clone:%s %p next clone:%s %p != %s %p\n", p->prevClone()->name().toLatin1().constData(), p->prevClone(), p->prevClone()->nextClone()->name().toLatin1().constData(), p->prevClone()->nextClone(), p->name().toLatin1().constData(), p);
261 }
262
263 //---------------------------------------------------------
264 // addPortCtrlEvents
265 //---------------------------------------------------------
266
addPortCtrlEvents(Part * part,bool doClones)267 void addPortCtrlEvents(Part* part, bool doClones)
268 {
269 // Traverse and process the clone chain ring until we arrive at the same part again.
270 // The loop is a safety net.
271 Part* p = part;
272 while(1)
273 {
274 Track* t = p->track();
275 if(t && t->isMidiTrack())
276 {
277 MidiTrack* mt = (MidiTrack*)t;
278 unsigned int len = p->lenTick();
279 for(ciEvent ie = p->events().begin(); ie != p->events().end(); ++ie)
280 {
281 const Event& ev = ie->second;
282 // Do not add events which are past the end of the part.
283 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
284 if((int)ev.tick() >= (int)len)
285 #else
286 if(ev.tick() >= len)
287 #endif
288 break;
289 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
290 if((int)ev.tick() < 0)
291 continue;
292 #endif
293
294 if(ev.type() == Controller)
295 {
296 unsigned int tck = ev.tick() + p->tick();
297 int cntrl = ev.dataA();
298 int val = ev.dataB();
299
300 MidiPort* mp;
301 int ch;
302 mt->mappedPortChanCtrl(&cntrl, nullptr, &mp, &ch);
303
304 mp->setControllerVal(ch, tck, cntrl, val, p);
305 }
306 }
307 }
308 if(!doClones)
309 break;
310 // Get the next clone in the chain ring.
311 p = p->nextClone();
312 // Same as original part? Finished.
313 if(p == part)
314 break;
315 }
316 }
317
318 //---------------------------------------------------------
319 // removePortCtrlEvents
320 //---------------------------------------------------------
321
removePortCtrlEvents(Part * part,bool doClones)322 void removePortCtrlEvents(Part* part, bool doClones)
323 {
324 // Traverse and process the clone chain ring until we arrive at the same part again.
325 // The loop is a safety net.
326 Part* p = part;
327 while(1)
328 {
329 Track* t = p->track();
330 if(t && t->isMidiTrack())
331 {
332 MidiTrack* mt = (MidiTrack*)t;
333 // MidiPort* mp = &MusEGlobal::midiPorts[mt->outPort()];
334 // int ch = mt->outChannel();
335 for(ciEvent ie = p->events().begin(); ie != p->events().end(); ++ie)
336 {
337 const Event& ev = ie->second;
338
339 if(ev.type() == Controller)
340 {
341 unsigned int tck = ev.tick() + p->tick();
342 int cntrl = ev.dataA();
343 int val = ev.dataB();
344
345 // Is it a drum controller event, according to the track port's instrument?
346 MidiPort* mp;
347 int ch;
348 mt->mappedPortChanCtrl(&cntrl, nullptr, &mp, &ch);
349
350 mp->deleteController(ch, tck, cntrl, val, p);
351 }
352 }
353 }
354
355 if(!doClones)
356 break;
357 // Get the next clone in the chain ring.
358 p = p->nextClone();
359 // Same as original part? Finished.
360 if(p == part)
361 break;
362 }
363 }
364
365 //---------------------------------------------------------
366 // addEvent
367 //---------------------------------------------------------
368
addEvent(Event & p)369 iEvent Part::addEvent(Event& p)
370 {
371 return _events.add(p);
372 }
373
374 //---------------------------------------------------------
375 // index
376 //---------------------------------------------------------
377
index(const Part * part) const378 int PartList::index(const Part* part) const
379 {
380 int index = 0;
381 for (ciPart i = begin(); i != end(); ++i, ++index)
382 if (i->second == part) {
383 return index;
384 }
385 if(MusEGlobal::debugMsg)
386 printf("PartList::index(): not found!\n");
387 return -1; // don't change that value. at least MidiEditor::addNewParts relies on this
388 }
389
390 //---------------------------------------------------------
391 // find
392 //---------------------------------------------------------
393
find(int idx)394 Part* PartList::find(int idx)
395 {
396 int index = 0;
397 for (iPart i = begin(); i != end(); ++i, ++index)
398 if (index == idx)
399 return i->second;
400 return nullptr;
401 }
402
403 //---------------------------------------------------------
404 // Part
405 //---------------------------------------------------------
406
Part(Track * t)407 Part::Part(Track* t)
408 {
409 _hiddenEvents = NoEventsHidden;
410 _prevClone = this;
411 _nextClone = this;
412 _backupClone = nullptr;
413 _sn = newSn();
414 _clonemaster_sn = _sn;
415 _track = t;
416 _selected = false;
417 _mute = false;
418 _colorIndex = 0;
419 }
420
~Part()421 Part::~Part()
422 {
423 if (_prevClone!=this || _nextClone!=this)
424 {
425 if (MusEGlobal::debugMsg) {
426 fprintf(stderr, "Part isn't unchained in ~Part()! Unchaining now...\n");
427 }
428 unchainClone();
429 }
430 }
431
duplicateEmpty() const432 WavePart* WavePart::duplicateEmpty() const
433 {
434 WavePart* part = new WavePart((WaveTrack*)this->_track);
435 part->setName(name());
436 part->setColorIndex(colorIndex());
437
438 *(PosLen*)part = *(PosLen*)this;
439 part->setMute(mute());
440
441 return part;
442 }
443
duplicate() const444 WavePart* WavePart::duplicate() const
445 {
446 return (WavePart*)Part::duplicate();
447 }
448
createNewClone() const449 WavePart* WavePart::createNewClone() const
450 {
451 return (WavePart*)Part::createNewClone();
452 }
453
duplicateEmpty() const454 MidiPart* MidiPart::duplicateEmpty() const
455 {
456 MidiPart* part = new MidiPart((MidiTrack*)this->_track);
457 part->setName(name());
458 part->setColorIndex(colorIndex());
459
460 *(PosLen*)part = *(PosLen*)this;
461 part->setMute(mute());
462
463 return part;
464 }
465
duplicate() const466 MidiPart* MidiPart::duplicate() const
467 {
468 return (MidiPart*)Part::duplicate();
469 }
470
createNewClone() const471 MidiPart* MidiPart::createNewClone() const
472 {
473 return (MidiPart*)Part::createNewClone();
474 }
475
476
createNewClone() const477 Part* Part::createNewClone() const
478 {
479 Part* clone = duplicateEmpty();
480 for (MusECore::ciEvent i = _events.begin(); i != _events.end(); ++i)
481 {
482 Event nev = i->second.clone(); // Create a non-shared clone of the event, having the same id.
483 clone->addEvent(nev);
484 }
485 clone->_backupClone=const_cast<Part*>(this);
486 return clone;
487 }
488
duplicate() const489 Part* Part::duplicate() const
490 {
491 Part* dup = duplicateEmpty();
492
493 // copy the eventlist; duplicate each Event(Ptr!).
494 for (MusECore::ciEvent i = _events.begin(); i != _events.end(); ++i)
495 {
496 Event nev = i->second.duplicate(); // Create a duplicate of the event, excluding the _id.
497
498 dup->addEvent(nev);
499 }
500
501 return dup;
502 }
503
selectEvents(bool select,unsigned long,unsigned long)504 bool Part::selectEvents(bool select, unsigned long /*t0*/, unsigned long /*t1*/)
505 {
506 bool ret = false;
507 EventList& el = nonconst_events();
508 for(iEvent ie = el.begin(); ie != el.end(); ++ie)
509 {
510 Event& e = ie->second;
511 // if(e.type() ???) // For t0 and t1
512 if(e.selected() != select)
513 ret = true;
514 e.setSelected(select);
515 }
516 return ret;
517 }
518
519 //---------------------------------------------------------
520 // WavePart
521 //---------------------------------------------------------
522
WavePart(WaveTrack * t)523 WavePart::WavePart(WaveTrack* t)
524 : Part(t)
525 {
526 setType(FRAMES);
527 }
528
529 //---------------------------------------------------------
530 // findPart
531 //---------------------------------------------------------
532
findPart(unsigned tick)533 iPart PartList::findPart(unsigned tick)
534 {
535 iPart i;
536 for (i = begin(); i != end(); ++i)
537 if (i->second->tick() == tick)
538 break;
539 return i;
540 }
541
542 //---------------------------------------------------------
543 // add
544 //---------------------------------------------------------
545
add(Part * part)546 iPart PartList::add(Part* part)
547 {
548 // Added by T356. A part list containing wave parts should be sorted by
549 // frames. WaveTrack::fetchData() relies on the sorting order, and
550 // there was a bug that waveparts were sometimes muted because of
551 // incorrect sorting order (by ticks).
552 // Also, when the tempo map is changed, every wavepart would have to be
553 // re-added to the part list so that the proper sorting order (by ticks)
554 // could be achieved.
555 // Note that in a med file, the tempo list is loaded AFTER all the tracks.
556 // There was a bug that all the wave parts' tick values were not correct,
557 // since they were computed BEFORE the tempo map was loaded.
558 if(part->type() == Pos::FRAMES)
559 return insert(PartListInsertPair_t(part->frame(), part));
560 else
561 return insert(PartListInsertPair_t(part->tick(), part));
562 }
563
564 //---------------------------------------------------------
565 // remove
566 //---------------------------------------------------------
567
remove(Part * part)568 void PartList::remove(Part* part)
569 {
570 iPart i;
571 for (i = begin(); i != end(); ++i) {
572 if (i->second == part) {
573 erase(i);
574 break;
575 }
576 }
577 if (i == end())
578 printf("THIS SHOULD NEVER HAPPEN: could not find the part in PartList::remove()!\n");
579 }
580
581 //---------------------------------------------------------
582 // addPart
583 //---------------------------------------------------------
584
addPart(Part * part)585 void Song::addPart(Part* part)
586 {
587 // adjust song len:
588 unsigned int epos = part->tick() + part->lenTick();
589
590 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
591 if ((int)epos > (int)len())
592 #else
593 if (epos > len())
594 #endif
595 _len = epos;
596
597 part->track()->addPart(part);
598
599 // Indicate do not do clones.
600 addPortCtrlEvents(part, false);
601 }
602
603 //---------------------------------------------------------
604 // removePart
605 //---------------------------------------------------------
606
removePart(Part * part)607 void Song::removePart(Part* part)
608 {
609 // Indicate do not do clones.
610 removePortCtrlEvents(part, false);
611 Track* track = part->track();
612 track->parts()->remove(part);
613 }
614
615 //---------------------------------------------------------
616 // splitPart
617 // split part "part" at "tick" position
618 // create two new parts p1 and p2
619 //---------------------------------------------------------
620
splitPart(unsigned int tickpos,Part * & p1,Part * & p2) const621 void Part::splitPart(unsigned int tickpos, Part*& p1, Part*& p2) const
622 {
623 unsigned int l1 = 0; // len of first new part (ticks or samples)
624 unsigned int l2 = 0; // len of second new part
625
626 unsigned int samplepos = MusEGlobal::tempomap.tick2frame(tickpos);
627
628 switch (track()->type()) {
629 case Track::WAVE:
630 if(samplepos <= frame() || lenFrame() <= l1)
631 return;
632 l1 = samplepos - frame();
633 l2 = lenFrame() - l1;
634 break;
635 case Track::MIDI:
636 case Track::DRUM:
637 if(tickpos <= tick() || lenTick() <= l1)
638 return;
639 l1 = tickpos - tick();
640 l2 = lenTick() - l1;
641 break;
642 default:
643 return;
644 }
645
646 p1 = this->duplicateEmpty(); // new left part
647 p2 = this->duplicateEmpty(); // new right part
648
649 switch (track()->type()) {
650 case Track::WAVE:
651 p1->setLenFrame(l1);
652 p2->setFrame(samplepos);
653 p2->setLenFrame(l2);
654 break;
655 case Track::MIDI:
656 case Track::DRUM:
657 p1->setLenTick(l1);
658 p2->setTick(tickpos);
659 p2->setLenTick(l2);
660 break;
661 default:
662 break;
663 }
664
665 if (track()->type() == Track::WAVE) {
666 unsigned int ps = this->frame();
667 unsigned int d1p1 = p1->frame();
668 unsigned int d2p1 = p1->endFrame();
669 unsigned int d1p2 = p2->frame();
670 unsigned int d2p2 = p2->endFrame();
671 for (ciEvent ie = _events.begin(); ie != _events.end(); ++ie) {
672 const Event& event = ie->second;
673 unsigned int s1 = event.frame() + ps;
674 unsigned int s2 = event.endFrame() + ps;
675
676 if ((s2 > d1p1) && (s1 < d2p1)) {
677 Event si = event.mid(d1p1 - ps, d2p1);
678 p1->addEvent(si);
679 }
680 if ((s2 > d1p2) && (s1 < d2p2)) {
681 Event si = event.mid(d1p2 - ps, d2p2);
682 p2->addEvent(si);
683 }
684 }
685 }
686 else {
687 for (ciEvent ie = _events.begin(); ie != _events.end(); ++ie) {
688 Event event = ie->second.clone();
689 unsigned int t = event.tick();
690 if (t >= l1) {
691 event.move(-l1);
692 p2->addEvent(event);
693 }
694 else
695 p1->addEvent(event);
696 }
697 }
698 }
699
700 //---------------------------------------------------------
701 // changePart
702 //---------------------------------------------------------
703
changePart(Part * oPart,Part * nPart)704 void Song::changePart(Part* oPart, Part* nPart)
705 {
706 nPart->setSn(oPart->sn());
707
708 Track* oTrack = oPart->track();
709 Track* nTrack = nPart->track();
710
711 oTrack->parts()->remove(oPart);
712 nTrack->parts()->add(nPart);
713
714 // Added by T356.
715 // adjust song len:
716 unsigned int epos = nPart->tick() + nPart->lenTick();
717 if (epos > len())
718 _len = epos;
719 }
720
721 //---------------------------------------------------------
722 // setViewState
723 //---------------------------------------------------------
724
setViewState(const MidiPartViewState & vs)725 void Part::setViewState(const MidiPartViewState& vs)
726 {
727 _viewState = vs;
728 }
729
730 //---------------------------------------------------------
731 // dump
732 //---------------------------------------------------------
733
dump(int n) const734 void Part::dump(int n) const
735 {
736 for (int i = 0; i < n; ++i)
737 putchar(' ');
738 printf("Part: <%s> ", _name.toLatin1().constData());
739 for (int i = 0; i < n; ++i)
740 putchar(' ');
741 PosLen::dump();
742 }
743
744
dump(int n) const745 void WavePart::dump(int n) const
746 {
747 Part::dump(n);
748 for (int i = 0; i < n; ++i)
749 putchar(' ');
750 printf("WavePart\n");
751 }
752
753
dump(int n) const754 void MidiPart::dump(int n) const
755 {
756 Part::dump(n);
757 for (int i = 0; i < n; ++i)
758 putchar(' ');
759 printf("MidiPart\n");
760 }
761
762 //---------------------------------------------------------
763 // hasHiddenEvents
764 // Returns combination of HiddenEventsType enum.
765 //---------------------------------------------------------
766
hasHiddenEvents() const767 int MidiPart::hasHiddenEvents() const
768 {
769 // TODO An idea for left-border hidden events with unsigned integer positions.
770 // It actually worked, as far as the left hidden events arrow, but really it can't work without much bigger switchovers to integer math.
771 // I guess we'll try it like this.
772 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
773 unsigned int len = lenTick();
774 _hiddenEvents = NoEventsHidden; // Cache the result for later.
775
776 const int c_comp = LeftEventsHidden | RightEventsHidden;
777 for(ciEvent ev=_events.begin(); ev!=_events.end(); ++ev)
778 {
779 // Is the time value less than zero? Note the conversion to signed here!
780 if(signed(ev->second.tick()) < 0)
781 _hiddenEvents |= LeftEventsHidden; // Cache the result for later.
782 if(signed(ev->second.endTick()) > signed(len))
783 _hiddenEvents |= RightEventsHidden; // Cache the result for later.
784 if(_hiddenEvents == c_comp)
785 break;
786 }
787 return _hiddenEvents;
788 #else
789 unsigned int len = lenTick();
790
791 // TODO: For now, we don't support events before the left border, only events past the right border.
792 for(ciEvent ev=_events.begin(); ev!=_events.end(); ev++)
793 {
794 if(ev->second.endTick() > len)
795 {
796 _hiddenEvents = RightEventsHidden; // Cache the result for later.
797 return _hiddenEvents;
798 }
799 }
800 _hiddenEvents = NoEventsHidden; // Cache the result for later.
801 return _hiddenEvents;
802 #endif
803 }
804
805 //---------------------------------------------------------
806 // hasHiddenEvents
807 // Returns combination of HiddenEventsType enum.
808 //---------------------------------------------------------
809
hasHiddenEvents() const810 int WavePart::hasHiddenEvents() const
811 {
812 // An idea for left-border hidden events with unsigned integer positions.
813 // It actually worked, as far as the left hidden events arrow, but really it can't work without much bigger switchovers to integer math.
814 // I guess we'll try it like this.
815 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
816 unsigned int len = lenFrame();
817 _hiddenEvents = NoEventsHidden; // Cache the result for later.
818
819 const int c_comp = LeftEventsHidden | RightEventsHidden;
820 for(ciEvent ev=_events.begin(); ev!=_events.end(); ++ev)
821 {
822 // Is the time value less than zero? Note the conversion to signed here!
823 if(signed(ev->second.frame()) < 0)
824 _hiddenEvents |= LeftEventsHidden; // Cache the result for later.
825 if(signed(ev->second.endFrame()) > signed(len))
826 _hiddenEvents |= RightEventsHidden; // Cache the result for later.
827 if(_hiddenEvents == c_comp)
828 break;
829 }
830 return _hiddenEvents;
831 #else
832 unsigned int len = lenFrame();
833
834 // TODO: For now, we don't support events before the left border, only events past the right border.
835 for(ciEvent ev=_events.begin(); ev!=_events.end(); ev++)
836 {
837 if(ev->second.endFrame() > len)
838 {
839 _hiddenEvents = RightEventsHidden; // Cache the result for later.
840 return _hiddenEvents;
841 }
842 }
843 _hiddenEvents = NoEventsHidden; // Cache the result for later.
844 return _hiddenEvents;
845 #endif
846 }
847
openAllEvents()848 bool WavePart::openAllEvents()
849 {
850 bool opened = false;
851 const EventList& el = events();
852 for(ciEvent ie = el.begin(); ie != el.end(); ++ie)
853 {
854 const Event& e = ie->second;
855 if(e.empty())
856 continue;
857 SndFileR f = e.sndFile();
858 if(!f.isNull() && !f.isOpen())
859 {
860 opened = true;
861 f.openRead();
862 }
863 }
864 return opened;
865 }
866
closeAllEvents()867 bool WavePart::closeAllEvents()
868 {
869 bool closed = false;
870 const EventList& el = events();
871 for(ciEvent ie = el.begin(); ie != el.end(); ++ie)
872 {
873 const Event& e = ie->second;
874 if(e.empty())
875 continue;
876 SndFileR f = e.sndFile();
877 if(!f.isNull() && f.isOpen())
878 {
879 closed = true;
880 f.close();
881 }
882 }
883 return closed;
884 }
885
886 //---------------------------------------------------------
887 // ClonePart
888 //---------------------------------------------------------
889
ClonePart(const Part * p,int i)890 ClonePart::ClonePart(const Part* p, int i)
891 {
892 cp = p;
893 id = i;
894 is_deleted = false;
895 _uuid = QUuid::createUuid();
896 }
897
898
899 } // namespace MusECore
900