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>
46 sor
1.5 KiB
C++
46 sor
1.5 KiB
C++
#pragma once
|
|
#include <JuceHeader.h>
|
|
|
|
// ============================================================
|
|
// Hann window lookup table (1024 points, computed once)
|
|
// ============================================================
|
|
struct GrainWindow
|
|
{
|
|
static constexpr int tableSize = 1024;
|
|
float table[tableSize];
|
|
|
|
GrainWindow()
|
|
{
|
|
for (int i = 0; i < tableSize; ++i)
|
|
{
|
|
float phase = (float) i / (float) (tableSize - 1);
|
|
table[i] = 0.5f * (1.0f - std::cos (juce::MathConstants<float>::twoPi * phase));
|
|
}
|
|
}
|
|
|
|
float getValue (float phase) const
|
|
{
|
|
float index = juce::jlimit (0.0f, 1.0f, phase) * (float) (tableSize - 1);
|
|
int i0 = (int) index;
|
|
int i1 = std::min (i0 + 1, tableSize - 1);
|
|
float frac = index - (float) i0;
|
|
return table[i0] + frac * (table[i1] - table[i0]);
|
|
}
|
|
};
|
|
|
|
// ============================================================
|
|
// Single grain
|
|
// ============================================================
|
|
struct Grain
|
|
{
|
|
int startSample = 0; // where in source buffer
|
|
int lengthSamples = 0; // grain duration in samples
|
|
float pitchRatio = 1.0f; // playback speed
|
|
double readPosition = 0.0; // current fractional read position
|
|
int samplesElapsed = 0; // output samples generated
|
|
float panPosition = 0.0f; // -1 left, +1 right
|
|
float volume = 1.0f;
|
|
bool reverse = false;
|
|
bool active = false;
|
|
};
|