iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IVMeterControl.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12
19#include "IControl.h"
20#include "ISender.h"
21#include "IPlugStructs.h"
22
23BEGIN_IPLUG_NAMESPACE
24BEGIN_IGRAPHICS_NAMESPACE
25
28template <int MAXNC = 1>
30{
31public:
32 enum class EResponse {
33 Linear,
34 Log,
35 };
36
37 IVMeterControl(const IRECT& bounds, const char* label, const IVStyle& style = DEFAULT_STYLE, EDirection dir = EDirection::Vertical, std::initializer_list<const char*> trackNames = {}, int totalNSegs = 0, EResponse response = EResponse::Linear, float lowRangeDB = -72.f, float highRangeDB = 12.f, std::initializer_list<int> markers = {0, -6, -12, -24, -48})
38 : IVTrackControlBase(bounds, label, style, MAXNC, totalNSegs, dir, trackNames)
39 , mResponse(response)
40 , mLowRangeDB(lowRangeDB)
41 , mHighRangeDB(highRangeDB)
42 , mMarkers(markers)
43 {
44 }
45
46 void SetResponse(EResponse response)
47 {
48 mResponse = response;
49 SetDirty(false);
50 }
51
52 void Draw(IGraphics& g) override
53 {
54 DrawBackground(g, mRECT);
55 DrawWidget(g);
56 DrawLabel(g);
57
58 if (mResponse == EResponse::Log)
59 {
60 DrawMarkers(g);
61 }
62
63 if (mStyle.drawFrame)
64 g.DrawRect(GetColor(kFR), mWidgetBounds, &mBlend, mStyle.frameThickness);
65 }
66
67 void DrawPeak(IGraphics& g, const IRECT& r, int chIdx, bool aboveBaseValue) override
68 {
69 g.FillRect(IVTrackControlBase::GetColor(kX1), r, &mBlend);
70 }
71
72 void DrawMarkers(IGraphics& g)
73 {
74 auto lowPointAbs = std::fabs(mLowRangeDB);
75 auto rangeDB = std::fabs(mHighRangeDB - mLowRangeDB);
76
77 for (auto pt : mMarkers)
78 {
79 auto linearPos = (pt + lowPointAbs)/rangeDB;
80
81 auto r = mWidgetBounds.FracRect(IVTrackControlBase::mDirection, linearPos);
82
83 if (IVTrackControlBase::mDirection == EDirection::Vertical)
84 {
85 r.B = r.T + 10.f;
86 g.DrawLine(IVTrackControlBase::GetColor(kHL), r.L , r.T, r.R, r.T);
87 }
88 else
89 {
90 r.L = r.R - 10.f;
91 g.DrawLine(IVTrackControlBase::GetColor(kHL), r.MW(), r.T, r.MW(), r.B);
92 }
93
94 if (mStyle.showValue)
95 {
96 WDL_String str;
97 str.SetFormatted(32, "%i dB", pt);
98 g.DrawText(DEFAULT_TEXT, str.Get(), r);
99 }
100 }
101 }
102
103 void OnMsgFromDelegate(int msgTag, int dataSize, const void* pData) override
104 {
105 if (!IsDisabled() && msgTag == ISender<>::kUpdateMessage)
106 {
107 IByteStream stream(pData, dataSize);
108
109 int pos = 0;
111 pos = stream.Get(&d, pos);
112
113 if (mResponse == EResponse::Log)
114 {
115 auto lowPointAbs = std::fabs(mLowRangeDB);
116 auto rangeDB = std::fabs(mHighRangeDB - mLowRangeDB);
117 for (auto c = d.chanOffset; c < (d.chanOffset + d.nChans); c++)
118 {
119 auto ampValue = AmpToDB(static_cast<double>(d.vals[c]));
120 auto linearPos = (ampValue + lowPointAbs)/rangeDB;
121 SetValue(Clip(linearPos, 0., 1.), c);
122 }
123 }
124 else
125 {
126 for (auto c = d.chanOffset; c < (d.chanOffset + d.nChans); c++)
127 {
128 SetValue(Clip(static_cast<double>(d.vals[c]), 0., 1.), c);
129 }
130 }
131
132 SetDirty(false);
133 }
134 }
135protected:
136 float mHighRangeDB;
137 float mLowRangeDB;
138 EResponse mResponse = EResponse::Linear;
139 std::vector<int> mMarkers;
140};
141
145template <int MAXNC = 1>
147{
148public:
149 IVPeakAvgMeterControl(const IRECT& bounds, const char* label, const IVStyle& style = DEFAULT_STYLE, EDirection dir = EDirection::Vertical,
150 std::initializer_list<const char*> trackNames = {}, int totalNSegs = 0, float lowRangeDB = -60.f, float highRangeDB = 12.f,
151 std::initializer_list<int> markers = {0, -6, -12, -24, -48})
152 : IVMeterControl<MAXNC>(bounds, label, style, dir, trackNames, totalNSegs, IVMeterControl<MAXNC>::EResponse::Log, lowRangeDB, highRangeDB, markers)
153 {
154 }
155
156 void DrawPeak(IGraphics& g, const IRECT& r, int chIdx, bool aboveBaseValue) override
157 {
159 float trackPos = mPeakValues[chIdx];
160 EVColor colorIdx = kX1;
161
162 if (trackPos < 0.0001)
163 return;
164
165 if (trackPos > 1.0)
166 {
167 trackPos = 1.0f;
168 colorIdx = kX2;
169 }
170
171 const auto widgetBounds = IVTrackControlBase::mWidgetBounds;
172 const auto dir = IVTrackControlBase::mDirection;
173 IRECT peakRect = widgetBounds.FracRect(dir, trackPos);
174
175 if (dir == EDirection::Vertical)
176 {
177 peakRect = peakRect.GetFromTop(IVTrackControlBase::mPeakSize);
178 peakRect.L = r.L;
179 peakRect.R = r.R;
180 }
181 else
182 {
183 peakRect = peakRect.GetFromRight(IVTrackControlBase::mPeakSize);
184 peakRect.T = r.T;
185 peakRect.B = r.B;
186 }
187 g.FillRect(IVTrackControlBase::GetColor(colorIdx), peakRect, &blend);
188 }
189
190 void OnMsgFromDelegate(int msgTag, int dataSize, const void* pData) override
191 {
193 {
194 IByteStream stream(pData, dataSize);
195
196 int pos = 0;
198 pos = stream.Get(&d, pos);
199
200 const auto lowRangeDB = IVPeakAvgMeterControl::mLowRangeDB;
201 const auto highRangeDB = IVPeakAvgMeterControl::mHighRangeDB;
202
203 double lowPointAbs = std::fabs(lowRangeDB);
204 double rangeDB = std::fabs(highRangeDB - lowRangeDB);
205
206 for (auto c = d.chanOffset; c < (d.chanOffset + d.nChans); c++)
207 {
208 double peakValue = AmpToDB(static_cast<double>(std::get<0>(d.vals[c])));
209 double avgValue = AmpToDB(static_cast<double>(std::get<1>(d.vals[c])));
210 double linearPeakPos = (peakValue + lowPointAbs)/rangeDB;
211 double linearAvgPos = (avgValue + lowPointAbs)/rangeDB;
212
213 IVTrackControlBase::SetValue(Clip(linearAvgPos, 0., 1.), c);
214 mPeakValues[c] = static_cast<float>(linearPeakPos);
215 }
216
218 }
219 }
220
221protected:
222 std::array<float, MAXNC> mPeakValues;
223};
224
225const static IColor LED1 = {255, 36, 157, 16};
226const static IColor LED2 = {255, 153, 191, 28};
227const static IColor LED3 = {255, 215, 222, 37};
228const static IColor LED4 = {255, 247, 153, 33};
229const static IColor LED5 = COLOR_RED;
230
234template <int MAXNC = 1>
236{
237public:
239 struct LEDRange
240 {
241 float lowRangeDB; // The lower bounds of the decibel range for this group of LED segments
242 float highRangeDB; // The upper bounds of the decibel range for this group of LED segments
243 int nSegs; // The number of LED segments
244 IColor color; // The color of the LEDs in this range
245
246 LEDRange(float lowRangeDB, float highRangeDB, int nSegs, IColor color)
247 : lowRangeDB(lowRangeDB)
248 , highRangeDB(highRangeDB)
249 , nSegs(nSegs)
250 , color(color)
251 {
252 }
253 };
254
255 IVLEDMeterControl(const IRECT& bounds, const char* label = "", const IVStyle& style = DEFAULT_STYLE, EDirection dir = EDirection::Vertical,
256 std::initializer_list<const char*> trackNames = {}, int totalNSegs = 13,
257 const std::vector<LEDRange>& ranges = {
258 {0., 6., 1, LED5},
259 {-18., 0., 3, LED4},
260 {-36., -18., 3, LED3},
261 {-54., -36., 3, LED2},
262 {-72., -54., 3, LED1}
263 })
264 : IVPeakAvgMeterControl<MAXNC>(bounds, label, style, dir, trackNames, totalNSegs)
265 , mLEDRanges(ranges)
266 {
268
269 float minRange = 0.;
270 float maxRange = 0.;
271 int nSegs = 0;
272
273 for (auto ledRange : ranges)
274 {
275 if (ledRange.lowRangeDB < minRange)
276 minRange = ledRange.lowRangeDB;
277
278 if (ledRange.highRangeDB > maxRange)
279 maxRange = ledRange.highRangeDB;
280
281 nSegs += ledRange.nSegs;
282 }
283
284 assert(totalNSegs == nSegs); // The ranges argument must contain the same number of segments as totalNSegs
285
288 }
289
290 void DrawTrackHandle(IGraphics& g, const IRECT& r, int chIdx, bool aboveBaseValue) override
291 {
292 /* NO-OP, TODO: could draw peak hold */
293 }
294
295 void DrawTrackBackground(IGraphics &g, const IRECT &r, int chIdx) override
296 {
297 const int totalNSegs = IVMeterControl<MAXNC>::mNSteps;
298 const EDirection dir = IVMeterControl<MAXNC>::mDirection;
299 const float val = static_cast<float>(IVMeterControl<MAXNC>::GetValue(chIdx));
300 const float valPos = (dir == EDirection::Vertical) ? r.B - (val * r.H()) : r.R - ((1.f-val) * r.W()); // threshold position for testing segment
301
302 int segIdx = 0; // keep track of how many segments have been drawn
303
304 for (auto ledRange : mLEDRanges)
305 {
306 for (auto i = 0; i < ledRange.nSegs; i++)
307 {
308 IRECT segRect;
309 if (dir == EDirection::Vertical)
310 {
311 segRect = r.GetGridCell(segIdx + i, totalNSegs, 1, dir, 1);
312
313 if (segRect.MH() > valPos)
314 g.FillRect(ledRange.color, segRect.GetPadded(-1.f));
315 }
316 else
317 {
318 segRect = r.GetGridCell(totalNSegs - 1 - (segIdx + i), 1, totalNSegs, dir, 1);
319
320 if (segRect.MW() < valPos)
321 g.FillRect(ledRange.color, segRect.GetPadded(-1.f));
322 }
323 }
324 segIdx += ledRange.nSegs;
325 }
326 }
327
328private:
329 std::vector<LEDRange> mLEDRanges;
330};
331
332END_IGRAPHICS_NAMESPACE
333END_IPLUG_NAMESPACE
This file contains the base IControl implementation, along with some base classes for specific types ...
Manages a non-owned block of memory, for receiving arbitrary message byte streams.
Definition: IPlugStructs.h:268
int Get(T *pDst, int startPos) const
Get arbitary typed data from the stream.
Definition: IPlugStructs.h:289
IBlend GetBlend() const
Get the Blend for this control.
Definition: IControl.h:299
bool IsDisabled() const
Definition: IControl.h:362
virtual void SetValue(double value, int valIdx=0)
Set one of the control's values.
Definition: IControl.cpp:147
double GetValue(int valIdx=0) const
Get the control's value.
Definition: IControl.cpp:153
virtual void SetDirty(bool triggerAction=true, int valIdx=kNoValIdx)
Mark the control as dirty, i.e.
Definition: IControl.cpp:198
The lowest level base class of an IGraphics context.
Definition: IGraphics.h:86
virtual void DrawRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)
Draw a rectangle to the graphics context.
Definition: IGraphics.cpp:2497
void DrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend=0)
Draw some text to the graphics context in a specific rectangle.
Definition: IGraphics.cpp:670
virtual void FillRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill a rectangular region of the graphics context with a color.
Definition: IGraphics.cpp:2569
virtual void DrawLine(const IColor &color, float x1, float y1, float x2, float y2, const IBlend *pBlend=0, float thickness=1.f)
Draw a line to the graphics context.
Definition: IGraphics.cpp:2416
ISender is a utility class which can be used to defer data from the realtime audio processing and sen...
Definition: ISender.h:65
Vectorial multi-channel capable meter control with segmented LEDs, log response.
void DrawTrackHandle(IGraphics &g, const IRECT &r, int chIdx, bool aboveBaseValue) override
Draw the main body of the track.
Vectorial multi-channel capable meter control, linear or log response.
void Draw(IGraphics &g) override
Draw the control to the graphics context.
void OnMsgFromDelegate(int msgTag, int dataSize, const void *pData) override
Implement to receive messages sent to the control, see IEditorDelegate:SendControlMsgFromDelegate()
Vectorial multi-channel capable meter control, with log response, held-peaks and filled-average/rms R...
void OnMsgFromDelegate(int msgTag, int dataSize, const void *pData) override
Implement to receive messages sent to the control, see IEditorDelegate:SendControlMsgFromDelegate()
A base class for mult-strip/track controls, such as multi-sliders, meters Track refers to the channel...
Definition: IControl.h:1426
void DrawWidget(IGraphics &g) override
Draw the IVControl main widget (override)
Definition: IControl.h:1551
virtual void DrawBackground(IGraphics &g, const IRECT &r) override
Draw the IVControl background (usually transparent)
Definition: IControl.h:1663
virtual void DrawLabel(IGraphics &g)
Draw the IVControl label text.
Definition: IControl.h:889
const IColor & GetColor(EVColor color) const
Get value of a specific EVColor in the IVControl.
Definition: IControl.h:801
BEGIN_IPLUG_NAMESPACE T Clip(T x, T lo, T hi)
Clips the value x between lo and hi.
static double AmpToDB(double amp)
Used to manage composite/blend operations, independent of draw class/platform.
Used to manage color data, independent of draw class/platform.
Used to manage a rectangular area, independent of draw class/platform.
IRECT GetFromRight(float amount) const
Get a subrect of this IRECT bounded in X by 'amount' and the right edge.
float MH() const
IRECT GetGridCell(int row, int col, int nRows, int nColumns) const
Get a subrect (by row, column) of this IRECT which is a cell in a grid of size (nRows * nColumns)
IRECT FracRect(EDirection layoutDir, float frac, bool fromTopOrRight=false) const
Get a new rectangle which is a fraction of this rectangle.
float W() const
IRECT GetFromTop(float amount) const
Get a subrect of this IRECT bounded in Y by the top edge and 'amount'.
float H() const
float MW() const
IRECT GetPadded(float padding) const
Get a copy of this IRECT with each value padded by padding N.B.
ISenderData is used to represent a typed data packet, that may contain values for multiple channels.
Definition: ISender.h:34
LED Range comprises info for a range of LED segments.
A struct encapsulating a set of properties used to configure IVControls.