Files
InstaDrums/Source/DrumPad.h
hariel1985 4cc22e0bf0 Initial commit: InstaDrums VST3 drum sampler plugin
- 12-pad drum sampler with 4x3 grid (expandable by 4)
- Velocity layers with round-robin (Salamander-style filename parsing)
- Rhythm Engine-style GUI: pad grid (left), sample editor (right top),
  FX panel (right bottom), master panel (bottom)
- Waveform thumbnails on pads + large waveform in sample editor
- ADSR envelope, pitch, pan per pad
- Drag & drop sample/folder loading
- Kit save/load (.drumkit XML presets)
- Load Folder with smart name matching (kick, snare, hihat, etc.)
- Choke groups, one-shot/polyphonic mode
- Dark modern LookAndFeel with neon accent colors
- Built with JUCE framework, CMake, MSVC 2022

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 10:59:31 +01:00

107 sor
3.0 KiB
C++

#pragma once
#include <JuceHeader.h>
class DrumPad
{
public:
// A single sample with its audio data and source sample rate
struct Sample
{
juce::AudioBuffer<float> buffer;
double sampleRate = 44100.0;
juce::File file;
};
// A velocity layer: velocity range + multiple round-robin samples
struct VelocityLayer
{
float velocityLow = 0.0f; // 0.0 - 1.0
float velocityHigh = 1.0f;
juce::OwnedArray<Sample> samples; // round-robin variations
int nextRoundRobin = 0;
Sample* getNextSample()
{
if (samples.isEmpty()) return nullptr;
auto* s = samples[nextRoundRobin % samples.size()];
nextRoundRobin = (nextRoundRobin + 1) % samples.size();
return s;
}
};
DrumPad();
~DrumPad();
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);
void stop();
void renderNextBlock (juce::AudioBuffer<float>& outputBuffer, int startSample, int numSamples);
// Pad properties
juce::String name;
int midiNote = 36;
float volume = 1.0f;
float pan = 0.0f;
float pitch = 0.0f;
bool oneShot = true;
int chokeGroup = -1;
juce::Colour colour { 0xff00ff88 };
// ADSR
float attack = 0.001f;
float decay = 0.1f;
float sustain = 1.0f;
float release = 0.05f;
// State
bool isPlaying() const { return playing; }
juce::String getLoadedFileName() const { return loadedFileName; }
juce::File getLoadedFile() const { return loadedFile; }
int getNumLayers() const { return layers.size(); }
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;
double sampleRate = 44100.0;
double readPosition = 0.0;
bool playing = false;
float currentVelocity = 1.0f;
// ADSR state
enum class EnvelopeStage { Idle, Attack, Decay, Sustain, Release };
EnvelopeStage envStage = EnvelopeStage::Idle;
float envLevel = 0.0f;
juce::String loadedFileName;
juce::File loadedFile;
void advanceEnvelope();
VelocityLayer* findLayerForVelocity (float velocity);
// 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);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DrumPad)
};