Audacity 3.2.0
Public Member Functions | Private Member Functions | Private Attributes | List of all members
Envelope Class Reference

Piecewise linear or piecewise exponential function from double to double. More...

#include <Envelope.h>

Inheritance diagram for Envelope:
[legend]
Collaboration diagram for Envelope:
[legend]

Public Member Functions

 Envelope (bool exponential, double minValue, double maxValue, double defaultValue)
 
 Envelope (const Envelope &orig)
 
 Envelope (const Envelope &orig, double t0, double t1)
 
void Initialize (int numPoints)
 
virtual ~Envelope ()
 
bool IsTrivial () const
 
bool ConsistencyCheck ()
 
double GetOffset () const
 
double GetTrackLen () const
 
bool GetExponential () const
 
void SetExponential (bool db)
 
void Flatten (double value)
 
double GetMinValue () const
 
double GetMaxValue () const
 
void SetRange (double minValue, double maxValue)
 
double ClampValue (double value)
 
bool HandleXMLTag (const std::string_view &tag, const AttributesList &attrs) override
 
XMLTagHandlerHandleXMLChild (const std::string_view &tag) override
 
void WriteXML (XMLWriter &xmlFile) const
 
void CollapseRegion (double t0, double t1, double sampleDur)
 
void PasteEnvelope (double t0, const Envelope *e, double sampleDur)
 
void InsertSpace (double t0, double tlen)
 
void SetOffset (double newOffset)
 
void SetTrackLen (double trackLen, double sampleDur=0.0)
 
void RescaleValues (double minValue, double maxValue)
 
void RescaleTimes (double newLength)
 
double GetValue (double t, double sampleDur=0) const
 Get envelope value at time t. More...
 
void GetValues (double *buffer, int len, double t0, double tstep) const
 Get many envelope points at once. More...
 
void Cap (double sampleDur)
 
double Average (double t0, double t1) const
 
double AverageOfInverse (double t0, double t1) const
 
double Integral (double t0, double t1) const
 
double IntegralOfInverse (double t0, double t1) const
 
double SolveIntegralOfInverse (double t0, double area) const
 
void print () const
 
void testMe ()
 
bool IsDirty () const
 
void Clear ()
 
int InsertOrReplace (double when, double value)
 Add a point at a particular absolute time coordinate. More...
 
int Reassign (double when, double value)
 Move a point at when to value. More...
 
void Delete (int point)
 DELETE a point by its position in array. More...
 
void Insert (int point, const EnvPoint &p)
 insert a point More...
 
void Insert (double when, double value)
 
size_t GetNumberOfPoints () const
 Return number of points. More...
 
const EnvPointoperator[] (int index) const
 Accessor for points. More...
 
void GetPoints (double *bufferWhen, double *bufferValue, int bufferLen) const
 Returns the sets of when and value pairs. More...
 
int GetDragPoint () const
 
void SetDragPoint (int dragPoint)
 
void SetDragPointValid (bool valid)
 
bool GetDragPointValid () const
 
void MoveDragPoint (double newWhen, double value)
 
void ClearDragPoint ()
 
- Public Member Functions inherited from XMLTagHandler
 XMLTagHandler ()
 
virtual ~XMLTagHandler ()
 
virtual bool HandleXMLTag (const std::string_view &tag, const AttributesList &attrs)=0
 
virtual void HandleXMLEndTag (const std::string_view &WXUNUSED(tag))
 
virtual void HandleXMLContent (const std::string_view &WXUNUSED(content))
 
virtual XMLTagHandlerHandleXMLChild (const std::string_view &tag)=0
 
void ReadXMLEndTag (const char *tag)
 
void ReadXMLContent (const char *s, int len)
 
XMLTagHandlerReadXMLChild (const char *tag)
 

Private Member Functions

std::pair< int, int > ExpandRegion (double t0, double tlen, double *pLeftVal, double *pRightVal)
 
void RemoveUnneededPoints (size_t startAt, bool rightward, bool testNeighbors=true)
 
double GetValueRelative (double t, bool leftLimit=false) const
 
void GetValuesRelative (double *buffer, int len, double t0, double tstep, bool leftLimit=false) const
 
int NumberOfPointsAfter (double t) const
 
double NextPointAfter (double t) const
 
int InsertOrReplaceRelative (double when, double value)
 Add a control point to the envelope. More...
 
std::pair< int, int > EqualRange (double when, double sampleDur) const
 
void 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
 
void BinarySearchForTime_LeftLimit (int &Lo, int &Hi, double t) const
 
double GetInterpolationStartValueAtPoint (int iPoint) const
 

Private Attributes

EnvArray mEnv
 
double mOffset { 0.0 }
 The time at which the envelope starts, i.e. the start offset. More...
 
double mTrackLen { 0.0 }
 The length of the envelope, which is the same as the length of the underlying track (normally) More...
 
double mTrackEpsilon { 1.0 / 200000.0 }
 The shortest distance apart that points on an envelope can be before being considered the same point. More...
 
bool mDB
 
double mMinValue
 
double mMaxValue
 
double mDefaultValue
 
bool mDragPointValid { false }
 
int mDragPoint { -1 }
 
int mSearchGuess { -2 }
 

Detailed Description

Piecewise linear or piecewise exponential function from double to double.

This class manages an envelope - i.e. a function that the user can edit by dragging control points around. The envelope is most commonly used to control the amplitude of a waveform, but it is also used to shape the Equalization curve, and in TimeTrack to determine a time warp.

Definition at line 72 of file Envelope.h.

Constructor & Destructor Documentation

◆ Envelope() [1/3]

Envelope::Envelope ( bool  exponential,
double  minValue,
double  maxValue,
double  defaultValue 
)

Definition at line 43 of file Envelope.cpp.

44 : mDB(exponential)
45 , mMinValue(minValue)
46 , mMaxValue(maxValue)
47 , mDefaultValue { ClampValue(defaultValue) }
48{
49}
double mMinValue
Definition: Envelope.h:250
bool mDB
Definition: Envelope.h:249
double ClampValue(double value)
Definition: Envelope.h:104
double mDefaultValue
Definition: Envelope.h:251
double mMaxValue
Definition: Envelope.h:250

◆ Envelope() [2/3]

Envelope::Envelope ( const Envelope orig)

Definition at line 262 of file Envelope.cpp.

263 : mDB(orig.mDB)
264 , mMinValue(orig.mMinValue)
265 , mMaxValue(orig.mMaxValue)
267{
268 mOffset = orig.mOffset;
269 mTrackLen = orig.mTrackLen;
270 CopyRange(orig, 0, orig.GetNumberOfPoints());
271}
double mOffset
The time at which the envelope starts, i.e. the start offset.
Definition: Envelope.h:239
size_t GetNumberOfPoints() const
Return number of points.
Definition: Envelope.cpp:694
double mTrackLen
The length of the envelope, which is the same as the length of the underlying track (normally)
Definition: Envelope.h:242
void CopyRange(const Envelope &orig, size_t begin, size_t end)
Definition: Envelope.cpp:273

References CopyRange(), GetNumberOfPoints(), mOffset, and mTrackLen.

Here is the call graph for this function:

◆ Envelope() [3/3]

Envelope::Envelope ( const Envelope orig,
double  t0,
double  t1 
)

Definition at line 248 of file Envelope.cpp.

249 : mDB(orig.mDB)
250 , mMinValue(orig.mMinValue)
251 , mMaxValue(orig.mMaxValue)
253{
254 mOffset = wxMax(t0, orig.mOffset);
255 mTrackLen = wxMin(t1, orig.mOffset + orig.mTrackLen) - mOffset;
256
257 auto range1 = orig.EqualRange( t0 - orig.mOffset, 0 );
258 auto range2 = orig.EqualRange( t1 - orig.mOffset, 0 );
259 CopyRange(orig, range1.first, range2.second);
260}
std::pair< int, int > EqualRange(double when, double sampleDur) const
Definition: Envelope.cpp:762

References CopyRange(), EqualRange(), mOffset, and mTrackLen.

Here is the call graph for this function:

◆ ~Envelope()

Envelope::~Envelope ( )
virtual

Definition at line 51 of file Envelope.cpp.

52{
53}

Member Function Documentation

◆ AddPointAtEnd()

void Envelope::AddPointAtEnd ( double  t,
double  val 
)
private

Definition at line 231 of file Envelope.cpp.

232{
233 mEnv.push_back( EnvPoint{ t, val } );
234
235 // Assume copied points were stored by nondecreasing time.
236 // Allow no more than two points at exactly the same time.
237 // Maybe that happened, because extra points were inserted at the boundary
238 // of the copied range, which were not in the source envelope.
239 auto nn = mEnv.size() - 1;
240 while ( nn >= 2 && mEnv[ nn - 2 ].GetT() == t ) {
241 // Of three or more points at the same time, erase one in the middle,
242 // not the one newly added.
243 mEnv.erase( mEnv.begin() + nn - 1 );
244 --nn;
245 }
246}
EnvPoint, derived from XMLTagHandler, provides Envelope with a draggable point type.
Definition: Envelope.h:29
EnvArray mEnv
Definition: Envelope.h:236

References mEnv.

