@@ -87,38 +87,60 @@ void Meter::checkModelPtrIsValid() const
8787void Meter::resized ()
8888{
8989 gradient = {};
90+ imageSource = {};
91+ imageClipped = {};
9092
9193 if (model == nullptr )
9294 return ;
9395
9496 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 ();
100102
101103 std::sort (std::begin (positions), std::end (positions),
102104 [] (const auto & lhs, const auto & rhs) { return lhs.decibels < rhs.decibels ; });
103105
104- const auto b = getLocalBounds ();
105106 const bool isHorizontal = model->isHorizontal ();
106107 if (isHorizontal)
107108 gradient = ColourGradient::horizontal (positions.front ().colour , positions.back ().colour , b);
108109 else
109110 gradient = ColourGradient::vertical (positions.front ().colour , positions.back ().colour , b);
110111
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
113125}
114126
115127void Meter::paint (Graphics& g)
116128{
117- if (gradient.getNumColours () <= 0 )
129+ // auto b = getLocalBounds();
130+ // DBG (b.toString());
131+
132+ if (imageSource.isNull ())
118133 return ; // Nothing to draw.
119134
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+ }
122144}
123145
124146bool Meter::refresh ()
@@ -135,37 +157,51 @@ bool Meter::refresh()
135157 needsMaxLevel = model->needsMaxLevel ();
136158 }
137159
138- bool areLevelsDifferent = false ;
139- bool isMaxLevelDelayExpired = false ;
140160 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 ;
141173
142174 for (int i = 0 ; i < numChans; ++i)
143175 {
144176 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 );
148181
149182 if (needsMaxLevel)
150183 {
151- if (channel.getLevel () > channel. getMaxLevel () )
184+ if (channel.level > lastMaxLevel )
152185 {
153- channel.setLastMaxAudioLevelTime ( Time::currentTimeMillis () );
154- channel.setMaxLevel (channel. getLevel ()) ;
186+ channel.timeOfMaximumMs = Time::currentTimeMillis ();
187+ channel.maxLevel = lastLevel ;
155188 }
156- else if (Time::currentTimeMillis () - channel.getLastMaxAudioLevelTime () > maxLevelExpiryMs)
189+ else if (Time::currentTimeMillis () - channel.timeOfMaximumMs > maxLevelExpiryMs)
157190 {
158- channel.setMaxLevel (channel. getMaxLevel () * decayRate) ;
191+ channel.maxLevel = lastMaxLevel * decayRate;
159192 isMaxLevelDelayExpired = true ;
160193 }
161194
162- areLevelsDifferent |= ! approximatelyEqual (channel.getMaxLevel (), channel. getLastMaxLevel () );
195+ areLevelsDifferent |= ! approximatelyEqual (channel.maxLevel , lastMaxLevel );
163196 }
164197
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 );
166201
167- channel.setLastLevel (channel.getLevel ());
168- channel.setLastMaxLevel (channel.getMaxLevel ());
202+ channel.meterArea = channel.meterArea
203+ .withWidth (chanWidthPx)
204+ .withHeight (roundToIntAccurate (h));
169205 }
170206
171207 if (areLevelsDifferent)
@@ -174,11 +210,11 @@ bool Meter::refresh()
174210 return areLevelsDifferent;
175211}
176212
177- void Meter::updateClippingLevel (bool timeToUpdate )
213+ void Meter::updateClippingLevel (bool forceUpdate )
178214{
179215 auto maxLevel = 0 .0f ;
180216 for (const auto & channel : channels)
181- maxLevel = std::max (channel.getLevel () , maxLevel);
217+ maxLevel = std::max (channel.level , maxLevel);
182218
183219 maxLevel = Decibels::gainToDecibels (maxLevel);
184220
@@ -190,6 +226,6 @@ void Meter::updateClippingLevel (bool timeToUpdate)
190226 currClippingLevel = ClippingLevel::warning;
191227
192228 // Only update if higher, or if the time delay has expired.
193- if (clippingLevel < currClippingLevel || timeToUpdate )
229+ if (clippingLevel < currClippingLevel || forceUpdate )
194230 clippingLevel = currClippingLevel;
195231}
0 commit comments