audacia/src/WaveClip.h

403 lines
12 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
WaveClip.h
?? Dominic Mazzoni
?? Markus Meyer
*******************************************************************/
#ifndef __AUDACITY_WAVECLIP__
#define __AUDACITY_WAVECLIP__
#include "Audacity.h"
#include "MemoryX.h"
#include "SampleFormat.h"
#include "widgets/ProgressDialog.h"
#include "ondemand/ODTaskThread.h"
#include "xml/XMLTagHandler.h"
#include "Experimental.h"
#include "RealFFTf.h"
#include <wx/gdicmn.h>
#include <wx/longlong.h>
#include <wx/msgdlg.h>
#include <vector>
class BlockArray;
class DirManager;
class Envelope;
class Sequence;
class SpectrogramSettings;
class WaveCache;
class WaveTrackCache;
class SpecCache {
public:
// Make invalid cache
SpecCache()
: algorithm(-1)
, pps(-1.0)
, start(-1.0)
, windowType(-1)
, frequencyGain(-1)
#if 0
, freq(NULL)
, where(NULL)
#endif
, dirty(-1)
{
}
// Make valid cache, to be filled in
SpecCache(size_t cacheLen, int algorithm_,
double pps_, double start_, int windowType_, size_t windowSize_,
unsigned zeroPaddingFactor_, int frequencyGain_)
: len(cacheLen)
, algorithm(algorithm_)
, pps(pps_)
, start(start_)
, windowType(windowType_)
, windowSize(windowSize_)
, zeroPaddingFactor(zeroPaddingFactor_)
, frequencyGain(frequencyGain_)
// len columns, and so many rows, column-major.
// Don't take column literally -- this isn't pixel data yet, it's the
// raw data to be mapped onto the display.
, freq(len * ((windowSize * zeroPaddingFactor) / 2))
// Sample counts corresponding to the columns, and to one past the end.
, where(len + 1)
, dirty(-1)
{
where[0] = 0;
}
~SpecCache()
{
}
bool Matches(int dirty_, double pixelsPerSecond,
const SpectrogramSettings &settings, double rate) const;
bool CalculateOneSpectrum
(const SpectrogramSettings &settings,
WaveTrackCache &waveTrackCache,
int xx, sampleCount numSamples,
double offset, double rate, double pixelsPerSecond,
int lowerBoundX, int upperBoundX,
const std::vector<float> &gainFactors,
float* __restrict scratch,
float* __restrict out) const;
void Populate
(const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache,
int copyBegin, int copyEnd, size_t numPixels,
sampleCount numSamples,
double offset, double rate, double pixelsPerSecond);
const size_t len { 0 }; // counts pixels, not samples
const int algorithm;
const double pps;
const double start;
const int windowType;
const size_t windowSize { 0 };
const unsigned zeroPaddingFactor { 0 };
const int frequencyGain;
std::vector<float> freq;
std::vector<sampleCount> where;
int dirty;
};
class SpecPxCache {
public:
SpecPxCache(size_t cacheLen)
{
len = cacheLen;
values = new float[len];
valid = false;
scaleType = 0;
range = gain = -1;
minFreq = maxFreq = -1;
}
~SpecPxCache()
{
delete[] values;
}
size_t len;
float *values;
bool valid;
int scaleType;
int range;
int gain;
int minFreq;
int maxFreq;
};
class WaveClip;
// Array of pointers that assume ownership
using WaveClipHolders = std::vector < movable_ptr< WaveClip > >;
using WaveClipConstHolders = std::vector < movable_ptr< const WaveClip > >;
// Temporary arrays of mere pointers
using WaveClipPointers = std::vector < WaveClip* >;
using WaveClipConstPointers = std::vector < const WaveClip* >;
// A bundle of arrays needed for drawing waveforms. The object may or may not
// own the storage for those arrays. If it does, it destroys them.
class WaveDisplay
{
public:
int width;
sampleCount *where;
float *min, *max, *rms;
int* bl;
std::vector<sampleCount> ownWhere;
std::vector<float> ownMin, ownMax, ownRms;
std::vector<int> ownBl;
public:
WaveDisplay(int w)
: width(w), where(0), min(0), max(0), rms(0), bl(0)
{
}
// Create "own" arrays.
void Allocate()
{
ownWhere.resize(width + 1);
ownMin.resize(width);
ownMax.resize(width);
ownRms.resize(width);
ownBl.resize(width);
where = &ownWhere[0];
if (width > 0) {
min = &ownMin[0];
max = &ownMax[0];
rms = &ownRms[0];
bl = &ownBl[0];
}
else {
min = max = rms = 0;
bl = 0;
}
}
~WaveDisplay()
{
}
};
class AUDACITY_DLL_API WaveClip final : public XMLTagHandler
{
private:
// It is an error to copy a WaveClip without specifying the DirManager.
WaveClip(const WaveClip&) PROHIBITED;
WaveClip& operator= (const WaveClip&) PROHIBITED;
public:
// typical constructor
WaveClip(const std::shared_ptr<DirManager> &projDirManager, sampleFormat format, int rate);
// essentially a copy constructor - but you must pass in the
// current project's DirManager, because we might be copying
// from one project to another
WaveClip(const WaveClip& orig, const std::shared_ptr<DirManager> &projDirManager);
virtual ~WaveClip();
void ConvertToSampleFormat(sampleFormat format);
void TimeToSamplesClip(double t0, sampleCount *s0) const;
int GetRate() const { return mRate; }
// Set rate without resampling. This will change the length of the clip
void SetRate(int rate);
// Resample clip. This also will set the rate, but without changing
// the length of the clip
bool Resample(int rate, ProgressDialog *progress = NULL);
void SetOffset(double offset);
double GetOffset() const { return mOffset; }
void Offset(double delta) { SetOffset(GetOffset() + delta); }
double GetStartTime() const;
double GetEndTime() const;
sampleCount GetStartSample() const;
sampleCount GetEndSample() const;
sampleCount GetNumSamples() const;
// One and only one of the following is true for a given t (unless the clip
// has zero length -- then BeforeClip() and AfterClip() can both be true).
// Within() is true if the time is substantially within the clip
bool WithinClip(double t) const;
bool BeforeClip(double t) const;
bool AfterClip(double t) const;
bool GetSamples(samplePtr buffer, sampleFormat format,
sampleCount start, size_t len) const;
bool SetSamples(samplePtr buffer, sampleFormat format,
sampleCount start, size_t len);
Envelope* GetEnvelope() { return mEnvelope.get(); }
const Envelope* GetEnvelope() const { return mEnvelope.get(); }
BlockArray* GetSequenceBlockArray();
// Get low-level access to the sequence. Whenever possible, don't use this,
// but use more high-level functions inside WaveClip (or add them if you
// think they are useful for general use)
Sequence* GetSequence() { return mSequence.get(); }
/** WaveTrack calls this whenever data in the wave clip changes. It is
* called automatically when WaveClip has a chance to know that something
* has changed, like when member functions SetSamples() etc. are called. */
void MarkChanged() { mDirty++; }
/// Create clip from copy, discarding previous information in the clip
bool CreateFromCopy(double t0, double t1, const WaveClip* other);
/** Getting high-level data from the for screen display and clipping
* calculations and Contrast */
bool GetWaveDisplay(WaveDisplay &display,
double t0, double pixelsPerSecond, bool &isLoadingOD) const;
bool GetSpectrogram(WaveTrackCache &cache,
const float *& spectrogram, const sampleCount *& where,
size_t numPixels,
double t0, double pixelsPerSecond) const;
bool GetMinMax(float *min, float *max, double t0, double t1) const;
bool GetRMS(float *rms, double t0, double t1);
// Set/clear/get rectangle that this WaveClip fills on screen. This is
// called by TrackArtist while actually drawing the tracks and clips.
void ClearDisplayRect() const;
void SetDisplayRect(const wxRect& r) const;
void GetDisplayRect(wxRect* r);
/** Whenever you do an operation to the sequence that will change the number
* of samples (that is, the length of the clip), you will want to call this
* function to tell the envelope about it. */
void UpdateEnvelopeTrackLen();
/// You must call Flush after the last Append
bool Append(samplePtr buffer, sampleFormat format,
size_t len, unsigned int stride=1,
XMLWriter* blockFileLog = NULL);
/// Flush must be called after last Append
bool Flush();
bool AppendAlias(const wxString &fName, sampleCount start,
size_t len, int channel,bool useOD);
bool AppendCoded(const wxString &fName, sampleCount start,
size_t len, int channel, int decodeType);
/// This name is consistent with WaveTrack::Clear. It performs a "Cut"
/// operation (but without putting the cutted audio to the clipboard)
bool Clear(double t0, double t1);
/// Clear, and add cut line that starts at t0 and contains everything until t1.
bool ClearAndAddCutLine(double t0, double t1);
/// Paste data from other clip, resampling it if not equal rate
bool Paste(double t0, const WaveClip* other);
/** Insert silence - note that this is an efficient operation for large
* amounts of silence */
bool InsertSilence(double t, double len);
/// Get access to cut lines list
WaveClipHolders &GetCutLines() { return mCutLines; }
const WaveClipConstHolders &GetCutLines() const
{ return reinterpret_cast< const WaveClipConstHolders& >( mCutLines ); }
size_t NumCutLines() const { return mCutLines.size(); }
/** Find cut line at (approximately) this position. Returns true and fills
* in cutLineStart and cutLineEnd (if specified) if a cut line at this
* position could be found. Return false otherwise. */
bool FindCutLine(double cutLinePosition,
double* cutLineStart = NULL,
double *cutLineEnd = NULL);
/** Expand cut line (that is, re-insert audio, then DELETE audio saved in
* cut line). Returns true if a cut line could be found and sucessfully
* expanded, false otherwise */
bool ExpandCutLine(double cutLinePosition);
/// Remove cut line, without expanding the audio in it
bool RemoveCutLine(double cutLinePosition);
void RemoveAllCutLines();
/// Offset cutlines right to time 't0' by time amount 'len'
void OffsetCutLines(double t0, double len);
/// Lock all blockfiles
void Lock();
/// Unlock all blockfiles
void Unlock();
void CloseLock(); //similar to Lock but should be called when the project closes.
// not balanced by unlocking calls.
///Delete the wave cache - force redraw. Thread-safe
void ClearWaveCache();
///Adds an invalid region to the wavecache so it redraws that portion only.
void AddInvalidRegion(sampleCount startSample, sampleCount endSample);
//
// 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 */;
// Cache of values to colour pixels of Spectrogram - used by TrackArtist
mutable std::unique_ptr<SpecPxCache> mSpecPxCache;
// AWD, Oct 2009: for pasting whitespace at the end of selection
bool GetIsPlaceholder() const { return mIsPlaceholder; }
void SetIsPlaceholder(bool val) { mIsPlaceholder = val; }
protected:
mutable wxRect mDisplayRect;
double mOffset;
int mRate;
int mDirty;
bool mIsCutLine;
std::unique_ptr<Sequence> mSequence;
std::unique_ptr<Envelope> mEnvelope;
mutable std::unique_ptr<WaveCache> mWaveCache;
mutable ODLock mWaveCacheMutex;
mutable std::unique_ptr<SpecCache> mSpecCache;
SampleBuffer mAppendBuffer;
size_t mAppendBufferLen;
// Cut Lines are nothing more than ordinary wave clips, with the
// offset relative to the start of the clip.
WaveClipHolders mCutLines;
// AWD, Oct. 2009: for whitespace-at-end-of-selection pasting
bool mIsPlaceholder;
};
#endif