1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-01 08:29:27 +02:00

Move many fields out of Envelope that are needed only during editing

This commit is contained in:
Paul Licameli 2016-01-25 22:46:56 -05:00 committed by Paul Licameli
parent 3c4a15f5cb
commit 0af9b46eac
11 changed files with 244 additions and 186 deletions

View File

@ -57,27 +57,19 @@ Envelope::Envelope()
mDB = true; mDB = true;
mDefaultValue = 1.0; mDefaultValue = 1.0;
mDragPoint = -1; mDragPoint = -1;
mDirty = false;
mIsDeleting = false;
mMirror = true;
mMinValue = 1.0e-7; mMinValue = 1.0e-7;
mMaxValue = 2.0; mMaxValue = 2.0;
mButton = wxMOUSE_BTN_NONE;
mSearchGuess = -1; mSearchGuess = -1;
mDragPointValid = false;
} }
Envelope::~Envelope() Envelope::~Envelope()
{ {
} }
void Envelope::Mirror(bool mirror)
{
mMirror = mirror;
}
/// Rescale function for time tracks (could also be used for other tracks though). /// 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 /// 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 /// range instead of storing the actual time track values. This function will change the range of the envelope
@ -112,6 +104,84 @@ void Envelope::Flatten(double value)
mDefaultValue = ClampValue(value); mDefaultValue = ClampValue(value);
} }
void Envelope::SetDragPoint(int dragPoint)
{
mDragPoint = std::max(-1, std::min(int(mEnv.size() - 1), dragPoint));
mDragPointValid = (mDragPoint >= 0);
}
void Envelope::SetDragPointValid(bool valid)
{
mDragPointValid = (valid && mDragPoint >= 0);
if (mDragPoint >= 0 && !valid) {
// We're going to be deleting the point; On
// screen we show this by having the envelope move to
// the position it will have after deletion of the point.
// Without deleting the point we move it left or right
// to the same position as the previous or next point.
static const double big = std::numeric_limits<double>::max();
auto size = mEnv.size();
if( size <= 1) {
// There is only one point - just move it
// off screen and at default height.
// temporary state when dragging only!
mEnv[mDragPoint].SetT(big);
mEnv[mDragPoint].SetVal(mDefaultValue);
return;
}
else if ( mDragPoint + 1 == size ) {
// Put the point at the height of the last point, but also off screen.
mEnv[mDragPoint].SetT(big);
mEnv[mDragPoint].SetVal(mEnv[ size - 1 ].GetVal());
}
else {
// Place it exactly on its right neighbour.
// That way the drawing code will overpaint the dark dot with
// a light dot, as if it were deleted.
const auto &neighbor = mEnv[mDragPoint + 1];
mEnv[mDragPoint].SetT(neighbor.GetT());
mEnv[mDragPoint].SetVal(neighbor.GetVal());
}
}
}
void Envelope::MoveDragPoint(double newWhen, double value)
{
SetDragPointValid(true);
if (!mDragPointValid)
return;
// We'll limit the drag point time to be between those of the preceding
// and next envelope point.
double limitLo = 0.0;
double limitHi = mTrackLen;
if (mDragPoint > 0)
limitLo = std::max(limitLo, mEnv[mDragPoint - 1].GetT());
if (mDragPoint + 1 < mEnv.size())
limitHi = std::min(limitHi, mEnv[mDragPoint + 1].GetT());
EnvPoint &dragPoint = mEnv[mDragPoint];
const double tt =
std::max(limitLo, std::min(limitHi, newWhen));
// This might temporary violate the constraint that at most two
// points share a time value.
dragPoint.SetT(tt);
dragPoint.SetVal(value);
}
void Envelope::ClearDragPoint()
{
if (!mDragPointValid && mDragPoint >= 0)
Delete(mDragPoint);
mDragPoint = -1;
mDragPointValid = false;
}
void Envelope::SetRange(double minValue, double maxValue) { void Envelope::SetRange(double minValue, double maxValue) {
mMinValue = minValue; mMinValue = minValue;
mMaxValue = maxValue; mMaxValue = maxValue;
@ -186,7 +256,7 @@ static void DrawPoint(wxDC & dc, const wxRect & r, int x, int y, bool top)
/// TODO: This should probably move to track artist. /// TODO: This should probably move to track artist.
void Envelope::DrawPoints(wxDC & dc, const wxRect & r, const ZoomInfo &zoomInfo, void Envelope::DrawPoints(wxDC & dc, const wxRect & r, const ZoomInfo &zoomInfo,
bool dB, double dBRange, bool dB, double dBRange,
float zoomMin, float zoomMax) const float zoomMin, float zoomMax, bool mirrored) const
{ {
dc.SetPen(AColor::envelopePen); dc.SetPen(AColor::envelopePen);
dc.SetBrush(*wxWHITE_BRUSH); dc.SetBrush(*wxWHITE_BRUSH);
@ -207,7 +277,7 @@ void Envelope::DrawPoints(wxDC & dc, const wxRect & r, const ZoomInfo &zoomInfo,
y = GetWaveYPos(v, zoomMin, zoomMax, r.height, dB, y = GetWaveYPos(v, zoomMin, zoomMax, r.height, dB,
true, dBRange, false); true, dBRange, false);
if (!mMirror) { if (!mirrored) {
DrawPoint(dc, r, x, y, true); DrawPoint(dc, r, x, y, true);
} }
else { else {
@ -311,7 +381,7 @@ inline int SQR(int x) { return x * x; }
/// @dB - display mode either linear or log. /// @dB - display mode either linear or log.
/// @zoomMin - vertical scale, typically -1.0 /// @zoomMin - vertical scale, typically -1.0
/// @zoomMax - vertical scale, typically +1.0 /// @zoomMax - vertical scale, typically +1.0
float Envelope::ValueOfPixel( int y, int height, bool upper, float EnvelopeEditor::ValueOfPixel( int y, int height, bool upper,
bool dB, double dBRange, bool dB, double dBRange,
float zoomMin, float zoomMax) float zoomMin, float zoomMax)
{ {
@ -320,9 +390,9 @@ float Envelope::ValueOfPixel( int y, int height, bool upper,
// MB: this is mostly equivalent to what the old code did, I'm not sure // MB: this is mostly equivalent to what the old code did, I'm not sure
// if anything special is needed for asymmetric ranges // if anything special is needed for asymmetric ranges
if(upper) if(upper)
return ClampValue(v); return mEnvelope.ClampValue(v);
else else
return ClampValue(-v); return mEnvelope.ClampValue(-v);
} }
/// HandleMouseButtonDown either finds an existing control point or adds a NEW one /// HandleMouseButtonDown either finds an existing control point or adds a NEW one
@ -331,13 +401,13 @@ float Envelope::ValueOfPixel( int y, int height, bool upper,
/// a given time value: /// a given time value:
/// We have an upper and lower envelope line. /// We have an upper and lower envelope line.
/// Also we may be showing an inner envelope (at 0.5 the range). /// Also we may be showing an inner envelope (at 0.5 the range).
bool Envelope::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r, bool EnvelopeEditor::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, const ZoomInfo &zoomInfo,
bool dB, double dBRange, bool dB, double dBRange,
float zoomMin, float zoomMax) float zoomMin, float zoomMax)
{ {
int ctr = (int)(r.height * zoomMax / (zoomMax - zoomMin)); int ctr = (int)(r.height * zoomMax / (zoomMax - zoomMin));
bool upper = !mMirror || (zoomMin >= 0.0) || (event.m_y - r.y < ctr); bool upper = !mMirrored || (zoomMin >= 0.0) || (event.m_y - r.y < ctr);
int clip_y = event.m_y - r.y; int clip_y = event.m_y - r.y;
if(clip_y < 0) clip_y = 0; //keeps point in rect r, even if mouse isn't if(clip_y < 0) clip_y = 0; //keeps point in rect r, even if mouse isn't
@ -348,16 +418,15 @@ bool Envelope::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
// Member variables hold state that will be needed in dragging. // Member variables hold state that will be needed in dragging.
mButton = event.GetButton(); mButton = event.GetButton();
mIsDeleting = false;
mContourOffset = false; mContourOffset = false;
// wxLogDebug(wxT("Y:%i Height:%i Offset:%i"), y, height, mContourOffset ); // wxLogDebug(wxT("Y:%i Height:%i Offset:%i"), y, height, mContourOffset );
int len = mEnv.size(); int len = mEnvelope.GetNumberOfPoints();
// TODO: extract this into a function FindNearestControlPoint() // TODO: extract this into a function FindNearestControlPoint()
// TODO: also fix it so that we can drag the last point on an envelope. // TODO: also fix it so that we can drag the last point on an envelope.
for (int i = 0; i < len; i++) { //search for control point nearest click for (int i = 0; i < len; i++) { //search for control point nearest click
const double time = mEnv[i].GetT() + mOffset; const double time = mEnvelope[i].GetT() + mEnvelope.GetOffset();
const wxInt64 position = zoomInfo.TimeToPosition(time); const wxInt64 position = zoomInfo.TimeToPosition(time);
if (position >= 0 && position < r.width) { if (position >= 0 && position < r.width) {
@ -366,7 +435,7 @@ bool Envelope::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
int numControlPoints; int numControlPoints;
// Outer control points // Outer control points
double value = mEnv[i].GetVal(); double value = mEnvelope[i].GetVal();
y[0] = GetWaveYPos(value, zoomMin, zoomMax, r.height, y[0] = GetWaveYPos(value, zoomMin, zoomMax, r.height,
dB, true, dBRange, false); dB, true, dBRange, false);
y[1] = GetWaveYPos(-value, zoomMin, zoomMax, r.height, y[1] = GetWaveYPos(-value, zoomMin, zoomMax, r.height,
@ -383,7 +452,7 @@ bool Envelope::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
if (y[2] > y[3]) if (y[2] > y[3])
numControlPoints = 2; numControlPoints = 2;
if (!mMirror) if (!mMirrored)
numControlPoints = 1; numControlPoints = 1;
const int deltaXSquared = SQR(x - (event.m_x - r.x)); const int deltaXSquared = SQR(x - (event.m_x - r.x));
@ -400,7 +469,7 @@ bool Envelope::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
} }
if (bestNum >= 0) { if (bestNum >= 0) {
mDragPoint = bestNum; mEnvelope.SetDragPoint(bestNum);
} }
else { else {
// TODO: Extract this into a function CreateNewPoint // TODO: Extract this into a function CreateNewPoint
@ -409,13 +478,13 @@ bool Envelope::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
// if (when <= 0 || when >= mTrackLen) // if (when <= 0 || when >= mTrackLen)
// return false; // return false;
const double v = GetValue( when ); const double v = mEnvelope.GetValue( when );
int ct = GetWaveYPos( v, zoomMin, zoomMax, r.height, dB, int ct = GetWaveYPos( v, zoomMin, zoomMax, r.height, dB,
false, dBRange, false) ; false, dBRange, false) ;
int cb = GetWaveYPos( -v-.000000001, zoomMin, zoomMax, r.height, dB, int cb = GetWaveYPos( -v-.000000001, zoomMin, zoomMax, r.height, dB,
false, dBRange, false) ; false, dBRange, false) ;
if( ct <= cb || !mMirror ){ if (ct <= cb || !mMirrored) {
int t = GetWaveYPos( v, zoomMin, zoomMax, r.height, dB, int t = GetWaveYPos( v, zoomMin, zoomMax, r.height, dB,
true, dBRange, false) ; true, dBRange, false) ;
int b = GetWaveYPos( -v, zoomMin, zoomMax, r.height, dB, int b = GetWaveYPos( -v, zoomMin, zoomMax, r.height, dB,
@ -424,7 +493,7 @@ bool Envelope::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
ct = (t + ct) / 2; ct = (t + ct) / 2;
cb = (b + cb) / 2; cb = (b + cb) / 2;
if(mMirror && if (mMirrored &&
(event.m_y - r.y) > ct && (event.m_y - r.y) > ct &&
((event.m_y - r.y) < cb)) ((event.m_y - r.y) < cb))
mContourOffset = true; mContourOffset = true;
@ -435,50 +504,22 @@ bool Envelope::HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
double newVal = ValueOfPixel(clip_y, r.height, upper, dB, dBRange, double newVal = ValueOfPixel(clip_y, r.height, upper, dB, dBRange,
zoomMin, zoomMax); zoomMin, zoomMax);
mDragPoint = Insert(when - mOffset, newVal); mEnvelope.SetDragPoint(mEnvelope.Insert(when - mEnvelope.GetOffset(), newVal));
mDirty = true; mDirty = true;
} }
mUpper = upper; mUpper = upper;
mInitialVal = mEnv[mDragPoint].GetVal(); // const int dragPoint = mEnvelope.GetDragPoint();
// mInitialVal = mEnvelope[dragPoint].GetVal();
mInitialY = event.m_y+mContourOffset; // mInitialY = event.m_y+mContourOffset;
return true; return true;
} }
/// Mark dragged point for deletion. void EnvelopeEditor::MoveDragPoint(const wxMouseEvent & event, wxRect & r,
/// It will be deleted on mouse button up. const ZoomInfo &zoomInfo, bool dB, double dBRange,
void Envelope::MarkDragPointForDeletion() float zoomMin, float zoomMax)
{
mIsDeleting = true;
// We're going to be deleting the point; On
// screen we show this by having the envelope move to
// the position it will have after deletion of the point.
// Without delting the point we move it left or right
// to the same position as the previous or next point.
if( mEnv.size() <= 1)
{
// There is only one point - just move it
// off screen and at default height.
// temporary state when dragging only!
mEnv[mDragPoint].SetT(-1000000.0);
mEnv[mDragPoint].SetVal(mDefaultValue);
return;
}
// Place it exactly on one of its neighbours.
int iNeighbourPoint = mDragPoint + ((mDragPoint > 0) ? -1:+1);
mEnv[mDragPoint].SetT(mEnv[iNeighbourPoint].GetT());
mEnv[mDragPoint].SetVal(mEnv[iNeighbourPoint].GetVal());
}
void Envelope::MoveDraggedPoint( const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax)
{ {
int clip_y = event.m_y - r.y; int clip_y = event.m_y - r.y;
if(clip_y < 0) clip_y = 0; if(clip_y < 0) clip_y = 0;
@ -491,29 +532,14 @@ void Envelope::MoveDraggedPoint( const wxMouseEvent & event, wxRect & r,
// TODO: However because mTrackEpsilon assumes 200KHz this use // TODO: However because mTrackEpsilon assumes 200KHz this use
// of epsilon is a tad bogus. What we need to do instead is DELETE // of epsilon is a tad bogus. What we need to do instead is DELETE
// a duplicated point on a mouse up. // a duplicated point on a mouse up.
double newWhen = zoomInfo.PositionToTime(event.m_x, r.x) - mOffset; double newWhen = zoomInfo.PositionToTime(event.m_x, r.x) - mEnvelope.GetOffset();
mEnvelope.MoveDragPoint(newWhen, newVal);
// We'll limit the drag point time to be between those of the preceding
// and next envelope point.
double limitLo = 0.0;
double limitHi = mTrackLen;
if (mDragPoint > 0)
limitLo = mEnv[mDragPoint - 1].GetT() + mTrackEpsilon;
if (mDragPoint < (int)mEnv.size() - 1 )
limitHi = mEnv[mDragPoint + 1].GetT() - mTrackEpsilon;
newWhen = Limit( limitLo, newWhen, limitHi );
newWhen = Limit( mTrackEpsilon, newWhen, mTrackLen - mTrackEpsilon);
mEnv[mDragPoint].SetT(newWhen);
mEnv[mDragPoint].SetVal(newVal);
} }
bool Envelope::HandleDragging( const wxMouseEvent & event, wxRect & r, bool EnvelopeEditor::HandleDragging(const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange, const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax) float zoomMin, float zoomMax,
float WXUNUSED(eMin), float WXUNUSED(eMax))
{ {
mDirty = true; mDirty = true;
@ -523,27 +549,24 @@ bool Envelope::HandleDragging( const wxMouseEvent & event, wxRect & r,
if (larger.Contains(event.m_x, event.m_y)) if (larger.Contains(event.m_x, event.m_y))
{ {
// IF we're in the rect THEN we're not deleting this point (anymore). // IF we're in the rect THEN we're not deleting this point (anymore).
mIsDeleting = false;
// ...we're dragging it. // ...we're dragging it.
MoveDraggedPoint( event, r, zoomInfo, dB, dBRange, zoomMin, zoomMax); MoveDragPoint( event, r, zoomInfo, dB, dBRange, zoomMin, zoomMax);
return true; return true;
} }
if(mIsDeleting ) if(!mEnvelope.GetDragPointValid())
// IF we already know we're deleting THEN no envelope point to update. // IF we already know we're deleting THEN no envelope point to update.
return false; return false;
MarkDragPointForDeletion(); // Invalidate the point
mEnvelope.SetDragPointValid(false);
return true; return true;
} }
// Exit dragging mode and deletes dragged point if neccessary. // Exit dragging mode and delete dragged point if neccessary.
bool Envelope::HandleMouseButtonUp() bool EnvelopeEditor::HandleMouseButtonUp()
{ {
if (mIsDeleting) { mEnvelope.ClearDragPoint();
Delete(mDragPoint);
}
mDragPoint = -1;
mButton = wxMOUSE_BTN_NONE; mButton = wxMOUSE_BTN_NONE;
return true; return true;
} }
@ -559,14 +582,14 @@ void Envelope::Insert(int point, const EnvPoint &p)
} }
// Returns true if parent needs to be redrawn // Returns true if parent needs to be redrawn
bool Envelope::MouseEvent(const wxMouseEvent & event, wxRect & r, bool EnvelopeEditor::MouseEvent(const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange, const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax) float zoomMin, float zoomMax)
{ {
if (event.ButtonDown() && mButton == wxMOUSE_BTN_NONE) if (event.ButtonDown() && mButton == wxMOUSE_BTN_NONE)
return HandleMouseButtonDown( event, r, zoomInfo, dB, dBRange, return HandleMouseButtonDown( event, r, zoomInfo, dB, dBRange,
zoomMin, zoomMax); zoomMin, zoomMax);
if (event.Dragging() && mDragPoint >= 0) if (event.Dragging() && mEnvelope.GetDragPoint() >= 0)
return HandleDragging( event, r, zoomInfo, dB, dBRange, return HandleDragging( event, r, zoomInfo, dB, dBRange,
zoomMin, zoomMax); zoomMin, zoomMax);
if (event.ButtonUp() && event.GetButton() == mButton) if (event.ButtonUp() && event.GetButton() == mButton)
@ -1523,7 +1546,6 @@ void Envelope::testMe()
double t0=0, t1=0; double t0=0, t1=0;
SetInterpolateDB(false); SetInterpolateDB(false);
Mirror(false);
Flatten(0.5); Flatten(0.5);
checkResult( 1, Integral(0.0,100.0), 50); checkResult( 1, Integral(0.0,100.0), 50);
@ -1575,3 +1597,18 @@ void Envelope::testMe()
checkResult( 19, NextPointAfter( 5 ), 10 ); checkResult( 19, NextPointAfter( 5 ), 10 );
} }
EnvelopeEditor::EnvelopeEditor(Envelope &envelope, bool mirrored)
: mEnvelope(envelope)
, mMirrored(mirrored)
, mContourOffset(-1)
// , mInitialVal(-1.0)
// , mInitialY(-1)
, mUpper(false)
, mButton(wxMOUSE_BTN_NONE)
, mDirty(false)
{
}
EnvelopeEditor::~EnvelopeEditor()
{
}

View File

@ -81,13 +81,14 @@ class Envelope final : public XMLTagHandler {
virtual ~ Envelope(); virtual ~ Envelope();
double GetOffset() const { return mOffset; }
double GetTrackLen() const { return mTrackLen; }
bool GetInterpolateDB() { return mDB; } bool GetInterpolateDB() { return mDB; }
void SetInterpolateDB(bool db) { mDB = db; } void SetInterpolateDB(bool db) { mDB = db; }
void Mirror(bool mirror);
void Rescale(double minValue, double maxValue); void Rescale(double minValue, double maxValue);
void Flatten(double value); void Flatten(double value);
int GetDragPoint(void) {return mDragPoint;}
double GetMinValue() const { return mMinValue; } double GetMinValue() const { return mMinValue; }
double GetMaxValue() const { return mMaxValue; } double GetMaxValue() const { return mMaxValue; }
@ -107,21 +108,8 @@ class Envelope final : public XMLTagHandler {
void WriteXML(XMLWriter &xmlFile) const /* not override */; void WriteXML(XMLWriter &xmlFile) const /* not override */;
void DrawPoints(wxDC & dc, const wxRect & r, const ZoomInfo &zoomInfo, void DrawPoints(wxDC & dc, const wxRect & r, const ZoomInfo &zoomInfo,
bool dB, double dBRange, bool dB, double dBRange,
float zoomMin, float zoomMax) const; float zoomMin, float zoomMax, bool mirrored) const;
// Event Handlers
// Each ofthese returns true if parents needs to be redrawn
bool MouseEvent(const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
bool HandleMouseButtonDown( const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
bool HandleDragging( const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
bool HandleMouseButtonUp();
// Handling Cut/Copy/Paste events // Handling Cut/Copy/Paste events
void CollapseRegion(double t0, double t1); void CollapseRegion(double t0, double t1);
@ -181,28 +169,38 @@ class Envelope final : public XMLTagHandler {
/** \brief Return number of points */ /** \brief Return number of points */
size_t GetNumberOfPoints() const; size_t GetNumberOfPoints() const;
private:
friend class EnvelopeEditor;
/** \brief Accessor for points */ /** \brief Accessor for points */
const EnvPoint &operator[] (int index) const EnvPoint &operator[] (int index)
{ {
return mEnv[index]; return mEnv[index];
} }
public:
/** \brief Returns the sets of when and value pairs */ /** \brief Returns the sets of when and value pairs */
void GetPoints(double *bufferWhen, void GetPoints(double *bufferWhen,
double *bufferValue, double *bufferValue,
int bufferLen) const; int bufferLen) const;
// UI-related
// The drag point needs to display differently.
int GetDragPoint() const { return mDragPoint; }
// Choose the drag point.
void SetDragPoint(int dragPoint);
// Mark or unmark the drag point for deletion.
void SetDragPointValid(bool valid);
bool GetDragPointValid() const { return mDragPointValid; }
// Modify the dragged point and change its value.
// But consistency constraints may move it less then you ask for.
void MoveDragPoint(double newWhen, double value);
// May delete the drag point. Restores envelope consistency.
void ClearDragPoint();
private: private:
EnvPoint * AddPointAtEnd( double t, double val ); EnvPoint * AddPointAtEnd( double t, double val );
void MarkDragPointForDeletion();
float ValueOfPixel( int y, int height, bool upper,
bool dB, double dBRange,
float zoomMin, float zoomMax);
void BinarySearchForTime( int &Lo, int &Hi, double t ) const; void BinarySearchForTime( int &Lo, int &Hi, double t ) const;
double GetInterpolationStartValueAtPoint( int iPoint ) const; double GetInterpolationStartValueAtPoint( int iPoint ) const;
void MoveDraggedPoint( const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
// Possibly inline functions: // Possibly inline functions:
// This function resets them integral memoizers (call whenever the Envelope changes) // This function resets them integral memoizers (call whenever the Envelope changes)
@ -210,7 +208,6 @@ private:
// The list of envelope control points. // The list of envelope control points.
EnvArray mEnv; EnvArray mEnv;
bool mMirror;
/** \brief The time at which the envelope starts, i.e. the start offset */ /** \brief The time at which the envelope starts, i.e. the start offset */
double mOffset; double mOffset;
@ -224,21 +221,7 @@ private:
* before being considered the same point */ * before being considered the same point */
double mTrackEpsilon; double mTrackEpsilon;
double mDefaultValue; double mDefaultValue;
/** \brief Number of pixels contour is from the true envelope. */
int mContourOffset;
double mInitialVal;
// These are used in dragging.
int mDragPoint;
int mInitialY;
bool mUpper;
bool mIsDeleting;
int mButton;
bool mDB; bool mDB;
bool mDirty;
double mMinValue, mMaxValue; double mMinValue, mMaxValue;
// These are memoizing variables for Integral() // These are memoizing variables for Integral()
@ -246,8 +229,11 @@ private:
double lastIntegral_t1; double lastIntegral_t1;
double lastIntegral_result; double lastIntegral_result;
mutable int mSearchGuess; // UI stuff
bool mDragPointValid;
int mDragPoint;
mutable int mSearchGuess;
}; };
inline EnvPoint::EnvPoint(Envelope *envelope, double t, double val) inline EnvPoint::EnvPoint(Envelope *envelope, double t, double val)
@ -262,5 +248,49 @@ inline void EnvPoint::SetVal(double val)
mVal = mEnvelope->ClampValue(val); mVal = mEnvelope->ClampValue(val);
} }
#endif // A class that holds state for the duration of dragging
// of an envelope point.
class EnvelopeEditor
{
public:
EnvelopeEditor(Envelope &envelope, bool mirrored);
~EnvelopeEditor();
// Event Handlers
// Each of these returns true if the envelope needs to be redrawn
bool MouseEvent(const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin = -1.0, float zoomMax = 1.0);
private:
bool HandleMouseButtonDown(const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin = -1.0, float zoomMax = 1.0);
bool HandleDragging(const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin = -1.0, float zoomMax = 1.0, float eMin = 0., float eMax = 2.);
bool HandleMouseButtonUp();
private:
float ValueOfPixel(int y, int height, bool upper,
bool dB, double dBRange,
float zoomMin, float zoomMax);
void MoveDragPoint(const wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
Envelope &mEnvelope;
const bool mMirrored;
/** \brief Number of pixels contour is from the true envelope. */
int mContourOffset;
// double mInitialVal;
// int mInitialY;
bool mUpper;
int mButton;
bool mDirty;
};
#endif

View File

@ -48,7 +48,6 @@ TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const Zo
mEnvelope->SetTrackLen(DBL_MAX); mEnvelope->SetTrackLen(DBL_MAX);
mEnvelope->SetInterpolateDB(true); mEnvelope->SetInterpolateDB(true);
mEnvelope->Flatten(1.0); mEnvelope->Flatten(1.0);
mEnvelope->Mirror(false);
mEnvelope->SetOffset(0); mEnvelope->SetOffset(0);
mEnvelope->SetRange(TIMETRACK_MIN, TIMETRACK_MAX); mEnvelope->SetRange(TIMETRACK_MIN, TIMETRACK_MAX);
@ -75,7 +74,6 @@ TimeTrack::TimeTrack(const TimeTrack &orig):
mEnvelope->SetTrackLen(DBL_MAX); mEnvelope->SetTrackLen(DBL_MAX);
SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB
mEnvelope->Flatten(1.0); mEnvelope->Flatten(1.0);
mEnvelope->Mirror(false);
mEnvelope->SetOffset(0); mEnvelope->SetOffset(0);
mEnvelope->SetRange(orig.mEnvelope->GetMinValue(), orig.mEnvelope->GetMaxValue()); mEnvelope->SetRange(orig.mEnvelope->GetMinValue(), orig.mEnvelope->GetMaxValue());
mEnvelope->Paste(0.0, orig.mEnvelope.get()); mEnvelope->Paste(0.0, orig.mEnvelope.get());

View File

@ -1926,7 +1926,7 @@ void TrackArtist::DrawClipWaveform(const WaveTrack *track,
if (drawEnvelope) { if (drawEnvelope) {
DrawEnvelope(dc, mid, env, zoomMin, zoomMax, dB, dBRange); DrawEnvelope(dc, mid, env, zoomMin, zoomMax, dB, dBRange);
clip->GetEnvelope()->DrawPoints(dc, rect, zoomInfo, dB, dBRange, zoomMin, zoomMax); clip->GetEnvelope()->DrawPoints(dc, rect, zoomInfo, dB, dBRange, zoomMin, zoomMax, true);
} }
// Draw arrows on the left side if the track extends to the left of the // Draw arrows on the left side if the track extends to the left of the
@ -3209,7 +3209,7 @@ void TrackArtist::DrawTimeTrack(const TimeTrack *track,
upper = LINEAR_TO_DB(std::max(1.0e-7, upper)) / mdBrange + 1.0; upper = LINEAR_TO_DB(std::max(1.0e-7, upper)) / mdBrange + 1.0;
} }
track->GetEnvelope()->DrawPoints(dc, envRect, zoomInfo, track->GetEnvelope()->DrawPoints(dc, envRect, zoomInfo,
track->GetDisplayLog(), mdBrange, lower, upper); track->GetDisplayLog(), mdBrange, lower, upper, false);
} }
void TrackArtist::UpdatePrefs() void TrackArtist::UpdatePrefs()

View File

@ -3213,8 +3213,13 @@ void TrackPanel::ForwardEventToTimeTrackEnvelope(wxMouseEvent & event)
lower = LINEAR_TO_DB(std::max(1.0e-7, lower)) / dBRange + 1.0; lower = LINEAR_TO_DB(std::max(1.0e-7, lower)) / dBRange + 1.0;
upper = LINEAR_TO_DB(std::max(1.0e-7, upper)) / dBRange + 1.0; upper = LINEAR_TO_DB(std::max(1.0e-7, upper)) / dBRange + 1.0;
} }
if (event.ButtonDown()) {
mEnvelopeEditor = std::make_unique<EnvelopeEditor>(*pspeedenvelope, false);
mEnvelopeEditorRight.reset();
}
bool needUpdate = bool needUpdate =
pspeedenvelope->MouseEvent( mEnvelopeEditor &&
mEnvelopeEditor->MouseEvent(
event, envRect, event, envRect,
*mViewInfo, *mViewInfo,
ptimetrack->GetDisplayLog(), dBRange, lower, upper); ptimetrack->GetDisplayLog(), dBRange, lower, upper);
@ -3250,7 +3255,13 @@ void TrackPanel::ForwardEventToWaveTrackEnvelope(wxMouseEvent & event)
wxRect envRect = mCapturedRect; wxRect envRect = mCapturedRect;
float zoomMin, zoomMax; float zoomMin, zoomMax;
pwavetrack->GetDisplayBounds(&zoomMin, &zoomMax); pwavetrack->GetDisplayBounds(&zoomMin, &zoomMax);
needUpdate = penvelope->MouseEvent( if (event.ButtonDown()) {
mEnvelopeEditor = std::make_unique<EnvelopeEditor>(*penvelope, true);
mEnvelopeEditorRight.reset();
}
needUpdate =
mEnvelopeEditor &&
mEnvelopeEditor->MouseEvent(
event, envRect, event, envRect,
*mViewInfo, *mViewInfo,
dB, dBRange, zoomMin, zoomMax); dB, dBRange, zoomMin, zoomMax);
@ -3260,30 +3271,23 @@ void TrackPanel::ForwardEventToWaveTrackEnvelope(wxMouseEvent & event)
// Assume linked track is wave or null // Assume linked track is wave or null
const auto link = static_cast<WaveTrack *>(mCapturedTrack->GetLink()); const auto link = static_cast<WaveTrack *>(mCapturedTrack->GetLink());
if (link) { if (link) {
Envelope *e2 = link->GetEnvelopeAtX(event.GetX()); if (event.ButtonDown()) {
// There isn't necessarily an envelope there; no guarantee a Envelope *e2 = link->GetEnvelopeAtX(event.GetX());
// linked track has the same WaveClip structure... if (e2)
bool updateNeeded = false; mEnvelopeEditorRight = std::make_unique<EnvelopeEditor>(*e2, true);
if (e2) { else {
// There isn't necessarily an envelope there; no guarantee a
// linked track has the same WaveClip structure...
}
}
if (mEnvelopeEditorRight) {
wxRect envRect = mCapturedRect; wxRect envRect = mCapturedRect;
float zoomMin, zoomMax; float zoomMin, zoomMax;
pwavetrack->GetDisplayBounds(&zoomMin, &zoomMax); pwavetrack->GetDisplayBounds(&zoomMin, &zoomMax);
updateNeeded = e2->MouseEvent(event, envRect, needUpdate|= mEnvelopeEditorRight->MouseEvent(event, envRect,
*mViewInfo, dB, dBRange, *mViewInfo,
zoomMin, zoomMax); dB, dBRange,
needUpdate |= updateNeeded; zoomMin, zoomMax);
}
if(!e2 || !updateNeeded) // no envelope found at this x point, or found but not updated
{
if( (e2 = link->GetActiveEnvelope()) != 0 ) // search for any active DragPoint
{
wxRect envRect = mCapturedRect;
float zoomMin, zoomMax;
pwavetrack->GetDisplayBounds(&zoomMin, &zoomMax);
needUpdate |= e2->MouseEvent(event, envRect,
*mViewInfo, dB, dBRange,
zoomMin, zoomMax);
}
} }
} }

View File

@ -30,6 +30,7 @@
class wxMenu; class wxMenu;
class wxRect; class wxRect;
class EnvelopeEditor;
class LabelTrack; class LabelTrack;
class SpectrumAnalyst; class SpectrumAnalyst;
class TrackPanel; class TrackPanel;
@ -809,6 +810,9 @@ protected:
// Keeps track of extra fractional vertical scroll steps // Keeps track of extra fractional vertical scroll steps
double mVertScrollRemainder; double mVertScrollRemainder;
std::unique_ptr<EnvelopeEditor> mEnvelopeEditor;
std::unique_ptr<EnvelopeEditor> mEnvelopeEditorRight;
protected: protected:
// The screenshot class needs to access internals // The screenshot class needs to access internals

View File

@ -2228,18 +2228,6 @@ Envelope* WaveTrack::GetEnvelopeAtX(int xcoord)
return NULL; return NULL;
} }
// Search for any active DragPoint on the current track
Envelope* WaveTrack::GetActiveEnvelope(void)
{
for (const auto &clip : mClips)
{
Envelope* env = clip->GetEnvelope() ;
if (env->GetDragPoint() >= 0)
return env;
}
return NULL;
}
Sequence* WaveTrack::GetSequenceAtX(int xcoord) Sequence* WaveTrack::GetSequenceAtX(int xcoord)
{ {
WaveClip* clip = GetClipAtX(xcoord); WaveClip* clip = GetClipAtX(xcoord);

View File

@ -264,7 +264,6 @@ class AUDACITY_DLL_API WaveTrack final : public Track {
WaveClip* GetClipAtX(int xcoord); WaveClip* GetClipAtX(int xcoord);
Sequence* GetSequenceAtX(int xcoord); Sequence* GetSequenceAtX(int xcoord);
Envelope* GetEnvelopeAtX(int xcoord); Envelope* GetEnvelopeAtX(int xcoord);
Envelope* GetActiveEnvelope(void);
WaveClip* GetClipAtSample(sampleCount sample); WaveClip* GetClipAtSample(sampleCount sample);

View File

@ -241,12 +241,10 @@ EffectEqualization::EffectEqualization()
mLogEnvelope = std::make_unique<Envelope>(); mLogEnvelope = std::make_unique<Envelope>();
mLogEnvelope->SetInterpolateDB(false); mLogEnvelope->SetInterpolateDB(false);
mLogEnvelope->Mirror(false);
mLogEnvelope->SetRange(MIN_dBMin, MAX_dBMax); // MB: this is the highest possible range mLogEnvelope->SetRange(MIN_dBMin, MAX_dBMax); // MB: this is the highest possible range
mLinEnvelope = std::make_unique<Envelope>(); mLinEnvelope = std::make_unique<Envelope>();
mLinEnvelope->SetInterpolateDB(false); mLinEnvelope->SetInterpolateDB(false);
mLinEnvelope->Mirror(false);
mLinEnvelope->SetRange(MIN_dBMin, MAX_dBMax); // MB: this is the highest possible range mLinEnvelope->SetRange(MIN_dBMin, MAX_dBMax); // MB: this is the highest possible range
mEnvelope = (mLin ? mLinEnvelope : mLogEnvelope).get(); mEnvelope = (mLin ? mLinEnvelope : mLogEnvelope).get();
@ -2365,7 +2363,6 @@ void EffectEqualization::ErrMin(void)
int j=0; int j=0;
Envelope testEnvelope; Envelope testEnvelope;
testEnvelope.SetInterpolateDB(false); testEnvelope.SetInterpolateDB(false);
testEnvelope.Mirror(false);
testEnvelope.SetRange(-120.0, 60.0); testEnvelope.SetRange(-120.0, 60.0);
testEnvelope.Flatten(0.); testEnvelope.Flatten(0.);
testEnvelope.SetTrackLen(1.0); testEnvelope.SetTrackLen(1.0);
@ -2893,8 +2890,8 @@ EqualizationPanel::EqualizationPanel(EffectEqualization *effect, wxWindow *paren
mWidth = 0; mWidth = 0;
mHeight = 0; mHeight = 0;
mEditor = std::make_unique<EnvelopeEditor>(*mEffect->mEnvelope, false);
mEffect->mEnvelope->Flatten(0.); mEffect->mEnvelope->Flatten(0.);
mEffect->mEnvelope->Mirror(false);
mEffect->mEnvelope->SetTrackLen(1.0); mEffect->mEnvelope->SetTrackLen(1.0);
ForceRecalc(); ForceRecalc();
@ -3103,7 +3100,7 @@ void EqualizationPanel::OnPaint(wxPaintEvent & WXUNUSED(event))
if( mEffect->mDraw->GetValue() ) if( mEffect->mDraw->GetValue() )
{ {
mEffect->mEnvelope->DrawPoints(memDC, mEnvRect, ZoomInfo(0.0, mEnvRect.width-1), false, 0.0, mEffect->mEnvelope->DrawPoints(memDC, mEnvRect, ZoomInfo(0.0, mEnvRect.width-1), false, 0.0,
mEffect->mdBMin, mEffect->mdBMax); mEffect->mdBMin, mEffect->mdBMax, false);
} }
dc.Blit(0, 0, mWidth, mHeight, &memDC, 0, 0, wxCOPY, FALSE); dc.Blit(0, 0, mWidth, mHeight, &memDC, 0, 0, wxCOPY, FALSE);
@ -3121,7 +3118,7 @@ void EqualizationPanel::OnMouseEvent(wxMouseEvent & event)
CaptureMouse(); CaptureMouse();
} }
if (mEffect->mEnvelope->MouseEvent(event, mEnvRect, ZoomInfo(0.0, mEnvRect.width), if (mEditor->MouseEvent(event, mEnvRect, ZoomInfo(0.0, mEnvRect.width),
false, 0.0, false, 0.0,
mEffect->mdBMin, mEffect->mdBMax)) mEffect->mdBMin, mEffect->mdBMax))
{ {

View File

@ -46,6 +46,7 @@
class Envelope; class Envelope;
class EnvelopeEditor;
class EqualizationPanel; class EqualizationPanel;
// //
@ -308,6 +309,7 @@ public:
private: private:
wxWindow *mParent; wxWindow *mParent;
EffectEqualization *mEffect; EffectEqualization *mEffect;
std::unique_ptr<EnvelopeEditor> mEditor;
bool mRecalcRequired; bool mRecalcRequired;

View File

@ -45,7 +45,6 @@
#include "NoiseRemoval.h" #include "NoiseRemoval.h"
#include "../Envelope.h"
#include "../WaveTrack.h" #include "../WaveTrack.h"
#include "../Prefs.h" #include "../Prefs.h"
#include "../Project.h" #include "../Project.h"
@ -883,4 +882,4 @@ void NoiseRemovalDialog::OnTimeSlider(wxCommandEvent & WXUNUSED(event))
mTimeT->SetValue(wxString::Format(wxT("%.2f"), mTime)); mTimeT->SetValue(wxString::Format(wxT("%.2f"), mTime));
} }
#endif #endif