Per-pad FX chain, animated toggles, GR meter, simplified master panel

- FX moved from master bus to per-pad processing:
  each pad has its own Filter, Distortion, EQ, Compressor, Reverb
  via DrumPad::applyPadFx() with temp buffer rendering
- FxPanel now edits the selected pad's FX parameters
- Animated toggle switches with smooth lerp transition and glow
- Per-pad compressor GR meter connected to FxPanel display
- Master panel simplified: Volume/Tune/Pan + Limiter toggle + VU meter
- Master bus chain: Vol/Pan → Output Limiter (0dB brickwall) → VU
- Pointer glow reduced to half intensity (4 layers, narrower spread)
- Smooth 8-layer arc glow with exponential opacity falloff

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hariel1985
2026-03-23 06:42:47 +01:00
szülő 20b9fe2674
commit a0e83fa0a4
11 fájl változott, egészen pontosan 500 új sor hozzáadva és 210 régi sor törölve

Fájl megtekintése

@@ -4,7 +4,6 @@
class DrumPad
{
public:
// A single sample with its audio data and source sample rate
struct Sample
{
juce::AudioBuffer<float> buffer;
@@ -12,12 +11,11 @@ public:
juce::File file;
};
// A velocity layer: velocity range + multiple round-robin samples
struct VelocityLayer
{
float velocityLow = 0.0f; // 0.0 - 1.0
float velocityLow = 0.0f;
float velocityHigh = 1.0f;
juce::OwnedArray<Sample> samples; // round-robin variations
juce::OwnedArray<Sample> samples;
int nextRoundRobin = 0;
Sample* getNextSample()
@@ -35,12 +33,8 @@ public:
void prepareToPlay (double sampleRate, int samplesPerBlock);
void releaseResources();
// Single sample loading (backwards compatible)
void loadSample (const juce::File& file, juce::AudioFormatManager& formatManager);
// Velocity layer loading from a folder
void loadLayersFromFolder (const juce::File& folder, juce::AudioFormatManager& formatManager);
bool hasSample() const;
void trigger (float velocity = 1.0f);
@@ -65,8 +59,29 @@ public:
float release = 0.05f;
// Per-pad filter
float filterCutoff = 20000.0f; // Hz
float filterReso = 0.707f; // Q
float filterCutoff = 20000.0f;
float filterReso = 0.707f;
// Per-pad FX parameters
bool fxCompEnabled = false;
float fxCompThreshold = -12.0f;
float fxCompRatio = 4.0f;
bool fxEqEnabled = false;
float fxEqLo = 0.0f;
float fxEqMid = 0.0f;
float fxEqHi = 0.0f;
bool fxDistEnabled = false;
float fxDistDrive = 0.0f;
float fxDistMix = 0.0f;
bool fxReverbEnabled = false;
float fxReverbSize = 0.3f;
float fxReverbDecay = 0.5f;
// Compressor GR readout (written by audio, read by GUI)
std::atomic<float> compGainReduction { 0.0f };
// State
bool isPlaying() const { return playing; }
@@ -77,24 +92,26 @@ public:
const juce::AudioBuffer<float>& getSampleBuffer() const;
private:
// Velocity layers (sorted by velocity range)
juce::OwnedArray<VelocityLayer> layers;
// Currently playing sample reference
Sample* activeSample = nullptr;
// Fallback empty buffer for getSampleBuffer when nothing loaded
juce::AudioBuffer<float> emptyBuffer;
juce::AudioBuffer<float> tempBuffer; // for per-pad FX processing
double sampleRate = 44100.0;
int blockSize = 512;
double readPosition = 0.0;
bool playing = false;
float currentVelocity = 1.0f;
// Per-pad low-pass filter (stereo)
// Per-pad filter (stereo)
juce::dsp::IIR::Filter<float> filterL, filterR;
float lastCutoff = 20000.0f;
// Per-pad FX processors
juce::dsp::Compressor<float> padCompressor;
juce::dsp::IIR::Filter<float> padEqLoL, padEqLoR, padEqMidL, padEqMidR, padEqHiL, padEqHiR;
juce::dsp::Reverb padReverb;
// ADSR state
enum class EnvelopeStage { Idle, Attack, Decay, Sustain, Release };
EnvelopeStage envStage = EnvelopeStage::Idle;
@@ -105,8 +122,8 @@ private:
void advanceEnvelope();
VelocityLayer* findLayerForVelocity (float velocity);
void applyPadFx (juce::AudioBuffer<float>& buf, int numSamples);
// Parse velocity tag from filename (e.g. "snare_OH_FF_1" -> FF)
static float velocityTagToLow (const juce::String& tag);
static float velocityTagToHigh (const juce::String& tag);