Referenced by CopyRange(), and SetTrackLen().

Here is the caller graph for this function:

◆ Average()

double Envelope::Average ( double  t0,
double  t1 
) const

Definition at line 1072 of file Envelope.cpp.

1073{
1074 if( t0 == t1 )
1075 return GetValue( t0 );
1076 else
1077 return Integral( t0, t1 ) / (t1 - t0);
1078}
double GetValue(double t, double sampleDur=0) const
Get envelope value at time t.
Definition: Envelope.cpp:828
double Integral(double t0, double t1) const
Definition: Envelope.cpp:1171

References GetValue(), and Integral().

Here is the call graph for this function:

◆ AverageOfInverse()

double Envelope::AverageOfInverse ( double  t0,
double  t1 
) const

Definition at line 1080 of file Envelope.cpp.

1081{
1082 if( t0 == t1 )
1083 return 1.0 / GetValue( t0 );
1084 else
1085 return IntegralOfInverse( t0, t1 ) / (t1 - t0);
1086}
double IntegralOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1234

References GetValue(), and IntegralOfInverse().

Referenced by anonymous_namespace{MixerSource.cpp}::ComputeWarpFactor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ BinarySearchForTime()

void Envelope::BinarySearchForTime ( int &  Lo,
int &  Hi,
double  t 
) const
private
Parameters
Loreturns last index at or before this time, maybe -1
Hireturns first index after this time, maybe past the end

Definition at line 848 of file Envelope.cpp.

849{
850 // Optimizations for the usual pattern of repeated calls with
851 // small increases of t.
852 {
853 if (mSearchGuess >= 0 && mSearchGuess < (int)mEnv.size()) {
854 if (t >= mEnv[mSearchGuess].GetT() &&
855 (1 + mSearchGuess == (int)mEnv.size() ||
856 t < mEnv[1 + mSearchGuess].GetT())) {
857 Lo = mSearchGuess;
858 Hi = 1 + mSearchGuess;
859 return;
860 }
861 }
862
863 ++mSearchGuess;
864 if (mSearchGuess >= 0 && mSearchGuess < (int)mEnv.size()) {
865 if (t >= mEnv[mSearchGuess].GetT() &&
866 (1 + mSearchGuess == (int)mEnv.size() ||
867 t < mEnv[1 + mSearchGuess].GetT())) {
868 Lo = mSearchGuess;
869 Hi = 1 + mSearchGuess;
870 return;
871 }
872 }
873 }
874
875 Lo = -1;
876 Hi = mEnv.size();
877
878 // Invariants: Lo is not less than -1, Hi not more than size
879 while (Hi > (Lo + 1)) {
880 int mid = (Lo + Hi) / 2;
881 // mid must be strictly between Lo and Hi, therefore a valid index
882 if (t < mEnv[mid].GetT())
883 Hi = mid;
884 else
885 Lo = mid;
886 }
887 wxASSERT( Hi == ( Lo+1 ));
888
889 mSearchGuess = Lo;
890}
int mSearchGuess
Definition: Envelope.h:257

References mEnv, and mSearchGuess.

Referenced by GetValuesRelative(), Integral(), IntegralOfInverse(), NextPointAfter(), NumberOfPointsAfter(), and SolveIntegralOfInverse().

Here is the caller graph for this function:

◆ BinarySearchForTime_LeftLimit()

void Envelope::BinarySearchForTime_LeftLimit ( int &  Lo,
int &  Hi,
double  t 
) const
private
Parameters
Loreturns last index before this time, maybe -1
Hireturns first index at or after this time, maybe past the end

Definition at line 895 of file Envelope.cpp.

896{
897 Lo = -1;
898 Hi = mEnv.size();
899
900 // Invariants: Lo is not less than -1, Hi not more than size
901 while (Hi > (Lo + 1)) {
902 int mid = (Lo + Hi) / 2;
903 // mid must be strictly between Lo and Hi, therefore a valid index
904 if (t <= mEnv[mid].GetT())
905 Hi = mid;
906 else
907 Lo = mid;
908 }
909 wxASSERT( Hi == ( Lo+1 ));
910
911 mSearchGuess = Lo;
912}

References mEnv, and mSearchGuess.

Referenced by GetValuesRelative().

Here is the caller graph for this function:

◆ Cap()

void Envelope::Cap ( double  sampleDur)

Definition at line 713 of file Envelope.cpp.

714{
715 auto range = EqualRange( mTrackLen, sampleDur );
716 if ( range.first == range.second )
718}
int InsertOrReplaceRelative(double when, double value)
Add a control point to the envelope.
Definition: Envelope.cpp:728
double GetValueRelative(double t, bool leftLimit=false) const
Definition: Envelope.cpp:837

References EqualRange(), GetValueRelative(), InsertOrReplaceRelative(), and mTrackLen.

Here is the call graph for this function:

◆ ClampValue()

double Envelope::ClampValue ( double  value)
inline

Definition at line 104 of file Envelope.h.

104{ return std::max(mMinValue, std::min(mMaxValue, value)); }
int min(int a, int b)

References min().

Referenced by SetEnvelopeCommand::ApplyInner(), Flatten(), RescaleValues(), SetRange(), EnvPoint::SetVal(), and EnvelopeEditor::ValueOfPixel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Clear()

void Envelope::Clear ( )
inline

Definition at line 172 of file Envelope.h.

172{ mEnv.clear(); }

Referenced by SetEnvelopeCommand::ApplyInner().

Here is the caller graph for this function:

◆ ClearDragPoint()

void Envelope::ClearDragPoint ( )

Definition at line 212 of file Envelope.cpp.

213{
214 if (!mDragPointValid && mDragPoint >= 0)
216
217 mDragPoint = -1;
218 mDragPointValid = false;
219}
int mDragPoint
Definition: Envelope.h:255
void Delete(int point)
DELETE a point by its position in array.
Definition: Envelope.cpp:361
bool mDragPointValid
Definition: Envelope.h:254

References Delete(), mDragPoint, and mDragPointValid.

Referenced by EnvelopeEditor::HandleMouseButtonUp().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CollapseRegion()

void Envelope::CollapseRegion ( double  t0,
double  t1,
double  sampleDur 
)
Exception safety guarantee:
No-fail

Definition at line 377 of file Envelope.cpp.

378{
379 if ( t1 <= t0 )
380 return;
381
382 // This gets called when somebody clears samples.
383
384 // Snip points in the interval (t0, t1), shift values left at times after t1.
385 // For the boundaries of the interval, preserve the left-side limit at the
386 // start and right-side limit at the end.
387
388 const auto epsilon = sampleDur / 2;
389 t0 = std::max( 0.0, std::min( mTrackLen, t0 - mOffset ) );
390 t1 = std::max( 0.0, std::min( mTrackLen, t1 - mOffset ) );
391 bool leftPoint = true, rightPoint = true;
392
393 // Determine the start of the range of points to remove from the array.
394 auto range0 = EqualRange( t0, 0 );
395 auto begin = range0.first;
396 if ( begin == range0.second ) {
397 if ( t0 > epsilon ) {
398 // There was no point exactly at t0;
399 // insert a point to preserve the value.
400 auto val = GetValueRelative( t0 );
401 InsertOrReplaceRelative( t0, val );
402 ++begin;
403 }
404 else
405 leftPoint = false;
406 }
407 else
408 // We will keep the first (or only) point that was at t0.
409 ++begin;
410
411 // We want end to be the index one past the range of points to remove from
412 // the array.
413 // At first, find index of the first point after t1:
414 auto range1 = EqualRange( t1, 0 );
415 auto end = range1.second;
416 if ( range1.first == end ) {
417 if ( mTrackLen - t1 > epsilon ) {
418 // There was no point exactly at t1; insert a point to preserve the value.
419 auto val = GetValueRelative( t1 );
420 InsertOrReplaceRelative( t1, val );
421 // end is now the index of this NEW point and that is correct.
422 }
423 else
424 rightPoint = false;
425 }
426 else
427 // We will keep the last (or only) point that was at t1.
428 --end;
429
430 if ( end < begin ) {
431 if ( leftPoint )
432 rightPoint = false;
433 }
434 else
435 mEnv.erase( mEnv.begin() + begin, mEnv.begin() + end );
436
437 // Shift points left after deleted region.
438 auto len = mEnv.size();
439 for ( size_t i = begin; i < len; ++i ) {
440 auto &point = mEnv[i];
441 if (rightPoint && (int)i == begin)
442 // Avoid roundoff error.
443 // Make exactly equal times of neighboring points so that we have
444 // a real discontinuity.
445 point.SetT( t0 );
446 else
447 point.SetT( point.GetT() - (t1 - t0) );
448 }
449
450 // See if the discontinuity is removable.
451 if ( rightPoint )
453 if ( leftPoint )
454 RemoveUnneededPoints( begin - 1, false );
455
456 mTrackLen -= ( t1 - t0 );
457}
void RemoveUnneededPoints(size_t startAt, bool rightward, bool testNeighbors=true)
Definition: Envelope.cpp:549
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150

References PackedArray::begin(), PackedArray::end(), EqualRange(), GetValueRelative(), InsertOrReplaceRelative(), mEnv, min(), mOffset, mTrackLen, and RemoveUnneededPoints().

