bool SetClipCommand::ApplyInner( const CommandContext & context, Track * t ) { static_cast<void>(context); // if no 'At' is specified, then any clip in any selected track will be set. t->TypeSwitch([&](WaveTrack *waveTrack) { WaveClipPointers ptrs( waveTrack->SortedClipArray()); for(auto it = ptrs.begin(); (it != ptrs.end()); it++ ){ WaveClip * pClip = *it; bool bFound = !bHasContainsTime || ( ( pClip->GetStartTime() <= mContainsTime ) && ( pClip->GetEndTime() >= mContainsTime ) ); if( bFound ) { // Inside this IF is where we actually apply the command if( bHasColour ) pClip->SetColourIndex(mColour); // No validation of overlap yet. We assume the user is sensible! if( bHasT0 ) pClip->SetOffset(mT0); // \todo Use SetClip to move a clip between tracks too. } } } ); return true; }
WaveClip* WaveTrack::GetLastOrCreateClip() { if (mClips.IsEmpty()) { WaveClip *clip = CreateClip(); clip->SetOffset(mOffset); return clip; } else return mClips.GetLast()->GetData(); }
//Trim trims within a clip, rather than trimming everything. //If a bound is outside a clip, it trims everything. bool WaveTrack::Trim (double t0, double t1) { bool inside0 = false; bool inside1 = false; //Keeps track of the offset of the first clip greater than // the left selection t0. double firstGreaterOffset = -1; WaveClipList::Node * it; for(it = GetClipIterator(); it; it = it->GetNext()) { WaveClip * clip = it->GetData(); //Find the first clip greater than the offset. //If we end up clipping the entire track, this is useful. if(firstGreaterOffset < 0 && clip->GetStartTime() >= t0) firstGreaterOffset = clip->GetStartTime(); if(t1 > clip->GetStartTime() && t1 < clip->GetEndTime()) { if (!clip->Clear(t1,clip->GetEndTime())) return false; inside1 = true; } if(t0 > clip->GetStartTime() && t0 < clip->GetEndTime()) { if (!clip->Clear(clip->GetStartTime(),t0)) return false; clip->SetOffset(t0); inside0 = true; } } //if inside0 is false, then the left selector was between //clips, so delete everything to its left. if(false == inside1) { if (!Clear(t1,GetEndTime())) return false; } if(false == inside0) { if (!Clear(0,t0)) return false; //Reset the track offset to be at the point of the first remaining clip. SetOffset(firstGreaterOffset ); } return true; }
void WaveTrack::SetOffset(double o) { double delta = o - GetOffset(); for (WaveClipList::Node* it=GetClipIterator(); it; it=it->GetNext()) { WaveClip* clip = it->GetData(); clip->SetOffset(clip->GetOffset() + delta); } mOffset = o; }
bool WaveTrack::Join(double t0, double t1) { // Merge all WaveClips overlapping selection into one WaveClipList::Node* it; WaveClipList clipsToDelete; WaveClip *newClip; for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); if (clip->GetStartTime() < t1-(1.0/mRate) && clip->GetEndTime()-(1.0/mRate) > t0) { // Put in sorted order int i; for(i=0; i<clipsToDelete.GetCount(); i++) if (clipsToDelete[i]->GetStartTime() > clip->GetStartTime()) break; //printf("Insert clip %.6f at position %d\n", clip->GetStartTime(), i); clipsToDelete.Insert(i, clip); } } newClip = CreateClip(); double t = clipsToDelete[0]->GetOffset(); newClip->SetOffset(t); for(it=clipsToDelete.GetFirst(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); //printf("t=%.6f adding clip (offset %.6f, %.6f ... %.6f)\n", // t, clip->GetOffset(), clip->GetStartTime(), clip->GetEndTime()); if (clip->GetOffset() - t > (1.0 / mRate)) { double addedSilence = (clip->GetOffset() - t); //printf("Adding %.6f seconds of silence\n"); newClip->InsertSilence(t, addedSilence); t += addedSilence; } //printf("Pasting at %.6f\n", t); newClip->Paste(t, clip); t = newClip->GetEndTime(); mClips.DeleteObject(clip); delete clip; } return true; }
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::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; }
bool EffectReverse::ProcessOneWave(int count, WaveTrack * track, sampleCount start, sampleCount len) { bool rValue = true; // return value sampleCount end = (sampleCount) start + len; // start, end, len refer to the selected reverse region // STEP 1: // If a reverse selection begins and/or ends at the inside of a clip // perform a split at the start and/or end of the reverse selection WaveClipList::compatibility_iterator node = track->GetClipIterator(); while (node) { WaveClip *clip = node->GetData(); sampleCount clipStart = clip->GetStartSample(); sampleCount clipEnd = clip->GetEndSample(); if (clipStart < start && clipEnd > start && clipEnd <= end) { // the reverse selection begins at the inside of a clip double splitTime = track->LongSamplesToTime(start); track->SplitAt(splitTime); } else if (clipStart >= start && clipStart < end && clipEnd > end) { // the reverse selection ends at the inside of a clip double splitTime = track->LongSamplesToTime(end); track->SplitAt(splitTime); } else if (clipStart < start && clipEnd > end) { // the selection begins AND ends at the inside of a clip double splitTime = track->LongSamplesToTime(start); track->SplitAt(splitTime); splitTime = track->LongSamplesToTime(end); track->SplitAt(splitTime); } node = node->GetNext(); } //STEP 2: // Individually reverse each clip inside the selected region // and apply the appropriate offset after detaching them from the track bool checkedFirstClip = false; // used in calculating the offset of clips to rearrange // holds the new end position of the current clip sampleCount currentEnd = (sampleCount)end; WaveClipList revClips; // holds the reversed clips WaveClipList otherClips; // holds the clips that appear after the reverse selection region WaveClipArray clipArray; track->FillSortedClipArray(clipArray); size_t i; for (i=0; i < clipArray.Count(); i++) { WaveClip *clip = clipArray.Item(i); sampleCount clipStart = clip->GetStartSample(); sampleCount clipEnd = clip->GetEndSample(); if (clipStart >= start && clipEnd <= end) { // if the clip is inside the selected region // this is used to check if the selected region begins with a whitespace. // if yes then clipStart (of the first clip) and start are not the same. // adjust currentEnd accordingly and set endMerge to false if(checkedFirstClip == false && clipStart > start) { checkedFirstClip = true; if(i > 0) { if (clipArray.Item(i-1)->GetEndSample() <= start) { currentEnd -= (clipStart - start); } } else { currentEnd -= (clipStart - start); } } sampleCount revStart = (clipStart >= start)? clipStart: start; sampleCount revEnd = (clipEnd >= end)? end: clipEnd; sampleCount revLen = (sampleCount)revEnd-revStart; if (revEnd >= revStart) { if(!ProcessOneClip(count, track, revStart, revLen, start, end)) // reverse the clip { rValue = false; break; } sampleCount clipOffsetStart = (sampleCount)(currentEnd - (clipEnd-clipStart)); // calculate the offset required double offsetStartTime = track->LongSamplesToTime(clipOffsetStart); if(i+1 < clipArray.Count()) // update currentEnd if there is a clip to process next { sampleCount nextClipStart = clipArray.Item(i+1)->GetStartSample(); currentEnd = (sampleCount)(currentEnd - (clipEnd - clipStart) - (nextClipStart - clipEnd)); } clip = track->RemoveAndReturnClip(clip); // detach the clip from track clip->SetOffset(track->LongSamplesToTime(track->TimeToLongSamples(offsetStartTime))); // align time to a sample and set offset revClips.Append(clip); } } else if (clipStart >= end) { // clip is after the selection region clip = track->RemoveAndReturnClip(clip); // simply remove and append to otherClips otherClips.Append(clip); } } // STEP 3: Append the clips from // revClips and otherClips back to the track size_t revClipsCount = revClips.GetCount(); for (i = 0; i < revClipsCount; i++) { WaveClipList::compatibility_iterator node = revClips.Item(revClipsCount - 1 - i); // the last clip of revClips is appended to the track first WaveClip *clip = node->GetData(); track->AddClip(clip); } for (i = 0; i < otherClips.GetCount(); i++) { WaveClipList::compatibility_iterator node = otherClips.Item(i); track->AddClip(node->GetData()); } return rValue; }