audacia/src/widgets/Meter.h

300 lines
8.4 KiB
C++

/**********************************************************************
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__
#include <wx/setup.h> // for wxUSE_* macros
#include <wx/brush.h> // member variable
#include <wx/defs.h>
#include <wx/timer.h> // member variable
#include "../SampleFormat.h"
#include "../Prefs.h"
#include "MeterPanelBase.h" // to inherit
#include "Ruler.h" // member variable
class AudacityProject;
// Increase this when we add support for multichannel meters
// (most of the code is already there)
const int kMaxMeterBars = 2;
struct MeterBar {
bool vert;
wxRect b; // Bevel around bar
wxRect r; // True bar drawing area
float peak;
float rms;
float peakHold;
double peakHoldTime;
wxRect rClip;
bool clipping;
bool isclipping; //ANSWER-ME: What's the diff between these bools?! "clipping" vs "isclipping" is not clear.
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 */
MeterUpdateMsg() { }
~MeterUpdateMsg() { }
/* 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:
explicit MeterUpdateQueue(size_t maxLen);
~MeterUpdateQueue();
bool Put(MeterUpdateMsg &msg);
bool Get(MeterUpdateMsg &msg);
void Clear();
private:
int mStart;
int mEnd;
size_t mBufferSize;
ArrayOf<MeterUpdateMsg> mBuffer{mBufferSize};
};
class MeterAx;
/********************************************************************//**
\brief MeterPanel is a panel that paints the meter used for monitoring
or playback.
************************************************************************/
class AUDACITY_DLL_API MeterPanel final
: public MeterPanelBase, private PrefsListener
{
DECLARE_DYNAMIC_CLASS(MeterPanel)
public:
// These should be kept in the same order as they appear
// in the menu
enum Style {
AutomaticStereo,
HorizontalStereo,
VerticalStereo,
MixerTrackCluster, // Doesn't show menu, icon, or L/R labels, but otherwise like VerticalStereo.
HorizontalStereoCompact, // Thinner.
VerticalStereoCompact, // Narrower.
};
MeterPanel(AudacityProject *,
wxWindow* parent, wxWindowID id,
bool isInput,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
Style style = HorizontalStereo,
float fDecayRate = 60.0f);
void SetFocusFromKbd() override;
void Clear() override;
Style GetStyle() const { return mStyle; }
Style GetDesiredStyle() const { return mDesiredStyle; }
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).
*/
void Reset(double sampleRate, bool resetClipping) override;
/** \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.
*/
void UpdateDisplay(unsigned numChannels,
int numFrames, float *sampleData) override;
// Vaughan, 2010-11-29: This not currently used. See comments in MixerTrackCluster::UpdateMeter().
//void UpdateDisplay(int numChannels, int numFrames,
// // Need to make these double-indexed max and min arrays if we handle more than 2 channels.
// float* maxLeft, float* rmsLeft,
// float* maxRight, float* rmsRight,
// const size_t kSampleCount);
/** \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).
*/
bool IsMeterDisabled() const override;
float GetMaxPeak() const override;
bool IsClipping() const override;
void StartMonitoring();
void StopMonitoring();
// These exist solely for the purpose of resetting the toolbars
struct State{ bool mSaved, mMonitoring, mActive; };
State SaveState();
void RestoreState(const State &state);
int GetDBRange() const override { return mDB ? mDBRange : -1; }
private:
void UpdatePrefs() override;
void UpdateSelectedPrefs( int ) override;
private:
//
// Event handlers
//
void OnErase(wxEraseEvent &evt);
void OnPaint(wxPaintEvent &evt);
void OnSize(wxSizeEvent &evt);
bool InIcon(wxMouseEvent *pEvent = nullptr) const;
void OnMouse(wxMouseEvent &evt);
void OnKeyDown(wxKeyEvent &evt);
void OnKeyUp(wxKeyEvent &evt);
void OnContext(wxContextMenuEvent &evt);
void OnSetFocus(wxFocusEvent &evt);
void OnKillFocus(wxFocusEvent &evt);
void OnAudioIOStatus(wxCommandEvent &evt);
void OnMeterUpdate(wxTimerEvent &evt);
void HandleLayout(wxDC &dc);
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;
//
// Pop-up menu
//
void ShowMenu(const wxPoint & pos);
void OnMonitor(wxCommandEvent &evt);
void OnPreferences(wxCommandEvent &evt);
wxString Key(const wxString & key) const;
AudacityProject *mProject;
MeterUpdateQueue mQueue;
wxTimer mTimer;
int mWidth;
int mHeight;
int mRulerWidth;
int mRulerHeight;
bool mIsInput;
Style mStyle;
Style mDesiredStyle;
bool mGradient;
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...
bool mMonitoring;
bool mActive;
unsigned mNumBars;
MeterBar mBar[kMaxMeterBars];
bool mLayoutValid;
std::unique_ptr<wxBitmap> mBitmap;
wxRect mIconRect;
wxPoint mLeftTextPos;
wxPoint mRightTextPos;
wxSize mLeftSize;
wxSize mRightSize;
std::unique_ptr<wxBitmap> mIcon;
wxPen mPen;
wxPen mDisabledPen;
wxPen mPeakPeakPen;
wxBrush mBrush;
wxBrush mRMSBrush;
wxBrush mClipBrush;
wxBrush mBkgndBrush;
wxBrush mDisabledBkgndBrush;
Ruler mRuler;
wxString mLeftText;
wxString mRightText;
bool mIsFocused;
wxRect mFocusRect;
#if defined(__WXMSW__)
bool mHadKeyDown;
#endif
bool mAccSilent;
friend class MeterAx;
bool mHighlighted {};
DECLARE_EVENT_TABLE()
};
#endif // __AUDACITY_METER__