Referenced by WaveClip::ClearAndAddCutLine(), and WaveClip::ClearSequence().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ConsistencyCheck()

bool Envelope::ConsistencyCheck ( )

Definition at line 60 of file Envelope.cpp.

61{
62 bool consistent = true;
63
64 bool disorder;
65 do {
66 disorder = false;
67 for ( size_t ii = 0, count = mEnv.size(); ii < count; ) {
68 // Find range of points with equal T
69 const double thisT = mEnv[ii].GetT();
70 double nextT = 0.0f;
71 auto nextI = ii + 1;
72 while ( nextI < count && thisT == ( nextT = mEnv[nextI].GetT() ) )
73 ++nextI;
74
75 if ( nextI < count && nextT < thisT )
76 disorder = true;
77
78 while ( nextI - ii > 2 ) {
79 // too many coincident time values
80 if ((int)ii == mDragPoint || (int)nextI - 1 == mDragPoint)
81 // forgivable
82 ;
83 else {
84 consistent = false;
85 // repair it
86 Delete( nextI - 2 );
87 if (mDragPoint >= (int)nextI - 2)
88 --mDragPoint;
89 --nextI, --count;
90 // wxLogError
91 }
92 }
93
94 ii = nextI;
95 }
96
97 if (disorder) {
98 consistent = false;
99 // repair it
100 std::stable_sort( mEnv.begin(), mEnv.end(),
101 []( const EnvPoint &a, const EnvPoint &b )
102 { return a.GetT() < b.GetT(); } );
103 }
104 } while ( disorder );
105
106 return consistent;
107}

References mEnv.

Referenced by PasteEnvelope().

Here is the caller graph for this function:

◆ CopyRange()

void Envelope::CopyRange ( const Envelope orig,
size_t  begin,
size_t  end 
)
private

Definition at line 273 of file Envelope.cpp.

274{
275 size_t len = orig.mEnv.size();
276 size_t i = begin;
277
278 // Create the point at 0 if it needs interpolated representation
279 if ( i > 0 )
281
282 // Copy points from inside the copied region
283 for (; i < end; ++i) {
284 const EnvPoint &point = orig[i];
285 const double when = point.GetT() + (orig.mOffset - mOffset);
286 AddPointAtEnd(when, point.GetVal());
287 }
288
289 // Create the final point if it needs interpolated representation
290 // If the last point of e was exactly at t1, this effectively copies it too.
291 if (mTrackLen > 0 && i < len)
293}
double GetVal() const
Definition: Envelope.h:37
double GetT() const
Definition: Envelope.h:35
void AddPointAtEnd(double t, double val)
Definition: Envelope.cpp:231

References AddPointAtEnd(), PackedArray::begin(), PackedArray::end(), EnvPoint::GetT(), EnvPoint::GetVal(), GetValue(), mEnv, mOffset, and mTrackLen.

Referenced by Envelope().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Delete()

void Envelope::Delete ( int  point)

DELETE a point by its position in array.

Definition at line 361 of file Envelope.cpp.

362{
363 mEnv.erase(mEnv.begin() + point);
364}

References mEnv.

Referenced by ClearDragPoint(), BoundedEnvelope::Envelope(), and RemoveUnneededPoints().

Here is the caller graph for this function:

◆ EqualRange()

std::pair< int, int > Envelope::EqualRange ( double  when,
double  sampleDur 
) const
private

Definition at line 762 of file Envelope.cpp.

763{
764 // Find range of envelope points matching the given time coordinate
765 // (within an interval of length sampleDur)
766 // by binary search; if empty, it still indicates where to
767 // insert.
768 const auto tolerance = sampleDur / 2;
769 auto begin = mEnv.begin();
770 auto end = mEnv.end();
771 auto first = std::lower_bound(
772 begin, end,
773 EnvPoint{ when - tolerance, 0.0 },
774 []( const EnvPoint &point1, const EnvPoint &point2 )
775 { return point1.GetT() < point2.GetT(); }
776 );
777 auto after = first;
778 while ( after != end && after->GetT() <= when + tolerance )
779 ++after;
780 return { first - begin, after - begin };
781}

References PackedArray::begin(), PackedArray::end(), EnvPoint::GetT(), and mEnv.

Referenced by Cap(), CollapseRegion(), Envelope(), ExpandRegion(), InsertOrReplaceRelative(), PasteEnvelope(), and SetTrackLen().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ExpandRegion()

std::pair< int, int > Envelope::ExpandRegion ( double  t0,
double  tlen,
double *  pLeftVal,
double *  pRightVal 
)
private
Exception safety guarantee:
No-fail

Definition at line 614 of file Envelope.cpp.

616{
617 // t0 is relative time
618
619 double val = GetValueRelative( t0 );
620 const auto range = EqualRange( t0, 0 );
621
622 // Preserve the left-side limit.
623 int index = 1 + range.first;
624 if ( index <= range.second )
625 // There is already a control point.
626 ;
627 else {
628 // Make a control point.
629 Insert( range.first, EnvPoint{ t0, val } );
630 }
631
632 // Shift points.
633 auto len = mEnv.size();
634 for ( unsigned int ii = index; ii < len; ++ii ) {
635 auto &point = mEnv[ ii ];
636 point.SetT( point.GetT() + tlen );
637 }
638
639 mTrackLen += tlen;
640
641 // Preserve the right-side limit.
642 if ( index < range.second )
643 // There was a control point already.
644 ;
645 else
646 // Make a control point.
647 Insert( index, EnvPoint{ t0 + tlen, val } );
648
649 // Make discontinuities at ends, maybe:
650
651 if ( pLeftVal )
652 // Make a discontinuity at the left side of the expansion
653 Insert( index++, EnvPoint{ t0, *pLeftVal } );
654
655 if ( pRightVal )
656 // Make a discontinuity at the right side of the expansion
657 Insert( index++, EnvPoint{ t0 + tlen, *pRightVal } );
658
659 // Return the range of indices that includes the inside limiting points,
660 // none, one, or two
661 return { 1 + range.first, index };
662}
void Insert(int point, const EnvPoint &p)
insert a point
Definition: Envelope.cpp:366

References EqualRange(), GetValueRelative(), Insert(), mEnv, and mTrackLen.

Referenced by InsertSpace(), and PasteEnvelope().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Flatten()

void Envelope::Flatten ( double  value)

Flatten removes all points from the envelope to make it horizontal at a chosen y-value. @value - the y-value for the flat envelope.

Definition at line 137 of file Envelope.cpp.

138{
139 mEnv.clear();
140 mDefaultValue = ClampValue(value);
141}

References ClampValue(), mDefaultValue, and mEnv.

Referenced by EqualizationBandSliders::GraphicEQ(), TimeTrack::testMe(), and testMe().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetDragPoint()

int Envelope::GetDragPoint ( ) const
inline

Definition at line 215 of file Envelope.h.

215{ return mDragPoint; }

Referenced by EnvelopeEditor::DrawPoints(), and EnvelopeEditor::MouseEvent().

Here is the caller graph for this function:

◆ GetDragPointValid()

bool Envelope::GetDragPointValid ( ) const
inline

Definition at line 220 of file Envelope.h.

220{ return mDragPointValid; }

Referenced by EnvelopeEditor::HandleDragging().

Here is the caller graph for this function:

◆ GetExponential()

bool Envelope::GetExponential ( ) const
inline

Definition at line 95 of file Envelope.h.

95{ return mDB; }

Referenced by CommonTrackView::GetEnvelopeValues().

Here is the caller graph for this function:

◆ GetInterpolationStartValueAtPoint()

double Envelope::GetInterpolationStartValueAtPoint ( int  iPoint) const
private

GetInterpolationStartValueAtPoint() is used to select either the envelope value or its log depending on whether we are doing linear or log interpolation.

Parameters
iPointindex in env array to look at.
Returns
value there, or its (safe) log10.

Definition at line 919 of file Envelope.cpp.

920{
921 double v = mEnv[ iPoint ].GetVal();
922 if( !mDB )
923 return v;
924 else
925 return log10(v);
926}

References mDB, and mEnv.

Referenced by GetValuesRelative().

Here is the caller graph for this function:

◆ GetMaxValue()

double Envelope::GetMaxValue ( ) const
inline

Definition at line 101 of file Envelope.h.

101{ return mMaxValue; }

◆ GetMinValue()

double Envelope::GetMinValue ( ) const
inline

Definition at line 100 of file Envelope.h.

100{ return mMinValue; }

◆ GetNumberOfPoints()

size_t Envelope::GetNumberOfPoints ( ) const

Return number of points.

Definition at line 694 of file Envelope.cpp.

695{
696 return mEnv.size();
697}

References mEnv.

Referenced by EnvelopeEditor::DrawPoints(), Envelope(), EqualizationCurvesList::EnvelopeUpdated(), EqualizationBandSliders::EnvLinToLog(), EqualizationBandSliders::EnvLogToLin(), EnvelopeEditor::HandleMouseButtonDown(), and GetInfoCommand::SendEnvelopes().

Here is the caller graph for this function:

◆ GetOffset()

double Envelope::GetOffset ( ) const
inline

