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