Files
InstaGrain/Source/EnvelopePanel.cpp
hariel1985 55b5f89ac5 Initial release — InstaGrain granular synthesizer v1.0
8-voice polyphonic granular synth (VST3/AU/LV2) with:
- 128 grain pool per voice, Hann windowing, linear interpolation
- Root note selector, sample rate correction, sustain pedal (CC64)
- Scatter controls, direction modes (Fwd/Rev/PingPong), freeze
- ADSR envelope, global filter (LP/HP/BP), reverb
- Waveform display with grain visualization
- Drag & drop sample loading, full state save/restore
- CI/CD for Windows/macOS/Linux

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:26:06 +01:00

64 sor
2.4 KiB
C++

#include "EnvelopePanel.h"
EnvelopePanel::EnvelopePanel()
{
titleLabel.setText ("ENVELOPE", juce::dontSendNotification);
titleLabel.setJustificationType (juce::Justification::centredLeft);
titleLabel.setColour (juce::Label::textColourId, InstaGrainLookAndFeel::textPrimary);
addAndMakeVisible (titleLabel);
setupKnob (attackKnob, aLabel, "A", 0.001, 2.0, 0.01, " s");
setupKnob (decayKnob, dLabel, "D", 0.001, 2.0, 0.1, " s");
setupKnob (sustainKnob, sLabel, "S", 0.0, 1.0, 1.0);
setupKnob (releaseKnob, rLabel, "R", 0.01, 5.0, 0.3, " s");
attackKnob.setSkewFactorFromMidPoint (0.2);
decayKnob.setSkewFactorFromMidPoint (0.3);
releaseKnob.setSkewFactorFromMidPoint (0.5);
}
void EnvelopePanel::setupKnob (juce::Slider& knob, juce::Label& label, const juce::String& name,
double min, double max, double def, const juce::String& suffix)
{
knob.setSliderStyle (juce::Slider::RotaryHorizontalVerticalDrag);
knob.setTextBoxStyle (juce::Slider::TextBoxBelow, false, 50, 14);
knob.setRange (min, max);
knob.setValue (def);
knob.setTextValueSuffix (suffix);
knob.getProperties().set (InstaGrainLookAndFeel::knobTypeProperty, "orange");
addAndMakeVisible (knob);
label.setText (name, juce::dontSendNotification);
label.setJustificationType (juce::Justification::centred);
label.setColour (juce::Label::textColourId, InstaGrainLookAndFeel::textSecondary);
addAndMakeVisible (label);
}
void EnvelopePanel::resized()
{
auto bounds = getLocalBounds().reduced (4);
titleLabel.setBounds (bounds.removeFromTop (20));
int knobW = bounds.getWidth() / 4;
juce::Slider* knobs[] = { &attackKnob, &decayKnob, &sustainKnob, &releaseKnob };
juce::Label* labels[] = { &aLabel, &dLabel, &sLabel, &rLabel };
for (int i = 0; i < 4; ++i)
{
auto col = bounds.removeFromLeft (knobW);
auto knobArea = col.withTrimmedBottom (16);
knobs[i]->setBounds (knobArea.reduced (2));
labels[i]->setBounds (col.getX(), knobArea.getBottom() - 2, col.getWidth(), 16);
}
}
void EnvelopePanel::paint (juce::Graphics& g)
{
auto bounds = getLocalBounds().toFloat();
g.setColour (InstaGrainLookAndFeel::bgMedium.withAlpha (0.5f));
g.fillRoundedRectangle (bounds, 4.0f);
g.setColour (InstaGrainLookAndFeel::bgLight.withAlpha (0.3f));
g.drawRoundedRectangle (bounds, 4.0f, 1.0f);
}