Audacity  2.2.2
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 #include "../Audacity.h"
18 #include "Reverse.h"
19 
20 #include <math.h>
21 
22 #include <wx/intl.h>
23 
24 #include "../LabelTrack.h"
25 #include "../WaveTrack.h"
26 
27 //
28 // EffectReverse
29 //
30 
32 {
33 }
34 
36 {
37 }
38 
39 // IdentInterface implementation
40 
42 {
43  return REVERSE_PLUGIN_SYMBOL;
44 }
45 
47 {
48  return _("Reverses the selected audio");
49 }
50 
51 // EffectIdentInterface implementation
52 
54 {
55  return EffectTypeProcess;
56 }
57 
59 {
60  return false;
61 }
62 
63 // Effect implementation
64 
66 {
67  //Track::All is needed because Reverse should move the labels too
68  this->CopyInputTracks(Track::All); // Set up mOutputTracks.
69  bool bGoodResult = true;
70 
71  TrackListIterator iter(mOutputTracks.get());
72  Track *t = iter.First();
73  int count = 0;
74  while (t) {
75  if (t->GetKind() == Track::Wave &&
76  (t->GetSelected() || t->IsSyncLockSelected()))
77  {
78  WaveTrack *track = (WaveTrack*)t;
79 
80  if (mT1 > mT0) {
81  auto start = track->TimeToLongSamples(mT0);
82  auto end = track->TimeToLongSamples(mT1);
83  auto len = end - start;
84 
85  if (!ProcessOneWave(count, track, start, len))
86  {
87  bGoodResult = false;
88  break;
89  }
90  }
91  }
92  else if (t->GetKind() == Track::Label &&
93  (t->GetSelected() || t->IsSyncLockSelected()))
94  {
95  LabelTrack *track = (LabelTrack*)t;
96  track->ChangeLabelsOnReverse(mT0, mT1);
97  }
98  t = iter.Next();
99  count++;
100  }
101 
102  this->ReplaceProcessedTracks(bGoodResult);
103  return bGoodResult;
104 }
105 
106 bool EffectReverse::ProcessOneWave(int count, WaveTrack * track, sampleCount start, sampleCount len)
107 {
108  bool rValue = true; // return value
109 
110  auto end = start + len; // start, end, len refer to the selected reverse region
111 
112  // STEP 1:
113  // If a reverse selection begins and/or ends at the inside of a clip
114  // perform a split at the start and/or end of the reverse selection
115  const auto &clips = track->GetClips();
116  // Beware, the array grows as we loop over it. Use integer subscripts, not iterators.
117  for (size_t ii = 0; ii < clips.size(); ++ii) {
118  const auto &clip = clips[ii].get();
119  auto clipStart = clip->GetStartSample();
120  auto clipEnd = clip->GetEndSample();
121  if (clipStart < start && clipEnd > start && clipEnd <= end) { // the reverse selection begins at the inside of a clip
122  double splitTime = track->LongSamplesToTime(start);
123  track->SplitAt(splitTime);
124  }
125  else if (clipStart >= start && clipStart < end && clipEnd > end) { // the reverse selection ends at the inside of a clip
126  double splitTime = track->LongSamplesToTime(end);
127  track->SplitAt(splitTime);
128  }
129  else if (clipStart < start && clipEnd > end) { // the selection begins AND ends at the inside of a clip
130  double splitTime = track->LongSamplesToTime(start);
131  track->SplitAt(splitTime);
132  splitTime = track->LongSamplesToTime(end);
133  track->SplitAt(splitTime);
134  }
135  }
136 
137  //STEP 2:
138  // Individually reverse each clip inside the selected region
139  // and apply the appropriate offset after detaching them from the track
140 
141  bool checkedFirstClip = false;
142 
143  // used in calculating the offset of clips to rearrange
144  // holds the NEW end position of the current clip
145  auto currentEnd = end;
146 
147  WaveClipHolders revClips; // holds the reversed clips
148  WaveClipHolders otherClips; // holds the clips that appear after the reverse selection region
149  auto clipArray = track->SortedClipArray();
150  size_t i;
151  for (i=0; i < clipArray.size(); i++) {
152 
153  WaveClip *clip = clipArray[i];
154  auto clipStart = clip->GetStartSample();
155  auto clipEnd = clip->GetEndSample();
156 
157  if (clipStart >= start && clipEnd <= end) { // if the clip is inside the selected region
158 
159  // this is used to check if the selected region begins with a whitespace.
160  // if yes then clipStart (of the first clip) and start are not the same.
161  // adjust currentEnd accordingly and set endMerge to false
162  if(checkedFirstClip == false && clipStart > start) {
163  checkedFirstClip = true;
164  if(i > 0) {
165  if (clipArray[i-1]->GetEndSample() <= start) {
166  currentEnd -= (clipStart - start);
167  }
168  }
169  else {
170  currentEnd -= (clipStart - start);
171  }
172  }
173 
174  auto revStart = (clipStart >= start)? clipStart: start;
175  auto revEnd = (clipEnd >= end)? end: clipEnd;
176  auto revLen = revEnd - revStart;
177  if (revEnd >= revStart) {
178  if(!ProcessOneClip(count, track, revStart, revLen, start, end)) // reverse the clip
179  {
180  rValue = false;
181  break;
182  }
183 
184  auto clipOffsetStart = currentEnd - (clipEnd - clipStart); // calculate the offset required
185  double offsetStartTime = track->LongSamplesToTime(clipOffsetStart);
186  if(i+1 < clipArray.size()) // update currentEnd if there is a clip to process next
187  {
188  auto nextClipStart = clipArray[i+1]->GetStartSample();
189  currentEnd = currentEnd - (clipEnd - clipStart) - (nextClipStart - clipEnd);
190  }
191 
192  revClips.push_back(track->RemoveAndReturnClip(clip)); // detach the clip from track
193  revClips.back()->SetOffset(track->LongSamplesToTime(track->TimeToLongSamples(offsetStartTime))); // align time to a sample and set offset
194  }
195  }
196  else if (clipStart >= end) { // clip is after the selection region
197  otherClips.push_back(track->RemoveAndReturnClip(clip)); // simply remove and append to otherClips
198  }
199  }
200 
201  // STEP 3: Append the clips from
202  // revClips and otherClips back to the track
203  // the last clip of revClips is appended to the track first
204  // PRL: I don't think that matters, the sequence of storage of clips in the track
205  // is not elsewhere assumed to be by time
206  for (auto it = revClips.rbegin(), end = revClips.rend(); it != end; ++it)
207  track->AddClip(std::move(*it));
208 
209  for (auto &clip : otherClips)
210  track->AddClip(std::move(clip));
211 
212  return rValue;
213 }
214 
216  sampleCount start, sampleCount len,
217  sampleCount originalStart, sampleCount originalEnd)
218 {
219  bool rc = true;
220  // keep track of two blocks whose data we will swap
221  auto first = start;
222 
223  auto blockSize = track->GetMaxBlockSize();
224  float tmp;
225  Floats buffer1{ blockSize };
226  Floats buffer2{ blockSize };
227 
228  auto originalLen = originalEnd - originalStart;
229 
230  while (len > 1) {
231  auto block =
232  limitSampleBufferSize( track->GetBestBlockSize(first), len / 2 );
233  auto second = first + (len - block);
234 
235  track->Get((samplePtr)buffer1.get(), floatSample, first, block);
236  track->Get((samplePtr)buffer2.get(), floatSample, second, block);
237  for (decltype(block) i = 0; i < block; i++) {
238  tmp = buffer1[i];
239  buffer1[i] = buffer2[block-i-1];
240  buffer2[block-i-1] = tmp;
241  }
242  track->Set((samplePtr)buffer1.get(), floatSample, first, block);
243  track->Set((samplePtr)buffer2.get(), floatSample, second, block);
244 
245  len -= 2 * block;
246  first += block;
247 
248  if( TrackProgress(count, 2 * ( first - originalStart ).as_double() /
249  originalLen.as_double() ) ) {
250  rc = false;
251  break;
252  }
253  }
254 
255  return rc;
256 }
EffectType GetType() override
Definition: Reverse.cpp:53
double mT1
Definition: Effect.h:464
void SplitAt(double t)
Definition: WaveTrack.cpp:2385
void ChangeLabelsOnReverse(double b, double e)
Definition: LabelTrack.cpp:213
bool TrackProgress(int whichTrack, double frac, const wxString &=wxEmptyString)
Definition: Effect.cpp:1988
bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true) const
Definition: WaveTrack.cpp:1977
void CopyInputTracks()
Definition: Effect.cpp:2039
bool ProcessOneWave(int count, WaveTrack *track, sampleCount start, sampleCount len)
Definition: Reverse.cpp:106
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: Effect.cpp:2170
WaveClipPointers SortedClipArray()
Definition: WaveTrack.cpp:2579
std::vector< WaveClipHolder > WaveClipHolders
Definition: WaveClip.h:122
size_t GetBestBlockSize(sampleCount t) const
Definition: WaveTrack.cpp:1613
wxString GetSymbol() override
Definition: Reverse.cpp:41
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:113
std::shared_ptr< WaveClip > RemoveAndReturnClip(WaveClip *clip)
Definition: WaveTrack.cpp:994
wxString GetDescription() override
Definition: Reverse.cpp:46
bool ProcessOneClip(int count, WaveTrack *track, sampleCount start, sampleCount len, sampleCount originalStart, sampleCount originalEnd)
Definition: Reverse.cpp:215
void Set(samplePtr buffer, sampleFormat format, sampleCount start, size_t len)
Definition: WaveTrack.cpp:2054
sampleCount GetEndSample() const
Definition: WaveClip.cpp:443
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:176
bool IsInteractive() override
Definition: Reverse.cpp:58
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
WaveClipHolders & GetClips()
Definition: WaveTrack.h:364
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:94
sampleCount GetStartSample() const
Definition: WaveClip.cpp:438
size_t GetMaxBlockSize() const
Definition: WaveTrack.cpp:1631
An iterator for a TrackList.
Definition: Track.h:394
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
#define REVERSE_PLUGIN_SYMBOL
Definition: Reverse.h:20
void AddClip(std::shared_ptr< WaveClip > &&clip)
Definition: WaveTrack.cpp:1007
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1849
bool Process() override
Definition: Reverse.cpp:65
virtual ~EffectReverse()
Definition: Reverse.cpp:35
double LongSamplesToTime(sampleCount pos) const
Convert correctly between an number of samples and an (absolute) time in seconds. ...
Definition: WaveTrack.cpp:1854
std::shared_ptr< TrackList > mOutputTracks
Definition: Effect.h:462
double mT0
Definition: Effect.h:463