Audacity  2.2.2
ODComputeSummaryTask.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ODComputeSummaryTask.cpp
6 
7  Created by Michael Chinen (mchinen) on 6/8/08.
8  Audacity(R) is copyright (c) 1999-2008 Audacity Team.
9  License: GPL v2. See License.txt.
10 
11 ******************************************************************//*******************************************************************/
18 
19 
20 
21 #include "ODComputeSummaryTask.h"
22 #include "../AudacityException.h"
23 #include "../blockfile/ODPCMAliasBlockFile.h"
24 #include "../Sequence.h"
25 #include "../WaveTrack.h"
26 #include <wx/wx.h>
27 
28 //36 blockfiles > 3 minutes stereo 44.1kHz per ODTask::DoSome
29 #define nBlockFilesPerDoSome 36
30 
33 {
34  mMaxBlockFiles = 0;
35  mHasUpdateRan=false;
36 }
37 
38 std::unique_ptr<ODTask> ODComputeSummaryTask::Clone() const
39 {
40  auto clone = std::make_unique<ODComputeSummaryTask>();
41  clone->mDemandSample = GetDemandSample();
42  // This std::move is needed to "upcast" the pointer type
43  return std::move(clone);
44 }
45 
46 
49 {
50  //The terminate block won't allow DoSomeInternal and this method to be run async, so this is thread-safe.
51  //Deref the block files since they are ref'ed when put into the array.
52  mBlockFilesMutex.Lock();
53  mBlockFiles.clear();
54  mBlockFilesMutex.Unlock();
55 }
56 
59 {
60  if(mBlockFiles.size()<=0)
61  {
62  mPercentCompleteMutex.Lock();
63  mPercentComplete = 1.0;
64  mPercentCompleteMutex.Unlock();
65  return;
66  }
67 
68  mBlockFilesMutex.Lock();
69  for(size_t j=0; j < mWaveTracks.size() && mBlockFiles.size();j++)
70  {
71  bool success = false;
72  const auto bf = mBlockFiles[0].lock();
73 
74  sampleCount blockStartSample = 0;
75  sampleCount blockEndSample = 0;
76 
77  if(bf)
78  {
79  // WriteSummary might throw, but this is a worker thread, so stop
80  // the exceptions here!
81  success = GuardedCall<bool>( [&] {
82  bf->DoWriteSummary();
83  return true;
84  } );
85  blockStartSample = bf->GetStart();
86  blockEndSample = blockStartSample + bf->GetLength();
87  }
88  else
89  {
90  success = true;
91  // The block file disappeared.
92  //the waveform in the wavetrack now is shorter, so we need to update mMaxBlockFiles
93  //because now there is less work to do.
95  }
96 
97  if (success)
98  {
99  //take it out of the array - we are done with it.
100  mBlockFiles.erase(mBlockFiles.begin());
101  }
102  else
103  // The task does not make progress
104  ;
105 
106  //This is a bit of a convenience in case someone tries to terminate the task by closing the trackpanel or window.
107  //ODComputeSummaryTask::Terminate() uses this lock to remove everything, and we don't want it to wait since the UI is being blocked.
108  mBlockFilesMutex.Unlock();
109  wxThread::This()->Yield();
110  mBlockFilesMutex.Lock();
111 
112  //update the gui for all associated blocks. It doesn't matter that we're hitting more wavetracks then we should
113  //because this loop runs a number of times equal to the number of tracks, they probably are getting processed in
114  //the next iteration at the same sample window.
115  if (success && bf) {
116  mWaveTrackMutex.Lock();
117  for(size_t i=0;i<mWaveTracks.size();i++)
118  {
119  if(success && mWaveTracks[i])
120  mWaveTracks[i]->AddInvalidRegion(blockStartSample,blockEndSample);
121  }
122  mWaveTrackMutex.Unlock();
123  }
124  }
125 
126  mBlockFilesMutex.Unlock();
127 
128  //update percentage complete.
130 }
131 
135 {
136  if(mMaxBlockFiles==0)
137  return 1.0;
138 
139  float nextPercent;
140  mPercentCompleteMutex.Lock();
141  nextPercent=mPercentComplete + ((float)nBlockFilesPerDoSome/(mMaxBlockFiles+1));
142  mPercentCompleteMutex.Unlock();
143 
144  return nextPercent;
145 }
146 
148 {
149  mHasUpdateRanMutex.Lock();
150  mHasUpdateRan=true;
151  mHasUpdateRanMutex.Unlock();
152 }
153 
155 {
156  bool ret;
157  mHasUpdateRanMutex.Lock();
158  ret = mHasUpdateRan;
159  mHasUpdateRanMutex.Unlock();
160  return ret;
161 }
162 
164 {
165  bool hasUpdateRan;
166  hasUpdateRan = HasUpdateRan();
167  mPercentCompleteMutex.Lock();
168  if(hasUpdateRan)
169  mPercentComplete = (float) 1.0 - ((float)mBlockFiles.size() / (mMaxBlockFiles+1));
170  else
171  mPercentComplete =0.0;
172  mPercentCompleteMutex.Unlock();
173 }
174 
178 {
179  std::vector< std::weak_ptr< ODPCMAliasBlockFile > > tempBlocks;
180 
181  mWaveTrackMutex.Lock();
182 
183  for(size_t j=0;j<mWaveTracks.size();j++)
184  {
185  if(mWaveTracks[j])
186  {
187  BlockArray *blocks;
188  Sequence *seq;
189 
190  //gather all the blockfiles that we should process in the wavetrack.
191  for (const auto &clip : mWaveTracks[j]->GetAllClips()) {
192  seq = clip->GetSequence();
193  //This lock may be way too big since the whole file is one sequence.
194  //TODO: test for large files and find a way to break it down.
196 
197  //See Sequence::Delete() for why need this for now..
198  //We don't need the mBlockFilesMutex here because it is only for the vector list.
199  //These are existing blocks, and its wavetrack or blockfiles won't be deleted because
200  //of the respective mWaveTrackMutex lock and LockDeleteUpdateMutex() call.
201  blocks = clip->GetSequenceBlockArray();
202  int i;
203  int insertCursor;
204 
205  insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n)
206 
207  for(i=0; i<(int)blocks->size(); i++)
208  {
209  //if there is data but no summary, this blockfile needs summarizing.
210  SeqBlock &block = (*blocks)[i];
211  const auto &file = block.f;
212  if(file->IsDataAvailable() && !file->IsSummaryAvailable())
213  {
214  const auto odpcmaFile =
215  std::static_pointer_cast<ODPCMAliasBlockFile>(file);
216  odpcmaFile->SetStart(block.start);
217  odpcmaFile->SetClipOffset(sampleCount(
218  clip->GetStartTime()*clip->GetRate()
219  ));
220 
221  //these will always be linear within a sequence-lets take advantage of this by keeping a cursor.
222  {
223  std::shared_ptr< ODPCMAliasBlockFile > ptr;
224  while(insertCursor < (int)tempBlocks.size() &&
225  (!(ptr = tempBlocks[insertCursor].lock()) ||
226  ptr->GetStart() + ptr->GetClipOffset() <
227  odpcmaFile->GetStart() + odpcmaFile->GetClipOffset()))
228  insertCursor++;
229  }
230 
231  tempBlocks.insert(tempBlocks.begin() + insertCursor++, odpcmaFile);
232  }
233  }
234  }
235  }
236  }
237  mWaveTrackMutex.Unlock();
238 
239  //get the NEW order.
240  mBlockFilesMutex.Lock();
241  OrderBlockFiles(tempBlocks);
242  mBlockFilesMutex.Unlock();
243 
244  MarkUpdateRan();
245 }
246 
247 
248 
251  (std::vector< std::weak_ptr< ODPCMAliasBlockFile > > &unorderedBlocks)
252 {
253  mBlockFiles.clear();
254  //Order the blockfiles into our queue in a fancy convenient way. (this could be user-prefs)
255  //for now just put them in linear. We start the order from the first block that includes the ondemand sample
256  //(which the user sets by clicking.)
257  //Note that this code assumes that the array is sorted in time.
258 
259  //find the startpoint
260  auto processStartSample = GetDemandSample();
261  std::shared_ptr< ODPCMAliasBlockFile > firstBlock;
262  for(auto i = unorderedBlocks.size(); i--;)
263  {
264  auto ptr = unorderedBlocks[i].lock();
265  if(ptr)
266  {
267  //test if the blockfiles are near the task cursor. we use the last mBlockFiles[0] as our point of reference
268  //and add ones that are closer.
269  if(firstBlock &&
270  ptr->GetGlobalEnd() >= processStartSample &&
271  ( firstBlock->GetGlobalEnd() < processStartSample ||
272  ptr->GetGlobalStart() <= firstBlock->GetGlobalStart())
273  )
274  {
275  //insert at the front of the list if we get blockfiles that are after the demand sample
276  firstBlock = ptr;
277  mBlockFiles.insert(mBlockFiles.begin(), unorderedBlocks[i]);
278  }
279  else
280  {
281  //otherwise no priority
282  if ( !firstBlock )
283  firstBlock = ptr;
284  mBlockFiles.push_back(unorderedBlocks[i]);
285  }
286  if(mMaxBlockFiles< (int) mBlockFiles.size())
287  mMaxBlockFiles = mBlockFiles.size();
288  }
289  else
290  {
291  // The block file disappeared.
292  // Let it be deleted and forget about it.
293  }
294  }
295 }
Data structure containing pointer to a BlockFile and a start time. Element of a BlockArray.
Definition: Sequence.h:31
An AliasBlockFile that references uncompressed data in an existing file.
virtual sampleCount GetDemandSample() const
Definition: ODTask.cpp:227
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:54
ODLock mWaveTrackMutex
Definition: ODTask.h:160
std::vector< std::weak_ptr< ODPCMAliasBlockFile > > mBlockFiles
void CalculatePercentComplete() override
recalculates the percentage complete.
sampleCount start
the sample in the global wavetrack that this block starts at.
Definition: Sequence.h:35
float ComputeNextWorkUntilPercentageComplete() override
std::vector< WaveTrack * > mWaveTracks
Definition: ODTask.h:159
volatile float mPercentComplete
Definition: ODTask.h:150
#define nBlockFilesPerDoSome
void MarkUpdateRan()
tells us whether or not Update has been run at least once.
void SetStart(sampleCount startSample)
Sets the value that indicates where the first sample in this block corresponds to the global sequence...
void OrderBlockFiles(std::vector< std::weak_ptr< ODPCMAliasBlockFile > > &unorderedBlocks)
Orders the input as either On-Demand or default layered order.
void Terminate() override
releases memory that the ODTask owns. Subclasses should override.
std::unique_ptr< ODTask > Clone() const override
ODLock mPercentCompleteMutex
Definition: ODTask.h:151
ODComputeSummaryTask()
Constructs an ODTask.
BlockFilePtr f
Definition: Sequence.h:33
void DoSomeInternal() override
Computes and writes the data for one BlockFile if it still has a refcount.