Better constructors for Envelope

This commit is contained in:
Paul Licameli 2017-05-02 20:55:40 -04:00
parent 3ba1ebc5c0
commit 4be19128c0
5 changed files with 100 additions and 92 deletions

View File

@ -42,28 +42,12 @@ a draggable point type.
#include "DirManager.h"
#include "TrackArtist.h"
Envelope::Envelope()
Envelope::Envelope(bool exponential, double minValue, double maxValue, double defaultValue)
: mDB(exponential)
, mMinValue(minValue)
, mMaxValue(maxValue)
, mDefaultValue { ClampValue(defaultValue) }
{
mOffset = 0.0;
mTrackLen = 0.0;
// Anything with a sample rate of no more than 200 KHz
// will have samples spaced apart by at least this amount,
// "epsilon". We use this to enforce that there aren't
// allowed to be multiple control points at the same t
// value.
mTrackEpsilon = 1.0 / 200000.0;
mDB = true;
mDefaultValue = 1.0;
mDragPoint = -1;
mMinValue = 1.0e-7;
mMaxValue = 2.0;
mSearchGuess = -1;
mDragPointValid = false;
}
Envelope::~Envelope()
@ -196,41 +180,51 @@ EnvPoint *Envelope::AddPointAtEnd( double t, double val )
return &mEnv.back();
}
void Envelope::CopyFrom(const Envelope *e, double t0, double t1)
Envelope::Envelope(const Envelope &orig, double t0, double t1)
: mDB(orig.mDB)
, mMinValue(orig.mMinValue)
, mMaxValue(orig.mMaxValue)
, mDefaultValue(orig.mDefaultValue)
{
wxASSERT( t0 <= t1 );
mOffset = wxMax(t0, orig.mOffset);
mTrackLen = wxMin(t1, orig.mOffset + orig.mTrackLen) - mOffset;
mOffset = wxMax(t0, e->mOffset);
mTrackLen = wxMin(t1, e->mOffset + e->mTrackLen) - mOffset;
auto range1 = orig.EqualRange( t0 - orig.mOffset, 0 );
auto range2 = orig.EqualRange( t1 - orig.mOffset, 0 );
CopyRange(orig, range1.first, range2.second);
}
mEnv.clear();
int len = e->mEnv.size();
int i = 0;
Envelope::Envelope(const Envelope &orig)
: mDB(orig.mDB)
, mMinValue(orig.mMinValue)
, mMaxValue(orig.mMaxValue)
, mDefaultValue(orig.mDefaultValue)
{
mOffset = orig.mOffset;
mTrackLen = orig.mTrackLen;
CopyRange(orig, 0, orig.GetNumberOfPoints());
}
// Skip the points that come before the copied region
while ((i < len) && e->mOffset + e->mEnv[i].GetT() <= t0)
i++;
void Envelope::CopyRange(const Envelope &orig, size_t begin, size_t end)
{
int len = orig.mEnv.size();
int i = begin;
// Create the point at 0 if it needs interpolated representation
if (i>0)
AddPointAtEnd( 0, e->GetValue(mOffset) );
if ( i > 0 )
AddPointAtEnd(0, orig.GetValue(mOffset));
// Copy points from inside the copied region
while (i < len) {
const EnvPoint &point = e->mEnv[i];
const double when = e->mOffset + point.GetT() - mOffset;
if (when < mTrackLen) {
AddPointAtEnd(when, point.GetVal());
i++;
}
else
break;
for (; i < end; ++i) {
const EnvPoint &point = orig[i];
const double when = point.GetT() + (orig.mOffset - mOffset);
AddPointAtEnd(when, point.GetVal());
}
// Create the final point if it needs interpolated representation
// If the last point of e was exatly at t1, this effectively copies it too.
if (mTrackLen > 0 && i < len)
AddPointAtEnd( mTrackLen, e->GetValue(mOffset + mTrackLen));
AddPointAtEnd( mTrackLen, orig.GetValue(mOffset + mTrackLen));
}
/// Limit() limits a double value to a range.
@ -998,6 +992,27 @@ int Envelope::Insert(double when, double value)
return i;
}
std::pair<int, int> Envelope::EqualRange( double when, double sampleTime ) const
{
// Find range of envelope points matching the given time coordinate
// (within an interval of length sampleTime)
// by binary search; if empty, it still indicates where to
// insert.
const auto tolerance = sampleTime / 2;
auto begin = mEnv.begin();
auto end = mEnv.end();
auto first = std::lower_bound(
begin, end,
EnvPoint{ const_cast<Envelope*>( this ), when - tolerance, 0.0 },
[]( const EnvPoint &point1, const EnvPoint &point2 )
{ return point1.GetT() < point2.GetT(); }
);
auto after = first;
while ( after != end && after->GetT() < when + tolerance )
++after;
return { first - begin, after - begin };
}
// Control
void Envelope::SetOffset(double newOffset)

