1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-22 07:28:03 +02:00
audacity/src/Envelope.h
Paul Licameli cf45a58fdc dB range is now in Waveforms preferences and view settings, and ...
... the preference is independent of those in Interface and Recording
preferences, which affect meters, sound activated recordings, time track,
and Plot Spectrum
2015-08-15 18:07:29 -04:00

259 lines
7.6 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
Envelope.h
Dominic Mazzoni
**********************************************************************/
#ifndef __AUDACITY_ENVELOPE__
#define __AUDACITY_ENVELOPE__
#include <stdlib.h>
#include <algorithm>
#include <wx/dynarray.h>
#include <wx/brush.h>
#include <wx/pen.h>
#include "xml/XMLTagHandler.h"
#include "Internat.h"
class wxRect;
class wxDC;
class wxMouseEvent;
class wxTextFile;
class DirManager;
class Envelope;
class ZoomInfo;
class EnvPoint : public XMLTagHandler {
public:
EnvPoint(Envelope *envelope, double t, double val)
{
mEnvelope = envelope;
mT = t;
mVal = ClampValue(val);
}
double ClampValue(double val); // this calls mEnvelope->ClampValue(), implementation is below the Envelope class
double GetT() { return mT; }
void SetT(double t) { mT = t; }
double GetVal() { return mVal; }
void SetVal(double val) { mVal = ClampValue(val); }
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs)
{
if (!wxStrcmp(tag, wxT("controlpoint"))) {
while (*attrs) {
const wxChar *attr = *attrs++;
const wxChar *value = *attrs++;
if (!wxStrcmp(attr, wxT("t")))
SetT(Internat::CompatibleToDouble(value));
else if (!wxStrcmp(attr, wxT("val")))
SetVal(Internat::CompatibleToDouble(value));
}
return true;
}
else
return false;
}
XMLTagHandler *HandleXMLChild(const wxChar * WXUNUSED(tag))
{
return NULL;
}
private:
Envelope *mEnvelope;
double mT;
double mVal;
};
// TODO: Become an array of EnvPoint rather than of pointers to.
// Really? wxWidgets help says:
// "wxArray is suitable for storing integer types and pointers which it does not
// treat as objects in any way..."
// And why is this a TODO in any case, if it works correctly?
WX_DEFINE_ARRAY(EnvPoint *, EnvArray);
class Envelope : public XMLTagHandler {
public:
Envelope();
void Initialize(int numPoints);
virtual ~ Envelope();
bool GetInterpolateDB() { return mDB; }
void SetInterpolateDB(bool db) { mDB = db; }
void Mirror(bool mirror);
void Rescale(double minValue, double maxValue);
void Flatten(double value);
int GetDragPoint(void) {return mDragPoint;}
double GetMinValue() const { return mMinValue; }
double GetMaxValue() const { return mMaxValue; }
void SetRange(double minValue, double maxValue);
double ClampValue(double value) { return std::max(mMinValue, std::min(mMaxValue, value)); }
#if LEGACY_PROJECT_FILE_SUPPORT
// File I/O
virtual bool Load(wxTextFile * in, DirManager * dirManager);
virtual bool Save(wxTextFile * out, bool overwrite);
#endif
// Newfangled XML file I/O
virtual bool HandleXMLTag(const wxChar *tag, const wxChar **attrs);
virtual XMLTagHandler *HandleXMLChild(const wxChar *tag);
virtual void WriteXML(XMLWriter &xmlFile);
void DrawPoints(wxDC & dc, const wxRect & r, const ZoomInfo &zoomInfo,
bool dB, double dBRange,
float zoomMin, float zoomMax);
// Event Handlers
// Each ofthese returns true if parents needs to be redrawn
bool MouseEvent(wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
bool HandleMouseButtonDown( wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
bool HandleDragging( wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
bool HandleMouseButtonUp();
// Handling Cut/Copy/Paste events
void CollapseRegion(double t0, double t1);
void CopyFrom(const Envelope * e, double t0, double t1);
void Paste(double t0, const Envelope *e);
void InsertSpace(double t0, double tlen);
void RemoveUnneededPoints(double time = -1, double tolerence = 0.001);
// Control
void SetOffset(double newOffset);
void SetTrackLen(double trackLen);
// Accessors
/** \brief Get envelope value at time t */
double GetValue(double t) const;
/** \brief 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. */
void GetValues(double *buffer, int len, double t0, double tstep) const;
/** \brief Get many envelope points at once, but don't assume uniform time step.
*/
void GetValues
(double *buffer, int bufferLen, int leftOffset, const ZoomInfo &zoomInfo) const;
int NumberOfPointsAfter(double t);
double NextPointAfter(double t);
double Average( double t0, double t1 );
double AverageOfInverse( double t0, double t1 );
double Integral( double t0, double t1 );
double IntegralOfInverse( double t0, double t1 );
double SolveIntegralOfInverse( double t0, double area);
void print();
void testMe();
bool IsDirty() const;
/** \brief Add a point at a particular spot */
int Insert(double when, double value);
/** \brief Move a point at when to value
*
* Returns 0 if point moved, -1 if not found.*/
int Move(double when, double value);
/** \brief delete a point by it's position in array */
void Delete(int point);
/** \brief Return number of points */
int GetNumberOfPoints() const;
/** \brief Returns the sets of when and value pairs */
void GetPoints(double *bufferWhen,
double *bufferValue,
int bufferLen) const;
private:
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;
double GetInterpolationStartValueAtPoint( int iPoint ) const;
void MoveDraggedPoint( wxMouseEvent & event, wxRect & r,
const ZoomInfo &zoomInfo, bool dB, double dBRange,
float zoomMin, float zoomMax);
// Possibly inline functions:
// This function resets them integral memoizers (call whenever the Envelope changes)
void resetIntegralMemoizer() { lastIntegral_t0=0; lastIntegral_t1=0; lastIntegral_result=0; }
// The list of envelope control points.
EnvArray mEnv;
bool mMirror;
/** \brief The time at which the envelope starts, i.e. the start offset */
double mOffset;
/** \brief The length of the envelope, which is the same as the length of the
* underlying track (normally) */
double mTrackLen;
// TODO: mTrackEpsilon based on assumption of 200KHz. Needs review if/when
// we support higher sample rates.
/** \brief The shortest distance appart that points on an envelope can be
* before being considered the same point */
double mTrackEpsilon;
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 mDirty;
double mMinValue, mMaxValue;
// These are memoizing variables for Integral()
double lastIntegral_t0;
double lastIntegral_t1;
double lastIntegral_result;
mutable int mSearchGuess;
};
inline double EnvPoint::ClampValue(double val)
{
return mEnvelope->ClampValue(val);
}
#endif