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)
 
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 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...
 
double GetDefaultValue () const
 
size_t GetVersion () const
 
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 }
 
size_t mVersion { 0 }
 
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:250
bool mDB
Definition: Envelope.h:249
double ClampValue(double value)
Definition: Envelope.h:102
double mDefaultValue
Definition: Envelope.h:251
double mMaxValue
Definition: Envelope.h:250

◆ Envelope() [2/3]

Envelope::Envelope ( const Envelope orig)

Definition at line 275 of file Envelope.cpp.

276 : mDB(orig.mDB)
277 , mMinValue(orig.mMinValue)
278 , mMaxValue(orig.mMaxValue)
280{
281 mOffset = orig.mOffset;
282 mTrackLen = orig.mTrackLen;
283 CopyRange(orig, 0, orig.GetNumberOfPoints());
284}
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:723
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:286

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

262 : mDB(orig.mDB)
263 , mMinValue(orig.mMinValue)
264 , mMaxValue(orig.mMaxValue)
266{
267 mOffset = wxMax(t0, orig.mOffset);
268 mTrackLen = wxMin(t1, orig.mOffset + orig.mTrackLen) - mOffset;
269
270 auto range1 = orig.EqualRange( t0 - orig.mOffset, 0 );
271 auto range2 = orig.EqualRange( t1 - orig.mOffset, 0 );
272 CopyRange(orig, range1.first, range2.second);
273}
std::pair< int, int > EqualRange(double when, double sampleDur) const noexcept
Definition: Envelope.cpp:801

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

243{
244 mEnv.push_back( EnvPoint{ t, val } );
245
246 // Assume copied points were stored by nondecreasing time.
247 // Allow no more than two points at exactly the same time.
248 // Maybe that happened, because extra points were inserted at the boundary
249 // of the copied range, which were not in the source envelope.
250 auto nn = mEnv.size() - 1;
251 while ( nn >= 2 && mEnv[ nn - 2 ].GetT() == t ) {
252 // Of three or more points at the same time, erase one in the middle,
253 // not the one newly added.
254 mEnv.erase( mEnv.begin() + nn - 1 );
255 --nn;
256 }
257
258 ++mVersion;
259}
EnvPoint, derived from XMLTagHandler, provides Envelope with a draggable point type.
Definition: Envelope.h:29
size_t mVersion
Definition: Envelope.h:256
EnvArray mEnv
Definition: Envelope.h:236

References mEnv, and mVersion.

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

1126{
1127 if( t0 == t1 )
1128 return GetValue( t0 );
1129 else
1130 return Integral( t0, t1 ) / (t1 - t0);
1131}
double GetValue(double t, double sampleDur=0) const
Get envelope value at time t.
Definition: Envelope.cpp:880
double Integral(double t0, double t1) const
Definition: Envelope.cpp:1224

References GetValue(), and Integral().

Here is the call graph for this function:

◆ AverageOfInverse()

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

Definition at line 1133 of file Envelope.cpp.

1134{
1135 if( t0 == t1 )
1136 return 1.0 / GetValue( t0 );
1137 else
1138 return IntegralOfInverse( t0, t1 ) / (t1 - t0);
1139}
double IntegralOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1287

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

901{
902 // Optimizations for the usual pattern of repeated calls with
903 // small increases of t.
904 {
905 if (mSearchGuess >= 0 && mSearchGuess < (int)mEnv.size()) {
906 if (t >= mEnv[mSearchGuess].GetT() &&
907 (1 + mSearchGuess == (int)mEnv.size() ||
908 t < mEnv[1 + mSearchGuess].GetT())) {
909 Lo = mSearchGuess;
910 Hi = 1 + mSearchGuess;
911 return;
912 }
913 }
914
915 ++mSearchGuess;
916 if (mSearchGuess >= 0 && mSearchGuess < (int)mEnv.size()) {
917 if (t >= mEnv[mSearchGuess].GetT() &&
918 (1 + mSearchGuess == (int)mEnv.size() ||
919 t < mEnv[1 + mSearchGuess].GetT())) {
920 Lo = mSearchGuess;
921 Hi = 1 + mSearchGuess;
922 return;
923 }
924 }
925 }
926
927 Lo = -1;
928 Hi = mEnv.size();
929
930 // Invariants: Lo is not less than -1, Hi not more than size
931 while (Hi > (Lo + 1)) {
932 int mid = (Lo + Hi) / 2;
933 // mid must be strictly between Lo and Hi, therefore a valid index
934 if (t < mEnv[mid].GetT())
935 Hi = mid;
936 else
937 Lo = mid;
938 }
939 wxASSERT( Hi == ( Lo+1 ));
940
941 mSearchGuess = Lo;
942}
int mSearchGuess
Definition: Envelope.h:258

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

