//========================================================= // MusE // Linux Music Editor // $Id: part.cpp,v 1.12.2.17 2009/06/25 05:13:02 terminator356 Exp $ // // (C) Copyright 1999/2000 Werner Schweer (ws@seh.de) //========================================================= #include #include #include #include "song.h" #include "part.h" #include "track.h" #include "globals.h" #include "event.h" #include "audio.h" #include "wave.h" #include "midiport.h" #include "drummap.h" int Part::snGen; //--------------------------------------------------------- // unchainClone //--------------------------------------------------------- void unchainClone(Part* p) { chainCheckErr(p); // Unchain the part. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); // Isolate the part. p->setPrevClone(p); p->setNextClone(p); } //--------------------------------------------------------- // chainClone // The quick way - if part to chain to is known... //--------------------------------------------------------- void chainClone(Part* p1, Part* p2) { chainCheckErr(p1); // Make sure the part to be chained is unchained first. p2->prevClone()->setNextClone(p2->nextClone()); p2->nextClone()->setPrevClone(p2->prevClone()); // Link the part to be chained. p2->setPrevClone(p1); p2->setNextClone(p1->nextClone()); // Re-link the existing part. p1->nextClone()->setPrevClone(p2); p1->setNextClone(p2); } //--------------------------------------------------------- // chainCloneInternal // No error check, so it can be called by replaceClone() //--------------------------------------------------------- void chainCloneInternal(Part* p) { Track* t = p->track(); Part* p1 = 0; // Look for a part with the same event list, that we can chain to. // It's faster if track type is known... if(!t || (t && t->isMidiTrack())) { MidiTrack* mt = 0; MidiTrackList* mtl = song->midis(); for(ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) { mt = *imt; const PartList* pl = mt->cparts(); for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) { // Added by Tim. p3.3.6 //printf("chainCloneInternal track %p %s part %p %s evlist %p\n", (*imt), (*imt)->name().latin1(), ip->second, ip->second->name().latin1(), ip->second->cevents()); if(ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; break; } } // If a suitable part was found on a different track, we're done. We will chain to it. // Otherwise keep looking for parts on another track. If no others found, then we // chain to any suitable part which was found on the same given track t. if(p1 && mt != t) break; } } if((!p1 && !t) || (t && t->type() == Track::WAVE)) { WaveTrack* wt = 0; WaveTrackList* wtl = song->waves(); for(ciWaveTrack iwt = wtl->begin(); iwt != wtl->end(); ++iwt) { wt = *iwt; const PartList* pl = wt->cparts(); for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) { if(ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; break; } } if(p1 && wt != t) break; } } // No part found with same event list? Done. if(!p1) return; // Make sure the part to be chained is unchained first. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); // Link the part to be chained. p->setPrevClone(p1); p->setNextClone(p1->nextClone()); // Re-link the existing part. p1->nextClone()->setPrevClone(p); p1->setNextClone(p); } //--------------------------------------------------------- // chainClone // The slow way - if part to chain to is not known... //--------------------------------------------------------- void chainClone(Part* p) { chainCheckErr(p); chainCloneInternal(p); } //--------------------------------------------------------- // replaceClone //--------------------------------------------------------- void replaceClone(Part* p1, Part* p2) { chainCheckErr(p1); // Make sure the replacement part is unchained first. p2->prevClone()->setNextClone(p2->nextClone()); p2->nextClone()->setPrevClone(p2->prevClone()); // If the two parts share the same event list, then this MUST // be a straight forward replacement operation. Continue on. // If not, and either part has more than one ref count, then do this... if(p1->cevents() != p2->cevents()) { bool ret = false; // If the part to be replaced is a single uncloned part, // and the replacement part is not, then this operation // MUST be an undo of a de-cloning of a cloned part. //if(p1->cevents()->refCount() <= 1 && p2->cevents()->refCount() > 1) if(p2->cevents()->refCount() > 1) { // Chain the replacement part. We don't know the chain it came from, // so we use the slow method. chainCloneInternal(p2); //return; ret = true; } // If the replacement part is a single uncloned part, // and the part to be replaced is not, then this operation // MUST be a de-cloning of a cloned part. //if(p1->cevents()->refCount() > 1 && p2->cevents()->refCount() <= 1) if(p1->cevents()->refCount() > 1) { // Unchain the part to be replaced. p1->prevClone()->setNextClone(p1->nextClone()); p1->nextClone()->setPrevClone(p1->prevClone()); // Isolate the part. p1->setPrevClone(p1); p1->setNextClone(p1); //return; ret = true; } // Was the operation handled? if(ret) return; // Note that two parts here with different event lists, each with more than one // reference count, would be an error. It's not done anywhere in muse. But just // to be sure, four lines above were changed to allow that condition. // If each of the two different event lists, has only one ref count, we // handle it like a regular replacement, below... } // If the part to be replaced is a clone not a single lone part, re-link its neighbours to the replacement part... if(p1->prevClone() != p1) { p1->prevClone()->setNextClone(p2); p2->setPrevClone(p1->prevClone()); } else p2->setPrevClone(p2); if(p1->nextClone() != p1) { p1->nextClone()->setPrevClone(p2); p2->setNextClone(p1->nextClone()); } else p2->setNextClone(p2); // Link the replacement... //p2->setPrevClone(p1->prevClone()); //p2->setNextClone(p1->nextClone()); // Isolate the replaced part. p1->setNextClone(p1); p1->setPrevClone(p1); // Added by Tim. p3.3.6 //printf("replaceClone p1: %s %p arefs:%d p2: %s %p arefs:%d\n", p1->name().latin1(), p1, ); } //--------------------------------------------------------- // unchainTrackParts //--------------------------------------------------------- void unchainTrackParts(Track* t, bool decRefCount) { PartList* pl = t->parts(); for(iPart ip = pl->begin(); ip != pl->end(); ++ip) { Part* p = ip->second; chainCheckErr(p); // Do we want to decrease the reference count? if(decRefCount) p->events()->incARef(-1); // Unchain the part. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); // Isolate the part. p->setPrevClone(p); p->setNextClone(p); } } //--------------------------------------------------------- // chainTrackParts //--------------------------------------------------------- void chainTrackParts(Track* t, bool incRefCount) { PartList* pl = t->parts(); for(iPart ip = pl->begin(); ip != pl->end(); ++ip) { Part* p = ip->second; chainCheckErr(p); // Do we want to increase the reference count? if(incRefCount) p->events()->incARef(1); // Added by Tim. p3.3.6 //printf("chainTrackParts track %p %s part %p %s evlist %p\n", t, t->name().latin1(), p, p->name().latin1(), p->cevents()); Part* p1 = 0; // Look for a part with the same event list, that we can chain to. // It's faster if track type is known... if(!t || (t && t->isMidiTrack())) { MidiTrack* mt = 0; MidiTrackList* mtl = song->midis(); for(ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) { mt = *imt; const PartList* pl = mt->cparts(); for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) { // Added by Tim. p3.3.6 //printf("chainTrackParts track %p %s part %p %s evlist %p\n", mt, mt->name().latin1(), ip->second, ip->second->name().latin1(), ip->second->cevents()); if(ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; break; } } // If a suitable part was found on a different track, we're done. We will chain to it. // Otherwise keep looking for parts on another track. If no others found, then we // chain to any suitable part which was found on the same given track t. if(p1 && mt != t) break; } } if((!p1 && !t) || (t && t->type() == Track::WAVE)) { WaveTrack* wt = 0; WaveTrackList* wtl = song->waves(); for(ciWaveTrack iwt = wtl->begin(); iwt != wtl->end(); ++iwt) { wt = *iwt; const PartList* pl = wt->cparts(); for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) { if(ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; break; } } if(p1 && wt != t) break; } } // No part found with same event list? Done. if(!p1) continue; // Make sure the part to be chained is unchained first. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); // Link the part to be chained. p->setPrevClone(p1); p->setNextClone(p1->nextClone()); // Re-link the existing part. p1->nextClone()->setPrevClone(p); p1->setNextClone(p); } } //--------------------------------------------------------- // chainCheckErr //--------------------------------------------------------- void chainCheckErr(Part* p) { // At all times these must be true... if(p->nextClone()->prevClone() != p) printf("chainCheckErr: Next clone:%s %p prev clone:%s %p != %s %p\n", p->nextClone()->name().latin1(), p->nextClone(), p->nextClone()->prevClone()->name().latin1(), p->nextClone()->prevClone(), p->name().latin1(), p); if(p->prevClone()->nextClone() != p) printf("chainCheckErr: Prev clone:%s %p next clone:%s %p != %s %p\n", p->prevClone()->name().latin1(), p->prevClone(), p->prevClone()->nextClone()->name().latin1(), p->prevClone()->nextClone(), p->name().latin1(), p); } //--------------------------------------------------------- // addPortCtrlEvents //--------------------------------------------------------- void addPortCtrlEvents(Event& event, Part* part, bool doClones) { // Traverse and process the clone chain ring until we arrive at the same part again. // The loop is a safety net. // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents, // we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain. Part* p = part; //int j = doClones ? p->cevents()->arefCount() : 1; //if(j > 0) { //for(int i = 0; i < j; ++i) while(1) { // Added by Tim. p3.3.6 //printf("addPortCtrlEvents i:%d %s %p events %p refs:%d arefs:%d\n", i, p->name().latin1(), p, part->cevents(), part->cevents()->refCount(), j); Track* t = p->track(); if(t && t->isMidiTrack()) { MidiTrack* mt = (MidiTrack*)t; int port = mt->outPort(); //const EventList* el = p->cevents(); unsigned len = p->lenTick(); //for(ciEvent ie = el->begin(); ie != el->end(); ++ie) //{ //const Event& ev = ie->second; // Added by Tim. p3.3.6 //printf("addPortCtrlEvents %s len:%d end:%d etick:%d\n", p->name().latin1(), p->lenTick(), p->endTick(), event.tick()); // Do not add events which are past the end of the part. if(event.tick() >= len) break; if(event.type() == Controller) { int ch = mt->outChannel(); int tck = event.tick() + p->tick(); int cntrl = event.dataA(); int val = event.dataB(); MidiPort* mp = &midiPorts[port]; // Is it a drum controller event, according to the track port's instrument? if(mt->type() == Track::DRUM) { MidiController* mc = mp->drumController(cntrl); if(mc) { int note = cntrl & 0x7f; cntrl &= ~0xff; ch = drumMap[note].channel; mp = &midiPorts[drumMap[note].port]; cntrl |= drumMap[note].anote; } } mp->setControllerVal(ch, tck, cntrl, val, p); } //} } if(!doClones) break; // Get the next clone in the chain ring. p = p->nextClone(); // Same as original part? Finished. if(p == part) break; } } } //--------------------------------------------------------- // addPortCtrlEvents //--------------------------------------------------------- void addPortCtrlEvents(Part* part, bool doClones) { // Traverse and process the clone chain ring until we arrive at the same part again. // The loop is a safety net. // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents, // we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain. Part* p = part; //int j = doClones ? p->cevents()->arefCount() : 1; //if(j > 0) { //for(int i = 0; i < j; ++i) while(1) { // Added by Tim. p3.3.6 //printf("addPortCtrlEvents i:%d %s %p events %p refs:%d arefs:%d\n", i, p->name().latin1(), p, part->cevents(), part->cevents()->refCount(), j); Track* t = p->track(); if(t && t->isMidiTrack()) { MidiTrack* mt = (MidiTrack*)t; int port = mt->outPort(); const EventList* el = p->cevents(); unsigned len = p->lenTick(); for(ciEvent ie = el->begin(); ie != el->end(); ++ie) { const Event& ev = ie->second; // Added by T356. Do not add events which are past the end of the part. if(ev.tick() >= len) break; if(ev.type() == Controller) { int ch = mt->outChannel(); int tck = ev.tick() + p->tick(); int cntrl = ev.dataA(); int val = ev.dataB(); MidiPort* mp = &midiPorts[port]; // Is it a drum controller event, according to the track port's instrument? if(mt->type() == Track::DRUM) { MidiController* mc = mp->drumController(cntrl); if(mc) { int note = cntrl & 0x7f; cntrl &= ~0xff; ch = drumMap[note].channel; mp = &midiPorts[drumMap[note].port]; cntrl |= drumMap[note].anote; } } mp->setControllerVal(ch, tck, cntrl, val, p); } } } if(!doClones) break; // Get the next clone in the chain ring. p = p->nextClone(); // Same as original part? Finished. if(p == part) break; } } } //--------------------------------------------------------- // removePortCtrlEvents //--------------------------------------------------------- void removePortCtrlEvents(Event& event, Part* part, bool doClones) { // Traverse and process the clone chain ring until we arrive at the same part again. // The loop is a safety net. // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents, // we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain. Part* p = part; //int j = doClones ? p->cevents()->arefCount() : 1; //if(j > 0) { //for(int i = 0; i < j; ++i) while(1) { Track* t = p->track(); if(t && t->isMidiTrack()) { MidiTrack* mt = (MidiTrack*)t; int port = mt->outPort(); //const EventList* el = p->cevents(); //unsigned len = p->lenTick(); //for(ciEvent ie = el->begin(); ie != el->end(); ++ie) //{ //const Event& ev = ie->second; // Added by T356. Do not remove events which are past the end of the part. // No, actually, do remove ALL of them belonging to the part. // Just in case there are stray values left after the part end. //if(ev.tick() >= len) // break; if(event.type() == Controller) { int ch = mt->outChannel(); int tck = event.tick() + p->tick(); int cntrl = event.dataA(); MidiPort* mp = &midiPorts[port]; // Is it a drum controller event, according to the track port's instrument? if(mt->type() == Track::DRUM) { MidiController* mc = mp->drumController(cntrl); if(mc) { int note = cntrl & 0x7f; cntrl &= ~0xff; ch = drumMap[note].channel; mp = &midiPorts[drumMap[note].port]; cntrl |= drumMap[note].anote; } } mp->deleteController(ch, tck, cntrl, p); } //} } if(!doClones) break; // Get the next clone in the chain ring. p = p->nextClone(); // Same as original part? Finished. if(p == part) break; } } } //--------------------------------------------------------- // removePortCtrlEvents //--------------------------------------------------------- void removePortCtrlEvents(Part* part, bool doClones) { // Traverse and process the clone chain ring until we arrive at the same part again. // The loop is a safety net. // Update: Due to the varying calls, and order of, incARefcount, (msg)ChangePart, replaceClone, and remove/addPortCtrlEvents, // we can not rely on the reference count as a safety net in these routines. We will just have to trust the clone chain. Part* p = part; //int j = doClones ? p->cevents()->arefCount() : 1; //if(j > 0) { //for(int i = 0; i < j; ++i) while(1) { Track* t = p->track(); if(t && t->isMidiTrack()) { MidiTrack* mt = (MidiTrack*)t; int port = mt->outPort(); const EventList* el = p->cevents(); //unsigned len = p->lenTick(); for(ciEvent ie = el->begin(); ie != el->end(); ++ie) { const Event& ev = ie->second; // Added by T356. Do not remove events which are past the end of the part. // No, actually, do remove ALL of them belonging to the part. // Just in case there are stray values left after the part end. //if(ev.tick() >= len) // break; if(ev.type() == Controller) { int ch = mt->outChannel(); int tck = ev.tick() + p->tick(); int cntrl = ev.dataA(); MidiPort* mp = &midiPorts[port]; // Is it a drum controller event, according to the track port's instrument? if(mt->type() == Track::DRUM) { MidiController* mc = mp->drumController(cntrl); if(mc) { int note = cntrl & 0x7f; cntrl &= ~0xff; ch = drumMap[note].channel; mp = &midiPorts[drumMap[note].port]; cntrl |= drumMap[note].anote; } } mp->deleteController(ch, tck, cntrl, p); } } } if(!doClones) break; // Get the next clone in the chain ring. p = p->nextClone(); // Same as original part? Finished. if(p == part) break; } } } //--------------------------------------------------------- // addEvent //--------------------------------------------------------- iEvent Part::addEvent(Event& p) { return _events->add(p); } //--------------------------------------------------------- // index //--------------------------------------------------------- int PartList::index(Part* part) { int index = 0; for (iPart i = begin(); i != end(); ++i, ++index) if (i->second == part) { return index; } if(debugMsg) printf("PartList::index(): not found!\n"); //return 0; return -1; } //--------------------------------------------------------- // find //--------------------------------------------------------- Part* PartList::find(int idx) { int index = 0; for (iPart i = begin(); i != end(); ++i, ++index) if (index == idx) return i->second; return 0; } //--------------------------------------------------------- // Part //--------------------------------------------------------- Part::Part(Track* t) { _prevClone = this; _nextClone = this; setSn(newSn()); _track = t; _selected = false; _mute = false; _colorIndex = 0; _events = new EventList; _events->incRef(1); _events->incARef(1); } //--------------------------------------------------------- // Part //--------------------------------------------------------- Part::Part(Track* t, EventList* ev) { _prevClone = this; _nextClone = this; setSn(newSn()); _track = t; _selected = false; _mute = false; _colorIndex = 0; _events = ev; _events->incRef(1); _events->incARef(1); } //--------------------------------------------------------- // MidiPart // copy constructor //--------------------------------------------------------- MidiPart::MidiPart(const MidiPart& p) : Part(p) { _prevClone = this; _nextClone = this; //setSn(newSn()); //_sn = p._sn; //_name = p._name; //_selected = p._selected; //_mute = p._mute; //_colorIndex = p._colorIndex; //_track = p._track; //_events = p._events; } //--------------------------------------------------------- // WavePart //--------------------------------------------------------- WavePart::WavePart(WaveTrack* t) : Part(t) { setType(FRAMES); } WavePart::WavePart(WaveTrack* t, EventList* ev) : Part(t, ev) { setType(FRAMES); } //--------------------------------------------------------- // WavePart // copy constructor //--------------------------------------------------------- WavePart::WavePart(const WavePart& p) : Part(p) { _prevClone = this; _nextClone = this; //setSn(newSn()); //_sn = p._sn; //_name = p._name; //_selected = p._selected; //_mute = p._mute; //_colorIndex = p._colorIndex; //_track = p._track; //_events = p._events; } //--------------------------------------------------------- // Part //--------------------------------------------------------- Part::~Part() { _events->incRef(-1); if (_events->refCount() <= 0) delete _events; } /* //--------------------------------------------------------- // unchainClone //--------------------------------------------------------- void Part::unchainClone() { chainCheckErr(); _prevClone->setNextClone(_nextClone); _nextClone->setPrevClone(_prevClone); _prevClone = this; _nextClone = this; } //--------------------------------------------------------- // chainClone // The quick way - if part to chain to is known... //--------------------------------------------------------- void Part::chainClone(const Part* p) { chainCheckErr(); // Make sure the part is unchained first. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); p->setPrevClone(this); p->setNextClone(_nextClone->prevClone()); _nextClone->setPrevClone(p); _nextClone = (Part*)p; } //--------------------------------------------------------- // chainClone // The slow way - if part to chain to is not known... //--------------------------------------------------------- void Part::chainClone() { chainCheckErr(); // Look for a part with the same event list, that we can chain to... Part* p = 0; if(!_track || (_track && _track->isMidiTrack())) { MidiTrackList* mtl = song->midis(); for(ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) { const PartList* pl = (*imt)->cparts(); for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) { if(ip->second != this && ip->second->events() == _events) { p = ip->second; break; } } } } if((!p && !_track) || (_track && _track->type() == Track::WAVE)) { WaveTrackList* wtl = song->waves(); for(ciWaveTrack iwt = wtl->begin(); iwt != wtl->end(); ++iwt) { const PartList* pl = (*iwt)->cparts(); for(ciPart ip = pl->begin(); ip != pl->end(); ++ip) { if(ip->second != this && ip->second->events() == _events) { p = ip->second; break; } } } } // No part found with same event list? Done. if(!p) return; // Make sure this part is unchained first. _prevClone->setNextClone(_nextClone); _nextClone->setPrevClone(_prevClone); _prevClone = p; _nextClone = p->nextClone(); p->nextClone()->setPrevClone(this); p->setNextClone(this); } //--------------------------------------------------------- // replaceClone //--------------------------------------------------------- void Part::replaceClone(const Part* p) { chainCheckErr(); // Make sure the part is unchained first. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); // If this part is a clone, not a single lone part... if(_prevClone != this) _prevClone->setNextClone(p); if(_nextClone != this) _nextClone->setPrevClone(p); p->setPrevClone(_prevClone); p->setNextClone(_nextClone); _nextClone = this; _prevClone = this; } //--------------------------------------------------------- // chainCheckErr //--------------------------------------------------------- void Part::chainCheckErr() { if(_nextClone->prevClone() != this) printf("Part::chainCheckErr Error! Next clone:%s %x prev clone:%s %x != this:%s %x\n", _nextClone->name().latin1(), _nextClone, _nextClone->prevClone()->name().latin1(), _nextClone->prevClone(), name().latin1(), this); if(_prevClone->nextClone() != this) printf("Part::chainCheckErr Error! Prev clone:%s %x next clone:%s %x != this:%s %x\n", _prevClone->name().latin1(), _prevClone, _prevClone->nextClone()->name().latin1(), _prevClone->nextClone(), name().latin1(), this); } */ //--------------------------------------------------------- // findPart //--------------------------------------------------------- iPart PartList::findPart(unsigned tick) { iPart i; for (i = begin(); i != end(); ++i) if (i->second->tick() == tick) break; return i; } //--------------------------------------------------------- // add //--------------------------------------------------------- iPart PartList::add(Part* part) { // Added by T356. A part list containing wave parts should be sorted by // frames. WaveTrack::fetchData() relies on the sorting order, and // there was a bug that waveparts were sometimes muted because of // incorrect sorting order (by ticks). // Also, when the tempo map is changed, every wavepart would have to be // re-added to the part list so that the proper sorting order (by ticks) // could be achieved. // Note that in a med file, the tempo list is loaded AFTER all the tracks. // There was a bug that all the wave parts' tick values were not correct, // since they were computed BEFORE the tempo map was loaded. if(part->type() == Pos::FRAMES) return insert(std::pair (part->frame(), part)); else return insert(std::pair (part->tick(), part)); } //--------------------------------------------------------- // remove //--------------------------------------------------------- void PartList::remove(Part* part) { iPart i; for (i = begin(); i != end(); ++i) { if (i->second == part) { erase(i); break; } } assert(i != end()); } //--------------------------------------------------------- // addPart //--------------------------------------------------------- void Song::addPart(Part* part) { // adjust song len: unsigned epos = part->tick() + part->lenTick(); if (epos > len()) _len = epos; part->track()->addPart(part); //part->addPortCtrlEvents(); // Indicate do not do clones. addPortCtrlEvents(part, false); } //--------------------------------------------------------- // removePart //--------------------------------------------------------- void Song::removePart(Part* part) { //part->removePortCtrlEvents(); // Indicate do not do clones. //removePortCtrlEvents(part); removePortCtrlEvents(part, false); Track* track = part->track(); track->parts()->remove(part); } //--------------------------------------------------------- // cmdResizePart //--------------------------------------------------------- void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len) { switch(track->type()) { case Track::WAVE: { WavePart* nPart = new WavePart(*(WavePart*)oPart); EventList* el = nPart->events(); unsigned new_partlength = tempomap.deltaTick2frame(oPart->tick(), oPart->tick() + len); //printf("new partlength in frames: %d\n", new_partlength); // If new nr of frames is less than previous what can happen is: // - 0 or more events are beginning after the new final position. Those are removed from the part // - The last event begins before new final position and ends after it. If so, it will be resized to end at new part length if (new_partlength < oPart->lenFrame()) { startUndo(); for (iEvent i = el->begin(); i != el->end(); i++) { Event e = i->second; unsigned event_startframe = e.frame(); unsigned event_endframe = event_startframe + e.lenFrame(); //printf("Event frame=%d, length=%d\n", event_startframe, event_length); if (event_endframe < new_partlength) continue; if (event_startframe > new_partlength) { // If event start was after the new length, remove it from part // Indicate no undo, and do not do port controller values and clone parts. //audio->msgDeleteEvent(e, nPart, false); audio->msgDeleteEvent(e, nPart, false, false, false); continue; } if (event_endframe > new_partlength) { // If this event starts before new length and ends after, shrink it Event newEvent = e.clone(); newEvent.setLenFrame(new_partlength - event_startframe); // Indicate no undo, and do not do port controller values and clone parts. //audio->msgChangeEvent(e, newEvent, nPart, false); audio->msgChangeEvent(e, newEvent, nPart, false, false, false); } } nPart->setLenFrame(new_partlength); // Indicate no undo, and do not do port controller values and clone parts. //audio->msgChangePart(oPart, nPart, false); audio->msgChangePart(oPart, nPart, false, false, false); endUndo(SC_PART_MODIFIED); } // If the part is expanded there can be no additional events beginning after the previous final position // since those are removed if the part has been shrunk at some time (see above) // The only thing we need to check is the final event: If it has data after the previous final position, // we'll expand that event else { if(!el->empty()) { iEvent i = el->end(); i--; Event last = i->second; unsigned last_start = last.frame(); SndFileR file = last.sndFile(); if (file.isNull()) return; unsigned clipframes = (file.samples() - last.spos());// / file.channels(); Event newEvent = last.clone(); //printf("SndFileR samples=%d channels=%d event samplepos=%d clipframes=%d\n", file.samples(), file.channels(), last.spos(), clipframes); unsigned new_eventlength = new_partlength - last_start; if (new_eventlength > clipframes) // Shrink event length if new partlength exceeds last clip new_eventlength = clipframes; newEvent.setLenFrame(new_eventlength); startUndo(); // Indicate no undo, and do not do port controller values and clone parts. //audio->msgChangeEvent(last, newEvent, nPart, false); audio->msgChangeEvent(last, newEvent, nPart, false, false, false); } else { startUndo(); } nPart->setLenFrame(new_partlength); // Indicate no undo, and do not do port controller values and clone parts. //audio->msgChangePart(oPart, nPart, false); audio->msgChangePart(oPart, nPart, false, false, false); endUndo(SC_PART_MODIFIED); } } break; case Track::MIDI: case Track::DRUM: { startUndo(); MidiPart* nPart = new MidiPart(*(MidiPart*)oPart); nPart->setLenTick(len); // Indicate no undo, and do port controller values but not clone parts. audio->msgChangePart(oPart, nPart, false, true, false); // cut Events in nPart // Changed by T356. Don't delete events if this is a clone part. // The other clones might be longer than this one and need these events. if(nPart->cevents()->arefCount() <= 1) { if(oPart->lenTick() > len) { EventList* el = nPart->events(); iEvent ie = el->lower_bound(len); for (; ie != el->end();) { iEvent i = ie; ++ie; // Indicate no undo, and do port controller values and clone parts. audio->msgDeleteEvent(i->second, nPart, false, true, true); } } } /* // cut Events in nPart // Changed by T356. Don't delete events if this is a clone part. // The other clones might be longer than this one and need these events. if(oPart->cevents()->arefCount() <= 1) { if (oPart->lenTick() > len) { EventList* el = nPart->events(); iEvent ie = el->lower_bound(len); for (; ie != el->end();) { iEvent i = ie; ++ie; // Indicate no undo, and do not do port controller values and clone parts. //audio->msgDeleteEvent(i->second, nPart, false); audio->msgDeleteEvent(i->second, nPart, false, false, false); } } } // Indicate no undo, and do port controller values but not clone parts. //audio->msgChangePart(oPart, nPart, false); audio->msgChangePart(oPart, nPart, false, true, false); */ endUndo(SC_PART_MODIFIED); break; } default: break; } } //--------------------------------------------------------- // splitPart // split part "part" at "tick" position // create two new parts p1 and p2 //--------------------------------------------------------- void Track::splitPart(Part* part, int tickpos, Part*& p1, Part*& p2) { int l1 = 0; // len of first new part (ticks or samples) int l2 = 0; // len of second new part int samplepos = tempomap.tick2frame(tickpos); switch (type()) { case WAVE: l1 = samplepos - part->frame(); l2 = part->lenFrame() - l1; break; case MIDI: case DRUM: l1 = tickpos - part->tick(); l2 = part->lenTick() - l1; break; default: return; } if (l1 <= 0 || l2 <= 0) return; p1 = newPart(part); // new left part p2 = newPart(part); // new right part // Added by Tim. p3.3.6 //printf("Track::splitPart part ev %p sz:%d ref:%d p1 %p sz:%d ref:%d p2 %p sz:%d ref:%d\n", part->events(), part->events()->size(), part->events()->arefCount(), p1->events(), p1->events()->size(), p1->events()->arefCount(), p2->events(), p2->events()->size(), p2->events()->arefCount()); switch (type()) { case WAVE: p1->setLenFrame(l1); p2->setFrame(samplepos); p2->setLenFrame(l2); break; case MIDI: case DRUM: p1->setLenTick(l1); p2->setTick(tickpos); p2->setLenTick(l2); break; default: break; } p2->setSn(p2->newSn()); EventList* se = part->events(); EventList* de1 = p1->events(); EventList* de2 = p2->events(); if (type() == WAVE) { int ps = part->frame(); int d1p1 = p1->frame(); int d2p1 = p1->endFrame(); int d1p2 = p2->frame(); int d2p2 = p2->endFrame(); for (iEvent ie = se->begin(); ie != se->end(); ++ie) { Event event = ie->second; int s1 = event.frame() + ps; int s2 = event.endFrame() + ps; if ((s2 > d1p1) && (s1 < d2p1)) { Event si = event.mid(d1p1 - ps, d2p1 - ps); de1->add(si); } if ((s2 > d1p2) && (s1 < d2p2)) { Event si = event.mid(d1p2 - ps, d2p2 - ps); de2->add(si); } } } else { for (iEvent ie = se->begin(); ie != se->end(); ++ie) { Event event = ie->second.clone(); int t = event.tick(); if (t >= l1) { event.move(-l1); de2->add(event); } else de1->add(event); } } } //--------------------------------------------------------- // cmdSplitPart //--------------------------------------------------------- void Song::cmdSplitPart(Track* track, Part* part, int tick) { int l1 = tick - part->tick(); int l2 = part->lenTick() - l1; if (l1 <= 0 || l2 <= 0) return; Part* p1; Part* p2; track->splitPart(part, tick, p1, p2); startUndo(); // Indicate no undo, and do port controller values but not clone parts. //audio->msgChangePart(part, p1, false); audio->msgChangePart(part, p1, false, true, false); audio->msgAddPart(p2, false); endUndo(SC_TRACK_MODIFIED | SC_PART_MODIFIED | SC_PART_INSERTED); } //--------------------------------------------------------- // changePart //--------------------------------------------------------- void Song::changePart(Part* oPart, Part* nPart) { nPart->setSn(oPart->sn()); Track* oTrack = oPart->track(); Track* nTrack = nPart->track(); // Added by Tim. p3.3.6 //printf("Song::changePart before oPart->removePortCtrlEvents oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); // Removed. Port controller events will have to be add/removed separately from this routine. //oPart->removePortCtrlEvents(); //removePortCtrlEvents(oPart); // Added by Tim. p3.3.6 //printf("Song::changePart after oPart->removePortCtrlEvents oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); oTrack->parts()->remove(oPart); nTrack->parts()->add(nPart); // Added by Tim. p3.3.6 //printf("Song::changePart after add(nPart) oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); //nPart->addPortCtrlEvents(); //addPortCtrlEvents(nPart); // Added by Tim. p3.3.6 //printf("Song::changePart after nPart->addPortCtrlEvents() oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); // Added by T356. // adjust song len: unsigned epos = nPart->tick() + nPart->lenTick(); if (epos > len()) _len = epos; // Added by Tim. p3.3.6 //printf("Song::changePart after len adjust oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oPart->events()->refCount(), oPart->events()->arefCount(), nPart->events()->refCount(), nPart->events()->arefCount()); } //--------------------------------------------------------- // cmdGluePart //--------------------------------------------------------- void Song::cmdGluePart(Track* track, Part* oPart) { // p3.3.54 if(track->type() != Track::WAVE && !track->isMidiTrack()) return; PartList* pl = track->parts(); Part* nextPart = 0; for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { if (ip->second == oPart) { ++ip; if (ip == pl->end()) return; nextPart = ip->second; break; } } Part* nPart = track->newPart(oPart); nPart->setLenTick(nextPart->tick() + nextPart->lenTick() - oPart->tick()); // populate nPart with Events from oPart and nextPart EventList* sl1 = oPart->events(); EventList* dl = nPart->events(); for (iEvent ie = sl1->begin(); ie != sl1->end(); ++ie) dl->add(ie->second); EventList* sl2 = nextPart->events(); //int frameOffset = nextPart->frame() - oPart->frame(); //for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { // Event event = ie->second.clone(); // event.setFrame(event.frame() + frameOffset); // dl->add(event); // } // p3.3.54 Changed. if(track->type() == Track::WAVE) { int frameOffset = nextPart->frame() - oPart->frame(); for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { Event event = ie->second.clone(); event.setFrame(event.frame() + frameOffset); dl->add(event); } } else if(track->isMidiTrack()) { int tickOffset = nextPart->tick() - oPart->tick(); for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { Event event = ie->second.clone(); event.setTick(event.tick() + tickOffset); dl->add(event); } } startUndo(); audio->msgRemovePart(nextPart, false); // Indicate no undo, and do port controller values but not clone parts. //audio->msgChangePart(oPart, nPart, false); audio->msgChangePart(oPart, nPart, false, true, false); endUndo(SC_PART_MODIFIED | SC_PART_REMOVED); } //--------------------------------------------------------- // dump //--------------------------------------------------------- void Part::dump(int n) const { for (int i = 0; i < n; ++i) putchar(' '); printf("Part: <%s> ", _name.latin1()); for (int i = 0; i < n; ++i) putchar(' '); PosLen::dump(); } void WavePart::dump(int n) const { Part::dump(n); for (int i = 0; i < n; ++i) putchar(' '); printf("WavePart\n"); } void MidiPart::dump(int n) const { Part::dump(n); for (int i = 0; i < n; ++i) putchar(' '); printf("MidiPart\n"); } //--------------------------------------------------------- // clone //--------------------------------------------------------- MidiPart* MidiPart::clone() const { return new MidiPart(*this); } WavePart* WavePart::clone() const { return new WavePart(*this); }