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

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 44 of file Envelope.cpp.

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

◆ Envelope() [2/3]

Envelope::Envelope ( const Envelope orig)

Definition at line 263 of file Envelope.cpp.

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

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 249 of file Envelope.cpp.

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

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

Here is the call graph for this function:

◆ ~Envelope()

Envelope::~Envelope ( )
virtual

Definition at line 52 of file Envelope.cpp.

53{
54}

Member Function Documentation

◆ AddPointAtEnd()

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

Definition at line 232 of file Envelope.cpp.

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

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 1083 of file Envelope.cpp.

1084{
1085 if( t0 == t1 )
1086 return GetValue( t0 );
1087 else
1088 return Integral( t0, t1 ) / (t1 - t0);
1089}
double GetValue(double t, double sampleDur=0) const
Get envelope value at time t.
Definition: Envelope.cpp:838
double Integral(double t0, double t1) const
Definition: Envelope.cpp:1182

References GetValue(), and Integral().

Here is the call graph for this function:

◆ AverageOfInverse()

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

Definition at line 1091 of file Envelope.cpp.

1092{
1093 if( t0 == t1 )
1094 return 1.0 / GetValue( t0 );
1095 else
1096 return IntegralOfInverse( t0, t1 ) / (t1 - t0);
1097}
double IntegralOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1245

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
privatenoexcept
Parameters
Loreturns last index at or before this time, maybe -1
Hireturns first index after this time, maybe past the end

Definition at line 858 of file Envelope.cpp.

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

Referenced by 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
privatenoexcept
Parameters
Loreturns last index before this time, maybe -1
Hireturns first index at or after this time, maybe past the end

Definition at line 905 of file Envelope.cpp.

907{
908 Lo = -1;
909 Hi = mEnv.size();
910
911 // Invariants: Lo is not less than -1, Hi not more than size
912 while (Hi > (Lo + 1)) {
913 int mid = (Lo + Hi) / 2;
914 // mid must be strictly between Lo and Hi, therefore a valid index
915 if (t <= mEnv[mid].GetT())
916 Hi = mid;
917 else
918 Lo = mid;
919 }
920 wxASSERT( Hi == ( Lo+1 ));
921
922 mSearchGuess = Lo;
923}

◆ Cap()

void Envelope::Cap ( double  sampleDur)

Definition at line 714 of file Envelope.cpp.

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

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 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 173 of file Envelope.h.

173{ mEnv.clear(); }

◆ ClearDragPoint()

void Envelope::ClearDragPoint ( )

Definition at line 213 of file Envelope.cpp.

214{
215 if (!mDragPointValid && mDragPoint >= 0)
217
218 mDragPoint = -1;
219 mDragPointValid = false;
220}
int mDragPoint
Definition: Envelope.h:257
void Delete(int point)
DELETE a point by its position in array.
Definition: Envelope.cpp:362
bool mDragPointValid
Definition: Envelope.h:256

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 
)
noexcept
Exception safety guarantee:
No-fail

Definition at line 378 of file Envelope.cpp.

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

References details::begin(), details::end(), and min().

Referenced by WaveClip::ClearAndAddCutLine(), and WaveClip::ClearSequenceFinisher::~ClearSequenceFinisher().

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

◆ ConsistencyCheck()

bool Envelope::ConsistencyCheck ( )

Definition at line 61 of file Envelope.cpp.

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

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 274 of file Envelope.cpp.

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

References AddPointAtEnd(), details::begin(), details::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 362 of file Envelope.cpp.

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

References mEnv.

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

Here is the caller graph for this function:

◆ EqualRange()

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

Definition at line 763 of file Envelope.cpp.

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

References details::begin(), details::end(), and EnvPoint::GetT().

Referenced by Cap(), Envelope(), ExpandRegion(), 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 615 of file Envelope.cpp.

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

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 138 of file Envelope.cpp.

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

References ClampValue(), mDefaultValue, and mEnv.

Referenced by EqualizationBandSliders::GraphicEQ(), testMe(), and TimeTrack::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 216 of file Envelope.h.