View File

@ -75,8 +75,15 @@ private:
typedef std::vector<EnvPoint> EnvArray;
class Envelope final : public XMLTagHandler {
public:
Envelope();
public:
// Envelope can define a piecewise linear function, or piecewise exponential.
Envelope(bool exponential, double minValue, double maxValue, double defaultValue);
Envelope(const Envelope &orig);
// Create from a subrange of another envelope.
Envelope(const Envelope &orig, double t0, double t1);
void Initialize(int numPoints);
virtual ~ Envelope();
@ -113,8 +120,6 @@ class Envelope final : public XMLTagHandler {
// Handling Cut/Copy/Paste events
void CollapseRegion(double t0, double t1);
// Takes absolute times, NOT offset-relative:
void CopyFrom(const Envelope * e, double t0, double t1);
void Paste(double t0, const Envelope *e);
void InsertSpace(double t0, double tlen);
void RemoveUnneededPoints(double time = -1, double tolerence = 0.001);
@ -172,11 +177,13 @@ class Envelope final : public XMLTagHandler {
private:
friend class EnvelopeEditor;
/** \brief Accessor for points */
EnvPoint &operator[] (int index)
const EnvPoint &operator[] (int index) const
{
return mEnv[index];
}
std::pair<int, int> EqualRange( double when, double sampleTime ) const;
public:
/** \brief Returns the sets of when and value pairs */
void GetPoints(double *bufferWhen,
@ -199,6 +206,7 @@ public:
private:
EnvPoint * AddPointAtEnd( double t, double val );
void CopyRange(const Envelope &orig, size_t begin, size_t end);
void BinarySearchForTime( int &Lo, int &Hi, double t ) const;
double GetInterpolationStartValueAtPoint( int iPoint ) const;
@ -206,25 +214,25 @@ private:
EnvArray mEnv;
/** \brief The time at which the envelope starts, i.e. the start offset */
double mOffset;
double mOffset { 0.0 };
/** \brief The length of the envelope, which is the same as the length of the
* underlying track (normally) */
double mTrackLen;
double mTrackLen { 0.0 };
// TODO: mTrackEpsilon based on assumption of 200KHz. Needs review if/when
// we support higher sample rates.
/** \brief The shortest distance appart that points on an envelope can be
* before being considered the same point */
double mTrackEpsilon;
double mDefaultValue;
double mTrackEpsilon { 1.0 / 200000.0 };
bool mDB;
double mMinValue, mMaxValue;
double mDefaultValue;
// UI stuff
bool mDragPointValid;
int mDragPoint;
bool mDragPointValid { false };
int mDragPoint { -1 };
mutable int mSearchGuess;
mutable int mSearchGuess { -2 };
};
inline EnvPoint::EnvPoint(Envelope *envelope, double t, double val)

View File

@ -45,12 +45,9 @@ TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const Zo
mRangeUpper = 1.1;
mDisplayLog = false;
mEnvelope = std::make_unique<Envelope>();
mEnvelope = std::make_unique<Envelope>(true, TIMETRACK_MIN, TIMETRACK_MAX, 1.0);
mEnvelope->SetTrackLen(DBL_MAX);
mEnvelope->SetInterpolateDB(true);
mEnvelope->Flatten(1.0);
mEnvelope->SetOffset(0);
mEnvelope->SetRange(TIMETRACK_MIN, TIMETRACK_MAX);
SetDefaultName(_("Time Track"));
SetName(GetDefaultName());
@ -67,18 +64,12 @@ TimeTrack::TimeTrack(const TimeTrack &orig, double *pT0, double *pT1)
{
Init(orig); // this copies the TimeTrack metadata (name, range, etc)
///@TODO: Give Envelope:: a copy-constructor instead of this?
mEnvelope = std::make_unique<Envelope>();
mEnvelope->Flatten(1.0);
mEnvelope->SetTrackLen(DBL_MAX);
SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB
mEnvelope->SetOffset(0);
mEnvelope->SetRange(orig.mEnvelope->GetMinValue(), orig.mEnvelope->GetMaxValue());
if ( pT0 && pT1 )
// restricted copy
mEnvelope->CopyFrom(orig.mEnvelope.get(), *pT0, *pT1);
if (pT0 && pT1)
mEnvelope = std::make_unique<Envelope>( *orig.mEnvelope, *pT0, *pT1 );
else
mEnvelope->Paste(0.0, orig.mEnvelope.get());
mEnvelope = std::make_unique<Envelope>( *orig.mEnvelope );
mEnvelope->SetTrackLen(DBL_MAX);
mEnvelope->SetOffset(0);
///@TODO: Give Ruler:: a copy-constructor instead of this?
mRuler = std::make_unique<Ruler>();

View File

@ -309,7 +309,7 @@ WaveClip::WaveClip(const std::shared_ptr<DirManager> &projDirManager,
mRate = rate;
mSequence = std::make_unique<Sequence>(projDirManager, format);
mEnvelope = std::make_unique<Envelope>();
mEnvelope = std::make_unique<Envelope>(true, 1e-7, 2.0, 1.0);
mWaveCache = std::make_unique<WaveCache>();
mSpecCache = std::make_unique<SpecCache>();
@ -328,10 +328,7 @@ WaveClip::WaveClip(const WaveClip& orig,
mRate = orig.mRate;
mSequence = std::make_unique<Sequence>(*orig.mSequence, projDirManager);
mEnvelope = std::make_unique<Envelope>();
mEnvelope->Paste(0.0, orig.mEnvelope.get());
mEnvelope->SetOffset(orig.GetOffset());
mEnvelope->SetTrackLen((orig.mSequence->GetNumSamples().as_double()) / orig.mRate);
mEnvelope = std::make_unique<Envelope>(*orig.mEnvelope);
mWaveCache = std::make_unique<WaveCache>();
mSpecCache = std::make_unique<SpecCache>();
@ -345,7 +342,6 @@ WaveClip::WaveClip(const WaveClip& orig,
mIsPlaceholder = orig.GetIsPlaceholder();
}
// to do
WaveClip::WaveClip(const WaveClip& orig,
const std::shared_ptr<DirManager> &projDirManager,
bool copyCutlines,
@ -369,10 +365,11 @@ WaveClip::WaveClip(const WaveClip& orig,
mSequence = orig.mSequence->Copy(s0, s1);
mEnvelope = std::make_unique<Envelope>();
mEnvelope->CopyFrom(orig.mEnvelope.get(),
mOffset + s0.as_double()/mRate,
mOffset + s1.as_double()/mRate);
mEnvelope = std::make_unique<Envelope>(
*orig.mEnvelope,
mOffset + s0.as_double()/mRate,
mOffset + s1.as_double()/mRate
);
if ( copyCutlines )
// Copy cutline clips that fall in the range

View File

@ -239,13 +239,15 @@ EffectEqualization::EffectEqualization()
mInterpolations.Add(wxGetTranslation(kInterpStrings[i]));
}
mLogEnvelope = std::make_unique<Envelope>();
mLogEnvelope->SetInterpolateDB(false);
mLogEnvelope->SetRange(MIN_dBMin, MAX_dBMax); // MB: this is the highest possible range
mLogEnvelope = std::make_unique<Envelope>
(false,
MIN_dBMin, MAX_dBMax, // MB: this is the highest possible range
1.0);
mLinEnvelope = std::make_unique<Envelope>();
mLinEnvelope->SetInterpolateDB(false);
mLinEnvelope->SetRange(MIN_dBMin, MAX_dBMax); // MB: this is the highest possible range
mLinEnvelope = std::make_unique<Envelope>
(false,
MIN_dBMin, MAX_dBMax, // MB: this is the highest possible range
1.0);
mEnvelope = (mLin ? mLinEnvelope : mLogEnvelope).get();
@ -2308,12 +2310,7 @@ void EffectEqualization::ErrMin(void)
double correction = 1.6;
bool flag;
size_t j=0;
Envelope testEnvelope;
testEnvelope.SetInterpolateDB(false);
testEnvelope.SetRange(-120.0, 60.0);
testEnvelope.Flatten(0.);
testEnvelope.SetTrackLen(1.0);
testEnvelope.CopyFrom(mLogEnvelope.get(), 0.0, 1.0);
Envelope testEnvelope{ *mLogEnvelope };
for(size_t i = 0; i < NUM_PTS; i++)
vals[i] = testEnvelope.GetValue(mWhens[i]);