Definition at line 92 of file Envelope.h.

92{ return mOffset; }

Referenced by EnvelopeEditor::DrawPoints(), EnvelopeEditor::HandleMouseButtonDown(), EnvelopeEditor::MoveDragPoint(), and GetInfoCommand::SendEnvelopes().

Here is the caller graph for this function:

◆ GetPoints()

void Envelope::GetPoints ( double *  bufferWhen,
double *  bufferValue,
int  bufferLen 
) const

Returns the sets of when and value pairs.

Definition at line 699 of file Envelope.cpp.

702{
703 int n = mEnv.size();
704 if (n > bufferLen)
705 n = bufferLen;
706 int i;
707 for (i = 0; i < n; i++) {
708 bufferWhen[i] = mEnv[i].GetT() - mOffset;
709 bufferValue[i] = mEnv[i].GetVal();
710 }
711}

References mEnv, and mOffset.

Referenced by EqualizationCurvesList::EnvelopeUpdated().

Here is the caller graph for this function:

◆ GetTrackLen()

double Envelope::GetTrackLen ( ) const
inline

Definition at line 93 of file Envelope.h.

93{ return mTrackLen; }

◆ GetValue()

double Envelope::GetValue ( double  t,
double  sampleDur = 0 
) const

Get envelope value at time t.

Definition at line 828 of file Envelope.cpp.

829{
830 // t is absolute time
831 double temp;
832
833 GetValues( &temp, 1, t, sampleDur );
834 return temp;
835}
void GetValues(double *buffer, int len, double t0, double tstep) const
Get many envelope points at once.
Definition: Envelope.cpp:928

References GetValues().

Referenced by Average(), AverageOfInverse(), EqualizationFilter::CalcFilter(), CopyRange(), anonymous_namespace{WaveformView.cpp}::DrawIndividualSamples(), EqualizationBandSliders::ErrMin(), SampleHandle::FindSampleEditingLevel(), CommonTrackView::GetEnvelopeValues(), EnvelopeEditor::HandleMouseButtonDown(), EnvelopeHandle::HitEnvelope(), SampleHandle::HitTest(), and PasteEnvelope().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetValueRelative()

double Envelope::GetValueRelative ( double  t,
bool  leftLimit = false 
) const
private

Definition at line 837 of file Envelope.cpp.

838{
839 double temp;
840
841 GetValuesRelative(&temp, 1, t, 0.0, leftLimit);
842 return temp;
843}
void GetValuesRelative(double *buffer, int len, double t0, double tstep, bool leftLimit=false) const
Definition: Envelope.cpp:937

References GetValuesRelative().

Referenced by Cap(), CollapseRegion(), ExpandRegion(), PasteEnvelope(), RemoveUnneededPoints(), and SetTrackLen().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetValues()

void Envelope::GetValues ( double *  buffer,
int  len,
double  t0,
double  tstep 
) const

Get many envelope points at once.

This is much faster than calling GetValue() multiple times if you need more than one value in a row.

Definition at line 928 of file Envelope.cpp.

930{
931 // Convert t0 from absolute to clip-relative time
932 t0 -= mOffset;
933 GetValuesRelative( buffer, bufferLen, t0, tstep);
934}

References GetValuesRelative(), and mOffset.

Referenced by GetValue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetValuesRelative()

void Envelope::GetValuesRelative ( double *  buffer,
int  len,
double  t0,
double  tstep,
bool  leftLimit = false 
) const
private

Definition at line 936 of file Envelope.cpp.

939{
940 // JC: If bufferLen ==0 we have probably just allocated a zero sized buffer.
941 // wxASSERT( bufferLen > 0 );
942
943 const auto epsilon = tstep / 2;
944 int len = mEnv.size();
945
946 double t = t0;
947 double increment = 0;
948 if ( len > 1 && t <= mEnv[0].GetT() && mEnv[0].GetT() == mEnv[1].GetT() )
949 increment = leftLimit ? -epsilon : epsilon;
950
951 double tprev, vprev, tnext = 0, vnext, vstep = 0;
952
953 for (int b = 0; b < bufferLen; b++) {
954
955 // Get easiest cases out the way first...
956 // IF empty envelope THEN default value
957 if (len <= 0) {
958 buffer[b] = mDefaultValue;
959 t += tstep;
960 continue;
961 }
962
963 auto tplus = t + increment;
964
965 // IF before envelope THEN first value
966 if ( leftLimit ? tplus <= mEnv[0].GetT() : tplus < mEnv[0].GetT() ) {
967 buffer[b] = mEnv[0].GetVal();
968 t += tstep;
969 continue;
970 }
971 // IF after envelope THEN last value
972 if ( leftLimit
973 ? tplus > mEnv[len - 1].GetT() : tplus >= mEnv[len - 1].GetT() ) {
974 buffer[b] = mEnv[len - 1].GetVal();
975 t += tstep;
976 continue;
977 }
978
979 // be careful to get the correct limit even in case epsilon == 0
980 if ( b == 0 ||
981 ( leftLimit ? tplus > tnext : tplus >= tnext ) ) {
982
983 // We're beyond our tnext, so find the next one.
984 // Don't just increment lo or hi because we might
985 // be zoomed far out and that could be a large number of
986 // points to move over. That's why we binary search.
987
988 int lo,hi;
989 if ( leftLimit )
990 BinarySearchForTime_LeftLimit( lo, hi, tplus );
991 else
992 BinarySearchForTime( lo, hi, tplus );
993
994 // mEnv[0] is before tplus because of eliminations above, therefore lo >= 0
995 // mEnv[len - 1] is after tplus, therefore hi <= len - 1
996 wxASSERT( lo >= 0 && hi <= len - 1 );
997
998 tprev = mEnv[lo].GetT();
999 tnext = mEnv[hi].GetT();
1000
1001 if ( hi + 1 < len && tnext == mEnv[ hi + 1 ].GetT() )
1002 // There is a discontinuity after this point-to-point interval.
1003 // Usually will stop evaluating in this interval when time is slightly
1004 // before tNext, then use the right limit.
1005 // This is the right intent
1006 // in case small roundoff errors cause a sample time to be a little
1007 // before the envelope point time.
1008 // Less commonly we want a left limit, so we continue evaluating in
1009 // this interval until shortly after the discontinuity.
1010 increment = leftLimit ? -epsilon : epsilon;
1011 else
1012 increment = 0;
1013
1016
1017 // Interpolate, either linear or log depending on mDB.
1018 double dt = (tnext - tprev);
1019 double to = t - tprev;
1020 double v;
1021 if (dt > 0.0)
1022 {
1023 v = (vprev * (dt - to) + vnext * to) / dt;
1024 vstep = (vnext - vprev) * tstep / dt;
1025 }
1026 else
1027 {
1028 v = vnext;
1029 vstep = 0.0;
1030 }
1031
1032 // An adjustment if logarithmic scale.
1033 if( mDB )
1034 {
1035 v = pow(10.0, v);
1036 vstep = pow( 10.0, vstep );
1037 }
1038
1039 buffer[b] = v;
1040 } else {
1041 if (mDB){
1042 buffer[b] = buffer[b - 1] * vstep;
1043 }else{
1044 buffer[b] = buffer[b - 1] + vstep;
1045 }
1046 }
1047
1048 t += tstep;
1049 }
1050}
void BinarySearchForTime(int &Lo, int &Hi, double t) const
Definition: Envelope.cpp:848
void BinarySearchForTime_LeftLimit(int &Lo, int &Hi, double t) const
Definition: Envelope.cpp:895
double GetInterpolationStartValueAtPoint(int iPoint) const
Definition: Envelope.cpp:919

References BinarySearchForTime(), BinarySearchForTime_LeftLimit(), GetInterpolationStartValueAtPoint(), mDB, mDefaultValue, and mEnv.

Referenced by GetValueRelative(), and GetValues().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ HandleXMLChild()

XMLTagHandler * Envelope::HandleXMLChild ( const std::string_view &  tag)
overridevirtual

Implements XMLTagHandler.

Definition at line 333 of file Envelope.cpp.

334{
335 if (tag != "controlpoint")
336 return NULL;
337
338 mEnv.push_back( EnvPoint{} );
339 return &mEnv.back();
340}

References mEnv.

Referenced by AUPImportFileHandle::HandleControlPoint().

Here is the caller graph for this function:

◆ HandleXMLTag()

bool Envelope::HandleXMLTag ( const std::string_view &  tag,
const AttributesList attrs 
)
overridevirtual

Implements XMLTagHandler.

Definition at line 308 of file Envelope.cpp.

309{
310 // Return unless it's the envelope tag.
311 if (tag != "envelope")
312 return false;
313
314 int numPoints = -1;
315
316 for (auto pair : attrs)
317 {
318 auto attr = pair.first;
319 auto value = pair.second;
320
321 if (attr == "numpoints")
322 value.TryGet(numPoints);
323 }
324
325 if (numPoints < 0)
326 return false;
327
328 mEnv.clear();
329 mEnv.reserve(numPoints);
330 return true;
331}

References mEnv.

◆ Initialize()

void Envelope::Initialize ( int  numPoints)

◆ Insert() [1/2]

void Envelope::Insert ( double  when,
double  value 
)

