forked from audacity/audacity
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBlockFile.h
More file actions
308 lines (238 loc) · 10.9 KB
/
Copy pathBlockFile.h
File metadata and controls
308 lines (238 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/**********************************************************************
Audacity: A Digital Audio Editor
BlockFile.h
Joshua Haberman
Dominic Mazzoni
**********************************************************************/
#ifndef __AUDACITY_BLOCKFILE__
#define __AUDACITY_BLOCKFILE__
#include "SampleFormat.h"
#include "wxFileNameWrapper.h" // member variable
#include "ondemand/ODTaskThread.h"
#include <functional>
class XMLWriter;
class SummaryInfo {
public:
SummaryInfo(size_t samples);
int fields; /* Usually 3 for Min, Max, RMS */
sampleFormat format;
int bytesPerFrame;
size_t frames64K;
int offset64K;
size_t frames256;
int offset256;
size_t totalSummaryBytes;
};
class BlockFile;
class AliasBlockFile;
using BlockFilePtr = std::shared_ptr<BlockFile>;
template< typename Result, typename... Args >
inline std::shared_ptr< Result > make_blockfile (Args && ... args)
{
return std::make_shared< Result > ( std::forward< Args > ( args )... );
}
class PROFILE_DLL_API BlockFile /* not final, abstract */ {
public:
// Type of function to be called when opening of an alias block file for read
// discovers that the other audio file it depends on is absent
using MissingAliasFileFoundHook =
std::function< void(const AliasBlockFile*) >;
// Install a hook, and return the previous hook
static MissingAliasFileFoundHook
SetMissingAliasFileFound( MissingAliasFileFoundHook hook );
// Constructor / Destructor
/// Construct a BlockFile.
BlockFile(wxFileNameWrapper &&fileName, size_t samples);
virtual ~BlockFile();
static unsigned long gBlockFileDestructionCount;
// Reading
/// Retrieves audio data from this BlockFile
/// Returns the number of samples really read, not more than len
/// If fewer can be read than len, throws an exception if mayThrow is true,
/// otherwise fills the remainder of data with zeroes.
virtual size_t ReadData(samplePtr data, sampleFormat format,
size_t start, size_t len, bool mayThrow = true)
const = 0;
// Other Properties
// Write cache to disk, if it has any
virtual bool GetNeedWriteCacheToDisk() { return false; }
virtual void WriteCacheToDisk() { /* no cache by default */ }
// Fill read cache of block file, if it has any
virtual bool GetNeedFillCache() { return false; }
virtual void FillCache() /* noexcept */ { /* no cache by default */ }
/// Stores a representation of this file in XML
virtual void SaveXML(XMLWriter &xmlFile) = 0;
/// Gets the filename of the disk file associated with this BlockFile
/// (can be empty -- some BlockFiles, like SilentBlockFile, correspond to
/// no file on disk)
/// Avoids copying wxFileName by returning a reference, but for some subclasses
/// of BlockFile, you must exclude other threads from changing the name so long
/// as you have only a reference. Thus, this wrapper object that guarantees release
/// of any lock when it goes out of scope. Call mLocker.reset() to unlock it sooner.
struct GetFileNameResult {
const wxFileName &name;
ODLocker mLocker;
GetFileNameResult(const wxFileName &name_, ODLocker &&locker = ODLocker{})
: name{ name_ }, mLocker{ std::move(locker) } {}
GetFileNameResult(const GetFileNameResult&) PROHIBITED;
GetFileNameResult &operator= (const GetFileNameResult&) PROHIBITED;
GetFileNameResult(GetFileNameResult &&that)
: name{ that.name }, mLocker{ std::move(that.mLocker) } {}
};
virtual GetFileNameResult GetFileName() const;
virtual void SetFileName(wxFileNameWrapper &&name);
// Managing an external file dependency
// Default always returns empty
virtual const wxFileNameWrapper &GetExternalFileName() const;
// Default does nothing (and gives assertion violation in debug)
virtual void SetExternalFileName( wxFileNameWrapper &&newName );
size_t GetLength() const { return mLen; }
void SetLength(size_t newLen) { mLen = newLen; }
/// Locks this BlockFile, to prevent it from being moved
virtual void Lock();
/// Unlock this BlockFile, allowing it to be moved
virtual void Unlock();
/// Returns TRUE if this BlockFile is locked
virtual bool IsLocked();
struct MinMaxRMS { float min, max, RMS; };
/// Gets extreme values for the specified region
virtual MinMaxRMS GetMinMaxRMS(size_t start, size_t len,
bool mayThrow = true) const;
/// Gets extreme values for the entire block
virtual MinMaxRMS GetMinMaxRMS(bool mayThrow = true) const;
/// Returns the 256 byte summary data block
virtual bool Read256(float *buffer, size_t start, size_t len);
/// Returns the 64K summary data block
virtual bool Read64K(float *buffer, size_t start, size_t len);
/// Returns TRUE if this block references another disk file
virtual bool IsAlias() const { return false; }
/// Returns TRUE if this block's complete summary has been computed and is ready (for OD)
virtual bool IsSummaryAvailable() const {return true;}
/// Returns TRUE if this block's complete data is ready to be accessed by Read()
virtual bool IsDataAvailable() const {return true;}
/// Returns TRUE if the summary has not yet been written, but is actively being computed and written to disk
virtual bool IsSummaryBeingComputed(){return false;}
/// Create a NEW BlockFile identical to this, using the given filename
virtual BlockFilePtr Copy(wxFileNameWrapper &&newFileName) = 0;
// Report disk space usage.
using DiskByteCount = unsigned long long;
virtual DiskByteCount GetSpaceUsage() const = 0;
/// if the on-disk state disappeared, either recover it (if it was
//summary only), write out a placeholder of silence data (missing
//.au) or mark the blockfile to deal some other way without spewing
//errors.
// May throw exceptions for i/o errors.
virtual void Recover() = 0;
/// if we've detected an on-disk problem, the user opted to
//continue and the error persists, don't keep reporting it. The
//Object implements this functionality internally, but we want to
//be able to tell the logging to shut up from outside too.
void SilenceLog() const { mSilentLog = TRUE; }
///when the project closes, it locks the blockfiles.
///Override this in case it needs special treatment.
// not balanced by unlocking calls.
virtual void CloseLock(){Lock();}
protected:
/// Prevents a read on other threads. The basic blockfile runs on only one thread, so does nothing.
virtual void LockRead() const {}
/// Allows reading on other threads.
virtual void UnlockRead() const {}
struct ReadLocker { void operator () ( const BlockFile *p ) const {
if (p) p->LockRead(); } };
struct ReadUnlocker { void operator () ( const BlockFile *p ) const {
if (p) p->UnlockRead(); } };
using ReadLockBase =
std::unique_ptr< const BlockFile, ReadUnlocker >;
public:
class ReadLock : public ReadLockBase
{
friend BlockFile;
ReadLock ( const BlockFile *p, const BlockFile::ReadUnlocker &u )
: ReadLockBase { p, u } {}
public:
ReadLock(ReadLock&&that) : ReadLockBase{ std::move(that) } {}
using Suspension = std::unique_ptr< const BlockFile, ReadLocker >;
Suspension Suspend() const
{ if (get()) get()->UnlockRead();
return Suspension{ get(), ReadLocker{} }; }
};
// RAII wrapper about the read locking functions
ReadLock LockForRead() const { LockRead(); return { this, ReadUnlocker{} }; }
private:
protected:
/// Calculate summary data for the given sample data
/// Overrides have differing details of memory management
virtual void *CalcSummary(samplePtr buffer, size_t len,
sampleFormat format,
// This gets filled, if the caller needs to deallocate. Else it is null.
ArrayOf<char> &cleanup);
// Common, nonvirtual calculation routine for the use of the above
void CalcSummaryFromBuffer(const float *fbuffer, size_t len,
float *summary256, float *summary64K);
/// Read the summary section of the file. Derived classes implement.
virtual bool ReadSummary(ArrayOf<char> &data) = 0;
/// Byte-swap the summary data, in case it was saved by a system
/// on a different platform
virtual void FixSummary(void *data);
static size_t CommonReadData(
bool mayThrow,
const wxFileName &fileName, bool &mSilentLog,
const AliasBlockFile *pAliasFile, sampleCount origin, unsigned channel,
samplePtr data, sampleFormat format, size_t start, size_t len,
const sampleFormat *pLegacyFormat = nullptr, size_t legacyLen = 0);
private:
int mLockCount;
static ArrayOf<char> fullSummary;
protected:
wxFileNameWrapper mFileName;
size_t mLen;
SummaryInfo mSummaryInfo;
float mMin, mMax, mRMS;
mutable bool mSilentLog;
};
/// A BlockFile that refers to data in an existing file
/// An AliasBlockFile references an existing disk file for its storage
/// instead of copying the data. It still writes a file to disk, but
/// only stores summary data in it.
///
/// This is a common base class for all alias block files. It handles
/// reading and writing summary data, leaving very little for derived
/// classes to need to implement.
class AliasBlockFile /* not final */ : public BlockFile
{
public:
// Constructor / Destructor
/// Constructs an AliasBlockFile
AliasBlockFile(wxFileNameWrapper &&baseFileName,
wxFileNameWrapper &&aliasedFileName, sampleCount aliasStart,
size_t aliasLen, int aliasChannel);
AliasBlockFile(wxFileNameWrapper &&existingSummaryFileName,
wxFileNameWrapper &&aliasedFileName, sampleCount aliasStart,
size_t aliasLen, int aliasChannel,
float min, float max, float RMS);
virtual ~AliasBlockFile();
// Reading
DiskByteCount GetSpaceUsage() const override;
/// as SilentLog (which would affect Summary data access), but
// applying to Alias file access
void SilenceAliasLog() const { mSilentAliasLog = TRUE; }
//
// These methods are for advanced use only!
//
const wxFileNameWrapper &GetAliasedFileName() const { return mAliasedFileName; }
void ChangeAliasedFileName(wxFileNameWrapper &&newAliasedFile);
bool IsAlias() const override { return true; }
const wxFileNameWrapper &GetExternalFileName() const override;
void SetExternalFileName( wxFileNameWrapper &&newName ) override;
protected:
// Introduce a NEW virtual.
/// Write the summary to disk, using the derived ReadData() to get the data
virtual void WriteSummary();
/// Read the summary into a buffer
bool ReadSummary(ArrayOf<char> &data) override;
wxFileNameWrapper mAliasedFileName;
sampleCount mAliasStart;
const int mAliasChannel;
mutable bool mSilentAliasLog;
};
#endif