/********************************************************************** Audacity: A Digital Audio Editor Sequence.h Dominic Mazzoni **********************************************************************/ #ifndef __AUDACITY_SEQUENCE__ #define __AUDACITY_SEQUENCE__ #include #include "SampleFormat.h" #include "xml/XMLTagHandler.h" #include "ondemand/ODTaskThread.h" #include "audacity/Types.h" class BlockFile; using BlockFilePtr = std::shared_ptr; class DirManager; class wxFileNameWrapper; // This is an internal data structure! For advanced use only. class SeqBlock { public: BlockFilePtr f; ///the sample in the global wavetrack that this block starts at. sampleCount start; SeqBlock() : f{}, start(0) {} SeqBlock(const BlockFilePtr &f_, sampleCount start_) : f(f_), start(start_) {} // Construct a SeqBlock with changed start, same file SeqBlock Plus(sampleCount delta) const { return SeqBlock(f, start + delta); } }; class BlockArray : public std::vector {}; using BlockPtrArray = std::vector; // 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 std::shared_ptr &projDirManager, sampleFormat format); // The copy constructor and duplicate operators take a // DirManager as a parameter, because you might be copying // from one project to another... Sequence(const Sequence &orig, const std::shared_ptr &projDirManager); // Sequence cannot be copied without specifying a DirManager Sequence(const Sequence&) PROHIBITED; 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 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, XMLWriter* blockFileLog=NULL); void Delete(sampleCount start, sampleCount len); using BlockFileFactory = std::function< BlockFilePtr( wxFileNameWrapper, size_t /* len */ ) >; // An overload of AppendBlockFile that passes the factory to DirManager // which supplies it with a file name void AppendBlockFile( const BlockFileFactory &factory, size_t len ); // Append a blockfile. The blockfile pointer is then "owned" by the // sequence. This function is used by the recording log crash recovery // code, but may be useful for other purposes. The blockfile must already // be registered within the dir manager hash. This is the case // when the blockfile is created using SimpleBlockFile or // loaded from an XML file via DirManager::HandleXMLTag void AppendBlockFile(const BlockFilePtr &blockFile); void SetSilence(sampleCount s0, sampleCount len); void InsertSilence(sampleCount s0, sampleCount len); const std::shared_ptr &GetDirManager() { return mDirManager; } // // 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 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; } /// void LockDeleteUpdateMutex(){mDeleteUpdateMutex.Lock();} void UnlockDeleteUpdateMutex(){mDeleteUpdateMutex.Unlock();} // RAII idiom wrapping the functions above struct DeleteUpdateMutexLocker { DeleteUpdateMutexLocker(Sequence &sequence) : mSequence(sequence) { mSequence.LockDeleteUpdateMutex(); } ~DeleteUpdateMutexLocker() { mSequence.UnlockDeleteUpdateMutex(); } private: Sequence &mSequence; }; private: // // Private static variables // static size_t sMaxDiskBlockSize; // // Private variables // std::shared_ptr mDirManager; 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 }; ///To block the Delete() method against the ODCalcSummaryTask::Update() method ODLock mDeleteUpdateMutex; // // Private methods // int FindBlock(sampleCount pos) const; static void AppendBlock (DirManager &dirManager, 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 (DirManager &dirManager, 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__