Definition at line 371 of file Envelope.cpp.

372{
373 mEnv.push_back( EnvPoint{ when, value });
374}

References mEnv.

◆ Insert() [2/2]

void Envelope::Insert ( int  point,
const EnvPoint p 
)

insert a point

Definition at line 366 of file Envelope.cpp.

367{
368 mEnv.insert(mEnv.begin() + point, p);
369}

References mEnv.

Referenced by ExpandRegion(), EqualizationBandSliders::GraphicEQ(), InsertOrReplaceRelative(), and RemoveUnneededPoints().

Here is the caller graph for this function:

◆ InsertOrReplace()

int Envelope::InsertOrReplace ( double  when,
double  value 
)
inline

Add a point at a particular absolute time coordinate.

Definition at line 175 of file Envelope.h.

176 { return InsertOrReplaceRelative( when - mOffset, value ); }

Referenced by SetEnvelopeCommand::ApplyInner(), EnvelopeEditor::HandleMouseButtonDown(), and TimeTrack::testMe().

Here is the caller graph for this function:

◆ InsertOrReplaceRelative()

int Envelope::InsertOrReplaceRelative ( double  when,
double  value 
)
private

Add a control point to the envelope.

Parameters
whenthe time in seconds when the envelope point should be created.
valuethe envelope value to use at the given point.
Returns
the index of the NEW envelope point within array of envelope points.

Definition at line 728 of file Envelope.cpp.

729{
730#if defined(_DEBUG)
731 // in debug builds, do a spot of argument checking
732 if(when > mTrackLen + 0.0000001)
733 {
734 wxString msg;
735 msg = wxString::Format(wxT("when %.20f mTrackLen %.20f diff %.20f"), when, mTrackLen, when-mTrackLen);
736 wxASSERT_MSG(when <= (mTrackLen), msg);
737 }
738 if(when < 0)
739 {
740 wxString msg;
741 msg = wxString::Format(wxT("when %.20f mTrackLen %.20f"), when, mTrackLen);
742 wxASSERT_MSG(when >= 0, msg);
743 }
744#endif
745
746 when = std::max( 0.0, std::min( mTrackLen, when ) );
747
748 auto range = EqualRange( when, 0 );
749 int index = range.first;
750
751 if ( index < range.second )
752 // modify existing
753 // In case of a discontinuity, ALWAYS CHANGING LEFT LIMIT ONLY!
754 mEnv[ index ].SetVal( this, value );
755 else
756 // Add NEW
757 Insert( index, EnvPoint { when, value } );
758
759 return index;
760}
wxT("CloseDown"))

References EqualRange(), Insert(), mEnv, min(), mTrackLen, and wxT().

Referenced by Cap(), CollapseRegion(), and testMe().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ InsertSpace()

void Envelope::InsertSpace ( double  t0,
double  tlen 
)
Exception safety guarantee:
No-fail

Definition at line 665 of file Envelope.cpp.

666{
667 auto range = ExpandRegion( t0 - mOffset, tlen, nullptr, nullptr );
668
669 // Simplify the boundaries if possible
670 RemoveUnneededPoints( range.second, true );
671 RemoveUnneededPoints( range.first - 1, false );
672}
std::pair< int, int > ExpandRegion(double t0, double tlen, double *pLeftVal, double *pRightVal)
Definition: Envelope.cpp:615

References ExpandRegion(), mOffset, and RemoveUnneededPoints().

Here is the call graph for this function:

◆ Integral()

double Envelope::Integral ( double  t0,
double  t1 
) const

Definition at line 1171 of file Envelope.cpp.

1172{
1173 if(t0 == t1)
1174 return 0.0;
1175 if(t0 > t1)
1176 {
1177 return -Integral(t1, t0); // this makes more sense than returning the default value
1178 }
1179
1180 unsigned int count = mEnv.size();
1181 if(count == 0) // 'empty' envelope
1182 return (t1 - t0) * mDefaultValue;
1183
1184 t0 -= mOffset;
1185 t1 -= mOffset;
1186
1187 double total = 0.0, lastT, lastVal;
1188 unsigned int i; // this is the next point to check
1189 if(t0 < mEnv[0].GetT()) // t0 preceding the first point
1190 {
1191 if(t1 <= mEnv[0].GetT())
1192 return (t1 - t0) * mEnv[0].GetVal();
1193 i = 1;
1194 lastT = mEnv[0].GetT();
1195 lastVal = mEnv[0].GetVal();
1196 total += (lastT - t0) * lastVal;
1197 }
1198 else if(t0 >= mEnv[count - 1].GetT()) // t0 at or following the last point
1199 {
1200 return (t1 - t0) * mEnv[count - 1].GetVal();
1201 }
1202 else // t0 enclosed by points
1203 {
1204 // Skip any points that come before t0 using binary search
1205 int lo, hi;
1206 BinarySearchForTime(lo, hi, t0);
1207 lastVal = InterpolatePoints(mEnv[lo].GetVal(), mEnv[hi].GetVal(), (t0 - mEnv[lo].GetT()) / (mEnv[hi].GetT() - mEnv[lo].GetT()), mDB);
1208 lastT = t0;
1209 i = hi; // the point immediately after t0.
1210 }
1211
1212 // loop through the rest of the envelope points until we get to t1
1213 while (1)
1214 {
1215 if(i >= count) // the requested range extends beyond the last point
1216 {
1217 return total + (t1 - lastT) * lastVal;
1218 }
1219 else if(mEnv[i].GetT() >= t1) // this point follows the end of the range
1220 {
1221 double thisVal = InterpolatePoints(mEnv[i - 1].GetVal(), mEnv[i].GetVal(), (t1 - mEnv[i - 1].GetT()) / (mEnv[i].GetT() - mEnv[i - 1].GetT()), mDB);
1222 return total + IntegrateInterpolated(lastVal, thisVal, t1 - lastT, mDB);
1223 }
1224 else // this point precedes the end of the range
1225 {
1226 total += IntegrateInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, mDB);
1227 lastT = mEnv[i].GetT();
1228 lastVal = mEnv[i].GetVal();
1229 i++;
1230 }
1231 }
1232}
static double InterpolatePoints(double y1, double y2, double factor, bool logarithmic)
Definition: Envelope.cpp:1098
static double IntegrateInterpolated(double y1, double y2, double time, bool logarithmic)
Definition: Envelope.cpp:1106

References BinarySearchForTime(), Integral(), IntegrateInterpolated(), InterpolatePoints(), mDB, mDefaultValue, mEnv, and mOffset.

Referenced by Average(), Integral(), TimeTrack::testMe(), and testMe().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IntegralOfInverse()

double Envelope::IntegralOfInverse ( double  t0,
double  t1 
) const

Definition at line 1234 of file Envelope.cpp.

1235{
1236 if(t0 == t1)
1237 return 0.0;
1238 if(t0 > t1)
1239 {
1240 return -IntegralOfInverse(t1, t0); // this makes more sense than returning the default value
1241 }
1242
1243 unsigned int count = mEnv.size();
1244 if(count == 0) // 'empty' envelope
1245 return (t1 - t0) / mDefaultValue;
1246
1247 t0 -= mOffset;
1248 t1 -= mOffset;
1249
1250 double total = 0.0, lastT, lastVal;
1251 unsigned int i; // this is the next point to check
1252 if(t0 < mEnv[0].GetT()) // t0 preceding the first point
1253 {
1254 if(t1 <= mEnv[0].GetT())
1255 return (t1 - t0) / mEnv[0].GetVal();
1256 i = 1;
1257 lastT = mEnv[0].GetT();
1258 lastVal = mEnv[0].GetVal();
1259 total += (lastT - t0) / lastVal;
1260 }
1261 else if(t0 >= mEnv[count - 1].GetT()) // t0 at or following the last point
1262 {
1263 return (t1 - t0) / mEnv[count - 1].GetVal();
1264 }
1265 else // t0 enclosed by points
1266 {
1267 // Skip any points that come before t0 using binary search
1268 int lo, hi;
1269 BinarySearchForTime(lo, hi, t0);
1270 lastVal = InterpolatePoints(mEnv[lo].GetVal(), mEnv[hi].GetVal(), (t0 - mEnv[lo].GetT()) / (mEnv[hi].GetT() - mEnv[lo].GetT()), mDB);
1271 lastT = t0;
1272 i = hi; // the point immediately after t0.
1273 }
1274
1275 // loop through the rest of the envelope points until we get to t1
1276 while (1)
1277 {
1278 if(i >= count) // the requested range extends beyond the last point
1279 {
1280 return total + (t1 - lastT) / lastVal;
1281 }
1282 else if(mEnv[i].GetT() >= t1) // this point follows the end of the range
1283 {
1284 double thisVal = InterpolatePoints(mEnv[i - 1].GetVal(), mEnv[i].GetVal(), (t1 - mEnv[i - 1].GetT()) / (mEnv[i].GetT() - mEnv[i - 1].GetT()), mDB);
1285 return total + IntegrateInverseInterpolated(lastVal, thisVal, t1 - lastT, mDB);
1286 }
1287 else // this point precedes the end of the range
1288 {
1289 total += IntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, mDB);
1290 lastT = mEnv[i].GetT();
1291 lastVal = mEnv[i].GetVal();
1292 i++;
1293 }
1294 }
1295}
static double IntegrateInverseInterpolated(double y1, double y2, double time, bool logarithmic)
Definition: Envelope.cpp:1127

