Update of /cvsroot/audacity/audacity-src/src/blockfile
In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv25965/blockfile
Modified Files:
SimpleBlockFile.cpp SimpleBlockFile.h
Log Message:
Implement block files cache (without limit/LRU so far)
Index: SimpleBlockFile.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/blockfile/SimpleBlockFile.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- SimpleBlockFile.h 4 Nov 2006 19:55:29 -0000 1.11
+++ SimpleBlockFile.h 6 Nov 2006 10:21:05 -0000 1.12
@@ -18,6 +18,14 @@
#include "../DirManager.h"
#include "../xml/XMLWriter.h"
+struct SimpleBlockFileCache {
+ bool active;
+ bool needWrite;
+ sampleFormat format;
+ samplePtr sampleData;
+ void* summaryData;
+};
+
class SimpleBlockFile : public BlockFile {
public:
@@ -26,7 +34,8 @@
/// Create a disk file and write summary and sample data to it
SimpleBlockFile(wxFileName baseFileName,
samplePtr sampleData, sampleCount sampleLen,
- sampleFormat format);
+ sampleFormat format,
+ bool allowDeferredWrite = false);
/// Create the memory structure to refer to the given block file
SimpleBlockFile(wxFileName existingFile, sampleCount len,
float min, float max, float rms);
@@ -50,6 +59,21 @@
virtual void Recover();
static BlockFile *BuildFromXML(DirManager &dm, const wxChar **attrs);
+
+ virtual bool GetNeedWriteCacheToDisk();
+ virtual void WriteCacheToDisk();
+
+ virtual bool GetNeedFillCache() { return !mCache.active; }
+ virtual void FillCache();
+
+ protected:
+
+ bool WriteSimpleBlockFile(samplePtr sampleData, sampleCount sampleLen,
+ sampleFormat format, void* summaryData);
+ static bool GetCache();
+ void ReadIntoCache();
+
+ SimpleBlockFileCache mCache;
};
#endif
Index: SimpleBlockFile.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/blockfile/SimpleBlockFile.cpp,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- SimpleBlockFile.cpp 4 Nov 2006 19:55:29 -0000 1.21
+++ SimpleBlockFile.cpp 6 Nov 2006 10:21:05 -0000 1.22
@@ -5,6 +5,7 @@
SimpleBlockFile.cpp
Joshua Haberman
+ Markus Meyer
*******************************************************************//**
@@ -25,6 +26,28 @@
is for when the file already exists and we simply want to create
the data structure to refer to it.
+The block file can be cached in two ways. Caching is enabled if the
+preference "/Directories/CacheBlockFiles" is set, otherwise disabled. The
+default is to disable caching.
+
+* Read-caching: If caching is enabled, all block files will always be
+ read-cached. Block files on disk will be read as soon as they are created
+ and hold in memory. New block files will be written to disk, but hold in
+ memory, so they are never read from disk in the current session.
+
+* Write-caching: If caching is enabled and the parameter allowDeferredWrite
+ is enabled at the block file constructor, new block files are hold in memory
+ and only written to disk when WriteCacheToDisk() is called. This is used
+ during recording to prevent disk access. After recording, WriteCacheToDisk()
+ will be called on all block files and they will be written to disk. During
+ normal editing, no write cache is active, that is, any block files will be
+ written to disk instantly.
+
+ Even with write cache, auto recovery during normal editing will work as
+ expected. However, auto recovery during recording will not work (not even
+ manual auto recovery, because the files are never written physically to
+ disk).
+
*//****************************************************************//**
\class auHeader
@@ -39,12 +62,17 @@
#include <wx/utils.h>
#include <wx/log.h>
+#include "../Prefs.h"
+
#include "SimpleBlockFile.h"
#include "../FileFormats.h"
#include "sndfile.h"
#include "../Internat.h"
+//#define DEBUG_OUTPUT(s) printf("[SimpleBlockFile] %s\n", s)
+#define DEBUG_OUTPUT(s)
+
// The AU formats we care about
enum {
AU_SAMPLE_FORMAT_16 = 3,
@@ -61,6 +89,18 @@
wxUint32 channels; // number of interleaved channels
} auHeader;
+wxUint32 SwapUintEndianess(wxUint32 in)
+{
+ wxUint32 out;
+ unsigned char *p_in = (unsigned char *) ∈
+ unsigned char *p_out = (unsigned char *) &out;
+ p_out[0] = p_in[3];
+ p_out[1] = p_in[2];
+ p_out[2] = p_in[1];
+ p_out[3] = p_in[0];
+ return out;
+}
+
/// Constructs a SimpleBlockFile based on sample data and writes
/// it to disk.
///
@@ -70,20 +110,81 @@
/// @param sampleData The sample data to be written to this block.
/// @param sampleLen The number of samples to be written to this block.
/// @param format The format of the given samples.
+/// @param allowDeferredWrite Allow deferred write-caching
SimpleBlockFile::SimpleBlockFile(wxFileName baseFileName,
samplePtr sampleData, sampleCount sampleLen,
- sampleFormat format):
+ sampleFormat format,
+ bool allowDeferredWrite /* = false */):
BlockFile(wxFileName(baseFileName.GetFullPath() + wxT(".au")), sampleLen)
{
+ mCache.active = false;
+
+ DEBUG_OUTPUT("SimpleBlockFile created based on sample data");
+
+ bool useCache = GetCache();
+
+ if (!(allowDeferredWrite && useCache))
+ WriteSimpleBlockFile(sampleData, sampleLen, format, NULL);
+
+ if (useCache) {
+ DEBUG_OUTPUT("Caching block file data");
+ mCache.active = true;
+ mCache.needWrite = true;
+ mCache.format = format;
+ mCache.sampleData = new char[sampleLen * SAMPLE_SIZE(format)];
+ memcpy(mCache.sampleData,
+ sampleData, sampleLen * SAMPLE_SIZE(format));
+ void* summaryData = BlockFile::CalcSummary(sampleData, sampleLen,
+ format);
+ mCache.summaryData = new char[mSummaryInfo.totalSummaryBytes];
+ memcpy(mCache.summaryData, summaryData,
+ (size_t)mSummaryInfo.totalSummaryBytes);
+ }
+}
+
+/// Construct a SimpleBlockFile memory structure that will point to an
+/// existing block file. This file must exist and be a valid block file.
+///
+/// @param existingFile The disk file this SimpleBlockFile should use.
+SimpleBlockFile::SimpleBlockFile(wxFileName existingFile, sampleCount len,
+ float min, float max, float rms):
+ BlockFile(existingFile, len)
+{
+ DEBUG_OUTPUT("SimpleBlockFile based on existing file created");
+
+ mMin = min;
+ mMax = max;
+ mRMS = rms;
+
+ mCache.active = false;
+}
+
+SimpleBlockFile::~SimpleBlockFile()
+{
+ if (mCache.active)
+ {
+ delete[] mCache.sampleData;
+ delete[] mCache.summaryData;
+ }
+}
+
+bool SimpleBlockFile::WriteSimpleBlockFile(
+ samplePtr sampleData,
+ sampleCount sampleLen,
+ sampleFormat format,
+ void* summaryData)
+{
// Now checked in the DirManager
//wxASSERT( !wxFileExists(FILENAME(mFileName.GetFullPath())) );
+
+ DEBUG_OUTPUT("Writing simple block file");
// Open and write the file
wxFFile file(mFileName.GetFullPath(), wxT("wb"));
if( !file.IsOpened() ){
// Can't do anything else.
- return;
+ return false;
}
auHeader header;
@@ -123,8 +224,9 @@
header.channels = 1;
// Write the file
- void *summaryData = BlockFile::CalcSummary(sampleData, sampleLen, format);
-
+ if (!summaryData)
+ summaryData = BlockFile::CalcSummary(sampleData, sampleLen, format);
+
file.Write(&header, sizeof(header));
file.Write(summaryData, mSummaryInfo.totalSummaryBytes);
@@ -148,24 +250,77 @@
// to disk
file.Write(sampleData, sampleLen * SAMPLE_SIZE(format));
}
+
+ DEBUG_OUTPUT("Wrote simple block file");
+
+ return true;
}
-/// Construct a SimpleBlockFile memory structure that will point to an
-/// existing block file. This file must exist and be a valid block file.
-///
-/// @param existingFile The disk file this SimpleBlockFile should use.
-SimpleBlockFile::SimpleBlockFile(wxFileName existingFile, sampleCount len,
- float min, float max, float rms):
- BlockFile(existingFile, len)
+void SimpleBlockFile::FillCache()
{
+ if (mCache.active)
+ return; // cache is already filled
- mMin = min;
- mMax = max;
- mRMS = rms;
-}
+ DEBUG_OUTPUT("Reading simple block file into cache");
+
+ // Check sample format
+ wxFFile file(mFileName.GetFullPath(), wxT("rb"));
+ if (!file.IsOpened())
+ {
+ // Don't read into cache if file not available
+ return;
+ }
-SimpleBlockFile::~SimpleBlockFile()
-{
+ auHeader header;
+
+ if (file.Read(&header, sizeof(header)) != sizeof(header))
+ {
+ // Corrupt file
+ return;
+ }
+
+ wxUint32 encoding;
+
+ if (header.magic == 0x2e736e64)
+ encoding = header.encoding; // correct endianness
+ else
+ encoding = SwapUintEndianess(header.encoding);
+
+ switch (encoding)
+ {
+ case AU_SAMPLE_FORMAT_16:
+ mCache.format = int16Sample;
+ break;
+ case AU_SAMPLE_FORMAT_24:
+ mCache.format = int24Sample;
+ break;
+ default:
+ // floatSample is a safe default (we will never loose data)
+ mCache.format = floatSample;
+ break;
+ }
+
+ file.Close();
+
+ // Read samples into cache
+ mCache.sampleData = new char[mLen * SAMPLE_SIZE(mCache.format)];
+ if (ReadData(mCache.sampleData, mCache.format, 0, mLen) != mLen)
+ {
+ // Could not read all samples
+ delete mCache.sampleData;
+ return;
+ }
+
+ // Read summary data into cache
+ mCache.summaryData = new char[mSummaryInfo.totalSummaryBytes];
+ if (!ReadSummary(mCache.summaryData))
+ memset(mCache.summaryData, 0, mSummaryInfo.totalSummaryBytes);
+
+ // Cache is active but already on disk
+ mCache.active = true;
+ mCache.needWrite = false;
+
+ DEBUG_OUTPUT("Succesfully read simple blockfile into cache");
}
/// Read the summary section of the disk file.
@@ -174,34 +329,44 @@
/// mSummaryinfo.totalSummaryBytes long.
bool SimpleBlockFile::ReadSummary(void *data)
{
- wxFFile file(mFileName.GetFullPath(), wxT("rb"));
+ if (mCache.active)
+ {
+ DEBUG_OUTPUT("ReadSummary: Summary is already in cache");
+ memcpy(data, mCache.summaryData, (size_t)mSummaryInfo.totalSummaryBytes);
+ return true;
+ } else
+ {
+ DEBUG_OUTPUT("ReadSummary: Reading summary from disk");
+
+ wxFFile file(mFileName.GetFullPath(), wxT("rb"));
- wxLogNull *silence=0;
- if(mSilentLog)silence= new wxLogNull();
+ wxLogNull *silence=0;
+ if(mSilentLog)silence= new wxLogNull();
- if(!file.IsOpened() ){
+ if(!file.IsOpened() ){
- memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes);
+ memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes);
- if(silence) delete silence;
- mSilentLog=TRUE;
+ if(silence) delete silence;
+ mSilentLog=TRUE;
- return true;
+ return true;
- }
+ }
- if(silence) delete silence;
- mSilentLog=FALSE;
+ if(silence) delete silence;
+ mSilentLog=FALSE;
- // The offset is just past the au header
- if( !file.Seek(sizeof(auHeader)) )
- return false;
+ // The offset is just past the au header
+ if( !file.Seek(sizeof(auHeader)) )
+ return false;
- int read = (int)file.Read(data, (size_t)mSummaryInfo.totalSummaryBytes);
+ int read = (int)file.Read(data, (size_t)mSummaryInfo.totalSummaryBytes);
- FixSummary(data);
+ FixSummary(data);
- return (read == mSummaryInfo.totalSummaryBytes);
+ return (read == mSummaryInfo.totalSummaryBytes);
+ }
}
/// Read the data portion of the block file using libsndfile. Convert it
@@ -214,64 +379,80 @@
int SimpleBlockFile::ReadData(samplePtr data, sampleFormat format,
sampleCount start, sampleCount len)
{
- SF_INFO info;
- wxLogNull *silence=0;
- if(mSilentLog)silence= new wxLogNull();
+ if (mCache.active)
+ {
+ DEBUG_OUTPUT("ReadData: Data is already in cache");
+
+ if (len > mLen - start)
+ len = mLen - start;
+ CopySamples(
+ (samplePtr)(((char*)mCache.sampleData) +
+ start * SAMPLE_SIZE(mCache.format)),
+ mCache.format, data, format, len);
+ return len;
+ } else
+ {
+ DEBUG_OUTPUT("ReadData: Reading data from disk");
+
+ SF_INFO info;
+ wxLogNull *silence=0;
+ if(mSilentLog)silence= new wxLogNull();
- memset(&info, 0, sizeof(info));
+ memset(&info, 0, sizeof(info));
- SNDFILE *sf=sf_open(OSFILENAME(mFileName.GetFullPath()), SFM_READ, &info);
- if (!sf){
+ SNDFILE *sf=sf_open(OSFILENAME(mFileName.GetFullPath()), SFM_READ,
&info);
+ if (!sf){
- memset(data,0,SAMPLE_SIZE(format)*len);
+ memset(data,0,SAMPLE_SIZE(format)*len);
- if(silence) delete silence;
- mSilentLog=TRUE;
+ if(silence) delete silence;
+ mSilentLog=TRUE;
- return len;
- }
- if(silence) delete silence;
- mSilentLog=FALSE;
+ return len;
+ }
+ if(silence) delete silence;
+ mSilentLog=FALSE;
- sf_seek(sf, start, SEEK_SET);
- samplePtr buffer = NewSamples(len, floatSample);
-
- int framesRead = 0;
+ sf_seek(sf, start, SEEK_SET);
+ samplePtr buffer = NewSamples(len, floatSample);
- // If both the src and dest formats are integer formats,
- // read integers from the file (otherwise we would be
- // converting to float and back, which is unneccesary)
- if (format == int16Sample &&
- sf_subtype_is_integer(info.format)) {
- framesRead = sf_readf_short(sf, (short *)data, len);
- }
- else
- if (format == int24Sample &&
- sf_subtype_is_integer(info.format))
- {
- framesRead = sf_readf_int(sf, (int *)data, len);
+ int framesRead = 0;
- // libsndfile gave us the 3 byte sample in the 3 most
- // significant bytes -- we want it in the 3 least
- // significant bytes.
- int *intPtr = (int *)data;
- for( int i = 0; i < framesRead; i++ )
- intPtr[i] = intPtr[i] >> 8;
- }
- else {
- // Otherwise, let libsndfile handle the conversion and
- // scaling, and pass us normalized data as floats. We can
- // then convert to whatever format we want.
- framesRead = sf_readf_float(sf, (float *)buffer, len);
- CopySamples(buffer, floatSample,
- (samplePtr)data, format, framesRead);
- }
+ // If both the src and dest formats are integer formats,
+ // read integers from the file (otherwise we would be
+ // converting to float and back, which is unneccesary)
+ if (format == int16Sample &&
+ sf_subtype_is_integer(info.format)) {
+ framesRead = sf_readf_short(sf, (short *)data, len);
+ }
+ else
+ if (format == int24Sample &&
+ sf_subtype_is_integer(info.format))
+ {
+ framesRead = sf_readf_int(sf, (int *)data, len);
- DeleteSamples(buffer);
+ // libsndfile gave us the 3 byte sample in the 3 most
+ // significant bytes -- we want it in the 3 least
+ // significant bytes.
+ int *intPtr = (int *)data;
+ for( int i = 0; i < framesRead; i++ )
+ intPtr[i] = intPtr[i] >> 8;
+ }
+ else {
+ // Otherwise, let libsndfile handle the conversion and
+ // scaling, and pass us normalized data as floats. We can
+ // then convert to whatever format we want.
+ framesRead = sf_readf_float(sf, (float *)buffer, len);
+ CopySamples(buffer, floatSample,
+ (samplePtr)data, format, framesRead);
+ }
- sf_close(sf);
+ DeleteSamples(buffer);
+
+ sf_close(sf);
- return framesRead;
+ return framesRead;
+ }
}
void SimpleBlockFile::SaveXML(XMLWriter &xmlFile)
@@ -327,8 +508,15 @@
wxLongLong SimpleBlockFile::GetSpaceUsage()
{
- wxFFile dataFile(mFileName.GetFullPath());
- return dataFile.Length();
+ if (mCache.active && mCache.needWrite)
+ {
+ // We don't know space usage yet
+ return 0;
+ } else
+ {
+ wxFFile dataFile(mFileName.GetFullPath());
+ return dataFile.Length();
+ }
}
void SimpleBlockFile::Recover(){
@@ -359,6 +547,30 @@
}
+void SimpleBlockFile::WriteCacheToDisk()
+{
+ if (!GetNeedWriteCacheToDisk())
+ return;
+
+ DEBUG_OUTPUT("WriteCacheToDisk");
+
+ if (WriteSimpleBlockFile(mCache.sampleData, mLen, mCache.format,
+ mCache.summaryData))
+ mCache.needWrite = false;
+}
+
+bool SimpleBlockFile::GetNeedWriteCacheToDisk()
+{
+ return mCache.active && mCache.needWrite;
+}
+
+bool SimpleBlockFile::GetCache()
+{
+ bool cacheBlockFiles = false;
+ gPrefs->Read(wxT("/Directories/CacheBlockFiles"), &cacheBlockFiles);
+ return cacheBlockFiles;
+}
+
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Audacity-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/audacity-cvs