949{
950 Lo = -1;
951 Hi = mEnv.size();
952
953 // Invariants: Lo is not less than -1, Hi not more than size
954 while (Hi > (Lo + 1)) {
955 int mid = (Lo + Hi) / 2;
956 // mid must be strictly between Lo and Hi, therefore a valid index
957 if (t <= mEnv[mid].GetT())
958 Hi = mid;
959 else
960 Lo = mid;
961 }
962 wxASSERT( Hi == ( Lo+1 ));
963
964 mSearchGuess = Lo;
965}

◆ Cap()

void Envelope::Cap ( double  sampleDur)

Definition at line 752 of file Envelope.cpp.

753{
754 auto range = EqualRange( mTrackLen, sampleDur );
755 if ( range.first == range.second )
757}
int InsertOrReplaceRelative(double when, double value) noexcept
Add a control point to the envelope.
Definition: Envelope.cpp:767
double GetValueRelative(double t, bool leftLimit=false) const noexcept
Definition: Envelope.cpp:889

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

Here is the call graph for this function:

◆ ClampValue()

double Envelope::ClampValue ( double  value)
inline

Definition at line 102 of file Envelope.h.

102{ 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 166 of file Envelope.h.

166{ mEnv.clear(); }

◆ ClearDragPoint()

void Envelope::ClearDragPoint ( )

Definition at line 221 of file Envelope.cpp.

222{
223 if (!mDragPointValid && mDragPoint >= 0)
225
226 mDragPoint = -1;
227 mDragPointValid = false;
228}
int mDragPoint
Definition: Envelope.h:255
void Delete(int point)
DELETE a point by its position in array.
Definition: Envelope.cpp:374
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 
)
noexcept
Exception safety guarantee:
No-fail

Definition at line 396 of file Envelope.cpp.

397{
398 if ( t1 <= t0 )
399 return;
400
401 // This gets called when somebody clears samples.
402
403 // Snip points in the interval (t0, t1), shift values left at times after t1.
404 // For the boundaries of the interval, preserve the left-side limit at the
405 // start and right-side limit at the end.
406
407 const auto epsilon = sampleDur / 2;
408 t0 = std::max( 0.0, std::min( mTrackLen, t0 - mOffset ) );
409 t1 = std::max( 0.0, std::min( mTrackLen, t1 - mOffset ) );
410 bool leftPoint = true, rightPoint = true;
411
412 // Determine the start of the range of points to remove from the array.
413 auto range0 = EqualRange(t0, 0);
414 auto begin = range0.first;
415 if ( begin == range0.second ) {
416 if ( t0 > epsilon ) {
417 // There was no point exactly at t0;
418 // insert a point to preserve the value.
419 auto val = GetValueRelative( t0 );
420 InsertOrReplaceRelative( t0, val );
421 ++begin;
422 }
423 else
424 leftPoint = false;
425 }
426 else
427 // We will keep the first (or only) point that was at t0.
428 ++begin;
429
430 // We want end to be the index one past the range of points to remove from
431 // the array.
432 // At first, find index of the first point after t1:
433 auto range1 = EqualRange( t1, 0 );
434 auto end = range1.second;
435 if ( range1.first == end ) {
436 if ( mTrackLen - t1 > epsilon ) {
437 // There was no point exactly at t1; insert a point to preserve the value.
438 auto val = GetValueRelative( t1 );
439 InsertOrReplaceRelative( t1, val );
440 // end is now the index of this NEW point and that is correct.
441 }
442 else
443 rightPoint = false;
444 }
445 else
446 // We will keep the last (or only) point that was at t1.
447 --end;
448
449 if ( end < begin ) {
450 if ( leftPoint )
451 rightPoint = false;
452 }
453 else
454 mEnv.erase( mEnv.begin() + begin, mEnv.begin() + end );
455
456 // Shift points left after deleted region.
457 auto len = mEnv.size();
458 for ( size_t i = begin; i < len; ++i ) {
459 auto &point = mEnv[i];
460 if (rightPoint && (int)i == begin)
461 // Avoid roundoff error.
462 // Make exactly equal times of neighboring points so that we have
463 // a real discontinuity.
464 point.SetT( t0 );
465 else
466 point.SetT( point.GetT() - (t1 - t0) );
467 }
468
469 // See if the discontinuity is removable.
470 if ( rightPoint )
472 if ( leftPoint )
473 RemoveUnneededPoints( begin - 1, false );
474
475 mTrackLen -= (t1 - t0);
476
477 ++mVersion;
478}
void RemoveUnneededPoints(size_t startAt, bool rightward, bool testNeighbors=true) noexcept
Definition: Envelope.cpp:571
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 ++mVersion;
100 consistent = false;
101 // repair it
102 std::stable_sort( mEnv.begin(), mEnv.end(),
103 []( const EnvPoint &a, const EnvPoint &b )
104 { return a.GetT() < b.GetT(); } );
105 }
106 } while ( disorder );
107
108 return consistent;
109}

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

287{
288 size_t len = orig.mEnv.size();
289 size_t i = begin;
290
291 // Create the point at 0 if it needs interpolated representation
292 if ( i > 0 )
294
295 // Copy points from inside the copied region
296 for (; i < end; ++i) {
297 const EnvPoint &point = orig[i];
298 const double when = point.GetT() + (orig.mOffset - mOffset);
299 AddPointAtEnd(when, point.GetVal());
300 }
301
302 // Create the final point if it needs interpolated representation
303 // If the last point of e was exactly at t1, this effectively copies it too.
304 if (mTrackLen > 0 && i < len)
306}
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:242

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

375{
376 mEnv.erase(mEnv.begin() + point);
377
378 ++mVersion;
379}

References mEnv, and mVersion.

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

803{
804 // Find range of envelope points matching the given time coordinate
805 // (within an interval of length sampleDur)
806 // by binary search; if empty, it still indicates where to
807 // insert.
808 const auto tolerance = sampleDur / 2;
809 auto begin = mEnv.begin();
810 auto end = mEnv.end();
811 auto first = std::lower_bound(
812 begin, end,
813 EnvPoint{ when - tolerance, 0.0 },
814 []( const EnvPoint &point1, const EnvPoint &point2 )
815 { return point1.GetT() < point2.GetT(); }
816 );
817 auto after = first;
818 while ( after != end && after->GetT() <= when + tolerance )
819 ++after;
820 return { first - begin, after - begin };
821}

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

642{
643 // t0 is relative time
644
645 double val = GetValueRelative( t0 );
646 const auto range = EqualRange( t0, 0 );
647
648 // Preserve the left-side limit.
649 int index = 1 + range.first;
650 if ( index <= range.second )
651 // There is already a control point.
652 ;
653 else {
654 // Make a control point.
655 Insert( range.first, EnvPoint{ t0, val } );
656 }
657
658 // Shift points.
659 auto len = mEnv.size();
660 for ( unsigned int ii = index; ii < len; ++ii ) {
661 auto &point = mEnv[ ii ];
662 point.SetT( point.GetT() + tlen );
663 }
664
665 mTrackLen += tlen;
666
667 // Preserve the right-side limit.
668 if ( index < range.second )
669 // There was a control point already.
670 ;
671 else
672 // Make a control point.
673 Insert( index, EnvPoint{ t0 + tlen, val } );
674
675 // Make discontinuities at ends, maybe:
676
677 if ( pLeftVal )
678 // Make a discontinuity at the left side of the expansion
679 Insert( index++, EnvPoint{ t0, *pLeftVal } );
680
681 if ( pRightVal )
682 // Make a discontinuity at the right side of the expansion
683 Insert( index++, EnvPoint{ t0 + tlen, *pRightVal } );
684
685 // Return the range of indices that includes the inside limiting points,
686 // none, one, or two
687 return { 1 + range.first, index };
688}
void Insert(int point, const EnvPoint &p) noexcept
insert a point
Definition: Envelope.cpp:381

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

141{
142 mEnv.clear();
143 mDefaultValue = ClampValue(value);
144
145 ++mVersion;
146}

References ClampValue(), mDefaultValue, mEnv, and mVersion.

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

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

◆ GetDefaultValue()

double Envelope::GetDefaultValue ( ) const

Definition at line 728 of file Envelope.cpp.

729{
730 return mDefaultValue;
731}

References mDefaultValue.

◆ GetDragPoint()

int Envelope::GetDragPoint ( ) const
inline

Definition at line 214 of file Envelope.h.

214{ 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 219 of file Envelope.h.

219{ return mDragPointValid; }

Referenced by EnvelopeEditor::HandleDragging().

Here is the caller graph for this function:

◆ GetExponential()

bool Envelope::GetExponential ( ) const
inline

Definition at line 93 of file Envelope.h.

93{ 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 972 of file Envelope.cpp.

973{
974 double v = mEnv[ iPoint ].GetVal();
975 if( !mDB )
976 return v;
977 else
978 return log10(v);
979}

◆ GetMaxValue()

double Envelope::GetMaxValue ( ) const
inline

Definition at line 99 of file Envelope.h.

99{ return mMaxValue; }

◆ GetMinValue()

double Envelope::GetMinValue ( ) const
inline

Definition at line 98 of file Envelope.h.

98{ return mMinValue; }

◆ GetNumberOfPoints()

size_t Envelope::GetNumberOfPoints ( ) const

Return number of points.

Definition at line 723 of file Envelope.cpp.

724{
725 return mEnv.size();
726}

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

90{ 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 738 of file Envelope.cpp.

741{
742 int n = mEnv.size();
743 if (n > bufferLen)
744 n = bufferLen;
745 int i;
746 for (i = 0; i < n; i++) {
747 bufferWhen[i] = mEnv[i].GetT() - mOffset;
748 bufferValue[i] = mEnv[i].GetVal();
749 }
750}

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

91{ return mTrackLen; }

◆ GetValue()

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

Get envelope value at time t.

Definition at line 880 of file Envelope.cpp.

881{
882 // t is absolute time
883 double temp;
884
885 GetValues( &temp, 1, t, sampleDur );
886 return temp;
887}
void GetValues(double *buffer, int len, double t0, double tstep) const
Get many envelope points at once.
Definition: Envelope.cpp:981

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

890{
891 double temp;
892
893 GetValuesRelative(&temp, 1, t, 0.0, leftLimit);
894 return temp;
895}
void GetValuesRelative(double *buffer, int len, double t0, double tstep, bool leftLimit=false) const noexcept
Definition: Envelope.cpp:990

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

983{
984 // Convert t0 from absolute to clip-relative time
985 t0 -= mOffset;
986 GetValuesRelative( buffer, bufferLen, t0, tstep);
987}

References GetValuesRelative(), and mOffset.

Referenced by GetValue(), and WaveBitmapCache::LookupHelper::PerformLookup().

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

992{
993 // JC: If bufferLen ==0 we have probably just allocated a zero sized buffer.
994 // wxASSERT( bufferLen > 0 );
995
996 const auto epsilon = tstep / 2;
997 int len = mEnv.size();
998
999 double t = t0;
1000 double increment = 0;
1001 if ( len > 1 && t <= mEnv[0].GetT() && mEnv[0].GetT() == mEnv[1].GetT() )
1002 increment = leftLimit ? -epsilon : epsilon;
1003
1004 double tprev, vprev, tnext = 0, vnext, vstep = 0;
1005
1006 for (int b = 0; b < bufferLen; b++) {
1007
1008 // Get easiest cases out the way first...
1009 // IF empty envelope THEN default value
1010 if (len <= 0) {
1011 buffer[b] = mDefaultValue;
1012 t += tstep;
1013 continue;
1014 }
1015
1016 auto tplus = t + increment;
1017
1018 // IF before envelope THEN first value
1019 if ( leftLimit ? tplus <= mEnv[0].GetT() : tplus < mEnv[0].GetT() ) {
1020 buffer[b] = mEnv[0].GetVal();
1021 t += tstep;
1022 continue;
1023 }
1024 // IF after envelope THEN last value
1025 if ( leftLimit
1026 ? tplus > mEnv[len - 1].GetT() : tplus >= mEnv[len - 1].GetT() ) {
1027 buffer[b] = mEnv[len - 1].GetVal();
1028 t += tstep;
1029 continue;
1030 }
1031
1032 // be careful to get the correct limit even in case epsilon == 0
1033 if ( b == 0 ||
1034 ( leftLimit ? tplus > tnext : tplus >= tnext ) ) {
1035
1036 // We're beyond our tnext, so find the next one.
1037 // Don't just increment lo or hi because we might
1038 // be zoomed far out and that could be a large number of
1039 // points to move over. That's why we binary search.
1040
1041 int lo,hi;
1042 if ( leftLimit )
1043 BinarySearchForTime_LeftLimit( lo, hi, tplus );
1044 else
1045 BinarySearchForTime( lo, hi, tplus );
1046
1047 // mEnv[0] is before tplus because of eliminations above, therefore lo >= 0
1048 // mEnv[len - 1] is after tplus, therefore hi <= len - 1
1049 wxASSERT( lo >= 0 && hi <= len - 1 );
1050
1051 tprev = mEnv[lo].GetT();
1052 tnext = mEnv[hi].GetT();
1053
1054 if ( hi + 1 < len && tnext == mEnv[ hi + 1 ].GetT() )
1055 // There is a discontinuity after this point-to-point interval.
1056 // Usually will stop evaluating in this interval when time is slightly
1057 // before tNext, then use the right limit.
1058 // This is the right intent
1059 // in case small roundoff errors cause a sample time to be a little
1060 // before the envelope point time.
1061 // Less commonly we want a left limit, so we continue evaluating in
1062 // this interval until shortly after the discontinuity.
1063 increment = leftLimit ? -epsilon : epsilon;
1064 else
1065 increment = 0;
1066
1069
1070 // Interpolate, either linear or log depending on mDB.
1071 double dt = (tnext - tprev);
1072 double to = t - tprev;
1073 double v;
1074 if (dt > 0.0)
1075 {
1076 v = (vprev * (dt - to) + vnext * to) / dt;
1077 vstep = (vnext - vprev) * tstep / dt;
1078 }
1079 else
1080 {
1081 v = vnext;
1082 vstep = 0.0;
1083 }
1084
1085 // An adjustment if logarithmic scale.
1086 if( mDB )
1087 {
1088 v = pow(10.0, v);
1089 vstep = pow( 10.0, vstep );
1090 }
1091
1092 buffer[b] = v;
1093 } else {
1094 if (mDB){
1095 buffer[b] = buffer[b - 1] * vstep;
1096 }else{
1097 buffer[b] = buffer[b - 1] + vstep;
1098 }
1099 }
1100
1101 t += tstep;
1102 }
1103}
void BinarySearchForTime(int &Lo, int &Hi, double t) const noexcept
Definition: Envelope.cpp:900
void BinarySearchForTime_LeftLimit(int &Lo, int &Hi, double t) const noexcept
Definition: Envelope.cpp:947
double GetInterpolationStartValueAtPoint(int iPoint) const noexcept
Definition: Envelope.cpp:972

Referenced by GetValues().

Here is the caller graph for this function:

◆ GetVersion()

size_t Envelope::GetVersion ( ) const

Definition at line 733 of file Envelope.cpp.

734{
735 return mVersion;
736}

References mVersion.

Referenced by WaveBitmapCache::CheckCache(), and WaveBitmapCache::SetPaintParameters().

Here is the caller graph for this function:

◆ HandleXMLChild()

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

Implements XMLTagHandler.

Definition at line 346 of file Envelope.cpp.

347{
348 if (tag != "controlpoint")
349 return NULL;
350
351 mEnv.push_back( EnvPoint{} );
352 return &mEnv.back();
353}

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

322{
323 // Return unless it's the envelope tag.
324 if (tag != "envelope")
325 return false;
326
327 int numPoints = -1;
328
329 for (auto pair : attrs)
330 {
331 auto attr = pair.first;
332 auto value = pair.second;
333
334 if (attr == "numpoints")
335 value.TryGet(numPoints);
336 }
337
338 if (numPoints < 0)
339 return false;
340
341 mEnv.clear();
342 mEnv.reserve(numPoints);
343 return true;
344}

References mEnv.

◆ Insert() [1/2]

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

Definition at line 388 of file Envelope.cpp.

389{
390 mEnv.push_back(EnvPoint { when, value });
391
392 ++mVersion;
393}

References mEnv, and mVersion.

◆ Insert() [2/2]

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

insert a point

Definition at line 381 of file Envelope.cpp.

382{
383 mEnv.insert(mEnv.begin() + point, p);
384
385 ++mVersion;
386}

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

170 { 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 767 of file Envelope.cpp.

768{
769#if defined(_DEBUG)
770 // in debug builds, do a spot of argument checking
771 if(when > mTrackLen + 0.0000001)
772 {
773 wxString msg;
774 msg = wxString::Format(wxT("when %.20f mTrackLen %.20f diff %.20f"), when, mTrackLen, when-mTrackLen);
775 wxASSERT_MSG(when <= (mTrackLen), msg);
776 }
777 if(when < 0)
778 {
779 wxString msg;
780 msg = wxString::Format(wxT("when %.20f mTrackLen %.20f"), when, mTrackLen);
781 wxASSERT_MSG(when >= 0, msg);
782 }
783#endif
784
785 when = std::max( 0.0, std::min( mTrackLen, when ) );
786
787 auto range = EqualRange( when, 0 );
788 int index = range.first;
789
790 if ( index < range.second )
791 // modify existing
792 // In case of a discontinuity, ALWAYS CHANGING LEFT LIMIT ONLY!
793 mEnv[ index ].SetVal( this, value );
794 else
795 // Add NEW
796 Insert( index, EnvPoint { when, value } );
797
798 return index;
799}
wxT("CloseDown"))

References min(), and wxT().

Referenced by Cap().

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

692{
693 auto range = ExpandRegion( t0 - mOffset, tlen, nullptr, nullptr );
694
695 // Simplify the boundaries if possible
696 RemoveUnneededPoints( range.second, true );
697 RemoveUnneededPoints( range.first - 1, false );
698}
std::pair< int, int > ExpandRegion(double t0, double tlen, double *pLeftVal, double *pRightVal)
Definition: Envelope.cpp:641

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

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

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

Referenced by Average(), Integral(), 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 1287 of file Envelope.cpp.

1288{
1289 if(t0 == t1)
1290 return 0.0;
1291 if(t0 > t1)
1292 {
1293 return -IntegralOfInverse(t1, t0); // this makes more sense than returning the default value
1294 }
1295
1296 unsigned int count = mEnv.size();
1297 if(count == 0) // 'empty' envelope
1298 return (t1 - t0) / mDefaultValue;
1299
1300 t0 -= mOffset;
1301 t1 -= mOffset;
1302
1303 double total = 0.0, lastT, lastVal;
1304 unsigned int i; // this is the next point to check
1305 if(t0 < mEnv[0].GetT()) // t0 preceding the first point
1306 {
1307 if(t1 <= mEnv[0].GetT())
1308 return (t1 - t0) / mEnv[0].GetVal();
1309 i = 1;
1310 lastT = mEnv[0].GetT();
1311 lastVal = mEnv[0].GetVal();
1312 total += (lastT - t0) / lastVal;
1313 }
1314 else if(t0 >= mEnv[count - 1].GetT()) // t0 at or following the last point
1315 {
1316 return (t1 - t0) / mEnv[count - 1].GetVal();
1317 }
1318 else // t0 enclosed by points
1319 {
1320 // Skip any points that come before t0 using binary search
1321 int lo, hi;
1322 BinarySearchForTime(lo, hi, t0);
1323 lastVal = InterpolatePoints(mEnv[lo].GetVal(), mEnv[hi].GetVal(), (t0 - mEnv[lo].GetT()) / (mEnv[hi].GetT() - mEnv[lo].GetT()), mDB);
1324 lastT = t0;
1325 i = hi; // the point immediately after t0.
1326 }
1327
1328 // loop through the rest of the envelope points until we get to t1
1329 while (1)
1330 {
1331 if(i >= count) // the requested range extends beyond the last point
1332 {
1333 return total + (t1 - lastT) / lastVal;
1334 }
1335 else if(mEnv[i].GetT() >= t1) // this point follows the end of the range
1336 {
1337 double thisVal = InterpolatePoints(mEnv[i - 1].GetVal(), mEnv[i].GetVal(), (t1 - mEnv[i - 1].GetT()) / (mEnv[i].GetT() - mEnv[i - 1].GetT()), mDB);
1338 return total + IntegrateInverseInterpolated(lastVal, thisVal, t1 - lastT, mDB);
1339 }
1340 else // this point precedes the end of the range
1341 {
1342 total += IntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, mDB);
1343 lastT = mEnv[i].GetT();
1344 lastVal = mEnv[i].GetVal();
1345 i++;
1346 }
1347 }
1348}
static double IntegrateInverseInterpolated(double y1, double y2, double time, bool logarithmic)
Definition: Envelope.cpp:1180

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:

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

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

References mDragPoint, mDragPointValid, mEnv, min(), mTrackLen, mVersion, 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 1115 of file Envelope.cpp.

1116{
1117 int lo,hi;
1118 BinarySearchForTime( lo, hi, t );
1119 if (hi >= (int)mEnv.size())
1120 return t;
1121 else
1122 return mEnv[hi].GetT();
1123}

References BinarySearchForTime(), and mEnv.

Here is the call graph for this function:

◆ NumberOfPointsAfter()

int Envelope::NumberOfPointsAfter ( double  t) const
private

Definition at line 1106 of file Envelope.cpp.

1107{
1108 int lo,hi;
1109 BinarySearchForTime( lo, hi, t );
1110
1111 return mEnv.size() - hi;
1112}

References BinarySearchForTime(), and mEnv.

Here is the call graph for this function:

◆ operator[]()

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

Accessor for points.

Definition at line 191 of file Envelope.h.

192 {
193 return mEnv[index];
194 }

◆ PasteEnvelope()

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

Definition at line 486 of file Envelope.cpp.

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

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

Here is the call graph for this function:

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

701{
702 when -= mOffset;
703
704 int len = mEnv.size();
705 if (len == 0)
706 return -1;
707
708 int i = 0;
709 while (i < len && when > mEnv[i].GetT())
710 i++;
711
712 if (i >= len || when < mEnv[i].GetT())
713 return -1;
714
715 mEnv[i].SetVal(this, value);
716
717 ++mVersion;
718
719 return 0;
720}

References mEnv, mOffset, and mVersion.

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

573{
574 // startAt is the index of a recently inserted point which might make no
575 // difference in envelope evaluation, or else might cause nearby points to
576 // make no difference.
577
578 auto isDiscontinuity = [this]( size_t index ) noexcept {
579 // Assume array accesses are in-bounds
580 const EnvPoint &point1 = mEnv[ index ];
581 const EnvPoint &point2 = mEnv[ index + 1 ];
582 return point1.GetT() == point2.GetT() &&
583 fabs( point1.GetVal() - point2.GetVal() ) > VALUE_TOLERANCE;
584 };
585
586 auto remove = [this]( size_t index, bool leftLimit ) noexcept {
587 // Assume array accesses are in-bounds
588 const auto &point = mEnv[ index ];
589 auto when = point.GetT();
590 auto val = point.GetVal();
591 Delete( index ); // try it to see if it's doing anything
592 auto val1 = GetValueRelative ( when, leftLimit );
593 if( fabs( val - val1 ) > VALUE_TOLERANCE ) {
594 // put it back, we needed it
595 Insert( index, EnvPoint{ when, val } );
596 return false;
597 }
598 else
599 {
600 ++mVersion;
601 return true;
602 }
603 };
604
605 auto len = mEnv.size();
606
607 bool leftLimit =
608 !rightward && startAt + 1 < len && isDiscontinuity( startAt );
609
610 bool removed = remove( startAt, leftLimit );
611
612 if ( removed )
613 // The given point was removable. Done!
614 return;
615
616 if ( !testNeighbors )
617 return;
618
619 // The given point was not removable. But did its insertion make nearby
620 // points removable?
621
622 int index = startAt + ( rightward ? 1 : -1 );
623 while ( index >= 0 && index < (int)len ) {
624 // Stop at any discontinuity
625 if ( index > 0 && isDiscontinuity( index - 1 ) )
626 break;
627 if ( (index + 1) < (int)len && isDiscontinuity( index ) )
628 break;
629
630 if ( ! remove( index, false ) )
631 break;
632
633 --len;
634 if ( ! rightward )
635 --index;
636 }
637}
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 855 of file Envelope.cpp.

856{
857 if ( mTrackLen == 0 ) {
858 for ( auto &point : mEnv )
859 point.SetT( 0 );
860 }
861 else {
862 auto ratio = newLength / mTrackLen;
863 for ( auto &point : mEnv )
864 point.SetT( point.GetT() * ratio );
865 }
866 mTrackLen = newLength;
867
868 ++mVersion;
869}

References mEnv, mTrackLen, and mVersion.

◆ RescaleTimesBy()

void Envelope::RescaleTimesBy ( double  ratio)

Definition at line 871 of file Envelope.cpp.

872{
873 for (auto& point : mEnv)
874 point.SetT(point.GetT() * ratio);
875 if (mTrackLen != DBL_MAX)
876 mTrackLen *= ratio;
877}

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

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

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

Here is the call graph for this function:

◆ SetDragPoint()

void Envelope::SetDragPoint ( int  dragPoint)

Definition at line 148 of file Envelope.cpp.

149{
150 mDragPoint = std::max(-1, std::min(int(mEnv.size() - 1), dragPoint));
152}

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

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

References mDefaultValue, mDragPoint, mDragPointValid, mEnv, mVersion, 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 94 of file Envelope.h.

94{ mDB = db; }

◆ SetOffset()

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

Definition at line 826 of file Envelope.cpp.

827{
828 mOffset = newOffset;
829}

References mOffset.

◆ SetRange()

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

Definition at line 230 of file Envelope.cpp.

230 {
231 mMinValue = minValue;
232 mMaxValue = maxValue;
234 for( unsigned int i = 0; i < mEnv.size(); i++ )
235 mEnv[i].SetVal( this, mEnv[i].GetVal() ); // this clamps the value to the NEW range
236
237 ++mVersion;
238}

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

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

833{
834 // Preserve the left-side limit at trackLen.
835 auto range = EqualRange( trackLen, sampleDur );
836 bool needPoint = ( range.first == range.second && trackLen < mTrackLen );
837 double value=0.0;
838 if ( needPoint )
839 value = GetValueRelative( trackLen );
840
841 mTrackLen = trackLen;
842
843 // Shrink the array.
844 // If more than one point already at the end, keep only the first of them.
845 int newLen = std::min( 1 + range.first, range.second );
846 mEnv.resize( newLen );
847
848 ++mVersion;
849
850 if ( needPoint )
851 AddPointAtEnd( mTrackLen, value );
852}

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

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

1351{
1352 if(area == 0.0)
1353 return t0;
1354
1355 const auto count = mEnv.size();
1356 if(count == 0) // 'empty' envelope
1357 return t0 + area * mDefaultValue;
1358
1359 // Correct for offset!
1360 t0 -= mOffset;
1361 return mOffset + [&] {
1362 // Now we can safely assume t0 is relative time!
1363 double lastT, lastVal;
1364 int i; // this is the next point to check
1365 if(t0 < mEnv[0].GetT()) // t0 preceding the first point
1366 {
1367 if (area < 0) {
1368 return t0 + area * mEnv[0].GetVal();
1369 }
1370 else {
1371 i = 1;
1372 lastT = mEnv[0].GetT();
1373 lastVal = mEnv[0].GetVal();
1374 double added = (lastT - t0) / lastVal;
1375 if(added >= area)
1376 return t0 + area * mEnv[0].GetVal();
1377 area -= added;
1378 }
1379 }
1380 else if(t0 >= mEnv[count - 1].GetT()) // t0 at or following the last point
1381 {
1382 if (area < 0) {
1383 i = (int)count - 2;
1384 lastT = mEnv[count - 1].GetT();
1385 lastVal = mEnv[count - 1].GetVal();
1386 double added = (lastT - t0) / lastVal; // negative
1387 if(added <= area)
1388 return t0 + area * mEnv[count - 1].GetVal();
1389 area -= added;
1390 }
1391 else {
1392 return t0 + area * mEnv[count - 1].GetVal();
1393 }
1394 }
1395 else // t0 enclosed by points
1396 {
1397 // Skip any points that come before t0 using binary search
1398 int lo, hi;
1399 BinarySearchForTime(lo, hi, t0);
1400 lastVal = InterpolatePoints(mEnv[lo].GetVal(), mEnv[hi].GetVal(), (t0 - mEnv[lo].GetT()) / (mEnv[hi].GetT() - mEnv[lo].GetT()), mDB);
1401 lastT = t0;
1402 if (area < 0)
1403 i = lo;
1404 else
1405 i = hi; // the point immediately after t0.
1406 }
1407
1408 if (area < 0) {
1409 // loop BACKWARDS through the rest of the envelope points until we get to t1
1410 // (which is less than t0)
1411 while (1)
1412 {
1413 if(i < 0) // the requested range extends beyond the leftmost point
1414 {
1415 return lastT + area * lastVal;
1416 }
1417 else
1418 {
1419 double added =
1420 -IntegrateInverseInterpolated(mEnv[i].GetVal(), lastVal, lastT - mEnv[i].GetT(), mDB);
1421 if(added <= area)
1422 return lastT - SolveIntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), lastT - mEnv[i].GetT(), -area, mDB);
1423 area -= added;
1424 lastT = mEnv[i].GetT();
1425 lastVal = mEnv[i].GetVal();
1426 --i;
1427 }
1428 }
1429 }
1430 else {
1431 // loop through the rest of the envelope points until we get to t1
1432 while (1)
1433 {
1434 if(i >= (int)count) // the requested range extends beyond the last point
1435 {
1436 return lastT + area * lastVal;
1437 }
1438 else
1439 {
1440 double added = IntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, mDB);
1441 if(added >= area)
1442 return lastT + SolveIntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, area, mDB);
1443 area -= added;
1444 lastT = mEnv[i].GetT();
1445 lastVal = mEnv[i].GetVal();
1446 i++;
1447 }
1448 }
1449 }
1450 }();
1451}
static double SolveIntegrateInverseInterpolated(double y1, double y2, double time, double area, bool logarithmic)
Definition: Envelope.cpp:1197

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:

◆ WriteXML()

void Envelope::WriteXML ( XMLWriter xmlFile) const

Definition at line 355 of file Envelope.cpp.

357{
358 unsigned int ctrlPt;
359
360 xmlFile.StartTag(wxT("envelope"));
361 xmlFile.WriteAttr(wxT("numpoints"), mEnv.size());
362
363 for (ctrlPt = 0; ctrlPt < mEnv.size(); ctrlPt++) {
364 const EnvPoint &point = mEnv[ctrlPt];
365 xmlFile.StartTag(wxT("controlpoint"));
366 xmlFile.WriteAttr(wxT("t"), point.GetT(), 12);
367 xmlFile.WriteAttr(wxT("val"), point.GetVal(), 12);
368 xmlFile.EndTag(wxT("controlpoint"));
369 }
370
371 xmlFile.EndTag(wxT("envelope"));
372}
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 249 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 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 CopyRange(), Envelope(), GetPoints(), GetValues(), InsertSpace(), Integral(), IntegralOfInverse(), PasteEnvelope(), Reassign(), SetOffset(), and SolveIntegralOfInverse().

◆ mSearchGuess

int Envelope::mSearchGuess { -2 }
mutableprivate

Definition at line 258 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 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(), CopyRange(), Envelope(), ExpandRegion(), MoveDragPoint(), PasteEnvelope(), RescaleTimes(), RescaleTimesBy(), and SetTrackLen().

◆ mVersion

size_t Envelope::mVersion { 0 }
private

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