mirror of
https://codeberg.org/armin/beamgrid.git
synced 2026-09-01 04:10:47 +02:00
Add BOOST, 3D depth, and gradient-angle knobs
- BOOST: global display level multiplier (0.75 - 2.5, 1.0 default) - 3D: pseudo-3D bevel/shading on bars, LEDs, peaks and curve (0 = flat) - G-ANG: 3D gradient angle (-180 - 180, 0 = top-lit) - Apply CURVING rounded corners to bars and peaks in BAR mode
This commit is contained in:
parent
ca9555af13
commit
aeb4b83281
7 changed files with 142 additions and 18 deletions
|
|
@ -38,6 +38,8 @@ public:
|
|||
const double gridZoomV = *params.getRawParameterValue ("gridzoom");
|
||||
const double gridFadeV = *params.getRawParameterValue ("gridfade");
|
||||
const double curveV = *params.getRawParameterValue ("curving");
|
||||
const double depthV = *params.getRawParameterValue ("depth3d");
|
||||
const double gradAngV = *params.getRawParameterValue ("gradangle");
|
||||
|
||||
analyser.setGraceSeconds (graceMs / 1000.0);
|
||||
analyser.setFalloffRate (0.1 + falloff * 5.0);
|
||||
|
|
@ -55,6 +57,8 @@ public:
|
|||
gridZoom = static_cast<float> (gridZoomV);
|
||||
gridFade = static_cast<float> (gridFadeV);
|
||||
curveAmount = static_cast<float> (curveV);
|
||||
depthAmount = static_cast<float> (depthV);
|
||||
gradAngle = static_cast<float> (gradAngV);
|
||||
|
||||
analyser.update (1.0 / 60.0);
|
||||
repaint();
|
||||
|
|
@ -159,9 +163,49 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// Build a top-lit 3D gradient across `bounds`. `angleDeg` rotates the
|
||||
// gradient direction (0 = vertical/bright-top, +/-90 = horizontal), `bright`
|
||||
// and `dark` scale the highlight/shadow strength (typically 0..1).
|
||||
juce::ColourGradient make3DGradient (juce::Colour base, const juce::Rectangle<float>& bounds,
|
||||
float angleDeg, float bright, float dark)
|
||||
{
|
||||
const float rad = juce::degreesToRadians (angleDeg);
|
||||
const float dx = std::sin (rad);
|
||||
const float dy = std::cos (rad);
|
||||
const juce::Point<float> c = bounds.getCentre();
|
||||
const float half = 0.5f * std::sqrt (bounds.getWidth() * bounds.getWidth()
|
||||
+ bounds.getHeight() * bounds.getHeight());
|
||||
const juce::Point<float> p1 = c - juce::Point<float> (dx, dy) * half;
|
||||
const juce::Point<float> p2 = c + juce::Point<float> (dx, dy) * half;
|
||||
juce::ColourGradient grad (base.brighter (bright), p1.x, p1.y,
|
||||
base.darker (dark), p2.x, p2.y, false);
|
||||
grad.addColour (0.5, base);
|
||||
return grad;
|
||||
}
|
||||
|
||||
// Fill a rounded rectangle with a top-lit 3D gradient. `depth` (0..1) blends
|
||||
// between a flat solid fill and a fully raised/beveled look, angled by the
|
||||
// G-ANG knob, so the two knobs control the 3D appearance.
|
||||
void fill3D (juce::Graphics& g, juce::Colour base, const juce::Rectangle<float>& r,
|
||||
float radius, float depth)
|
||||
{
|
||||
if (depth <= 0.001f)
|
||||
{
|
||||
g.setColour (base);
|
||||
g.fillRoundedRectangle (r, radius);
|
||||
return;
|
||||
}
|
||||
|
||||
g.setGradientFill (make3DGradient (base, r, gradAngle, depth, depth));
|
||||
g.fillRoundedRectangle (r, radius);
|
||||
}
|
||||
|
||||
void drawBars (juce::Graphics& g, int n, const juce::Rectangle<float>& plot,
|
||||
float gap, float bandWidth, float baseY)
|
||||
{
|
||||
const float peakH = 3.0f;
|
||||
const float peakRadius = curveAmount * juce::jmin (bandWidth, peakH) * 0.5f;
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
const float level = analyser.getLevel (i);
|
||||
|
|
@ -171,12 +215,12 @@ private:
|
|||
const float h = level * plot.getHeight();
|
||||
const float y = baseY - h;
|
||||
|
||||
g.setColour (lf.getTeal());
|
||||
g.fillRect (x, y, bandWidth, h);
|
||||
const float barRadius = curveAmount * juce::jmin (bandWidth, h, 8.0f) * 0.5f;
|
||||
|
||||
fill3D (g, lf.getTeal(), juce::Rectangle<float> (x, y, bandWidth, h), barRadius, depthAmount);
|
||||
|
||||
const float peakY = baseY - peak * plot.getHeight();
|
||||
g.setColour (lf.getPeak());
|
||||
g.fillRect (x, peakY - 2.0f, bandWidth, 3.0f);
|
||||
fill3D (g, lf.getPeak(), juce::Rectangle<float> (x, peakY - 2.0f, bandWidth, peakH), peakRadius, depthAmount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -237,14 +281,23 @@ private:
|
|||
wave.lineTo (plot.getX(), baseY);
|
||||
wave.closeSubPath();
|
||||
|
||||
// Brighter at the top, darker toward the bottom.
|
||||
juce::ColourGradient grad (lf.getTeal().brighter (0.35f), 0.0f, plot.getY(),
|
||||
lf.getTeal().darker (0.85f), 0.0f, plot.getBottom(), false);
|
||||
g.setGradientFill (grad);
|
||||
g.fillPath (wave);
|
||||
// 3D: a top-lit gradient (bright edge fading to a darker underside),
|
||||
// angled by the G-ANG knob. `depthAmount` blends from a flat fill (0)
|
||||
// to a fully raised look (1).
|
||||
const juce::Colour base = lf.getTeal();
|
||||
if (depthAmount <= 0.001f)
|
||||
{
|
||||
g.setColour (base);
|
||||
g.fillPath (wave);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.setGradientFill (make3DGradient (base, plot, gradAngle, 0.7f * depthAmount, depthAmount));
|
||||
g.fillPath (wave);
|
||||
}
|
||||
|
||||
// Bright outline tracing the waveform.
|
||||
g.setColour (lf.getTeal().brighter (0.5f));
|
||||
// Bright top-edge outline (the "lit" highlight), stronger with depth.
|
||||
g.setColour (base.brighter (0.3f + 0.5f * depthAmount));
|
||||
g.strokePath (wave, juce::PathStrokeType (1.5f));
|
||||
|
||||
// Smooth peak-hold wave: per-band peaks, smoothed with the same
|
||||
|
|
@ -287,7 +340,16 @@ private:
|
|||
}
|
||||
peakWave.quadraticTo (ppts[n - 1], ppts[n - 1]);
|
||||
peakWave.lineTo (plot.getRight(), baseY - peaks[n - 1] * plot.getHeight());
|
||||
g.setColour (lf.getPeak());
|
||||
// Peak wave gets the same top-lit 3D shading.
|
||||
const juce::Colour pbase = lf.getPeak();
|
||||
if (depthAmount <= 0.001f)
|
||||
{
|
||||
g.setColour (pbase);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.setGradientFill (make3DGradient (pbase, plot, gradAngle, 0.7f * depthAmount, depthAmount));
|
||||
}
|
||||
g.strokePath (peakWave, juce::PathStrokeType (2.0f));
|
||||
}
|
||||
|
||||
|
|
@ -319,16 +381,15 @@ private:
|
|||
if (b < litCount)
|
||||
{
|
||||
const float frac = (b + 0.5f) / static_cast<float> (leds);
|
||||
g.setColour (lf.getTeal().withMultipliedBrightness (0.35f + 0.65f * frac));
|
||||
g.fillRoundedRectangle (juce::Rectangle<float> (x, blockTop, bandWidth, blockLen), radius);
|
||||
const juce::Colour base = lf.getTeal().withMultipliedBrightness (0.35f + 0.65f * frac);
|
||||
fill3D (g, base, juce::Rectangle<float> (x, blockTop, bandWidth, blockLen), radius, depthAmount);
|
||||
}
|
||||
|
||||
// Peak honours the same discrete blocks: draw the peak block in the
|
||||
// peak colour (a single, fully-filled block).
|
||||
if (b == peakBlock - 1)
|
||||
{
|
||||
g.setColour (lf.getPeak());
|
||||
g.fillRoundedRectangle (juce::Rectangle<float> (x, blockTop, bandWidth, blockLen), radius);
|
||||
fill3D (g, lf.getPeak(), juce::Rectangle<float> (x, blockTop, bandWidth, blockLen), radius, depthAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -345,6 +406,8 @@ private:
|
|||
float gridZoom = 1.0f;
|
||||
float gridFade = 0.0f;
|
||||
float curveAmount = 0.0f;
|
||||
float depthAmount = 0.0f;
|
||||
float gradAngle = 0.0f;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnalyserComponent)
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue