bool WaveTrack::Get(samplePtr buffer, sampleFormat format, longSampleCount start, sampleCount len) { // Simple optimization: When this buffer is completely contained within one clip, // don't clear anything (because we never won't have to). Otherwise, just clear // everything to be on the safe side. WaveClipList::Node* it; bool doClear = true; for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); if (start >= clip->GetStartSample() && start+len <= clip->GetEndSample()) { doClear = false; break; } } if (doClear) ClearSamples(buffer, format, 0, len); for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); longSampleCount clipStart = clip->GetStartSample(); longSampleCount clipEnd = clip->GetEndSample(); if (clipEnd > start && clipStart < start+len) { // Clip sample region and Get/Put sample region overlap sampleCount samplesToCopy = start+len - clipStart; if (samplesToCopy > clip->GetNumSamples()) samplesToCopy = clip->GetNumSamples(); longSampleCount inclipDelta = 0; longSampleCount startDelta = clipStart - start; if (startDelta < 0) { inclipDelta = -startDelta; // make positive value samplesToCopy -= inclipDelta; startDelta = 0; } if (!clip->GetSamples((samplePtr)(((char*)buffer)+startDelta*SAMPLE_SIZE(format)), format, inclipDelta, samplesToCopy)) { wxASSERT(false); // should always work return false; } } } return true; }
bool WaveTrack::Silence(double t0, double t1) { if (t1 < t0) return false; longSampleCount start = (longSampleCount)floor(t0 * mRate + 0.5); longSampleCount len = (longSampleCount)floor(t1 * mRate + 0.5) - start; bool result = true; for (WaveClipList::Node* it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); longSampleCount clipStart = clip->GetStartSample(); longSampleCount clipEnd = clip->GetEndSample(); if (clipEnd > start && clipStart < start+len) { // Clip sample region and Get/Put sample region overlap sampleCount samplesToCopy = start+len - clipStart; if (samplesToCopy > clip->GetNumSamples()) samplesToCopy = clip->GetNumSamples(); longSampleCount inclipDelta = 0; longSampleCount startDelta = clipStart - start; if (startDelta < 0) { inclipDelta = -startDelta; // make positive value samplesToCopy -= inclipDelta; startDelta = 0; } if (!clip->GetSequence()->SetSilence(inclipDelta, samplesToCopy)) { wxASSERT(false); // should always work return false; } clip->MarkChanged(); } } return result; }
bool WaveTrack::Set(samplePtr buffer, sampleFormat format, longSampleCount start, sampleCount len) { bool result = true; for (WaveClipList::Node* it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); longSampleCount clipStart = clip->GetStartSample(); longSampleCount clipEnd = clip->GetEndSample(); if (clipEnd > start && clipStart < start+len) { // Clip sample region and Get/Put sample region overlap sampleCount samplesToCopy = start+len - clipStart; if (samplesToCopy > clip->GetNumSamples()) samplesToCopy = clip->GetNumSamples(); longSampleCount inclipDelta = 0; longSampleCount startDelta = clipStart - start; if (startDelta < 0) { inclipDelta = -startDelta; // make positive value samplesToCopy -= inclipDelta; startDelta = 0; } if (!clip->SetSamples((samplePtr)(((char*)buffer)+startDelta*SAMPLE_SIZE(format)), format, inclipDelta, samplesToCopy)) { wxASSERT(false); // should always work return false; } clip->MarkChanged(); } } return result; }
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; }
bool EffectReverse::ProcessOneWave(int count, WaveTrack * track, sampleCount start, sampleCount len) { bool rValue = true; // return value auto end = 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 const auto &clips = track->GetClips(); // Beware, the array grows as we loop over it. Use integer subscripts, not iterators. for (int ii = 0; ii < clips.size(); ++ii) { const auto &clip = clips[ii].get(); auto clipStart = clip->GetStartSample(); auto 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); } } //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 auto currentEnd = end; WaveClipHolders revClips; // holds the reversed clips WaveClipHolders otherClips; // holds the clips that appear after the reverse selection region auto clipArray = track->SortedClipArray(); size_t i; for (i=0; i < clipArray.size(); i++) { WaveClip *clip = clipArray[i]; auto clipStart = clip->GetStartSample(); auto 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[i-1]->GetEndSample() <= start) { currentEnd -= (clipStart - start); } } else { currentEnd -= (clipStart - start); } } auto revStart = (clipStart >= start)? clipStart: start; auto revEnd = (clipEnd >= end)? end: clipEnd; auto revLen = revEnd - revStart; if (revEnd >= revStart) { if(!ProcessOneClip(count, track, revStart, revLen, start, end)) // reverse the clip { rValue = false; break; } auto clipOffsetStart = currentEnd - (clipEnd - clipStart); // calculate the offset required double offsetStartTime = track->LongSamplesToTime(clipOffsetStart); if(i+1 < clipArray.size()) // update currentEnd if there is a clip to process next { auto nextClipStart = clipArray[i+1]->GetStartSample(); currentEnd = currentEnd - (clipEnd - clipStart) - (nextClipStart - clipEnd); } revClips.push_back(track->RemoveAndReturnClip(clip)); // detach the clip from track revClips.back()->SetOffset(track->LongSamplesToTime(track->TimeToLongSamples(offsetStartTime))); // align time to a sample and set offset } } else if (clipStart >= end) { // clip is after the selection region otherClips.push_back(track->RemoveAndReturnClip(clip)); // simply remove and append to otherClips } } // STEP 3: Append the clips from // revClips and otherClips back to the track // the last clip of revClips is appended to the track first // PRL: I don't think that matters, the sequence of storage of clips in the track // is not elsewhere assumed to be by time for (auto it = revClips.rbegin(), end = revClips.rend(); it != end; ++it) track->AddClip(std::move(*it)); for (auto &clip : otherClips) track->AddClip(std::move(clip)); return rValue; }