feat(gui): add GUI components and displays
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
#include "LFODisplay.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
void LFODisplay::setShapeData (const std::vector<float>& data, int s)
|
||||
{
|
||||
steps = juce::jlimit (2, 64, s);
|
||||
shapeData = data;
|
||||
if ((int) shapeData.size() < 64)
|
||||
shapeData.resize (64, 0.0f);
|
||||
repaint();
|
||||
}
|
||||
|
||||
float LFODisplay::valueAt (float phase) const noexcept
|
||||
{
|
||||
switch ((LfoShape) shape)
|
||||
{
|
||||
case LfoShape::Sine: return std::sin (phase * 6.2831853f);
|
||||
case LfoShape::Triangle: return 1.0f - 4.0f * std::abs (phase - 0.5f);
|
||||
case LfoShape::Saw: return 2.0f * phase - 1.0f;
|
||||
case LfoShape::Square: return (phase < 0.5f) ? 1.0f : -1.0f;
|
||||
case LfoShape::SampleHold:
|
||||
{
|
||||
const int step = juce::jlimit (0, 15, (int) (phase * 16.0f));
|
||||
return ((step * 2654435761u) & 0xffffu) / 32768.0f - 1.0f;
|
||||
}
|
||||
case LfoShape::StepSeq:
|
||||
{
|
||||
const int idx = juce::jlimit (0, steps - 1, (int) (phase * steps));
|
||||
return shapeData.empty() ? 0.0f : shapeData[(size_t) idx];
|
||||
}
|
||||
case LfoShape::Freehand:
|
||||
{
|
||||
if (shapeData.empty()) return 0.0f;
|
||||
const float pos = phase * (float) (steps - 1);
|
||||
const int i0 = (int) pos;
|
||||
const int i1 = juce::jmin (i0 + 1, steps - 1);
|
||||
const float frac = pos - (float) i0;
|
||||
return shapeData[(size_t) i0] * (1.0f - frac) + shapeData[(size_t) i1] * frac;
|
||||
}
|
||||
default: return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void LFODisplay::paint (juce::Graphics& g)
|
||||
{
|
||||
const auto b = getLocalBounds().toFloat();
|
||||
g.setColour (juce::Colours::black.withAlpha (0.4f));
|
||||
g.fillRoundedRectangle (b, 4.0f);
|
||||
g.setColour (theme::outline);
|
||||
g.drawRoundedRectangle (b.reduced (0.5f), 4.0f, 1.0f);
|
||||
|
||||
const float midY = b.getCentreY();
|
||||
g.setColour (theme::outline);
|
||||
g.drawLine (b.getX() + 4.0f, midY, b.getRight() - 4.0f, midY, 1.0f);
|
||||
|
||||
// Editable shapes show step markers.
|
||||
if (shape == (int) LfoShape::StepSeq)
|
||||
{
|
||||
const float stepW = (b.getWidth() - 8.0f) / (float) steps;
|
||||
for (int i = 0; i < steps; ++i)
|
||||
{
|
||||
const float v = shapeData.empty() ? 0.0f : shapeData[(size_t) i];
|
||||
const float x = b.getX() + 4.0f + stepW * i;
|
||||
const float y = midY - v * (b.getHeight() * 0.42f);
|
||||
g.setColour (theme::amber);
|
||||
g.fillRect (x + 1.0f, juce::jmin (y, midY), stepW - 2.0f, std::abs (midY - y));
|
||||
}
|
||||
}
|
||||
|
||||
juce::Path path;
|
||||
path.startNewSubPath (b.getX() + 4.0f, midY);
|
||||
const int n = 256;
|
||||
for (int i = 0; i <= n; ++i)
|
||||
{
|
||||
const float phase = (float) i / (float) n;
|
||||
const float v = valueAt (phase);
|
||||
const float x = b.getX() + 4.0f + phase * (b.getWidth() - 8.0f);
|
||||
const float y = midY - v * (b.getHeight() * 0.42f);
|
||||
if (i == 0) path.startNewSubPath (x, y);
|
||||
else path.lineTo (x, y);
|
||||
}
|
||||
g.setColour (theme::green);
|
||||
g.strokePath (path, juce::PathStrokeType (1.5f));
|
||||
}
|
||||
|
||||
void LFODisplay::editAt (float x, float y)
|
||||
{
|
||||
const auto b = getLocalBounds().toFloat();
|
||||
const float midY = b.getCentreY();
|
||||
const float normX = juce::jlimit (0.0f, 1.0f, (x - b.getX() - 4.0f) / (b.getWidth() - 8.0f));
|
||||
const float v = juce::jlimit (-1.0f, 1.0f, (midY - y) / (b.getHeight() * 0.42f));
|
||||
|
||||
if (shapeData.empty())
|
||||
shapeData.assign (64, 0.0f);
|
||||
|
||||
if (shape == (int) LfoShape::StepSeq)
|
||||
{
|
||||
const int idx = juce::jlimit (0, steps - 1, (int) (normX * steps));
|
||||
shapeData[(size_t) idx] = v;
|
||||
}
|
||||
else if (shape == (int) LfoShape::Freehand)
|
||||
{
|
||||
const int idx = juce::jlimit (0, steps - 1, (int) (normX * steps));
|
||||
shapeData[(size_t) idx] = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (onEdited)
|
||||
onEdited (shapeData, steps);
|
||||
repaint();
|
||||
}
|
||||
|
||||
void LFODisplay::mouseDown (const juce::MouseEvent& e)
|
||||
{
|
||||
editAt (e.x, e.y);
|
||||
}
|
||||
|
||||
void LFODisplay::mouseDrag (const juce::MouseEvent& e)
|
||||
{
|
||||
editAt (e.x, e.y);
|
||||
}
|
||||
|
||||
} // namespace serum
|
||||
Reference in New Issue
Block a user