References BinarySearchForTime(), IntegralOfInverse(), IntegrateInverseInterpolated(), InterpolatePoints(), mDB, mDefaultValue, mEnv, and mOffset.

Referenced by AverageOfInverse(), GeneratedUpdater::ComputeWarpedLength(), PlaybackSchedule::ComputeWarpedLength(), IntegralOfInverse(), and TimeTrack::testMe().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsDirty()

bool Envelope::IsDirty ( ) const

◆ IsTrivial()

bool Envelope::IsTrivial ( ) const

Definition at line 55 of file Envelope.cpp.

56{
57 return mDefaultValue == 1.0 && mEnv.empty();
58}

References mDefaultValue, and mEnv.

◆ MoveDragPoint()

void Envelope::MoveDragPoint ( double  newWhen,
double  value 
)

Definition at line 186 of file Envelope.cpp.

187{
188 SetDragPointValid(true);
189 if (!mDragPointValid)
190 return;
191
192 // We'll limit the drag point time to be between those of the preceding
193 // and next envelope point.
194 double limitLo = 0.0;
195 double limitHi = mTrackLen;
196
197 if (mDragPoint > 0)
198 limitLo = std::max(limitLo, mEnv[mDragPoint - 1].GetT());
199 if (mDragPoint + 1 < (int)mEnv.size())
200 limitHi = std::min(limitHi, mEnv[mDragPoint + 1].GetT());
201
202 EnvPoint &dragPoint = mEnv[mDragPoint];
203 const double tt =
204 std::max(limitLo, std::min(limitHi, newWhen));
205
206 // This might temporary violate the constraint that at most two
207 // points share a time value.
208 dragPoint.SetT(tt);
209 dragPoint.SetVal( this, value );
210}
void SetT(double t)
Definition: Envelope.h:36
void SetVal(Envelope *pEnvelope, double val)
Definition: Envelope.h:260
void SetDragPointValid(bool valid)
Definition: Envelope.cpp:149

References mDragPoint, mDragPointValid, mEnv, min(), mTrackLen, SetDragPointValid(), EnvPoint::SetT(), and EnvPoint::SetVal().

Referenced by EnvelopeEditor::MoveDragPoint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ NextPointAfter()

double Envelope::NextPointAfter ( double  t) const
private

Definition at line 1062 of file Envelope.cpp.

1063{
1064 int lo,hi;
1065 BinarySearchForTime( lo, hi, t );
1066 if (hi >= (int)mEnv.size())
1067 return t;
1068 else
1069 return mEnv[hi].GetT();
1070}

References BinarySearchForTime(), and mEnv.

Referenced by testMe().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ NumberOfPointsAfter()

int Envelope::NumberOfPointsAfter ( double  t) const
private

Definition at line 1053 of file Envelope.cpp.

1054{
1055 int lo,hi;
1056 BinarySearchForTime( lo, hi, t );
1057
1058 return mEnv.size() - hi;
1059}

References BinarySearchForTime(), and mEnv.

Referenced by testMe().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator[]()

const EnvPoint & Envelope::operator[] ( int  index) const
inline

Accessor for points.

Definition at line 197 of file Envelope.h.

198 {
199 return mEnv[index];
200 }

◆ PasteEnvelope()

void Envelope::PasteEnvelope ( double  t0,
const Envelope e,
double  sampleDur 
)
Exception safety guarantee:
No-fail

Definition at line 465 of file Envelope.cpp.

466{
467 const bool wasEmpty = (this->mEnv.size() == 0);
468 auto otherSize = e->mEnv.size();
469 const double otherDur = e->mTrackLen;
470 const auto otherOffset = e->mOffset;
471 const auto deltat = otherOffset + otherDur;
472
473 if ( otherSize == 0 && wasEmpty && e->mDefaultValue == this->mDefaultValue )
474 {
475 // msmeyer: The envelope is empty and has the same default value, so
476 // there is nothing that must be inserted, just return. This avoids
477 // the creation of unnecessary duplicate control points
478 // MJS: but the envelope does get longer
479 // PRL: Assuming t0 is in the domain of the envelope
480 mTrackLen += deltat;
481 return;
482 }
483
484 // Make t0 relative to the offset of the envelope we are pasting into,
485 // and trim it to the domain of this
486 t0 = std::min( mTrackLen, std::max( 0.0, t0 - mOffset ) );
487
488 // Adjust if the insertion point rounds off near a discontinuity in this
489 if ( true )
490 {
491 double newT0;
492 auto range = EqualRange( t0, sampleDur );
493 auto index = range.first;
494 if ( index + 2 == range.second &&
495 ( newT0 = mEnv[ index ].GetT() ) == mEnv[ 1 + index ].GetT() )
496 t0 = newT0;
497 }
498
499 // Open up a space
500 double leftVal = e->GetValue( 0 );
501 double rightVal = e->GetValueRelative( otherDur );
502 // This range includes the right-side limit of the left end of the space,
503 // and the left-side limit of the right end:
504 const auto range = ExpandRegion( t0, deltat, &leftVal, &rightVal );
505 // Where to put the copied points from e -- after the first of the
506 // two points in range:
507 auto insertAt = range.first + 1;
508
509 // Copy points from e -- maybe skipping those at the extremes
510 auto end = e->mEnv.end();
511 if ( otherSize != 0 && e->mEnv[ otherSize - 1 ].GetT() == otherDur )
512 // ExpandRegion already made an equivalent limit point
513 --end, --otherSize;
514 auto begin = e->mEnv.begin();
515 if ( otherSize != 0 && otherOffset == 0.0 && e->mEnv[ 0 ].GetT() == 0.0 )
516 ++begin, --otherSize;
517 mEnv.insert( mEnv.begin() + insertAt, begin, end );
518
519 // Adjust their times
520 for ( size_t index = insertAt, last = insertAt + otherSize;
521 index < last; ++index ) {
522 auto &point = mEnv[ index ];
523 // The mOffset of the envelope-pasted-from is irrelevant.
524 // The GetT() times in it are relative to its start.
525 // The new GetT() times are relative to the envelope-pasted-to start.
526 // We are pasting at t0 relative to the envelope-pasted-to start.
527 // Hence we adjust by just t0.
528 // Bug 1844 was that we also adjusted by the envelope-pasted-from offset.
529 point.SetT( point.GetT() + /*otherOffset +*/ t0 );
530 }
531
532 // Treat removable discontinuities
533 // Right edge outward:
534 RemoveUnneededPoints( insertAt + otherSize + 1, true );
535 // Right edge inward:
536 RemoveUnneededPoints( insertAt + otherSize, false, false );
537
538 // Left edge inward:
539 RemoveUnneededPoints( range.first, true, false );
540 // Left edge outward:
541 RemoveUnneededPoints( range.first - 1, false );
542
543 // Guarantee monotonicity of times, against little round-off mistakes perhaps
545}
bool ConsistencyCheck()
Definition: Envelope.cpp:60

References PackedArray::begin(), ConsistencyCheck(), PackedArray::end(), EqualRange(), ExpandRegion(), GetValue(), GetValueRelative(), mDefaultValue, mEnv, min(), mOffset, mTrackLen, and RemoveUnneededPoints().

Here is the call graph for this function:

◆ print()

void Envelope::print ( ) const

Definition at line 1400 of file Envelope.cpp.

1401{
1402 for( unsigned int i = 0; i < mEnv.size(); i++ )
1403 wxPrintf( "(%.2f, %.2f)\n", mEnv[i].GetT(), mEnv[i].GetVal() );
1404}

References mEnv.

◆ Reassign()

int Envelope::Reassign ( double  when,
double  value 
)

Move a point at when to value.

Returns 0 if point moved, -1 if not found.

Definition at line 674 of file Envelope.cpp.

675{
676 when -= mOffset;
677
678 int len = mEnv.size();
679 if (len == 0)
680 return -1;
681
682 int i = 0;
683 while (i < len && when > mEnv[i].GetT())
684 i++;
685
686 if (i >= len || when < mEnv[i].GetT())
687 return -1;
688
689 mEnv[i].SetVal( this, value );
690 return 0;
691}

References mEnv, and mOffset.

Referenced by EqualizationBandSliders::GraphicEQ().

Here is the caller graph for this function:

◆ RemoveUnneededPoints()

void Envelope::RemoveUnneededPoints ( size_t  startAt,
bool  rightward,
bool  testNeighbors = true 
)
private
Exception safety guarantee:
No-fail

Definition at line 548 of file Envelope.cpp.

