Audacity 3.2.0
Reverse.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Reverse.cpp
6
7 Mark Phillips
8
9*******************************************************************//********************************************************************/
15
16
17
18#include "Reverse.h"
19#include "LoadEffects.h"
20
21#include <math.h>
22
23#include <wx/intl.h>
24
25#include "../LabelTrack.h"
26#include "../SyncLock.h"
27#include "../WaveClip.h"
28#include "../WaveTrack.h"
29
30//
31// EffectReverse
32//
33
35{ XO("Reverse") };
36
38
40{
41}
42
44{
45}
46
47// ComponentInterface implementation
48
50{
51 return Symbol;
52}
53
55{
56 return XO("Reverses the selected audio");
57}
58
59// EffectDefinitionInterface implementation
60
62{
63 return EffectTypeProcess;
64}
65
67{
68 return false;
69}
70
71// Effect implementation
72
74{
75 //all needed because Reverse should move the labels too
76 this->CopyInputTracks(true); // Set up mOutputTracks.
77 bool bGoodResult = true;
78 int count = 0;
79
80 auto trackRange =
82 trackRange.VisitWhile( bGoodResult,
83 [&](WaveTrack * track) {
84 if (mT1 > mT0) {
85 auto start = track->TimeToLongSamples(mT0);
86 auto end = track->TimeToLongSamples(mT1);
87 auto len = end - start;
88
89 if (!ProcessOneWave(count, track, start, len))
90 bGoodResult = false;
91 }
92 count++;
93 },
94 [&](LabelTrack * track) {
95 track->ChangeLabelsOnReverse(mT0, mT1);
96 count++;
97 }
98 );
99
100 this->ReplaceProcessedTracks(bGoodResult);
101 return bGoodResult;
102}
103
105{
106 bool rValue = true; // return value
107
108 auto end = start + len; // start, end, len refer to the selected reverse region
109
110 // STEP 1:
111 // If a reverse selection begins and/or ends at the inside of a clip
112 // perform a split at the start and/or end of the reverse selection
113 const auto &clips = track->GetClips();
114 // Beware, the array grows as we loop over it. Use integer subscripts, not iterators.
115 for (size_t ii = 0; ii < clips.size(); ++ii) {
116 const auto &clip = clips[ii].get();
117 auto clipStart = clip->GetPlayStartSample();
118 auto clipEnd = clip->GetPlayEndSample();
119 if (clipStart < start && clipEnd > start && clipEnd <= end) { // the reverse selection begins at the inside of a clip
120 double splitTime = track->LongSamplesToTime(start);
121 track->SplitAt(splitTime);
122 }
123 else if (clipStart >= start && clipStart < end && clipEnd > end) { // the reverse selection ends at the inside of a clip
124 double splitTime = track->LongSamplesToTime(end);
125 track->SplitAt(splitTime);
126 }
127 else if (clipStart < start && clipEnd > end) { // the selection begins AND ends at the inside of a clip
128 double splitTime = track->LongSamplesToTime(start);
129 track->SplitAt(splitTime);
130 splitTime = track->LongSamplesToTime(end);
131 track->SplitAt(splitTime);
132 }
133 }
134
135 //STEP 2:
136 // Individually reverse each clip inside the selected region
137 // and apply the appropriate offset after detaching them from the track
138
139 bool checkedFirstClip = false;
140
141 // used in calculating the offset of clips to rearrange
142 // holds the NEW end position of the current clip
143 auto currentEnd = end;
144
145 WaveClipHolders revClips; // holds the reversed clips
146 WaveClipHolders otherClips; // holds the clips that appear after the reverse selection region
147 auto clipArray = track->SortedClipArray();
148 size_t i;
149 for (i=0; i < clipArray.size(); i++) {
150
151 WaveClip *clip = clipArray[i];
152 auto clipStart = clip->GetPlayStartSample();
153 auto clipEnd = clip->GetPlayEndSample();
154
155 if (clipStart >= start && clipEnd <= end) { // if the clip is inside the selected region
156
157 // this is used to check if the selected region begins with a whitespace.
158 // if yes then clipStart (of the first clip) and start are not the same.
159 // adjust currentEnd accordingly and set endMerge to false
160 if(checkedFirstClip == false && clipStart > start) {
161 checkedFirstClip = true;
162 if(i > 0) {
163 if (clipArray[i-1]->GetPlayEndSample() <= start) {
164 currentEnd -= (clipStart - start);
165 }
166 }
167 else {
168 currentEnd -= (clipStart - start);
169 }
170 }
171
172 auto revStart = (clipStart >= start)? clipStart: start;
173 auto revEnd = (clipEnd >= end)? end: clipEnd;
174 auto revLen = revEnd - revStart;
175 if (revEnd >= revStart) {
176 if(!ProcessOneClip(count, track, revStart, revLen, start, end)) // reverse the clip
177 {
178 rValue = false;
179 break;
180 }
181
182 auto clipOffsetStart = currentEnd - (clipEnd - clipStart); // calculate the offset required
183 double offsetStartTime = track->LongSamplesToTime(clipOffsetStart);
184 if(i+1 < clipArray.size()) // update currentEnd if there is a clip to process next
185 {
186 auto nextClipStart = clipArray[i+1]->GetPlayStartSample();
187 currentEnd = currentEnd - (clipEnd - clipStart) - (nextClipStart - clipEnd);
188 }
189
190 revClips.push_back(track->RemoveAndReturnClip(clip)); // detach the clip from track
191 revClips.back()->SetPlayStartTime(track->LongSamplesToTime(track->TimeToLongSamples(offsetStartTime))); // align time to a sample and set offset
192 }
193 }
194 else if (clipStart >= end) { // clip is after the selection region
195 otherClips.push_back(track->RemoveAndReturnClip(clip)); // simply remove and append to otherClips
196 }
197 }
198
199 // STEP 3: Append the clips from
200 // revClips and otherClips back to the track
201 // the last clip of revClips is appended to the track first
202 // PRL: I don't think that matters, the sequence of storage of clips in the track
203 // is not elsewhere assumed to be by time
204 {
205 for (auto it = revClips.rbegin(), revEnd = revClips.rend(); rValue && it != revEnd; ++it)
206 rValue = track->AddClip(*it);
207 }
208
209 for (auto &clip : otherClips)
210 if (!(rValue = track->AddClip(clip)))
211 break;
212
213 return rValue;
214}
215
217 sampleCount start, sampleCount len,
218 sampleCount originalStart, sampleCount originalEnd)
219{
220 bool rc = true;
221 // keep track of two blocks whose data we will swap
222 auto first = start;
223
224 auto blockSize = track->GetMaxBlockSize();
225 float tmp;
226 Floats buffer1{ blockSize };
227 Floats buffer2{ blockSize };
228
229 auto originalLen = originalEnd - originalStart;
230
231 while (len > 1) {
232 auto block =
233 limitSampleBufferSize( track->GetBestBlockSize(first), len / 2 );
234 auto second = first + (len - block);
235
236 track->GetFloats(buffer1.get(), first, block);
237 track->GetFloats(buffer2.get(), second, block);
238 for (decltype(block) i = 0; i < block; i++) {
239 tmp = buffer1[i];
240 buffer1[i] = buffer2[block-i-1];
241 buffer2[block-i-1] = tmp;
242 }
243 track->Set((samplePtr)buffer1.get(), floatSample, first, block);
244 track->Set((samplePtr)buffer2.get(), floatSample, second, block);
245
246 len -= 2 * block;
247 first += block;
248
249 if( TrackProgress(count, 2 * ( first - originalStart ).as_double() /
250 originalLen.as_double() ) ) {
251 rc = false;
252 break;
253 }
254 }
255
256 return rc;
257}
EffectType
@ EffectTypeProcess
#define XO(s)
Definition: Internat.h:31
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:23
@ floatSample
Definition: SampleFormat.h:34
char * samplePtr
Definition: SampleFormat.h:49
std::vector< WaveClipHolder > WaveClipHolders
Definition: WaveClip.h:42
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
double mT1
Definition: EffectBase.h:107
std::shared_ptr< TrackList > mOutputTracks
Definition: EffectBase.h:105
double mT0
Definition: EffectBase.h:106
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: EffectBase.cpp:236
void CopyInputTracks(bool allSyncLockSelected=false)
Definition: Effect.cpp:741
bool TrackProgress(int whichTrack, double frac, const TranslatableString &={}) const
Definition: Effect.cpp:693
Performs effect computation.
static const ComponentInterfaceSymbol Symbol
Definition: Reverse.h:21
ComponentInterfaceSymbol GetSymbol() const override
Definition: Reverse.cpp:49
EffectType GetType() const override
Type determines how it behaves.
Definition: Reverse.cpp:61
bool ProcessOneClip(int count, WaveTrack *track, sampleCount start, sampleCount len, sampleCount originalStart, sampleCount originalEnd)
Definition: Reverse.cpp:216
TranslatableString GetDescription() const override
Definition: Reverse.cpp:54
virtual ~EffectReverse()
Definition: Reverse.cpp:43
bool Process(EffectInstance &instance, EffectSettings &settings) override
Actually do the effect here.
Definition: Reverse.cpp:73
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
Definition: Reverse.cpp:66
bool ProcessOneWave(int count, WaveTrack *track, sampleCount start, sampleCount len)
Definition: Reverse.cpp:104
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:89
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
Retrieve samples from a track in floating-point format, regardless of the storage format.
Definition: SampleTrack.h:67
double LongSamplesToTime(sampleCount pos) const
Convert correctly between a number of samples and an (absolute) time in seconds.
Definition: SampleTrack.cpp:47
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: SampleTrack.cpp:42
static bool IsSelectedOrSyncLockSelected(const Track *pTrack)
Definition: SyncLock.cpp:73
Holds a msgid for the translation catalog; may also bind format arguments.
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:101
sampleCount GetPlayEndSample() const
Definition: WaveClip.cpp:925
sampleCount GetPlayStartSample() const
Definition: WaveClip.cpp:920
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
void SplitAt(double t)
Definition: WaveTrack.cpp:2525
bool AddClip(const std::shared_ptr< WaveClip > &clip)
Append a clip to the track; which must have the same block factory as this track; return success.
Definition: WaveTrack.cpp:1220
size_t GetMaxBlockSize() const override
This returns a nonnegative number of samples meant to size a memory buffer.
Definition: WaveTrack.cpp:1806
size_t GetBestBlockSize(sampleCount t) const override
This returns a nonnegative number of samples meant to size a memory buffer.
Definition: WaveTrack.cpp:1788
WaveClipPointers SortedClipArray()
Definition: WaveTrack.cpp:2723
void Set(constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len)
Definition: WaveTrack.cpp:2195
std::shared_ptr< WaveClip > RemoveAndReturnClip(WaveClip *clip)
Definition: WaveTrack.cpp:1207
WaveClipHolders & GetClips()
Definition: WaveTrack.h:329
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
BuiltinEffectsModule::Registration< EffectReverse > reg
Definition: Reverse.cpp:37
Externalized state of a plug-in.