#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