550{
551 // startAt is the index of a recently inserted point which might make no
552 // difference in envelope evaluation, or else might cause nearby points to
553 // make no difference.
554
555 auto isDiscontinuity = [this]( size_t index ) {
556 // Assume array accesses are in-bounds
557 const EnvPoint &point1 = mEnv[ index ];
558 const EnvPoint &point2 = mEnv[ index + 1 ];
559 return point1.GetT() == point2.GetT() &&
560 fabs( point1.GetVal() - point2.GetVal() ) > VALUE_TOLERANCE;
561 };
562
563 auto remove = [this]( size_t index, bool leftLimit ) {
564 // Assume array accesses are in-bounds
565 const auto &point = mEnv[ index ];
566 auto when = point.GetT();
567 auto val = point.GetVal();
568 Delete( index ); // try it to see if it's doing anything
569 auto val1 = GetValueRelative ( when, leftLimit );
570 if( fabs( val - val1 ) > VALUE_TOLERANCE ) {
571 // put it back, we needed it
572 Insert( index, EnvPoint{ when, val } );
573 return false;
574 }
575 else
576 return true;
577 };
578
579 auto len = mEnv.size();
580
581 bool leftLimit =
582 !rightward && startAt + 1 < len && isDiscontinuity( startAt );
583
584 bool removed = remove( startAt, leftLimit );
585
586 if ( removed )
587 // The given point was removable. Done!
588 return;
589
590 if ( !testNeighbors )
591 return;
592
593 // The given point was not removable. But did its insertion make nearby
594 // points removable?
595
596 int index = startAt + ( rightward ? 1 : -1 );
597 while ( index >= 0 && index < (int)len ) {
598 // Stop at any discontinuity
599 if ( index > 0 && isDiscontinuity( index - 1 ) )
600 break;
601 if ( (index + 1) < (int)len && isDiscontinuity( index ) )
602 break;
603
604 if ( ! remove( index, false ) )
605 break;
606
607 --len;
608 if ( ! rightward )
609 --index;
610 }
611}
static const double VALUE_TOLERANCE
Definition: Envelope.cpp:41

References Delete(), EnvPoint::GetT(), EnvPoint::GetVal(), GetValueRelative(), Insert(), mEnv, and VALUE_TOLERANCE.

Referenced by CollapseRegion(), InsertSpace(), and PasteEnvelope().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ RescaleTimes()

void Envelope::RescaleTimes ( double  newLength)
Exception safety guarantee:
No-fail

Definition at line 813 of file Envelope.cpp.

814{
815 if ( mTrackLen == 0 ) {
816 for ( auto &point : mEnv )
817 point.SetT( 0 );
818 }
819 else {
820 auto ratio = newLength / mTrackLen;
821 for ( auto &point : mEnv )
822 point.SetT( point.GetT() * ratio );
823 }
824 mTrackLen = newLength;
825}

References mEnv, and mTrackLen.

◆ RescaleValues()

void Envelope::RescaleValues ( double  minValue,
double  maxValue 
)

Rescale function for time tracks (could also be used for other tracks though). This is used to load old time track project files where the envelope used a 0 to 1 range instead of storing the actual time track values. This function will change the range of the envelope and rescale all envelope points accordingly (unlike SetRange, which clamps the envelope points to the NEW range). @minValue - the NEW minimum value @maxValue - the NEW maximum value

Definition at line 115 of file Envelope.cpp.

116{
117 double oldMinValue = mMinValue;
118 double oldMaxValue = mMaxValue;
119 mMinValue = minValue;
120 mMaxValue = maxValue;
121
122 // rescale the default value
123 double factor = (mDefaultValue - oldMinValue) / (oldMaxValue - oldMinValue);
125
126 // rescale all points
127 for( unsigned int i = 0; i < mEnv.size(); i++ ) {
128 factor = (mEnv[i].GetVal() - oldMinValue) / (oldMaxValue - oldMinValue);
129 mEnv[i].SetVal( this, mMinValue + (mMaxValue - mMinValue) * factor );
130 }
131
132}

References ClampValue(), mDefaultValue, mEnv, mMaxValue, and mMinValue.

Here is the call graph for this function:

◆ SetDragPoint()

void Envelope::SetDragPoint ( int  dragPoint)

Definition at line 143 of file Envelope.cpp.

144{
145 mDragPoint = std::max(-1, std::min(int(mEnv.size() - 1), dragPoint));
147}

References mDragPoint, mDragPointValid, mEnv, and min().

Referenced by EnvelopeEditor::HandleMouseButtonDown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetDragPointValid()

void Envelope::SetDragPointValid ( bool  valid)

Definition at line 149 of file Envelope.cpp.

150{
151 mDragPointValid = (valid && mDragPoint >= 0);
152 if (mDragPoint >= 0 && !valid) {
153 // We're going to be deleting the point; On
154 // screen we show this by having the envelope move to
155 // the position it will have after deletion of the point.
156 // Without deleting the point we move it left or right
157 // to the same position as the previous or next point.
158
159 static const double big = std::numeric_limits<double>::max();
160 auto size = mEnv.size();
161
162 if( size <= 1) {
163 // There is only one point - just move it
164 // off screen and at default height.
165 // temporary state when dragging only!
166 mEnv[mDragPoint].SetT(big);
167 mEnv[mDragPoint].SetVal( this, mDefaultValue );
168 return;
169 }
170 else if ( mDragPoint + 1 == (int)size ) {
171 // Put the point at the height of the last point, but also off screen.
172 mEnv[mDragPoint].SetT(big);
173 mEnv[mDragPoint].SetVal( this, mEnv[ size - 1 ].GetVal() );
174 }
175 else {
176 // Place it exactly on its right neighbour.
177 // That way the drawing code will overpaint the dark dot with
178 // a light dot, as if it were deleted.
179 const auto &neighbor = mEnv[mDragPoint + 1];
180 mEnv[mDragPoint].SetT(neighbor.GetT());
181 mEnv[mDragPoint].SetVal( this, neighbor.GetVal() );
182 }
183 }
184}

References mDefaultValue, mDragPoint, mDragPointValid, mEnv, and size.

Referenced by EnvelopeEditor::HandleDragging(), and MoveDragPoint().

Here is the caller graph for this function:

◆ SetExponential()

void Envelope::SetExponential ( bool  db)
inline

Definition at line 96 of file Envelope.h.

96{ mDB = db; }

Referenced by testMe().

Here is the caller graph for this function:

◆ SetOffset()

void Envelope::SetOffset ( double  newOffset)
Exception safety guarantee:
No-fail

Definition at line 786 of file Envelope.cpp.

787{
788 mOffset = newOffset;
789}

References mOffset.

◆ SetRange()

void Envelope::SetRange ( double  minValue,
double  maxValue 
)

Definition at line 221 of file Envelope.cpp.

221 {
222 mMinValue = minValue;
223 mMaxValue = maxValue;
225 for( unsigned int i = 0; i < mEnv.size(); i++ )
226 mEnv[i].SetVal( this, mEnv[i].GetVal() ); // this clamps the value to the NEW range
227}

References ClampValue(), mDefaultValue, mEnv, mMaxValue, and mMinValue.

Here is the call graph for this function:

◆ SetTrackLen()

void Envelope::SetTrackLen ( double  trackLen,
double  sampleDur = 0.0 
)
Exception safety guarantee:
No-fail

Definition at line 792 of file Envelope.cpp.

793{
794 // Preserve the left-side limit at trackLen.
795 auto range = EqualRange( trackLen, sampleDur );
796 bool needPoint = ( range.first == range.second && trackLen < mTrackLen );
797 double value=0.0;
798 if ( needPoint )
799 value = GetValueRelative( trackLen );
800
801 mTrackLen = trackLen;
802
803 // Shrink the array.
804 // If more than one point already at the end, keep only the first of them.
805 int newLen = std::min( 1 + range.first, range.second );
806 mEnv.resize( newLen );
807
808 if ( needPoint )
809 AddPointAtEnd( mTrackLen, value );
810}

References AddPointAtEnd(), EqualRange(), GetValueRelative(), mEnv, min(), and mTrackLen.

Referenced by EqualizationFilter::EqualizationFilter(), and EqualizationBandSliders::GraphicEQ().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SolveIntegralOfInverse()

double Envelope::SolveIntegralOfInverse ( double  t0,
double  area 
) const

Definition at line 1297 of file Envelope.cpp.

