1 /********************************************************************** 2 3 Audacity: A Digital Audio Editor 4 5 MeterPanel.h 6 7 Dominic Mazzoni 8 9 VU Meter, for displaying recording/playback level 10 11 This is a bunch of common code that can display many different 12 forms of VU meters and other displays. 13 14 **********************************************************************/ 15 16 #ifndef __AUDACITY_METER_PANEL__ 17 #define __AUDACITY_METER_PANEL__ 18 19 #include <wx/setup.h> // for wxUSE_* macros 20 #include <wx/brush.h> // member variable 21 #include <wx/defs.h> 22 #include <wx/timer.h> // member variable 23 24 #include "SampleFormat.h" 25 #include "Prefs.h" 26 #include "MeterPanelBase.h" // to inherit 27 #include "Ruler.h" // member variable 28 29 class AudacityProject; 30 31 // Increase this when we add support for multichannel meters 32 // (most of the code is already there) 33 const int kMaxMeterBars = 2; 34 35 struct MeterBar { 36 bool vert; 37 wxRect b; // Bevel around bar 38 wxRect r; // True bar drawing area 39 float peak; 40 float rms; 41 float peakHold; 42 double peakHoldTime; 43 wxRect rClip; 44 bool clipping; 45 bool isclipping; //ANSWER-ME: What's the diff between these bools?! "clipping" vs "isclipping" is not clear. 46 int tailPeakCount; 47 float peakPeakHold; 48 }; 49 50 class MeterUpdateMsg 51 { 52 public: 53 int numFrames; 54 float peak[kMaxMeterBars]; 55 float rms[kMaxMeterBars]; 56 bool clipping[kMaxMeterBars]; 57 int headPeakCount[kMaxMeterBars]; 58 int tailPeakCount[kMaxMeterBars]; 59 60 /* neither constructor nor destructor do anything */ MeterUpdateMsg()61 MeterUpdateMsg() { } ~MeterUpdateMsg()62 ~MeterUpdateMsg() { } 63 /* for debugging purposes, printing the values out is really handy */ 64 /** \brief Print out all the values in the meter update message */ 65 wxString toString(); 66 /** \brief Only print meter updates if clipping may be happening */ 67 wxString toStringIfClipped(); 68 }; 69 70 // Thread-safe queue of update messages 71 class MeterUpdateQueue 72 { 73 public: 74 explicit MeterUpdateQueue(size_t maxLen); 75 ~MeterUpdateQueue(); 76 77 bool Put(MeterUpdateMsg &msg); 78 bool Get(MeterUpdateMsg &msg); 79 80 void Clear(); 81 82 private: 83 int mStart; 84 int mEnd; 85 size_t mBufferSize; 86 ArrayOf<MeterUpdateMsg> mBuffer{mBufferSize}; 87 }; 88 89 class MeterAx; 90 91 /********************************************************************//** 92 \brief MeterPanel is a panel that paints the meter used for monitoring 93 or playback. 94 ************************************************************************/ 95 class AUDACITY_DLL_API MeterPanel final 96 : public MeterPanelBase, private PrefsListener 97 { 98 DECLARE_DYNAMIC_CLASS(MeterPanel) 99 100 public: 101 // These should be kept in the same order as they appear 102 // in the menu 103 enum Style { 104 AutomaticStereo, 105 HorizontalStereo, 106 VerticalStereo, 107 MixerTrackCluster, // Doesn't show menu, icon, or L/R labels, but otherwise like VerticalStereo. 108 HorizontalStereoCompact, // Thinner. 109 VerticalStereoCompact, // Narrower. 110 }; 111 112 113 MeterPanel(AudacityProject *, 114 wxWindow* parent, wxWindowID id, 115 bool isInput, 116 const wxPoint& pos = wxDefaultPosition, 117 const wxSize& size = wxDefaultSize, 118 Style style = HorizontalStereo, 119 float fDecayRate = 60.0f); 120 121 void SetFocusFromKbd() override; 122 123 void Clear() override; 124 GetStyle()125 Style GetStyle() const { return mStyle; } GetDesiredStyle()126 Style GetDesiredStyle() const { return mDesiredStyle; } 127 void SetStyle(Style newStyle); 128 129 /** \brief 130 * 131 * This method is thread-safe! Feel free to call from a 132 * different thread (like from an audio I/O callback). 133 */ 134 void Reset(double sampleRate, bool resetClipping) override; 135 136 /** \brief Update the meters with a block of audio data 137 * 138 * Process the supplied block of audio data, extracting the peak and RMS 139 * levels to send to the meter. Also record runs of clipped samples to detect 140 * clipping that lies on block boundaries. 141 * This method is thread-safe! Feel free to call from a different thread 142 * (like from an audio I/O callback). 143 * 144 * First overload: 145 * \param numChannels The number of channels of audio being played back or 146 * recorded. 147 * \param numFrames The number of frames (samples) in this data block. It is 148 * assumed that there are the same number of frames in each channel. 149 * \param sampleData The audio data itself, as interleaved samples. So 150 * indexing through the array we get the first sample of channel, first 151 * sample of channel 2 etc up to the first sample of channel (numChannels), 152 * then the second sample of channel 1, second sample of channel 2, and so 153 * to the second sample of channel (numChannels). The last sample in the 154 * array will be the (numFrames) sample for channel (numChannels). 155 * 156 * The second overload is for ease of use in MixerBoard. 157 */ 158 void UpdateDisplay(unsigned numChannels, 159 int numFrames, const float *sampleData) override; 160 161 // Vaughan, 2010-11-29: This not currently used. See comments in MixerTrackCluster::UpdateMeter(). 162 //void UpdateDisplay(int numChannels, int numFrames, 163 // // Need to make these double-indexed max and min arrays if we handle more than 2 channels. 164 // float* maxLeft, float* rmsLeft, 165 // float* maxRight, float* rmsRight, 166 // const size_t kSampleCount); 167 168 /** \brief Find out if the level meter is disabled or not. 169 * 170 * This method is thread-safe! Feel free to call from a 171 * different thread (like from an audio I/O callback). 172 */ 173 bool IsMeterDisabled() const override; 174 175 float GetMaxPeak() const override; 176 177 bool IsClipping() const override; 178 179 void StartMonitoring(); 180 void StopMonitoring(); 181 182 // These exist solely for the purpose of resetting the toolbars 183 struct State{ bool mSaved, mMonitoring, mActive; }; 184 State SaveState(); 185 void RestoreState(const State &state); 186 GetDBRange()187 int GetDBRange() const override { return mDB ? mDBRange : -1; } 188 189 private: 190 void UpdatePrefs() override; 191 void UpdateSelectedPrefs( int ) override; 192 193 private: 194 // 195 // Event handlers 196 // 197 void OnErase(wxEraseEvent &evt); 198 void OnPaint(wxPaintEvent &evt); 199 void OnSize(wxSizeEvent &evt); 200 bool InIcon(wxMouseEvent *pEvent = nullptr) const; 201 void OnMouse(wxMouseEvent &evt); 202 void OnKeyDown(wxKeyEvent &evt); 203 void OnKeyUp(wxKeyEvent &evt); 204 void OnContext(wxContextMenuEvent &evt); 205 void OnSetFocus(wxFocusEvent &evt); 206 void OnKillFocus(wxFocusEvent &evt); 207 208 void OnAudioIOStatus(wxCommandEvent &evt); 209 210 void OnMeterUpdate(wxTimerEvent &evt); 211 212 void HandleLayout(wxDC &dc); 213 void SetActiveStyle(Style style); 214 void SetBarAndClip(int iBar, bool vert); 215 void DrawMeterBar(wxDC &dc, MeterBar *meterBar); 216 void ResetBar(MeterBar *bar, bool resetClipping); 217 void RepaintBarsNow(); 218 wxFont GetFont() const; 219 220 // 221 // Pop-up menu 222 // 223 void ShowMenu(const wxPoint & pos); 224 void OnMonitor(wxCommandEvent &evt); 225 void OnPreferences(wxCommandEvent &evt); 226 227 wxString Key(const wxString & key) const; 228 229 AudacityProject *mProject; 230 MeterUpdateQueue mQueue; 231 wxTimer mTimer; 232 233 int mWidth; 234 int mHeight; 235 236 int mRulerWidth; 237 int mRulerHeight; 238 239 bool mIsInput; 240 241 Style mStyle; 242 Style mDesiredStyle; 243 bool mGradient; 244 bool mDB; 245 int mDBRange; 246 bool mDecay; 247 float mDecayRate; // dB/sec 248 bool mClip; 249 int mNumPeakSamplesToClip; 250 double mPeakHoldDuration; 251 double mT; 252 double mRate; 253 long mMeterRefreshRate; 254 long mMeterDisabled; //is used as a bool, needs long for easy gPrefs... 255 256 bool mMonitoring; 257 258 bool mActive; 259 260 unsigned mNumBars; 261 MeterBar mBar[kMaxMeterBars]; 262 263 bool mLayoutValid; 264 265 std::unique_ptr<wxBitmap> mBitmap; 266 wxRect mIconRect; 267 wxPoint mLeftTextPos; 268 wxPoint mRightTextPos; 269 wxSize mLeftSize; 270 wxSize mRightSize; 271 std::unique_ptr<wxBitmap> mIcon; 272 wxPen mPen; 273 wxPen mDisabledPen; 274 wxPen mPeakPeakPen; 275 wxBrush mBrush; 276 wxBrush mRMSBrush; 277 wxBrush mClipBrush; 278 wxBrush mBkgndBrush; 279 wxBrush mDisabledBkgndBrush; 280 Ruler mRuler; 281 wxString mLeftText; 282 wxString mRightText; 283 284 bool mIsFocused; 285 wxRect mFocusRect; 286 #if defined(__WXMSW__) 287 bool mHadKeyDown; 288 #endif 289 290 bool mAccSilent; 291 292 friend class MeterAx; 293 294 bool mHighlighted {}; 295 296 DECLARE_EVENT_TABLE() 297 }; 298 299 #endif // __AUDACITY_METER_PANEL__ 300