bool WaveTrack::InsertSilence(double t, double len) { if (len <= 0) return false; if (mClips.IsEmpty()) { // Special case if there is no clip yet WaveClip* clip = CreateClip(); return clip->InsertSilence(0, len); } for (WaveClipList::Node* it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); if (clip->GetStartTime() > t) clip->Offset(len); else if (clip->GetEndTime() > t) { return clip->InsertSilence(t, len); } } return true; }
bool WaveTrack::SplitAt(double t) { for (WaveClipList::Node* it=GetClipIterator(); it; it=it->GetNext()) { WaveClip* c = it->GetData(); if (t > c->GetStartTime() && t < c->GetEndTime()) { WaveClip* newClip = new WaveClip(*c, mDirManager); if (!c->Clear(t, c->GetEndTime())) { delete newClip; return false; } if (!newClip->Clear(c->GetStartTime(), t)) { delete newClip; return false; } newClip->Offset(t - c->GetStartTime()); mClips.Append(newClip); return true; } } return true; }
bool WaveClip::Clear(double t0, double t1) { sampleCount s0, s1; TimeToSamplesClip(t0, &s0); TimeToSamplesClip(t1, &s1); if (GetSequence()->Delete(s0, s1-s0)) { // msmeyer // // Delete all cutlines that are within the given area, if any. // // Note that when cutlines are active, two functions are used: // Clear() and ClearAndAddCutLine(). ClearAndAddCutLine() is called // whenever the user directly calls a command that removes some audio, e.g. // "Cut" or "Clear" from the menu. This command takes care about recursive // preserving of cutlines within clips. Clear() is called when internal // operations want to remove audio. In the latter case, it is the right // thing to just remove all cutlines within the area. // double clip_t0 = t0; double clip_t1 = t1; if (clip_t0 < GetStartTime()) clip_t0 = GetStartTime(); if (clip_t1 > GetEndTime()) clip_t1 = GetEndTime(); WaveClipList::compatibility_iterator nextIt; for (WaveClipList::compatibility_iterator it = mCutLines.GetFirst(); it; it=nextIt) { nextIt = it->GetNext(); WaveClip* clip = it->GetData(); double cutlinePosition = mOffset + clip->GetOffset(); if (cutlinePosition >= t0 && cutlinePosition <= t1) { // This cutline is within the area, delete it delete clip; mCutLines.DeleteNode(it); } else if (cutlinePosition >= t1) { clip->Offset(clip_t0-clip_t1); } } // Collapse envelope GetEnvelope()->CollapseRegion(t0, t1); if (t0 < GetStartTime()) Offset(-(GetStartTime() - t0)); MarkChanged(); return true; } return false; }
void WaveClip::OffsetCutLines(double t0, double len) { for (WaveClipList::compatibility_iterator it = mCutLines.GetFirst(); it; it=it->GetNext()) { WaveClip* cutLine = it->GetData(); if (mOffset + cutLine->GetOffset() >= t0) cutLine->Offset(len); } }
bool WaveClip::Paste(double t0, WaveClip* other) { WaveClip* pastedClip; bool clipNeedsResampling = other->mRate != mRate; if (clipNeedsResampling) { // The other clip's rate is different to our's, so resample pastedClip = new WaveClip(*other, mSequence->GetDirManager()); if (!pastedClip->Resample(mRate)) { delete pastedClip; return false; } } else { // No resampling needed, just use original clip without making a copy pastedClip = other; } sampleCount s0; TimeToSamplesClip(t0, &s0); // Force sample formats to match. if (pastedClip->mSequence->GetSampleFormat() != mSequence->GetSampleFormat()) pastedClip->ConvertToSampleFormat(mSequence->GetSampleFormat()); bool result = false; if (mSequence->Paste(s0, pastedClip->mSequence)) { MarkChanged(); mEnvelope->Paste((double)s0/mRate + mOffset, pastedClip->mEnvelope); mEnvelope->RemoveUnneededPoints(); OffsetCutLines(t0, pastedClip->GetEndTime() - pastedClip->GetStartTime()); // Paste cut lines contained in pasted clip for (WaveClipList::compatibility_iterator it = pastedClip->mCutLines.GetFirst(); it; it=it->GetNext()) { WaveClip* cutline = it->GetData(); WaveClip* newCutLine = new WaveClip(*cutline, mSequence->GetDirManager()); newCutLine->Offset(t0 - mOffset); mCutLines.Append(newCutLine); } result = true; } if (clipNeedsResampling) { // Clip was constructed as a copy, so delete it delete pastedClip; } return result; }
bool WaveClip::ClearAndAddCutLine(double t0, double t1) { if (t0 > GetEndTime() || t1 < GetStartTime()) return true; // time out of bounds WaveClip *newClip = new WaveClip(mSequence->GetDirManager(), mSequence->GetSampleFormat(), mRate); double clip_t0 = t0; double clip_t1 = t1; if (clip_t0 < GetStartTime()) clip_t0 = GetStartTime(); if (clip_t1 > GetEndTime()) clip_t1 = GetEndTime(); if (!newClip->CreateFromCopy(clip_t0, clip_t1, this)) return false; newClip->SetOffset(clip_t0-mOffset); // Sort out cutlines that belong to the new cutline WaveClipList::compatibility_iterator nextIt; for (WaveClipList::compatibility_iterator it = mCutLines.GetFirst(); it; it=nextIt) { nextIt = it->GetNext(); WaveClip* clip = it->GetData(); double cutlinePosition = mOffset + clip->GetOffset(); if (cutlinePosition >= t0 && cutlinePosition <= t1) { clip->SetOffset(cutlinePosition - newClip->GetOffset() - mOffset); newClip->mCutLines.Append(clip); mCutLines.DeleteNode(it); } else if (cutlinePosition >= t1) { clip->Offset(clip_t0-clip_t1); } } // Clear actual audio data sampleCount s0, s1; TimeToSamplesClip(t0, &s0); TimeToSamplesClip(t1, &s1); if (GetSequence()->Delete(s0, s1-s0)) { // Collapse envelope GetEnvelope()->CollapseRegion(t0, t1); if (t0 < GetStartTime()) Offset(-(GetStartTime() - t0)); MarkChanged(); mCutLines.Append(newClip); return true; } else { delete newClip; return false; } }
bool WaveTrack::HandleClear(double t0, double t1, bool addCutLines, bool split) { if (t1 < t0) return false; WaveClipList::Node* it; WaveClipList clipsToDelete; WaveClipList clipsToAdd; for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); if (t0 <= clip->GetStartTime() && t1 >= clip->GetEndTime()) { // Whole clip must be deleted - remember this clipsToDelete.Append(clip); } else if (t1 > clip->GetStartTime() && t0 < clip->GetEndTime()) { // Clip data is affected by command if (addCutLines) { if (!clip->ClearAndAddCutLine(t0,t1)) return false; } else { if (split) { // Three cases: if (t0 <= clip->GetStartTime()) { // Delete from the left edge clip->Clear(clip->GetStartTime(), t1); clip->Offset(t1-clip->GetStartTime()); } else if (t1 >= clip->GetEndTime()) { // Delete to right edge clip->Clear(t0, clip->GetEndTime()); } else { // Delete in the middle of the clip...we actually create two // new clips out of the left and right halves... WaveClip *left = new WaveClip(*clip, mDirManager); left->Clear(t0, clip->GetEndTime()); clipsToAdd.Append(left); WaveClip *right = new WaveClip(*clip, mDirManager); right->Clear(clip->GetStartTime(), t1); right->Offset(t1-clip->GetStartTime()); clipsToAdd.Append(right); clipsToDelete.Append(clip); } } else { if (!clip->Clear(t0,t1)) return false; } } } else if (clip->GetStartTime() >= t1) { // Clip is "behind" the region -- offset it unless we're splitting if (!split) clip->Offset(-(t1-t0)); } } for (it=clipsToDelete.GetFirst(); it; it=it->GetNext()) { mClips.DeleteObject(it->GetData()); delete it->GetData(); } for (it=clipsToAdd.GetFirst(); it; it=it->GetNext()) { mClips.Append(it->GetData()); } return true; }
bool WaveTrack::Paste(double t0, Track *src) { //printf("paste: entering WaveTrack::Paste\n"); if (src->GetKind() != Track::Wave) return false; //printf("paste: we have a wave track\n"); WaveTrack* other = (WaveTrack*)src; // // Pasting is a bit complicated, because with the existence of multiclip mode, // we must guess the behaviour the user wants. // // Currently, two modes are implemented: // // - If a single clip should be pasted, and it should be pasted inside another // clip, no new clips are generated. The audio is simply inserted. // This resembles the old (pre-multiclip support) behaviour. However, if // the clip is pasted outside of any clip, a new clip is generated. This is // the only behaviour which is different to what was done before, but it // shouldn't confuse users too much. // // - If multiple clips should be pasted, these are always pasted as single // clips, and the current clip is splitted, when necessary. This may seem // strange at first, but it probably is better than trying to auto-merge // anything. The user can still merge the clips by hand (which should be // a simple command reachable by a hotkey or single mouse click). // if (other->GetNumClips() == 0) return false; //printf("paste: we have at least one clip\n"); double insertDuration = other->GetEndTime(); WaveClipList::Node* it; //printf("Check if we need to make room for the pasted data\n"); // Make room for the pasted data, unless the space being pasted in is empty of // any clips if (!IsEmpty(t0, t0+insertDuration-1.0/mRate)) { for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip* clip = it->GetData(); //printf("paste: offsetting already existing clip %i by %f seconds\n", //(int)clip, insertDuration); if (clip->GetStartTime() > t0-(1.0/mRate)) clip->Offset(insertDuration); } } if (other->GetNumClips() == 1) { // Single clip mode // printf("paste: checking for single clip mode!\n"); WaveClip *insideClip = NULL; for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); // The 1.0/mRate is the time for one sample - kind of a fudge factor, // because an overlap of less than a sample should not trigger // traditional behaviour. if (t0+src->GetEndTime()-1.0/mRate > clip->GetStartTime() && t0 < clip->GetEndTime() - 1.0/mRate) { //printf("t0=%.6f: inside clip is %.6f ... %.6f\n", // t0, clip->GetStartTime(), clip->GetEndTime()); insideClip = clip; break; } } if (insideClip) { // Exhibit traditional behaviour //printf("paste: traditional behaviour\n"); return insideClip->Paste(t0, other->GetClipByIndex(0)); } // Just fall through and exhibit new behaviour } // Insert new clips //printf("paste: multi clip mode!\n"); for (it=other->GetClipIterator(); it; it=it->GetNext()) { WaveClip* clip = it->GetData(); WaveClip* newClip = new WaveClip(*clip, mDirManager); newClip->Offset(t0); newClip->MarkChanged(); mClips.Append(newClip); } return true; }
bool WaveTrack::Copy(double t0, double t1, Track **dest) { *dest = NULL; if (t1 <= t0) return false; WaveTrack *newTrack = new WaveTrack(mDirManager); newTrack->Init(*this); WaveClipList::Node* it; for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); if (t0 <= clip->GetStartTime() && t1 >= clip->GetEndTime()) { // Whole clip is in copy region //printf("copy: clip %i is in copy region\n", (int)clip); WaveClip *newClip = new WaveClip(*clip, mDirManager); newClip->RemoveAllCutLines(); newClip->Offset(-t0); newTrack->mClips.Append(newClip); } else if (t1 > clip->GetStartTime() && t0 < clip->GetEndTime()) { // Clip is affected by command //printf("copy: clip %i is affected by command\n", (int)clip); WaveClip *newClip = new WaveClip(*clip, mDirManager); newClip->RemoveAllCutLines(); double clip_t0 = t0; double clip_t1 = t1; if (clip_t0 < clip->GetStartTime()) clip_t0 = clip->GetStartTime(); if (clip_t1 > clip->GetEndTime()) clip_t1 = clip->GetEndTime(); //printf("copy: clip_t0=%f, clip_t1=%f\n", clip_t0, clip_t1); newClip->Offset(-t0); if (newClip->GetOffset() < 0) newClip->SetOffset(0); //printf("copy: clip offset is now %f\n", newClip->GetOffset()); if (!newClip->CreateFromCopy(clip_t0, clip_t1, clip)) { //printf("paste: CreateFromCopy(%f, %f, %i) returns false, quitting\n", // clip_t0, clip_t1, (int)clip); return false; } newTrack->mClips.Append(newClip); } } *dest = newTrack; return true; }