1298{
1299 if(area == 0.0)
1300 return t0;
1301
1302 const auto count = mEnv.size();
1303 if(count == 0) // 'empty' envelope
1304 return t0 + area * mDefaultValue;
1305
1306 // Correct for offset!
1307 t0 -= mOffset;
1308 return mOffset + [&] {
1309 // Now we can safely assume t0 is relative time!
1310 double lastT, lastVal;
1311 int i; // this is the next point to check
1312 if(t0 < mEnv[0].GetT()) // t0 preceding the first point
1313 {
1314 if (area < 0) {
1315 return t0 + area * mEnv[0].GetVal();
1316 }
1317 else {
1318 i = 1;
1319 lastT = mEnv[0].GetT();
1320 lastVal = mEnv[0].GetVal();
1321 double added = (lastT - t0) / lastVal;
1322 if(added >= area)
1323 return t0 + area * mEnv[0].GetVal();
1324 area -= added;
1325 }
1326 }
1327 else if(t0 >= mEnv[count - 1].GetT()) // t0 at or following the last point
1328 {
1329 if (area < 0) {
1330 i = (int)count - 2;
1331 lastT = mEnv[count - 1].GetT();
1332 lastVal = mEnv[count - 1].GetVal();
1333 double added = (lastT - t0) / lastVal; // negative
1334 if(added <= area)
1335 return t0 + area * mEnv[count - 1].GetVal();
1336 area -= added;
1337 }
1338 else {
1339 return t0 + area * mEnv[count - 1].GetVal();
1340 }
1341 }
1342 else // t0 enclosed by points
1343 {
1344 // Skip any points that come before t0 using binary search
1345 int lo, hi;
1346 BinarySearchForTime(lo, hi, t0);
1347 lastVal = InterpolatePoints(mEnv[lo].GetVal(), mEnv[hi].GetVal(), (t0 - mEnv[lo].GetT()) / (mEnv[hi].GetT() - mEnv[lo].GetT()), mDB);
1348 lastT = t0;
1349 if (area < 0)
1350 i = lo;
1351 else
1352 i = hi; // the point immediately after t0.
1353 }
1354
1355 if (area < 0) {
1356 // loop BACKWARDS through the rest of the envelope points until we get to t1
1357 // (which is less than t0)
1358 while (1)
1359 {
1360 if(i < 0) // the requested range extends beyond the leftmost point
1361 {
1362 return lastT + area * lastVal;
1363 }
1364 else
1365 {
1366 double added =
1367 -IntegrateInverseInterpolated(mEnv[i].GetVal(), lastVal, lastT - mEnv[i].GetT(), mDB);
1368 if(added <= area)
1369 return lastT - SolveIntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), lastT - mEnv[i].GetT(), -area, mDB);
1370 area -= added;
1371 lastT = mEnv[i].GetT();
1372 lastVal = mEnv[i].GetVal();
1373 --i;
1374 }
1375 }
1376 }
1377 else {
1378 // loop through the rest of the envelope points until we get to t1
1379 while (1)
1380 {
1381 if(i >= (int)count) // the requested range extends beyond the last point
1382 {
1383 return lastT + area * lastVal;
1384 }
1385 else
1386 {
1387 double added = IntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, mDB);
1388 if(added >= area)
1389 return lastT + SolveIntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, area, mDB);
1390 area -= added;
1391 lastT = mEnv[i].GetT();
1392 lastVal = mEnv[i].GetVal();
1393 i++;
1394 }
1395 }
1396 }
1397 }();
1398}
static double SolveIntegrateInverseInterpolated(double y1, double y2, double time, double area, bool logarithmic)
Definition: Envelope.cpp:1144

References BinarySearchForTime(), IntegrateInverseInterpolated(), InterpolatePoints(), mDB, mDefaultValue, mEnv, mOffset, and SolveIntegrateInverseInterpolated().

Referenced by PlaybackSchedule::SolveWarpedLength().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ testMe()

void Envelope::testMe ( )

Definition at line 1415 of file Envelope.cpp.

1416{
1417 double t0=0, t1=0;
1418
1419 SetExponential(false);
1420
1421 Flatten(0.5);
1422 checkResult( 1, Integral(0.0,100.0), 50);
1423 checkResult( 2, Integral(-10.0,10.0), 10);
1424
1425 Flatten(0.5);
1426 checkResult( 3, Integral(0.0,100.0), 50);
1427 checkResult( 4, Integral(-10.0,10.0), 10);
1428 checkResult( 5, Integral(-20.0,-10.0), 5);
1429
1430 Flatten(0.5);
1431 InsertOrReplaceRelative( 5.0, 0.5 );
1432 checkResult( 6, Integral(0.0,100.0), 50);
1433 checkResult( 7, Integral(-10.0,10.0), 10);
1434
1435 Flatten(0.0);
1436 InsertOrReplaceRelative( 0.0, 0.0 );
1437 InsertOrReplaceRelative( 5.0, 1.0 );
1438 InsertOrReplaceRelative( 10.0, 0.0 );
1439 t0 = 10.0 - .1;
1440 t1 = 10.0 + .1;
1441 double result = Integral(0.0,t1);
1442 double resulta = Integral(0.0,t0);
1443 double resultb = Integral(t0,t1);
1444 // Integrals should be additive
1445 checkResult( 8, result - resulta - resultb, 0);
1446
1447 Flatten(0.0);
1448 InsertOrReplaceRelative( 0.0, 0.0 );
1449 InsertOrReplaceRelative( 5.0, 1.0 );
1450 InsertOrReplaceRelative( 10.0, 0.0 );
1451 t0 = 10.0 - .1;
1452 t1 = 10.0 + .1;
1453 checkResult( 9, Integral(0.0,t1), 5);
1454 checkResult( 10, Integral(0.0,t0), 4.999);
1455 checkResult( 11, Integral(t0,t1), .001);
1456
1457 mEnv.clear();
1458 InsertOrReplaceRelative( 0.0, 0.0 );
1459 InsertOrReplaceRelative( 5.0, 1.0 );
1460 InsertOrReplaceRelative( 10.0, 0.0 );
1461 checkResult( 12, NumberOfPointsAfter( -1 ), 3 );
1462 checkResult( 13, NumberOfPointsAfter( 0 ), 2 );
1463 checkResult( 14, NumberOfPointsAfter( 1 ), 2 );
1464 checkResult( 15, NumberOfPointsAfter( 5 ), 1 );
1465 checkResult( 16, NumberOfPointsAfter( 7 ), 1 );
1466 checkResult( 17, NumberOfPointsAfter( 10 ), 0 );
1467 checkResult( 18, NextPointAfter( 0 ), 5 );
1468 checkResult( 19, NextPointAfter( 5 ), 10 );
1469}
static void checkResult(int n, double a, double b)
Definition: Envelope.cpp:1406
int NumberOfPointsAfter(double t) const
Definition: Envelope.cpp:1053
double NextPointAfter(double t) const
Definition: Envelope.cpp:1062
void SetExponential(bool db)
Definition: Envelope.h:96
void Flatten(double value)
Definition: Envelope.cpp:137

References checkResult(), Flatten(), InsertOrReplaceRelative(), Integral(), mEnv, NextPointAfter(), NumberOfPointsAfter(), and SetExponential().

Here is the call graph for this function:

◆ WriteXML()

void Envelope::WriteXML ( XMLWriter xmlFile) const

Definition at line 342 of file Envelope.cpp.

344{
345 unsigned int ctrlPt;
346
347 xmlFile.StartTag(wxT("envelope"));
348 xmlFile.WriteAttr(wxT("numpoints"), mEnv.size());
349
350 for (ctrlPt = 0; ctrlPt < mEnv.size(); ctrlPt++) {
351 const EnvPoint &point = mEnv[ctrlPt];
352 xmlFile.StartTag(wxT("controlpoint"));
353 xmlFile.WriteAttr(wxT("t"), point.GetT(), 12);
354 xmlFile.WriteAttr(wxT("val"), point.GetVal(), 12);
355 xmlFile.EndTag(wxT("controlpoint"));
356 }
357
358 xmlFile.EndTag(wxT("envelope"));
359}
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:79
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:36
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:102

References EnvPoint::GetT(), EnvPoint::GetVal(), and wxT().

Here is the call graph for this function:

Member Data Documentation

◆ mDB

bool Envelope::mDB
private

◆ mDefaultValue

double Envelope::mDefaultValue
private

◆ mDragPoint

int Envelope::mDragPoint { -1 }
private

◆ mDragPointValid

bool Envelope::mDragPointValid { false }
private

Definition at line 254 of file Envelope.h.

Referenced by ClearDragPoint(), MoveDragPoint(), SetDragPoint(), and SetDragPointValid().

◆ mEnv

EnvArray Envelope::mEnv
private

◆ mMaxValue

double Envelope::mMaxValue
private

Definition at line 250 of file Envelope.h.

Referenced by RescaleValues(), and SetRange().

◆ mMinValue

double Envelope::mMinValue
private

Definition at line 250 of file Envelope.h.

Referenced by RescaleValues(), and SetRange().

◆ mOffset

double Envelope::mOffset { 0.0 }
private

The time at which the envelope starts, i.e. the start offset.

Definition at line 239 of file Envelope.h.

Referenced by CollapseRegion(), CopyRange(), Envelope(), GetPoints(), GetValues(), InsertSpace(), Integral(), IntegralOfInverse(), PasteEnvelope(), Reassign(), SetOffset(), and SolveIntegralOfInverse().

◆ mSearchGuess

int Envelope::mSearchGuess { -2 }
mutableprivate

Definition at line 257 of file Envelope.h.

Referenced by BinarySearchForTime(), and BinarySearchForTime_LeftLimit().

◆ mTrackEpsilon

double Envelope::mTrackEpsilon { 1.0 / 200000.0 }
private

The shortest distance apart that points on an envelope can be before being considered the same point.

Definition at line 248 of file Envelope.h.

◆ mTrackLen

double Envelope::mTrackLen { 0.0 }
private

The length of the envelope, which is the same as the length of the underlying track (normally)

Definition at line 242 of file Envelope.h.

Referenced by Cap(), CollapseRegion(), CopyRange(), Envelope(), ExpandRegion(), InsertOrReplaceRelative(), MoveDragPoint(), PasteEnvelope(), RescaleTimes(), and SetTrackLen().


The documentation for this class was generated from the following files: