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

Private Member Functions

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

Private Attributes

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

Detailed Description

Piecewise linear or piecewise exponential function from double to double.

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

Definition at line 72 of file Envelope.h.

Constructor & Destructor Documentation

◆ Envelope() [1/3]

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

Definition at line 43 of file Envelope.cpp.

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

◆ Envelope() [2/3]

Envelope::Envelope ( const Envelope orig)

Definition at line 257 of file Envelope.cpp.

258 : mDB(orig.mDB)
259 , mMinValue(orig.mMinValue)
260 , mMaxValue(orig.mMaxValue)
262{
263 mOffset = orig.mOffset;
264 mTrackLen = orig.mTrackLen;
265 CopyRange(orig, 0, orig.GetNumberOfPoints());
266}
double mOffset
The time at which the envelope starts, i.e. the start offset.
Definition: Envelope.h:237
size_t GetNumberOfPoints() const
Return number of points.
Definition: Envelope.cpp:689
double mTrackLen
The length of the envelope, which is the same as the length of the underlying track (normally)
Definition: Envelope.h:240
void CopyRange(const Envelope &orig, size_t begin, size_t end)
Definition: Envelope.cpp:268

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

244 : mDB(orig.mDB)
245 , mMinValue(orig.mMinValue)
246 , mMaxValue(orig.mMaxValue)
248{
249 mOffset = wxMax(t0, orig.mOffset);
250 mTrackLen = wxMin(t1, orig.mOffset + orig.mTrackLen) - mOffset;
251
252 auto range1 = orig.EqualRange( t0 - orig.mOffset, 0 );
253 auto range2 = orig.EqualRange( t1 - orig.mOffset, 0 );
254 CopyRange(orig, range1.first, range2.second);
255}
std::pair< int, int > EqualRange(double when, double sampleDur) const
Definition: Envelope.cpp:757

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

Here is the call graph for this function:

◆ ~Envelope()

Envelope::~Envelope ( )
virtual

Definition at line 51 of file Envelope.cpp.

52{
53}

Member Function Documentation

◆ AddPointAtEnd()

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

Definition at line 226 of file Envelope.cpp.

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

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

1068{
1069 if( t0 == t1 )
1070 return GetValue( t0 );
1071 else
1072 return Integral( t0, t1 ) / (t1 - t0);
1073}
double GetValue(double t, double sampleDur=0) const
Get envelope value at time t.
Definition: Envelope.cpp:823
double Integral(double t0, double t1) const
Definition: Envelope.cpp:1166

References GetValue(), and Integral().

Here is the call graph for this function:

◆ AverageOfInverse()

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

Definition at line 1075 of file Envelope.cpp.

1076{
1077 if( t0 == t1 )
1078 return 1.0 / GetValue( t0 );
1079 else
1080 return IntegralOfInverse( t0, t1 ) / (t1 - t0);
1081}
double IntegralOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1229

References GetValue(), and IntegralOfInverse().

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

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

◆ BinarySearchForTime()

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

Definition at line 843 of file Envelope.cpp.

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

References mEnv, and mSearchGuess.

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

Here is the caller graph for this function:

◆ BinarySearchForTime_LeftLimit()

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

Definition at line 890 of file Envelope.cpp.

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

References mEnv, and mSearchGuess.

Referenced by GetValuesRelative().

Here is the caller graph for this function:

◆ Cap()

void Envelope::Cap ( double  sampleDur)

Definition at line 708 of file Envelope.cpp.

709{
710 auto range = EqualRange( mTrackLen, sampleDur );
711 if ( range.first == range.second )
713}
int InsertOrReplaceRelative(double when, double value)
Add a control point to the envelope.
Definition: Envelope.cpp:723
double GetValueRelative(double t, bool leftLimit=false) const
Definition: Envelope.cpp:832

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 SetEnvelopeCommand::ApplyInner(), Flatten(), RescaleValues(), SetRange(), EnvPoint::SetVal(), and EnvelopeEditor::ValueOfPixel().

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

◆ Clear()

void Envelope::Clear ( )
inline

Definition at line 170 of file Envelope.h.

170{ mEnv.clear(); }

Referenced by SetEnvelopeCommand::ApplyInner().

Here is the caller graph for this function:

◆ ClearDragPoint()

void Envelope::ClearDragPoint ( )

Definition at line 207 of file Envelope.cpp.

208{
209 if (!mDragPointValid && mDragPoint >= 0)
211
212 mDragPoint = -1;
213 mDragPointValid = false;
214}
int mDragPoint
Definition: Envelope.h:253
void Delete(int point)
DELETE a point by its position in array.
Definition: Envelope.cpp:356
bool mDragPointValid
Definition: Envelope.h:252

References Delete(), mDragPoint, and mDragPointValid.

Referenced by EnvelopeEditor::HandleMouseButtonUp().

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

◆ CollapseRegion()

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

Definition at line 372 of file Envelope.cpp.

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

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

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

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

◆ ConsistencyCheck()

bool Envelope::ConsistencyCheck ( )

Definition at line 55 of file Envelope.cpp.

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

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

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

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

Referenced by Envelope().

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

◆ Delete()

void Envelope::Delete ( int  point)

DELETE a point by its position in array.

Definition at line 356 of file Envelope.cpp.

357{
358 mEnv.erase(mEnv.begin() + point);
359}

References mEnv.

Referenced by ClearDragPoint(), and RemoveUnneededPoints().

Here is the caller graph for this function:

◆ EqualRange()

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

Definition at line 757 of file Envelope.cpp.

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

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

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

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

◆ ExpandRegion()

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

Definition at line 609 of file Envelope.cpp.

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

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

133{
134 mEnv.clear();
135 mDefaultValue = ClampValue(value);
136}

References ClampValue(), mDefaultValue, and mEnv.

Referenced by EffectEqualization::GraphicEQ(), EffectEqualization::setCurve(), 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 213 of file Envelope.h.

213{ 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 218 of file Envelope.h.

218{ 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 CommonTrackView::GetEnvelopeValues().

Here is the caller graph for this function:

◆ GetInterpolationStartValueAtPoint()

double Envelope::GetInterpolationStartValueAtPoint ( int  iPoint) const
private

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

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

Definition at line 914 of file Envelope.cpp.

915{
916 double v = mEnv[ iPoint ].GetVal();
917 if( !mDB )
918 return v;
919 else
920 return log10(v);
921}

References mDB, and mEnv.

Referenced by GetValuesRelative().

Here is the caller graph for this function:

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

690{
691 return mEnv.size();
692}

References mEnv.

Referenced by EnvelopeEditor::DrawPoints(), Envelope(), EffectEqualization::EnvelopeUpdated(), EnvelopeEditor::HandleMouseButtonDown(), and GetInfoCommand::SendEnvelopes().

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

Here is the caller graph for this function:

◆ GetPoints()

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

Returns the sets of when and value pairs.

Definition at line 694 of file Envelope.cpp.

697{
698 int n = mEnv.size();
699 if (n > bufferLen)
700 n = bufferLen;
701 int i;
702 for (i = 0; i < n; i++) {
703 bufferWhen[i] = mEnv[i].GetT() - mOffset;
704 bufferValue[i] = mEnv[i].GetVal();
705 }
706}

References mEnv, and mOffset.

Referenced by EffectEqualization::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 823 of file Envelope.cpp.

824{
825 // t is absolute time
826 double temp;
827
828 GetValues( &temp, 1, t, sampleDur );
829 return temp;
830}
void GetValues(double *buffer, int len, double t0, double tstep) const
Get many envelope points at once.
Definition: Envelope.cpp:923

References GetValues().

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

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

◆ GetValueRelative()

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

Definition at line 832 of file Envelope.cpp.

833{
834 double temp;
835
836 GetValuesRelative(&temp, 1, t, 0.0, leftLimit);
837 return temp;
838}
void GetValuesRelative(double *buffer, int len, double t0, double tstep, bool leftLimit=false) const
Definition: Envelope.cpp:932

References GetValuesRelative().

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

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

◆ GetValues()

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

Get many envelope points at once.

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

Definition at line 923 of file Envelope.cpp.

925{
926 // Convert t0 from absolute to clip-relative time
927 t0 -= mOffset;
928 GetValuesRelative( buffer, bufferLen, t0, tstep);
929}

References GetValuesRelative(), and mOffset.

Referenced by GetValue(), and EqualizationPanel::OnPaint().

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

◆ GetValuesRelative()

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

Definition at line 931 of file Envelope.cpp.

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

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

Referenced by GetValueRelative(), and GetValues().

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

◆ HandleXMLChild()

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

Implements XMLTagHandler.

Definition at line 328 of file Envelope.cpp.

329{
330 if (tag != "controlpoint")
331 return NULL;
332
333 mEnv.push_back( EnvPoint{} );
334 return &mEnv.back();
335}

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

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

References mEnv.

◆ Initialize()

void Envelope::Initialize ( int  numPoints)

◆ Insert() [1/2]

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

Definition at line 366 of file Envelope.cpp.

367{
368 mEnv.push_back( EnvPoint{ when, value });
369}

References mEnv.

◆ Insert() [2/2]

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

insert a point

Definition at line 361 of file Envelope.cpp.

362{
363 mEnv.insert(mEnv.begin() + point, p);
364}

References mEnv.

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

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

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

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

Here is the caller graph for this function:

◆ InsertOrReplaceRelative()

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

Add a control point to the envelope.

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

Definition at line 723 of file Envelope.cpp.

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

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

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

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

◆ InsertSpace()

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

Definition at line 660 of file Envelope.cpp.

661{
662 auto range = ExpandRegion( t0 - mOffset, tlen, nullptr, nullptr );
663
664 // Simplify the boundaries if possible
665 RemoveUnneededPoints( range.second, true );
666 RemoveUnneededPoints( range.first - 1, false );
667}
std::pair< int, int > ExpandRegion(double t0, double tlen, double *pLeftVal, double *pRightVal)
Definition: Envelope.cpp:610

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

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

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

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

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

Referenced by AverageOfInverse(), anonymous_namespace{Ruler.cpp}::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

◆ MoveDragPoint()

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

Definition at line 181 of file Envelope.cpp.

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

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

1058{
1059 int lo,hi;
1060 BinarySearchForTime( lo, hi, t );
1061 if (hi >= (int)mEnv.size())
1062 return t;
1063 else
1064 return mEnv[hi].GetT();
1065}

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

1049{
1050 int lo,hi;
1051 BinarySearchForTime( lo, hi, t );
1052
1053 return mEnv.size() - hi;
1054}

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

196 {
197 return mEnv[index];
198 }

◆ PasteEnvelope()

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

Definition at line 460 of file Envelope.cpp.

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

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

Here is the call graph for this function:

◆ print()

void Envelope::print ( ) const

Definition at line 1395 of file Envelope.cpp.

1396{
1397 for( unsigned int i = 0; i < mEnv.size(); i++ )
1398 wxPrintf( "(%.2f, %.2f)\n", mEnv[i].GetT(), mEnv[i].GetVal() );
1399}

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

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

References mEnv, and mOffset.

Referenced by EffectEqualization::GraphicEQ().

Here is the caller graph for this function:

◆ RemoveUnneededPoints()

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

Definition at line 543 of file Envelope.cpp.

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

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

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

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

◆ RescaleTimes()

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

Definition at line 808 of file Envelope.cpp.

809{
810 if ( mTrackLen == 0 ) {
811 for ( auto &point : mEnv )
812 point.SetT( 0 );
813 }
814 else {
815 auto ratio = newLength / mTrackLen;
816 for ( auto &point : mEnv )
817 point.SetT( point.GetT() * ratio );
818 }
819 mTrackLen = newLength;
820}

References mEnv, and mTrackLen.

◆ RescaleValues()

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

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

Definition at line 110 of file Envelope.cpp.

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

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

Here is the call graph for this function:

◆ SetDragPoint()

void Envelope::SetDragPoint ( int  dragPoint)

Definition at line 138 of file Envelope.cpp.

139{
140 mDragPoint = std::max(-1, std::min(int(mEnv.size() - 1), dragPoint));
142}

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

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

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

94{ 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 781 of file Envelope.cpp.

782{
783 mOffset = newOffset;
784}

References mOffset.

◆ SetRange()

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

Definition at line 216 of file Envelope.cpp.

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

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

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

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

Referenced by EffectEqualization::GraphicEQ(), and EffectEqualization::setCurve().

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

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

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

Referenced by anonymous_namespace{Ruler.cpp}::SolveWarpedLength(), and 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 1410 of file Envelope.cpp.

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

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

339{
340 unsigned int ctrlPt;
341
342 xmlFile.StartTag(wxT("envelope"));
343 xmlFile.WriteAttr(wxT("numpoints"), mEnv.size());
344
345 for (ctrlPt = 0; ctrlPt < mEnv.size(); ctrlPt++) {
346 const EnvPoint &point = mEnv[ctrlPt];
347 xmlFile.StartTag(wxT("controlpoint"));
348 xmlFile.WriteAttr(wxT("t"), point.GetT(), 12);
349 xmlFile.WriteAttr(wxT("val"), point.GetVal(), 12);
350 xmlFile.EndTag(wxT("controlpoint"));
351 }
352
353 xmlFile.EndTag(wxT("envelope"));
354}
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:80
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:37
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:103

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

Here is the call graph for this function:

Member Data Documentation

◆ mDB

bool Envelope::mDB
private

◆ mDefaultValue

double Envelope::mDefaultValue
private

◆ mDragPoint

int Envelope::mDragPoint { -1 }
private

Definition at line 253 of file Envelope.h.

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

◆ mDragPointValid

bool Envelope::mDragPointValid { false }
private

Definition at line 252 of file Envelope.h.

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

◆ mEnv

EnvArray Envelope::mEnv
private

◆ mMaxValue

double Envelope::mMaxValue
private

Definition at line 248 of file Envelope.h.

Referenced by RescaleValues(), and SetRange().

◆ mMinValue

double Envelope::mMinValue
private

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

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

◆ mSearchGuess

int Envelope::mSearchGuess { -2 }
mutableprivate

Definition at line 255 of file Envelope.h.

Referenced by BinarySearchForTime(), and BinarySearchForTime_LeftLimit().

◆ mTrackEpsilon

double Envelope::mTrackEpsilon { 1.0 / 200000.0 }
private

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

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

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


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