Audacity  2.2.2
ODDecodeBlockFile.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ODDecodeBlockFile.cpp
6 
7  Created by Michael Chinen (mchinen)
8  Audacity(R) is copyright (c) 1999-2008 Audacity Team.
9  License: GPL v2. See License.txt.
10 
11 ******************************************************************//*******************************************************************/
18 
19 #include "../Audacity.h"
20 #include "ODDecodeBlockFile.h"
21 
22 #include <float.h>
23 
24 #include <wx/utils.h>
25 #include <wx/wxchar.h>
26 #include <wx/log.h>
27 #include <wx/thread.h>
28 #include <sndfile.h>
29 
30 #include "../FileException.h"
31 #include "../FileFormats.h"
32 #include "../Internat.h"
34 
35 const int bheaderTagLen = 20;
36 char bheaderTag[bheaderTagLen + 1] = "AudacityBlockFile112";
37 
38 
39 
41 ODDecodeBlockFile::ODDecodeBlockFile(wxFileNameWrapper &&baseFileName, wxFileNameWrapper &&audioFileName, sampleCount aliasStart,
42  size_t aliasLen, int aliasChannel,unsigned int decodeType)
43 try
44  : SimpleBlockFile{ std::move(baseFileName),
45  NULL, aliasLen, floatSample, true, true },
46  //floatSample has no effect. last two bools - bypass writing of blockfile and cache
47 
48  mType(decodeType),
49  mAliasStart(aliasStart),
50  mAliasChannel(aliasChannel)
51 {
52  mDecoder = NULL;
53  mAudioFileName = std::move(audioFileName);
54  mFormat = int16Sample;
55 }
56 catch ( const FileException & WXUNUSED(e) )
57 {
58  // The constructor SimpleBlockFile sometimes throws this,
59  // but it never will for the arguments that were passed to it here.
60  // So add a catch for completeness, but just assert that this won't happen.
61  wxASSERT(false);
62  throw;
63 }
64 
66 ODDecodeBlockFile::ODDecodeBlockFile(wxFileNameWrapper &&existingFile, wxFileNameWrapper &&audioFileName, sampleCount aliasStart,
67  size_t aliasLen, int aliasChannel, unsigned int decodeType,
68  float min, float max, float rms, bool dataAvailable):
69  SimpleBlockFile{ std::move(existingFile), aliasLen, min, max, rms },
70 
71  mType(decodeType),
72  mDataAvailable( dataAvailable ),
73  mAliasStart(aliasStart),
74  mAliasChannel(aliasChannel)
75 {
76  mDecoder = NULL;
77  mAudioFileName = std::move(audioFileName);
78  mFormat = int16Sample;
79 }
80 
81 
82 
84 {
85 
86 }
87 
88 
89 //Check to see if we have the file for these calls.
91 {
92  if(IsSummaryAvailable())
93  {
94  wxFFile summaryFile(mFileName.GetFullPath());
95  return summaryFile.Length();
96  }
97  else
98  {
99  return 0;
100  }
101 }
102 
103 
106  size_t start, size_t len, bool mayThrow) const -> MinMaxRMS
107 {
108  if(IsSummaryAvailable())
109  {
110  return SimpleBlockFile::GetMinMaxRMS(start, len, mayThrow);
111  }
112  else
113  {
114  if (mayThrow)
115  throw NotYetAvailableException{ mAudioFileName };
116 
117  //fake values. These values are used usually for normalization and amplifying, so we want
118  //the max to be maximal and the min to be minimal
119  return {
120  -1.0f, 1.0f, 0.707f //sin with amp of 1 rms
121  };
122  }
123 }
124 
126 auto ODDecodeBlockFile::GetMinMaxRMS(bool mayThrow) const -> MinMaxRMS
127 {
128  if(IsSummaryAvailable())
129  {
130  return SimpleBlockFile::GetMinMaxRMS(mayThrow);
131  }
132  else
133  {
134  if (mayThrow)
135  throw NotYetAvailableException{ mAudioFileName };
136 
137  //fake values. These values are used usually for normalization and amplifying, so we want
138  //the max to be maximal and the min to be minimal
139  return {
140  -1.0f, 1.0f, 0.707f //sin with amp of 1 rms
141  };
142  }
143 }
144 
147 bool ODDecodeBlockFile::Read256(float *buffer, size_t start, size_t len)
148 {
149  if(IsSummaryAvailable())
150  {
151  return SimpleBlockFile::Read256(buffer,start,len);
152  }
153  else
154  {
155  ClearSamples((samplePtr)buffer, floatSample, 0, len);
156  return false;
157  }
158 }
159 
162 bool ODDecodeBlockFile::Read64K(float *buffer, size_t start, size_t len)
163 {
164  if(IsSummaryAvailable())
165  {
166  return SimpleBlockFile::Read64K(buffer,start,len);
167  }
168  else
169  {
170  ClearSamples((samplePtr)buffer, floatSample, 0, len);
171  return false;
172  }
173 }
174 
180 {
181  BlockFilePtr newBlockFile;
182 
183  //mAliasedFile can change so we lock readdatamutex, which is responsible for it.
184  auto locker = LockForRead();
185  if(IsSummaryAvailable())
186  {
187  //create a simpleblockfile, because once it has the summary it is a simpleblockfile for all intents an purposes
188  newBlockFile = SimpleBlockFile::Copy(std::move(newFileName)) ;
189  }
190  else
191  {
192  //Summary File might exist in this case, but it probably (99.999% of the time) won't.
193  newBlockFile = make_blockfile<ODDecodeBlockFile>
194  (std::move(newFileName), wxFileNameWrapper{mAudioFileName},
197  //The client code will need to schedule this blockfile for OD decoding if it is going to a NEW track.
198  //It can do this by checking for IsDataAvailable()==false.
199  }
200 
201  return newBlockFile;
202 }
203 
204 
210 // may throw
211 {
212  auto locker = LockForRead();
213  if(IsSummaryAvailable())
214  {
215  SimpleBlockFile::SaveXML(xmlFile);
216  }
217  else
218  {
219  xmlFile.StartTag(wxT("oddecodeblockfile"));
220  {
221  //unlock to prevent deadlock and resume lock after.
222  auto suspension = locker.Suspend();
223  ODLocker locker2{ &mFileNameMutex };
224  xmlFile.WriteAttr(wxT("summaryfile"), mFileName.GetFullName());
225  }
226  xmlFile.WriteAttr(wxT("audiofile"), mAudioFileName.GetFullPath());
227  xmlFile.WriteAttr(wxT("aliasstart"),
228  mAliasStart.as_long_long());
229  xmlFile.WriteAttr(wxT("aliaslen"), mLen);
230  xmlFile.WriteAttr(wxT("aliaschannel"), mAliasChannel);
231  xmlFile.WriteAttr(wxT("decodetype"), (size_t)mType);
232 
233  xmlFile.EndTag(wxT("oddecodeblockfile"));
234  }
235 }
236 
239 // BuildFromXML methods should always return a BlockFile, not NULL,
240 // even if the result is flawed (e.g., refers to nonexistent file),
241 // as testing will be done in DirManager::ProjectFSCK().
243 {
244  wxFileNameWrapper summaryFileName;
245  wxFileNameWrapper audioFileName;
246  sampleCount aliasStart = 0;
247  size_t aliasLen = 0;
248  int aliasChannel=0;
249  long nValue;
250  long long nnValue;
251  unsigned int decodeType=0;
252 
253  while(*attrs)
254  {
255  const wxChar *attr = *attrs++;
256  const wxChar *value = *attrs++;
257  if (!value)
258  break;
259 
260  const wxString strValue = value;
261  if (!wxStricmp(attr, wxT("summaryfile")) &&
262  // Can't use XMLValueChecker::IsGoodFileName here, but do part of its test.
264  (strValue.Length() + 1 + dm.GetProjectDataDir().Length() <= PLATFORM_MAX_PATH))
265  {
266  if (!dm.AssignFile(summaryFileName, strValue, false))
267  // Make sure summaryFileName is back to uninitialized state so we can detect problem later.
268  summaryFileName.Clear();
269  }
270  else if( !wxStricmp(attr, wxT("audiofile")) )
271  {
272  if (XMLValueChecker::IsGoodPathName(strValue))
273  audioFileName.Assign(strValue);
274  else if (XMLValueChecker::IsGoodFileName(strValue, dm.GetProjectDataDir()))
275  // Allow fallback of looking for the file name, located in the data directory.
276  audioFileName.Assign(dm.GetProjectDataDir(), strValue);
277  else if (XMLValueChecker::IsGoodPathString(strValue))
278  // If the file is missing, we failed XMLValueChecker::IsGoodPathName()
279  // and XMLValueChecker::IsGoodFileName, because both do existence tests,
280  // but we want to keep the reference to the file because it's a good path string.
281  audioFileName.Assign(strValue);
282  }
283  else if ( !wxStricmp(attr, wxT("aliasstart")) )
284  {
285  if (XMLValueChecker::IsGoodInt64(strValue) &&
286  strValue.ToLongLong(&nnValue) && (nnValue >= 0))
287  aliasStart = nnValue;
288  }
289  else if (XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
290  { // integer parameters
291  if (!wxStricmp(attr, wxT("aliaslen")) && (nValue >= 0))
292  aliasLen = nValue;
293  else if (!wxStricmp(attr, wxT("aliaschannel")) && XMLValueChecker::IsValidChannel(aliasChannel))
294  aliasChannel = nValue;
295  else if( !wxStricmp(attr, wxT("decodetype")) )
296  decodeType = nValue;
297  }
298  }
299 
300  return make_blockfile<ODDecodeBlockFile>
301  (std::move(summaryFileName), std::move(audioFileName),
302  aliasStart, aliasLen, aliasChannel, decodeType, 0, 0, 0, false);
303 }
304 
305 
306 
308 {
309  if(IsSummaryAvailable())
310  {
312  }
313 }
314 
316 {
317  return IsDataAvailable();
318 }
319 
321 {
322  return mDataAvailable != 0;
323 }
324 
329 {
330 
331  // To build the summary data, call ReadData (implemented by the
332  // derived classes) to get the sample data
333  SampleBuffer sampleData;// = NewSamples(mLen, floatSample);
334  int ret;
335 
336  {
337  //use the decoder here.
338  ODLocker locker{ &mDecoderMutex };
339 
340  if(!mDecoder)
341  return -1;
342 
343  //sampleData and mFormat are set by the decoder.
344  ret = mDecoder->Decode(sampleData, mFormat, mAliasStart, mLen, mAliasChannel);
345 
346  if(ret < 0) {
347  wxPrintf("ODDecodeBlockFile Decode failure\n");
348  return ret; //failure
349  }
350  }
351 
352  {
353  //the summary is also calculated here.
354  ODLocker locker{ &mFileNameMutex };
355  //TODO: we may need to write a version of WriteSimpleBlockFile that uses threadsafe FILE vs wxFile
356  bool bSuccess =
358  sampleData.ptr(),
359  mLen,
360  mFormat,
361  NULL);
362  if ( !bSuccess )
363  return -1;
364  }
365 
366  wxAtomicInc( mDataAvailable );
367 
368  return ret;
369 }
370 
373 {
374  mFileNameMutex.Lock();
375  mFileName=std::move(name);
376 /* mchinen oct 9 2009 don't think we need the char* but leaving it in for now just as a reminder that we might
377  if wxFileName isn't threadsafe.
378  mFileNameChar.reinit(strlen(mFileName.GetFullPath().mb_str(wxConvUTF8))+1);
379  strcpy(mFileNameChar.get(), mFileName.GetFullPath().mb_str(wxConvUTF8)); */
380  mFileNameMutex.Unlock();
381 }
382 
385 {
386  return { mFileName, ODLocker{ &mFileNameMutex } };
387 }
388 
406 void *ODDecodeBlockFile::CalcSummary(samplePtr buffer, size_t len,
407  sampleFormat format, ArrayOf<char> &cleanup)
408 {
410  char* localFullSummary = cleanup.get();
411 
412  memcpy(localFullSummary, bheaderTag, bheaderTagLen);
413 
414  float *summary64K = (float *)(localFullSummary + mSummaryInfo.offset64K);
415  float *summary256 = (float *)(localFullSummary + mSummaryInfo.offset256);
416 
417  Floats floats;
418  float *fbuffer;
419 
420  //mchinen: think we can hack this - don't allocate and copy if we don't need to.,
421  if(format==floatSample)
422  {
423  fbuffer = (float*)buffer;
424  }
425  else
426  {
427  floats.reinit(len);
428  fbuffer = floats.get();
429  CopySamples(buffer, format,
430  (samplePtr)fbuffer, floatSample, len);
431  }
432 
433  BlockFile::CalcSummaryFromBuffer(fbuffer, len, summary256, summary64K);
434 
435  return localFullSummary;
436 }
437 
438 
439 
440 
448 size_t ODDecodeBlockFile::ReadData(samplePtr data, sampleFormat format,
449  size_t start, size_t len, bool mayThrow) const
450 {
451  auto locker = LockForRead();
452  if(IsSummaryAvailable())
453  return SimpleBlockFile::ReadData(data, format, start, len, mayThrow);
454  else
455  {
456  if (mayThrow)
458 
459  //we should do an ODRequest to start processing the data here, and wait till it finishes. and just do a SimpleBlockFile
460  //ReadData.
461  ClearSamples(data, format, 0, len);
462  return 0;
463  }
464 }
465 
473 {
474  //I dont think we need to add a mutex here because only the main thread changes filenames and calls ReadSummary
475  if(IsSummaryAvailable())
476  return SimpleBlockFile::ReadSummary(data);
477 
479  memset(data.get(), 0, mSummaryInfo.totalSummaryBytes);
480  return false;
481 }
482 
485 {
486  //since this is the only place that writes to mdecoder, it is totally thread-safe to read check without the mutex
487  if(decoder == mDecoder)
488  return;
489  mDecoderMutex.Lock();
490  mDecoder = decoder;
491  mDecoderMutex.Unlock();
492 }
493 
494 
497 {
498  mReadDataMutex.Lock();
499 }
502 {
503  mReadDataMutex.Unlock();
504 }
505 
510 {
511  mAudioFileName = std::move(newAudioFile);
512 }
513 
514 
515 
char bheaderTag[bheaderTagLen+1]
ReadLock LockForRead() const
Definition: BlockFile.h:208
MinMaxRMS GetMinMaxRMS(size_t start, size_t len, bool mayThrow) const override
Gets extreme values for the specified region.
wxAtomicInt mDataAvailable
Creates and manages BlockFile objects.
Definition: DirManager.h:54
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:78
void SaveXML(XMLWriter &xmlFile) override
Write an XML representation of this file.
wxFileNameWrapper mFileName
Definition: BlockFile.h:243
virtual void WriteAttr(const wxString &name, const wxString &value)
Definition: XMLWriter.cpp:131
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:101
void CalcSummaryFromBuffer(const float *fbuffer, size_t len, float *summary256, float *summary64K)
Definition: BlockFile.cpp:203
static bool IsValidChannel(const int nValue)
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:499
int offset64K
Definition: BlockFile.h:38
void CopySamples(samplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, unsigned int len, bool highQuality, unsigned int srcStride, unsigned int dstStride)
static bool IsGoodInt64(const wxString &strInt)
Check that the supplied string can be converted to a 64bit integer.
class to decode a particular file (one per file). Saves info such as filename and length (after the h...
Definition: ODDecodeTask.h:100
void SetFileName(wxFileNameWrapper &&name) override
sets the file name the summary info will be saved in. threadsafe.
A BlockFile that reads and writes uncompressed data using libsndfile.
bool IsSummaryAvailable() const override
Returns TRUE if this block's complete summary has been computed and is ready (for OD) ...
bool IsDataAvailable() const override
Returns TRUE if this block's complete data is ready to be accessed by Read()
static bool IsGoodPathName(const wxString &strPathName)
SummaryInfo mSummaryInfo
Definition: BlockFile.h:245
BlockFilePtr Copy(wxFileNameWrapper &&newFileName) override
Create a NEW block file identical to this one.
virtual bool Read256(float *buffer, size_t start, size_t len)
Returns the 256 byte summary data block.
Definition: BlockFile.cpp:415
float mMin
Definition: BlockFile.h:246
static bool IsGoodPathString(const wxString &str)
const int bheaderTagLen
bool ReadSummary(ArrayOf< char > &data) override
Read the summary section of the disk file.
bool Read256(float *buffer, size_t start, size_t len) override
Returns the 256 byte summary data block.
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
#define PLATFORM_MAX_PATH
Definition: Audacity.h:118
void SaveXML(XMLWriter &xmlFile) override
Saves as xml ODDecodeBlockFile or SimpleBlockFile depending on summary availability.
unsigned long long DiskByteCount
Definition: BlockFile.h:152
GetFileNameResult GetFileName() const override
sets the file name the summary info will be saved in. threadsafe.
std::shared_ptr< BlockFile > BlockFilePtr
Definition: BlockFile.h:48
void ChangeAudioFile(wxFileNameWrapper &&newAudioFile)
void UnlockRead() const override
Allows reading of encoded file on other threads.
int format
Definition: ExportPCM.cpp:56
ODFileDecoder * mDecoder
BlockFilePtr Copy(wxFileNameWrapper &&fileName) override
Makes NEW ODDecodeBlockFile or SimpleBlockFile depending on summary availability. ...
void SetODFileDecoder(ODFileDecoder *decoder)
set the decoder,
float mRMS
Definition: BlockFile.h:246
bool ReadSummary(ArrayOf< char > &data) override
Read the summary into a buffer.
void Recover(void) override
Writes the summary file if summary data is available.
size_t totalSummaryBytes
Definition: BlockFile.h:41
bool Read64K(float *buffer, size_t start, size_t len) override
Returns the 64K summary data block.
size_t ReadData(samplePtr data, sampleFormat format, size_t start, size_t len, bool mayThrow) const override
Read the data section of the disk file.
virtual int Decode(SampleBuffer &data, sampleFormat &format, sampleCount start, size_t len, unsigned int channel)=0
int min(int a, int b)
samplePtr ptr() const
Definition: SampleFormat.h:81
wxString GetProjectDataDir()
Definition: DirManager.cpp:679
size_t mLen
Definition: BlockFile.h:244
static BlockFilePtr BuildFromXML(DirManager &dm, const wxChar **attrs)
Reconstructs from XML a ODDecodeBlockFile and reschedules it for OD loading.
bool WriteSimpleBlockFile(samplePtr sampleData, size_t sampleLen, sampleFormat format, void *summaryData)
DiskByteCount GetSpaceUsage() const override
const wxChar * name
Definition: Distortion.cpp:94
static bool IsGoodFileString(const wxString &str)
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
static bool IsGoodFileName(const wxString &strFileName, const wxString &strDirName=wxEmptyString)
void LockRead() const override
Prevents a read on other threads of the encoded audio file.
ODDecodeBlockFile(wxFileNameWrapper &&baseFileName, wxFileNameWrapper &&audioFileName, sampleCount aliasStart, size_t aliasLen, int aliasChannel, unsigned int decodeType)
Create a disk file and write summary and sample data to it.
virtual MinMaxRMS GetMinMaxRMS(size_t start, size_t len, bool mayThrow=true) const
Gets extreme values for the specified region.
Definition: BlockFile.cpp:369
wxFileNameWrapper mAudioFileName
The original file the audio came from.
int offset256
Definition: BlockFile.h:40
float mMax
Definition: BlockFile.h:246
void * CalcSummary(samplePtr buffer, size_t len, sampleFormat format, ArrayOf< char > &cleanup) override
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:22
ODLock mReadDataMutex
For accessing the audio file that will be decoded. Used by dir manager;.
bool AssignFile(wxFileNameWrapper &filename, const wxString &value, bool check)
Definition: DirManager.cpp:752
size_t ReadData(samplePtr data, sampleFormat format, size_t start, size_t len, bool mayThrow) const override
Reads the specified data from the aliased file using libsndfile.
virtual bool Read64K(float *buffer, size_t start, size_t len)
Returns the 64K summary data block.
Definition: BlockFile.cpp:454