@@ -87,38 +87,60 @@ void Meter::checkModelPtrIsValid() const
87
87
void Meter::resized ()
88
88
{
89
89
gradient = {};
90
+ imageSource = {};
91
+ imageClipped = {};
90
92
91
93
if (model == nullptr )
92
94
return ;
93
95
94
96
auto positions = model->getColourPositions ();
95
- if (positions. size () < 2 )
96
- {
97
- jassertfalse ;
98
- return ;
99
- }
97
+
98
+ // Must have at least 1 colour!
99
+ jassert (! positions. empty ()) ;
100
+
101
+ const auto b = getLocalBounds ();
100
102
101
103
std::sort (std::begin (positions), std::end (positions),
102
104
[] (const auto & lhs, const auto & rhs) { return lhs.decibels < rhs.decibels ; });
103
105
104
- const auto b = getLocalBounds ();
105
106
const bool isHorizontal = model->isHorizontal ();
106
107
if (isHorizontal)
107
108
gradient = ColourGradient::horizontal (positions.front ().colour , positions.back ().colour , b);
108
109
else
109
110
gradient = ColourGradient::vertical (positions.front ().colour , positions.back ().colour , b);
110
111
111
- for (size_t i = 1 ; i < (positions.size () - 1 ); ++i)
112
- positions[i].addToGradient (gradient, isHorizontal);
112
+ if (const auto numPos = (int64) positions.size (); numPos > 1 )
113
+ for (int64 i = 1 ; i < (numPos - 1 ); ++i)
114
+ positions[(size_t ) i].addToGradient (gradient, isHorizontal);
115
+
116
+ {
117
+ imageSource = { Image::RGB, getWidth (), getHeight (), false };
118
+ Graphics ig (imageSource);
119
+ ig.setGradientFill (gradient);
120
+ ig.fillAll ();
121
+ }
122
+
123
+ imageClipped = imageSource;
124
+ // TODO force refresh async + repaint
113
125
}
114
126
115
127
void Meter::paint (Graphics& g)
116
128
{
117
- if (gradient.getNumColours () <= 0 )
129
+ // auto b = getLocalBounds();
130
+ // DBG (b.toString());
131
+
132
+ if (imageSource.isNull ())
118
133
return ; // Nothing to draw.
119
134
120
- g.setGradientFill (gradient);
121
- g.fillAll ();
135
+ g.setColour (Colours::red);
136
+
137
+ for (const auto & c : channels)
138
+ {
139
+ // imageClipped = imageSource.getClippedImage (c.meterArea);
140
+ // g.drawImage (imageClipped, c.meterArea.toFloat(), RectanglePlacement::doNotResize);
141
+
142
+ g.fillRect (c.meterArea );
143
+ }
122
144
}
123
145
124
146
bool Meter::refresh ()
@@ -135,37 +157,51 @@ bool Meter::refresh()
135
157
needsMaxLevel = model->needsMaxLevel ();
136
158
}
137
159
138
- bool areLevelsDifferent = false ;
139
- bool isMaxLevelDelayExpired = false ;
140
160
const auto numChans = std::min (levels.size (), channels.size ());
161
+ const auto chanWidthPx = [&]()
162
+ {
163
+ auto v = roundToIntAccurate ((double ) getWidth () / (double ) numChans);
164
+ v -= 2 ;
165
+ jassert (v > 2 );
166
+ return v;
167
+ }();
168
+
169
+ const auto hPx = getHeight ();
170
+
171
+ bool areLevelsDifferent = channels.getFirst ().meterArea .getWidth () != chanWidthPx;
172
+ bool isMaxLevelDelayExpired = false ;
141
173
142
174
for (int i = 0 ; i < numChans; ++i)
143
175
{
144
176
auto & channel = channels.getReference (i);
145
- auto level = lerp (channel.getLevel (), levels[i], 0 .9f );
146
- dsp::util::snapToZero (level);
147
- channel.setLevel (level);
177
+ const auto lastLevel = channel.level ;
178
+ const auto lastMaxLevel = channel.maxLevel ;
179
+
180
+ channel.level = lerp (lastLevel, levels[i], 0 .9f );
148
181
149
182
if (needsMaxLevel)
150
183
{
151
- if (channel.getLevel () > channel. getMaxLevel () )
184
+ if (channel.level > lastMaxLevel )
152
185
{
153
- channel.setLastMaxAudioLevelTime ( Time::currentTimeMillis () );
154
- channel.setMaxLevel (channel. getLevel ()) ;
186
+ channel.timeOfMaximumMs = Time::currentTimeMillis ();
187
+ channel.maxLevel = lastLevel ;
155
188
}
156
- else if (Time::currentTimeMillis () - channel.getLastMaxAudioLevelTime () > maxLevelExpiryMs)
189
+ else if (Time::currentTimeMillis () - channel.timeOfMaximumMs > maxLevelExpiryMs)
157
190
{
158
- channel.setMaxLevel (channel. getMaxLevel () * decayRate) ;
191
+ channel.maxLevel = lastMaxLevel * decayRate;
159
192
isMaxLevelDelayExpired = true ;
160
193
}
161
194
162
- areLevelsDifferent |= ! approximatelyEqual (channel.getMaxLevel (), channel. getLastMaxLevel () );
195
+ areLevelsDifferent |= ! approximatelyEqual (channel.maxLevel , lastMaxLevel );
163
196
}
164
197
165
- areLevelsDifferent |= ! approximatelyEqual (channel.getLevel (), channel.getLastLevel ());
198
+ areLevelsDifferent |= ! approximatelyEqual (channel.level , lastLevel);
199
+
200
+ const auto h = (double ) hPx * (double ) DecibelHelpers::gainToMeterProportion ((double ) channel.level );
166
201
167
- channel.setLastLevel (channel.getLevel ());
168
- channel.setLastMaxLevel (channel.getMaxLevel ());
202
+ channel.meterArea = channel.meterArea
203
+ .withWidth (chanWidthPx)
204
+ .withHeight (roundToIntAccurate (h));
169
205
}
170
206
171
207
if (areLevelsDifferent)
@@ -174,11 +210,11 @@ bool Meter::refresh()
174
210
return areLevelsDifferent;
175
211
}
176
212
177
- void Meter::updateClippingLevel (bool timeToUpdate )
213
+ void Meter::updateClippingLevel (bool forceUpdate )
178
214
{
179
215
auto maxLevel = 0 .0f ;
180
216
for (const auto & channel : channels)
181
- maxLevel = std::max (channel.getLevel () , maxLevel);
217
+ maxLevel = std::max (channel.level , maxLevel);
182
218
183
219
maxLevel = Decibels::gainToDecibels (maxLevel);
184
220
@@ -190,6 +226,6 @@ void Meter::updateClippingLevel (bool timeToUpdate)
190
226
currClippingLevel = ClippingLevel::warning;
191
227
192
228
// Only update if higher, or if the time delay has expired.
193
- if (clippingLevel < currClippingLevel || timeToUpdate )
229
+ if (clippingLevel < currClippingLevel || forceUpdate )
194
230
clippingLevel = currClippingLevel;
195
231
}
0 commit comments