static void removeOverlaps(std::vector<RprMidiNote *> &midiNotes) { for(int noteOffset = 0; (midiNotes.begin() + noteOffset) != midiNotes.end(); ++noteOffset) { std::vector<RprMidiNote *>::iterator i = midiNotes.begin() + noteOffset; RprMidiNote *lhs = *i; for(std::vector<RprMidiNote *>::iterator j = i + 1; j != midiNotes.end(); j++) { RprMidiNote *rhs = *j; if(rhs->getItemPosition() >= lhs->getItemPosition() + lhs->getItemLength()) { break; } if(lhs->getPitch() != rhs->getPitch()) { continue; } if(lhs->getChannel() != rhs->getChannel()) { continue; } if(lhs->getItemPosition() + lhs->getItemLength() >= rhs->getItemPosition()) { int lhsLength = rhs->getItemPosition() - lhs->getItemPosition(); if(lhsLength <= 0) { delete lhs; i = midiNotes.erase(i); noteOffset--; } else { lhs->setItemLength(lhsLength); } break; } } } }
RprMidiTake::~RprMidiTake() { if (isReadOnly()) { cleanup(); return; } std::vector<RprMidiEvent *> midiEvents; std::sort(mNotes.begin(), mNotes.end(), compareMidiPositions<RprMidiNote>); for(int i = 0; i < 128; i++) { std::sort(mCCs[i].begin(), mCCs[i].end(), compareMidiPositions<RprMidiCC>); } removeDuplicates(mNotes); removeDuplicates(mCCs); removeOverlaps(mNotes); midiEvents.reserve(mNotes.size() * 2 + mOtherEvents.size()); RprMidiEvent* allNotesOffEvent = NULL; if (!mCCs[0x7b].empty()) { allNotesOffEvent = (*mCCs[0x7b].begin())->mCC; } for(std::vector<RprMidiNote *>::const_iterator i = mNotes.begin(); i != mNotes.end(); ++i) { RprMidiNote* note = *i; if (allNotesOffEvent) { if (note->getItemPosition() >= allNotesOffEvent->getOffset()) { continue; } if (note->getItemPosition() + note->getItemLength() > allNotesOffEvent->getOffset()) { note->setItemLength(allNotesOffEvent->getOffset() - note->getItemPosition()); } } midiEvents.push_back((*i)->mNoteOn); midiEvents.push_back((*i)->mNoteOff); } for(int j = 0; j < 128; j++) { // ignore all-notes-off event, handle this separately below if (j == 0x7b) { continue; } for(std::vector<RprMidiCC *>::const_iterator i = mCCs[j].begin(); i != mCCs[j].end(); ++i) { midiEvents.push_back((*i)->mCC); } } for(std::vector<RprMidiEvent *>::const_iterator i = mOtherEvents.begin(); i != mOtherEvents.end(); ++i) { midiEvents.push_back(*i); } std::sort(midiEvents.begin(), midiEvents.end(), sortMidiBase); if (allNotesOffEvent) { midiEvents.push_back(allNotesOffEvent); } int firstEventOffset = 0; if (!midiEvents.empty()) { firstEventOffset = (*midiEvents.begin())->getOffset(); } int offset = 0; if (firstEventOffset < 0) { double takeStartPosition = mTake.getParent().getPosition() - mTake.getStartOffset() / mContext->getPlayRate(); // convert to Quarter notes and subtract first event offset double newTakeQNStartPosition = TimeToQN(takeStartPosition) + ((double)firstEventOffset / mContext->getTicksPerQN()) / mContext->getPlayRate(); //convert back to seconds / playrate mNewTakeOffset = takeStartPosition - QNtoTime(newTakeQNStartPosition) + mTake.getStartOffset() / mContext->getPlayRate(); //convert to seconds mNewTakeOffset *= mContext->getPlayRate(); // Hack! Have to set start offset after setting item state so // set a flag to indicate we need a new start offset set mSetNewTakeOffset = true; // set initial offset to -ve value to get rid of -ve deltas offset = firstEventOffset; } for(std::vector<RprMidiEvent *>::iterator i = midiEvents.begin(); i != midiEvents.end(); ++i) { RprMidiEvent *current = *i; int delta = current->getOffset() - offset; current->setDelta(delta); offset += delta; } midiEventsToMidiNode(midiEvents, RprMidiTemplate::getMidiSourceNode(), mMidiEventsOffset); cleanup(); }