216{ 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 221 of file Envelope.h.

221{ 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 CommonChannelView::GetEnvelopeValues().

Here is the caller graph for this function:

◆ GetInterpolationStartValueAtPoint()

double Envelope::GetInterpolationStartValueAtPoint ( int  iPoint) const
privatenoexcept

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 930 of file Envelope.cpp.

931{
932 double v = mEnv[ iPoint ].GetVal();
933 if( !mDB )
934 return v;
935 else
936 return log10(v);
937}

◆ 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 695 of file Envelope.cpp.

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

References mEnv.

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

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(), and EnvelopeEditor::MoveDragPoint().

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 700 of file Envelope.cpp.

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

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 838 of file Envelope.cpp.

839{
840 // t is absolute time
841 double temp;
842
843 GetValues( &temp, 1, t, sampleDur );
844 return temp;
845}
void GetValues(double *buffer, int len, double t0, double tstep) const
Get many envelope points at once.
Definition: Envelope.cpp:939

References GetValues().

Referenced by Average(), AverageOfInverse(), EqualizationFilter::CalcFilter(), CopyRange(), anonymous_namespace{WaveformView.cpp}::DrawIndividualSamples(), EqualizationBandSliders::ErrMin(), CommonChannelView::GetEnvelopeValues(), EnvelopeEditor::HandleMouseButtonDown(), EnvelopeHandle::HitEnvelope(), 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
privatenoexcept

Definition at line 847 of file Envelope.cpp.

848{
849 double temp;
850
851 GetValuesRelative(&temp, 1, t, 0.0, leftLimit);
852 return temp;
853}
void GetValuesRelative(double *buffer, int len, double t0, double tstep, bool leftLimit=false) const noexcept
Definition: Envelope.cpp:948

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

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 939 of file Envelope.cpp.

941{
942 // Convert t0 from absolute to clip-relative time
943 t0 -= mOffset;
944 GetValuesRelative( buffer, bufferLen, t0, tstep);
945}

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
privatenoexcept

Definition at line 947 of file Envelope.cpp.

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

Referenced by GetValues().

Here is the caller graph for this function:

◆ HandleXMLChild()

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

Implements XMLTagHandler.

Definition at line 334 of file Envelope.cpp.

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

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 309 of file Envelope.cpp.

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

References mEnv.

◆ Initialize()

void Envelope::Initialize ( int  numPoints)

◆ Insert() [1/2]

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

Definition at line 372 of file Envelope.cpp.

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

References mEnv.

◆ Insert() [2/2]

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

insert a point

Definition at line 367 of file Envelope.cpp.

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

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

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 176 of file Envelope.h.

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

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

Here is the caller graph for this function:

◆ InsertOrReplaceRelative()

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

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 729 of file Envelope.cpp.

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

References min(), and wxT().

Referenced by Cap(), 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 666 of file Envelope.cpp.

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

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 1182 of file Envelope.cpp.

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

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

Referenced by Average(), Integral(), testMe(), and TimeTrack::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 1245 of file Envelope.cpp.

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

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 56 of file Envelope.cpp.

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

References mDefaultValue, and mEnv.

◆ MoveDragPoint()

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

Definition at line 187 of file Envelope.cpp.

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

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 1073 of file Envelope.cpp.

1074{
1075 int lo,hi;
1076 BinarySearchForTime( lo, hi, t );
1077 if (hi >= (int)mEnv.size())
1078 return t;
1079 else
1080 return mEnv[hi].GetT();
1081}

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 1064 of file Envelope.cpp.

1065{
1066 int lo,hi;
1067 BinarySearchForTime( lo, hi, t );
1068
1069 return mEnv.size() - hi;
1070}

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 198 of file Envelope.h.

199 {
200 return mEnv[index];
201 }

◆ PasteEnvelope()

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

Definition at line 466 of file Envelope.cpp.

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

References details::begin(), ConsistencyCheck(), details::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 1411 of file Envelope.cpp.

1412{
1413 for( unsigned int i = 0; i < mEnv.size(); i++ )
1414 wxPrintf( "(%.2f, %.2f)\n", mEnv[i].GetT(), mEnv[i].GetVal() );
1415}

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 675 of file Envelope.cpp.

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

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 
)
privatenoexcept
Exception safety guarantee:
No-fail

Definition at line 549 of file Envelope.cpp.

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

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

Referenced by 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 815 of file Envelope.cpp.

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

References mEnv, and mTrackLen.

◆ RescaleTimesBy()

void Envelope::RescaleTimesBy ( double  ratio)

Definition at line 829 of file Envelope.cpp.

830{
831 for (auto& point : mEnv)
832 point.SetT(point.GetT() * ratio);
833 if (mTrackLen != DBL_MAX)
834 mTrackLen *= ratio;
835}

References mEnv, and mTrackLen.

Referenced by DEFINE_ATTACHED_VIRTUAL_OVERRIDE().

Here is the caller graph for this function:

◆ 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 116 of file Envelope.cpp.

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

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

Here is the call graph for this function:

◆ SetDragPoint()

void Envelope::SetDragPoint ( int  dragPoint)

Definition at line 144 of file Envelope.cpp.

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

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 150 of file Envelope.cpp.

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

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 788 of file Envelope.cpp.

789{
790 mOffset = newOffset;
791}

References mOffset.

◆ SetRange()

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

Definition at line 222 of file Envelope.cpp.

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

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 794 of file Envelope.cpp.

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

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 1308 of file Envelope.cpp.

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

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 1426 of file Envelope.cpp.

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

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 343 of file Envelope.cpp.

345{
346 unsigned int ctrlPt;
347
348 xmlFile.StartTag(wxT("envelope"));
349 xmlFile.WriteAttr(wxT("numpoints"), mEnv.size());
350
351 for (ctrlPt = 0; ctrlPt < mEnv.size(); ctrlPt++) {
352 const EnvPoint &point = mEnv[ctrlPt];
353 xmlFile.StartTag(wxT("controlpoint"));
354 xmlFile.WriteAttr(wxT("t"), point.GetT(), 12);
355 xmlFile.WriteAttr(wxT("val"), point.GetVal(), 12);
356 xmlFile.EndTag(wxT("controlpoint"));
357 }
358
359 xmlFile.EndTag(wxT("envelope"));
360}
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

Definition at line 251 of file Envelope.h.

Referenced by Integral(), IntegralOfInverse(), and SolveIntegralOfInverse().

◆ mDefaultValue

double Envelope::mDefaultValue
private

◆ mDragPoint

int Envelope::mDragPoint { -1 }
private

◆ mDragPointValid

bool Envelope::mDragPointValid { false }
private

Definition at line 256 of file Envelope.h.

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

◆ mEnv

EnvArray Envelope::mEnv
private

◆ mMaxValue

double Envelope::mMaxValue
private

Definition at line 252 of file Envelope.h.

Referenced by RescaleValues(), and SetRange().

◆ mMinValue

double Envelope::mMinValue
private

Definition at line 252 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 241 of file Envelope.h.

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

◆ mSearchGuess

int Envelope::mSearchGuess { -2 }
mutableprivate

Definition at line 259 of file Envelope.h.

◆ 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 250 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 244 of file Envelope.h.

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


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