Files
serumalt/Source/GUI/EnvelopeDisplay.cpp
T

81 lines
2.6 KiB
C++

#include "EnvelopeDisplay.h"
namespace serum
{
void EnvelopeDisplay::setParams (float a, float d, float s, float r, float c)
{
attack = a; decay = d; sustain = s; release = r; curve = c;
}
void EnvelopeDisplay::paint (juce::Graphics& g)
{
const auto b = getLocalBounds().toFloat().reduced (4.0f);
g.setColour (juce::Colours::black.withAlpha (0.4f));
g.fillRoundedRectangle (b.expanded (4.0f), 4.0f);
g.setColour (theme::outline);
g.drawRoundedRectangle (b.expanded (4.0f).reduced (0.5f), 4.0f, 1.0f);
const float atkShape = 0.3f + curve * 2.7f;
const float decShape = 3.0f - curve * 2.7f;
// Normalise durations for display (attack 0..1, decay 0..0.6, release 0..0.6).
const float aSec = maps::toSeconds (attack);
const float dSec = maps::toSeconds (decay);
const float rSec = maps::toSeconds (release);
const float total = aSec + dSec + rSec + 0.01f;
const float ax = (aSec / total);
const float dx = (dSec / total);
const float rx = (rSec / total);
const float left = b.getX();
const float right = b.getRight();
const float bottom = b.getBottom();
const float top = b.getY();
const float sustainY = bottom - sustain * b.getHeight();
juce::Path path;
path.startNewSubPath (left, bottom);
path.lineTo (left, top);
// Attack (curve-shaped).
const int steps = 48;
const float peakX = left + ax * b.getWidth();
for (int i = 0; i <= steps; ++i)
{
const float p = (float) i / steps;
const float y = top + (bottom - top) * std::pow (p, atkShape);
path.lineTo (left + p * (peakX - left), y);
}
// Decay to sustain.
const float decX = peakX + dx * b.getWidth();
for (int i = 0; i <= steps; ++i)
{
const float p = (float) i / steps;
const float y = sustainY + (bottom - sustainY) * std::pow (1.0f - p, decShape);
path.lineTo (peakX + p * (decX - peakX), y);
}
path.lineTo (decX, sustainY);
path.lineTo (right - rx * b.getWidth(), sustainY);
// Release.
const float relStartX = right - rx * b.getWidth();
for (int i = 0; i <= steps; ++i)
{
const float p = (float) i / steps;
const float y = sustainY + (bottom - sustainY) * std::pow (1.0f - p, decShape);
path.lineTo (relStartX + p * (right - relStartX), y);
}
g.setColour (theme::accent2.withAlpha (0.3f));
juce::Path fill = path;
fill.lineTo (right, bottom);
fill.closeSubPath();
g.fillPath (fill);
g.setColour (theme::accent2);
g.strokePath (path, juce::PathStrokeType (1.5f));
}
} // namespace serum