2014-10-03 06:15:29 +00:00
|
|
|
/**********************************************************************
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
|
|
|
|
Meter.h
|
|
|
|
|
|
|
|
Dominic Mazzoni
|
|
|
|
|
|
|
|
VU Meter, for displaying recording/playback level
|
|
|
|
|
|
|
|
This is a bunch of common code that can display many different
|
|
|
|
forms of VU meters and other displays.
|
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
#ifndef __AUDACITY_METER__
|
|
|
|
#define __AUDACITY_METER__
|
|
|
|
|
2019-03-23 18:28:37 +00:00
|
|
|
#include <wx/setup.h> // for wxUSE_* macros
|
2018-11-14 19:10:04 +00:00
|
|
|
#include <wx/brush.h> // member variable
|
2019-03-23 18:28:37 +00:00
|
|
|
#include <wx/defs.h>
|
2018-11-14 16:48:46 +00:00
|
|
|
#include <wx/timer.h> // member variable
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
#include "../SampleFormat.h"
|
2018-02-17 22:42:14 +00:00
|
|
|
#include "../Prefs.h"
|
2019-06-04 04:35:19 +00:00
|
|
|
#include "MeterPanelBase.h" // to inherit
|
2019-03-30 20:07:00 +00:00
|
|
|
#include "Ruler.h" // member variable
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2018-10-23 20:36:02 +00:00
|
|
|
class AudacityProject;
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
// Increase this when we add support for multichannel meters
|
|
|
|
// (most of the code is already there)
|
|
|
|
const int kMaxMeterBars = 2;
|
|
|
|
|
|
|
|
struct MeterBar {
|
|
|
|
bool vert;
|
2014-12-28 03:18:00 +00:00
|
|
|
wxRect b; // Bevel around bar
|
|
|
|
wxRect r; // True bar drawing area
|
2010-01-23 19:44:49 +00:00
|
|
|
float peak;
|
|
|
|
float rms;
|
|
|
|
float peakHold;
|
|
|
|
double peakHoldTime;
|
|
|
|
wxRect rClip;
|
|
|
|
bool clipping;
|
2010-11-19 05:15:08 +00:00
|
|
|
bool isclipping; //ANSWER-ME: What's the diff between these bools?! "clipping" vs "isclipping" is not clear.
|
2010-01-23 19:44:49 +00:00
|
|
|
int tailPeakCount;
|
|
|
|
float peakPeakHold;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MeterUpdateMsg
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int numFrames;
|
|
|
|
float peak[kMaxMeterBars];
|
|
|
|
float rms[kMaxMeterBars];
|
|
|
|
bool clipping[kMaxMeterBars];
|
|
|
|
int headPeakCount[kMaxMeterBars];
|
|
|
|
int tailPeakCount[kMaxMeterBars];
|
|
|
|
|
|
|
|
/* neither constructor nor destructor do anything */
|
2015-07-05 15:22:03 +00:00
|
|
|
MeterUpdateMsg() { }
|
|
|
|
~MeterUpdateMsg() { }
|
2010-01-23 19:44:49 +00:00
|
|
|
/* for debugging purposes, printing the values out is really handy */
|
|
|
|
/** \brief Print out all the values in the meter update message */
|
|
|
|
wxString toString();
|
|
|
|
/** \brief Only print meter updates if clipping may be happening */
|
|
|
|
wxString toStringIfClipped();
|
|
|
|
};
|
|
|
|
|
|
|
|
// Thread-safe queue of update messages
|
|
|
|
class MeterUpdateQueue
|
|
|
|
{
|
|
|
|
public:
|
2016-04-14 05:50:34 +00:00
|
|
|
explicit MeterUpdateQueue(size_t maxLen);
|
2010-01-23 19:44:49 +00:00
|
|
|
~MeterUpdateQueue();
|
|
|
|
|
|
|
|
bool Put(MeterUpdateMsg &msg);
|
|
|
|
bool Get(MeterUpdateMsg &msg);
|
|
|
|
|
|
|
|
void Clear();
|
|
|
|
|
|
|
|
private:
|
|
|
|
int mStart;
|
|
|
|
int mEnd;
|
2016-04-14 05:50:34 +00:00
|
|
|
size_t mBufferSize;
|
|
|
|
ArrayOf<MeterUpdateMsg> mBuffer{mBufferSize};
|
2010-01-23 19:44:49 +00:00
|
|
|
};
|
|
|
|
|
2015-01-04 09:24:26 +00:00
|
|
|
class MeterAx;
|
|
|
|
|
2018-02-21 19:25:22 +00:00
|
|
|
/********************************************************************//**
|
|
|
|
\brief MeterPanel is a panel that paints the meter used for monitoring
|
|
|
|
or playback.
|
|
|
|
************************************************************************/
|
2020-09-28 12:50:18 +00:00
|
|
|
class AUDACITY_DLL_API MeterPanel final
|
|
|
|
: public MeterPanelBase, private PrefsListener
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2018-02-21 19:25:22 +00:00
|
|
|
DECLARE_DYNAMIC_CLASS(MeterPanel)
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
// These should be kept in the same order as they appear
|
|
|
|
// in the menu
|
|
|
|
enum Style {
|
2014-12-28 03:18:00 +00:00
|
|
|
AutomaticStereo,
|
2010-01-23 19:44:49 +00:00
|
|
|
HorizontalStereo,
|
|
|
|
VerticalStereo,
|
2014-11-09 15:47:09 +00:00
|
|
|
MixerTrackCluster, // Doesn't show menu, icon, or L/R labels, but otherwise like VerticalStereo.
|
2014-12-28 03:18:00 +00:00
|
|
|
HorizontalStereoCompact, // Thinner.
|
|
|
|
VerticalStereoCompact, // Narrower.
|
2010-01-23 19:44:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-02-21 19:25:22 +00:00
|
|
|
MeterPanel(AudacityProject *,
|
2014-12-19 16:38:56 +00:00
|
|
|
wxWindow* parent, wxWindowID id,
|
2010-01-23 19:44:49 +00:00
|
|
|
bool isInput,
|
|
|
|
const wxPoint& pos = wxDefaultPosition,
|
2014-06-03 20:30:19 +00:00
|
|
|
const wxSize& size = wxDefaultSize,
|
|
|
|
Style style = HorizontalStereo,
|
2010-01-23 19:44:49 +00:00
|
|
|
float fDecayRate = 60.0f);
|
|
|
|
|
2016-06-25 04:06:22 +00:00
|
|
|
void SetFocusFromKbd() override;
|
2015-09-16 18:08:03 +00:00
|
|
|
|
2019-06-04 04:20:42 +00:00
|
|
|
void Clear() override;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2014-12-28 03:18:00 +00:00
|
|
|
Style GetStyle() const { return mStyle; }
|
|
|
|
Style GetDesiredStyle() const { return mDesiredStyle; }
|
2010-01-23 19:44:49 +00:00
|
|
|
void SetStyle(Style newStyle);
|
|
|
|
|
|
|
|
/** \brief
|
|
|
|
*
|
|
|
|
* This method is thread-safe! Feel free to call from a
|
|
|
|
* different thread (like from an audio I/O callback).
|
|
|
|
*/
|
2019-06-04 04:20:42 +00:00
|
|
|
void Reset(double sampleRate, bool resetClipping) override;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
/** \brief Update the meters with a block of audio data
|
|
|
|
*
|
|
|
|
* Process the supplied block of audio data, extracting the peak and RMS
|
|
|
|
* levels to send to the meter. Also record runs of clipped samples to detect
|
|
|
|
* clipping that lies on block boundaries.
|
|
|
|
* This method is thread-safe! Feel free to call from a different thread
|
|
|
|
* (like from an audio I/O callback).
|
|
|
|
*
|
|
|
|
* First overload:
|
|
|
|
* \param numChannels The number of channels of audio being played back or
|
|
|
|
* recorded.
|
|
|
|
* \param numFrames The number of frames (samples) in this data block. It is
|
|
|
|
* assumed that there are the same number of frames in each channel.
|
|
|
|
* \param sampleData The audio data itself, as interleaved samples. So
|
|
|
|
* indexing through the array we get the first sample of channel, first
|
|
|
|
* sample of channel 2 etc up to the first sample of channel (numChannels),
|
|
|
|
* then the second sample of channel 1, second sample of channel 2, and so
|
|
|
|
* to the second sample of channel (numChannels). The last sample in the
|
|
|
|
* array will be the (numFrames) sample for channel (numChannels).
|
|
|
|
*
|
|
|
|
* The second overload is for ease of use in MixerBoard.
|
|
|
|
*/
|
2016-09-02 19:53:09 +00:00
|
|
|
void UpdateDisplay(unsigned numChannels,
|
2019-06-04 04:20:42 +00:00
|
|
|
int numFrames, float *sampleData) override;
|
2014-12-28 03:18:00 +00:00
|
|
|
|
2010-11-29 22:36:32 +00:00
|
|
|
// Vaughan, 2010-11-29: This not currently used. See comments in MixerTrackCluster::UpdateMeter().
|
2014-06-03 20:30:19 +00:00
|
|
|
//void UpdateDisplay(int numChannels, int numFrames,
|
2010-11-29 22:36:32 +00:00
|
|
|
// // Need to make these double-indexed max and min arrays if we handle more than 2 channels.
|
2014-06-03 20:30:19 +00:00
|
|
|
// float* maxLeft, float* rmsLeft,
|
|
|
|
// float* maxRight, float* rmsRight,
|
2016-09-06 13:19:27 +00:00
|
|
|
// const size_t kSampleCount);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
/** \brief Find out if the level meter is disabled or not.
|
|
|
|
*
|
|
|
|
* This method is thread-safe! Feel free to call from a
|
|
|
|
* different thread (like from an audio I/O callback).
|
|
|
|
*/
|
2019-06-04 04:20:42 +00:00
|
|
|
bool IsMeterDisabled() const override;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2019-06-04 04:20:42 +00:00
|
|
|
float GetMaxPeak() const override;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2019-07-02 16:28:25 +00:00
|
|
|
bool IsClipping() const override;
|
2014-10-03 06:15:29 +00:00
|
|
|
|
|
|
|
void StartMonitoring();
|
2017-04-05 16:29:24 +00:00
|
|
|
void StopMonitoring();
|
2014-10-03 06:15:29 +00:00
|
|
|
|
2016-04-14 05:50:34 +00:00
|
|
|
// These exist solely for the purpose of resetting the toolbars
|
|
|
|
struct State{ bool mSaved, mMonitoring, mActive; };
|
|
|
|
State SaveState();
|
|
|
|
void RestoreState(const State &state);
|
2015-01-01 23:29:08 +00:00
|
|
|
|
2019-07-02 16:28:25 +00:00
|
|
|
int GetDBRange() const override { return mDB ? mDBRange : -1; }
|
2018-08-08 21:05:27 +00:00
|
|
|
|
2016-06-25 04:06:22 +00:00
|
|
|
private:
|
2018-02-17 22:42:14 +00:00
|
|
|
void UpdatePrefs() override;
|
|
|
|
void UpdateSelectedPrefs( int ) override;
|
|
|
|
|
2014-10-03 06:15:29 +00:00
|
|
|
private:
|
2010-01-23 19:44:49 +00:00
|
|
|
//
|
|
|
|
// Event handlers
|
|
|
|
//
|
|
|
|
void OnErase(wxEraseEvent &evt);
|
|
|
|
void OnPaint(wxPaintEvent &evt);
|
|
|
|
void OnSize(wxSizeEvent &evt);
|
2016-05-04 14:59:18 +00:00
|
|
|
bool InIcon(wxMouseEvent *pEvent = nullptr) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
void OnMouse(wxMouseEvent &evt);
|
2015-01-03 09:29:42 +00:00
|
|
|
void OnKeyDown(wxKeyEvent &evt);
|
2015-01-05 16:36:17 +00:00
|
|
|
void OnKeyUp(wxKeyEvent &evt);
|
2015-01-04 02:25:56 +00:00
|
|
|
void OnContext(wxContextMenuEvent &evt);
|
2015-01-04 09:24:26 +00:00
|
|
|
void OnSetFocus(wxFocusEvent &evt);
|
|
|
|
void OnKillFocus(wxFocusEvent &evt);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2014-12-19 16:38:56 +00:00
|
|
|
void OnAudioIOStatus(wxCommandEvent &evt);
|
2014-12-17 19:16:08 +00:00
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
void OnMeterUpdate(wxTimerEvent &evt);
|
|
|
|
|
2014-10-03 06:15:29 +00:00
|
|
|
void HandleLayout(wxDC &dc);
|
2014-12-28 03:18:00 +00:00
|
|
|
void SetActiveStyle(Style style);
|
|
|
|
void SetBarAndClip(int iBar, bool vert);
|
|
|
|
void DrawMeterBar(wxDC &dc, MeterBar *meterBar);
|
|
|
|
void ResetBar(MeterBar *bar, bool resetClipping);
|
|
|
|
void RepaintBarsNow();
|
|
|
|
wxFont GetFont() const;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
//
|
2015-01-03 09:29:42 +00:00
|
|
|
// Pop-up menu
|
2010-01-23 19:44:49 +00:00
|
|
|
//
|
2015-01-03 09:29:42 +00:00
|
|
|
void ShowMenu(const wxPoint & pos);
|
2010-01-23 19:44:49 +00:00
|
|
|
void OnMonitor(wxCommandEvent &evt);
|
|
|
|
void OnPreferences(wxCommandEvent &evt);
|
2014-12-28 03:18:00 +00:00
|
|
|
|
|
|
|
wxString Key(const wxString & key) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2014-12-19 16:38:56 +00:00
|
|
|
AudacityProject *mProject;
|
2010-01-23 19:44:49 +00:00
|
|
|
MeterUpdateQueue mQueue;
|
|
|
|
wxTimer mTimer;
|
|
|
|
|
|
|
|
int mWidth;
|
|
|
|
int mHeight;
|
|
|
|
|
2014-12-28 03:18:00 +00:00
|
|
|
int mRulerWidth;
|
|
|
|
int mRulerHeight;
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
bool mIsInput;
|
|
|
|
|
2014-12-28 03:18:00 +00:00
|
|
|
Style mStyle;
|
|
|
|
Style mDesiredStyle;
|
2014-10-04 09:47:48 +00:00
|
|
|
bool mGradient;
|
2010-01-23 19:44:49 +00:00
|
|
|
bool mDB;
|
|
|
|
int mDBRange;
|
|
|
|
bool mDecay;
|
|
|
|
float mDecayRate; // dB/sec
|
|
|
|
bool mClip;
|
|
|
|
int mNumPeakSamplesToClip;
|
|
|
|
double mPeakHoldDuration;
|
|
|
|
double mT;
|
|
|
|
double mRate;
|
|
|
|
long mMeterRefreshRate;
|
|
|
|
long mMeterDisabled; //is used as a bool, needs long for easy gPrefs...
|
|
|
|
|
2014-12-17 19:16:08 +00:00
|
|
|
bool mMonitoring;
|
|
|
|
|
2014-12-19 16:38:56 +00:00
|
|
|
bool mActive;
|
|
|
|
|
2016-09-02 19:53:09 +00:00
|
|
|
unsigned mNumBars;
|
2010-01-23 19:44:49 +00:00
|
|
|
MeterBar mBar[kMaxMeterBars];
|
|
|
|
|
|
|
|
bool mLayoutValid;
|
|
|
|
|
2016-04-06 22:32:14 +00:00
|
|
|
std::unique_ptr<wxBitmap> mBitmap;
|
2014-12-28 03:18:00 +00:00
|
|
|
wxRect mIconRect;
|
2010-01-23 19:44:49 +00:00
|
|
|
wxPoint mLeftTextPos;
|
|
|
|
wxPoint mRightTextPos;
|
|
|
|
wxSize mLeftSize;
|
|
|
|
wxSize mRightSize;
|
2016-04-06 22:32:14 +00:00
|
|
|
std::unique_ptr<wxBitmap> mIcon;
|
2010-01-23 19:44:49 +00:00
|
|
|
wxPen mPen;
|
|
|
|
wxPen mDisabledPen;
|
|
|
|
wxPen mPeakPeakPen;
|
|
|
|
wxBrush mBrush;
|
|
|
|
wxBrush mRMSBrush;
|
|
|
|
wxBrush mClipBrush;
|
|
|
|
wxBrush mBkgndBrush;
|
|
|
|
wxBrush mDisabledBkgndBrush;
|
|
|
|
Ruler mRuler;
|
2014-10-03 06:15:29 +00:00
|
|
|
wxString mLeftText;
|
|
|
|
wxString mRightText;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2015-01-04 09:24:26 +00:00
|
|
|
bool mIsFocused;
|
|
|
|
wxRect mFocusRect;
|
2015-01-09 15:27:58 +00:00
|
|
|
#if defined(__WXMSW__)
|
|
|
|
bool mHadKeyDown;
|
|
|
|
#endif
|
2015-01-04 09:24:26 +00:00
|
|
|
|
2015-01-19 17:47:39 +00:00
|
|
|
bool mAccSilent;
|
|
|
|
|
2015-01-04 09:24:26 +00:00
|
|
|
friend class MeterAx;
|
|
|
|
|
2016-05-04 14:59:18 +00:00
|
|
|
bool mHighlighted {};
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
DECLARE_EVENT_TABLE()
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // __AUDACITY_METER__
|