mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-05 06:39:26 +02:00
* Define SampleBlockFactory replacing static members of SampleBlock... ... This will become an abstract base class * Sequence and WaveTrack only store SampleBlockFactory not Project... ... This adds a dependency from Track to SampleBlock which temporarily enlarges a cycle in the dependency graph * Register a global factory of SampleBlockFactory... ... so that later we can make an abstract SampleBlockFactory, separate from the concrete implementation in terms of sqlite, and inject the dependency at startup avoiding static dependency * New concrete classes SqliteSampleBlock, SqliteSampleBlockFactory... ... separated from abstract base classes and put into a new source file, breaking dependency cycles, and perhaps allowing easy reimplementation for other databases in the future. Note that the new file is a header-less plug-in! Nothing depends on it. It uses static initialization to influence the program's behavior. * Compile dependency on sqlite3.h limited to just two .cpp files... ... these are ProjectFileIO.cpp and SqliteSampleBlock.cpp. But there is still close cooperation of ProjectFileIO and SqliteSampleBlock.cpp. This suggests that these files ought to be merged, and perhaps ProjectFileIO also needs to be split into abstract and concrete classes, and there should be another injection of a factory function at startup. That will make the choice of database implementation even more modular. Also removed one unnecessary inclusion of ProjectFileIO.h * Fix crashes cutting and pasting cross-project... ... in case the source project is closed before the paste happens. This caused destruction of the ProjectFileIO object and a closing of the sqlite database with the sample data in it, leaving dangling references in the SqliteSampleBlock objects. The fix is that the SqliteSampleBlockFactory object holds a shared_ptr to the ProjectFileIO object. So the clipboard may own WaveTracks, which own WaveClips, which own Sequences, which own SqliteSampleBlockFactories, which keep the ProjectFileIO and the database connection alive until the clipboard is cleared. The consequence of the fix is delayed closing of the entire database associated with the source project. If the source project is reopened before the clipboard is cleared, will there be correct concurrent access to the same persistent store? My preliminary trials suggest this is so (reopening a saved project, deleting from it, closing it again -- the clipboard contents are still unchanged and available).
266 lines
7.4 KiB
C++
266 lines
7.4 KiB
C++
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
Sequence.h
|
|
|
|
Dominic Mazzoni
|
|
|
|
**********************************************************************/
|
|
|
|
#ifndef __AUDACITY_SEQUENCE__
|
|
#define __AUDACITY_SEQUENCE__
|
|
|
|
#include <vector>
|
|
|
|
#include "SampleFormat.h"
|
|
#include "xml/XMLTagHandler.h"
|
|
|
|
#include "audacity/Types.h"
|
|
|
|
class SampleBlock;
|
|
class SampleBlockFactory;
|
|
using SampleBlockFactoryPtr = std::shared_ptr<SampleBlockFactory>;
|
|
|
|
// This is an internal data structure! For advanced use only.
|
|
class SeqBlock {
|
|
public:
|
|
using SampleBlockPtr = std::shared_ptr<SampleBlock>;
|
|
SampleBlockPtr sb;
|
|
///the sample in the global wavetrack that this block starts at.
|
|
sampleCount start;
|
|
|
|
SeqBlock()
|
|
: sb{}, start(0)
|
|
{}
|
|
|
|
SeqBlock(const SampleBlockPtr &sb_, sampleCount start_)
|
|
: sb(sb_), start(start_)
|
|
{}
|
|
|
|
// Construct a SeqBlock with changed start, same file
|
|
SeqBlock Plus(sampleCount delta) const
|
|
{
|
|
return SeqBlock(sb, start + delta);
|
|
}
|
|
};
|
|
class BlockArray : public std::vector<SeqBlock> {};
|
|
using BlockPtrArray = std::vector<SeqBlock*>; // non-owning pointers
|
|
|
|
class PROFILE_DLL_API Sequence final : public XMLTagHandler{
|
|
public:
|
|
|
|
//
|
|
// Static methods
|
|
//
|
|
|
|
static void SetMaxDiskBlockSize(size_t bytes);
|
|
static size_t GetMaxDiskBlockSize();
|
|
|
|
//
|
|
// Constructor / Destructor / Duplicator
|
|
//
|
|
|
|
Sequence(const SampleBlockFactoryPtr &pFactory, sampleFormat format);
|
|
|
|
Sequence(const Sequence &orig, const SampleBlockFactoryPtr &pFactory);
|
|
|
|
Sequence& operator= (const Sequence&) PROHIBITED;
|
|
|
|
~Sequence();
|
|
|
|
//
|
|
// Editing
|
|
//
|
|
|
|
sampleCount GetNumSamples() const { return mNumSamples; }
|
|
|
|
bool Get(samplePtr buffer, sampleFormat format,
|
|
sampleCount start, size_t len, bool mayThrow) const;
|
|
|
|
// Note that len is not size_t, because nullptr may be passed for buffer, in
|
|
// which case, silence is inserted, possibly a large amount.
|
|
void SetSamples(samplePtr buffer, sampleFormat format,
|
|
sampleCount start, sampleCount len);
|
|
|
|
// where is input, assumed to be nondecreasing, and its size is len + 1.
|
|
// min, max, rms, bl are outputs, and their lengths are len.
|
|
// Each position in the output arrays corresponds to one column of pixels.
|
|
// The column for pixel p covers samples from
|
|
// where[p] up to (but excluding) where[p + 1].
|
|
// bl is negative wherever data are not yet available.
|
|
// Return true if successful.
|
|
bool GetWaveDisplay(float *min, float *max, float *rms, int* bl,
|
|
size_t len, const sampleCount *where) const;
|
|
|
|
// Return non-null, or else throw!
|
|
std::unique_ptr<Sequence> Copy(sampleCount s0, sampleCount s1) const;
|
|
void Paste(sampleCount s0, const Sequence *src);
|
|
|
|
size_t GetIdealAppendLen() const;
|
|
void Append(samplePtr buffer, sampleFormat format, size_t len);
|
|
void Delete(sampleCount start, sampleCount len);
|
|
|
|
void SetSilence(sampleCount s0, sampleCount len);
|
|
void InsertSilence(sampleCount s0, sampleCount len);
|
|
|
|
const SampleBlockFactoryPtr &GetFactory() { return mpFactory; }
|
|
|
|
//
|
|
// XMLTagHandler callback methods for loading and saving
|
|
//
|
|
|
|
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override;
|
|
void HandleXMLEndTag(const wxChar *tag) override;
|
|
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
|
|
void WriteXML(XMLWriter &xmlFile) const /* not override */;
|
|
|
|
bool GetErrorOpening() { return mErrorOpening; }
|
|
|
|
//
|
|
// Lock/Unlock all of this sequence's BlockFiles, keeping them
|
|
// from being moved. Call this if you want to copy a
|
|
// track to a different DirManager. See BlockFile.h
|
|
// for details.
|
|
//
|
|
|
|
bool Lock();
|
|
bool Unlock();
|
|
|
|
bool CloseLock();//similar to Lock but should be called upon project close.
|
|
// not balanced by unlocking calls.
|
|
|
|
//
|
|
// Manipulating Sample Format
|
|
//
|
|
|
|
sampleFormat GetSampleFormat() const;
|
|
|
|
// Return true iff there is a change
|
|
bool ConvertToSampleFormat(sampleFormat format);
|
|
|
|
//
|
|
// Retrieving summary info
|
|
//
|
|
|
|
std::pair<float, float> GetMinMax(
|
|
sampleCount start, sampleCount len, bool mayThrow) const;
|
|
float GetRMS(sampleCount start, sampleCount len, bool mayThrow) const;
|
|
|
|
//
|
|
// Getting block size and alignment information
|
|
//
|
|
|
|
// This returns a possibly large or negative value
|
|
sampleCount GetBlockStart(sampleCount position) const;
|
|
|
|
// These return a nonnegative number of samples meant to size a memory buffer
|
|
size_t GetBestBlockSize(sampleCount start) const;
|
|
size_t GetMaxBlockSize() const;
|
|
size_t GetIdealBlockSize() const;
|
|
|
|
//
|
|
// This should only be used if you really, really know what
|
|
// you're doing!
|
|
//
|
|
|
|
BlockArray &GetBlockArray() { return mBlock; }
|
|
const BlockArray &GetBlockArray() const { return mBlock; }
|
|
|
|
private:
|
|
|
|
//
|
|
// Private static variables
|
|
//
|
|
|
|
static size_t sMaxDiskBlockSize;
|
|
|
|
//
|
|
// Private variables
|
|
//
|
|
|
|
SampleBlockFactoryPtr mpFactory;
|
|
|
|
BlockArray mBlock;
|
|
sampleFormat mSampleFormat;
|
|
|
|
// Not size_t! May need to be large:
|
|
sampleCount mNumSamples{ 0 };
|
|
|
|
size_t mMinSamples; // min samples per block
|
|
size_t mMaxSamples; // max samples per block
|
|
|
|
bool mErrorOpening{ false };
|
|
|
|
//
|
|
// Private methods
|
|
//
|
|
|
|
int FindBlock(sampleCount pos) const;
|
|
|
|
static void AppendBlock(BlockArray &blocks,
|
|
sampleCount &numSamples,
|
|
const SeqBlock &b);
|
|
|
|
static bool Read(samplePtr buffer,
|
|
sampleFormat format,
|
|
const SeqBlock &b,
|
|
size_t blockRelativeStart,
|
|
size_t len,
|
|
bool mayThrow);
|
|
|
|
// Accumulate NEW block files onto the end of a block array.
|
|
// Does not change this sequence. The intent is to use
|
|
// CommitChangesIfConsistent later.
|
|
static void Blockify(SampleBlockFactory &factory,
|
|
size_t maxSamples,
|
|
sampleFormat format,
|
|
BlockArray &list,
|
|
sampleCount start,
|
|
samplePtr buffer,
|
|
size_t len);
|
|
|
|
bool Get(int b,
|
|
samplePtr buffer,
|
|
sampleFormat format,
|
|
sampleCount start,
|
|
size_t len,
|
|
bool mayThrow) const;
|
|
|
|
public:
|
|
|
|
//
|
|
// Public methods
|
|
//
|
|
|
|
// This function throws if the track is messed up
|
|
// because of inconsistent block starts & lengths
|
|
void ConsistencyCheck (const wxChar *whereStr, bool mayThrow = true) const;
|
|
|
|
// This function prints information to stdout about the blocks in the
|
|
// tracks and indicates if there are inconsistencies.
|
|
static void DebugPrintf
|
|
(const BlockArray &block, sampleCount numSamples, wxString *dest);
|
|
|
|
private:
|
|
static void ConsistencyCheck
|
|
(const BlockArray &block, size_t maxSamples, size_t from,
|
|
sampleCount numSamples, const wxChar *whereStr,
|
|
bool mayThrow = true);
|
|
|
|
// The next two are used in methods that give a strong guarantee.
|
|
// They either throw because final consistency check fails, or swap the
|
|
// changed contents into place.
|
|
|
|
void CommitChangesIfConsistent
|
|
(BlockArray &newBlock, sampleCount numSamples, const wxChar *whereStr);
|
|
|
|
void AppendBlocksIfConsistent
|
|
(BlockArray &additionalBlocks, bool replaceLast,
|
|
sampleCount numSamples, const wxChar *whereStr);
|
|
|
|
};
|
|
|
|
#endif // __AUDACITY_SEQUENCE__
|
|
|