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>
53 sor
1.8 KiB
C++
53 sor
1.8 KiB
C++
#pragma once
|
|
#include <JuceHeader.h>
|
|
#include "Grain.h"
|
|
|
|
class GrainCloud
|
|
{
|
|
public:
|
|
static constexpr int maxGrains = 128;
|
|
|
|
enum class Direction { Forward, Reverse, PingPong };
|
|
|
|
GrainCloud();
|
|
|
|
void prepare (double sampleRate);
|
|
void processBlock (juce::AudioBuffer<float>& output, int numSamples,
|
|
const juce::AudioBuffer<float>& sourceBuffer);
|
|
void reset();
|
|
|
|
// Parameters (atomic — GUI writes, audio reads)
|
|
std::atomic<float> position { 0.5f }; // 0-1
|
|
std::atomic<float> grainSizeMs { 100.0f }; // 10-500
|
|
std::atomic<float> density { 10.0f }; // 1-100 grains/sec
|
|
std::atomic<float> pitchSemitones { 0.0f }; // -24..+24
|
|
std::atomic<float> pan { 0.0f }; // -1..+1
|
|
std::atomic<float> posScatter { 0.0f }; // 0-1
|
|
std::atomic<float> sizeScatter { 0.0f }; // 0-1
|
|
std::atomic<float> pitchScatter { 0.0f }; // 0-1
|
|
std::atomic<float> panScatter { 0.0f }; // 0-1
|
|
std::atomic<int> direction { 0 }; // 0=Fwd, 1=Rev, 2=PingPong
|
|
std::atomic<bool> freeze { false };
|
|
|
|
// Extra pitch offset from MIDI note
|
|
float midiPitchOffset = 0.0f;
|
|
|
|
// Sample rate correction: sourceSampleRate / dawSampleRate
|
|
float sampleRateRatio = 1.0f;
|
|
|
|
// For visualization — snapshot of active grains
|
|
struct GrainInfo { int startSample; int lengthSamples; float progress; };
|
|
std::array<GrainInfo, maxGrains> getActiveGrainInfo() const;
|
|
int getActiveGrainCount() const;
|
|
|
|
private:
|
|
double currentSampleRate = 44100.0;
|
|
std::array<Grain, maxGrains> grains;
|
|
GrainWindow window;
|
|
int samplesUntilNextGrain = 0;
|
|
juce::Random rng;
|
|
|
|
void spawnGrain (const juce::AudioBuffer<float>& sourceBuffer);
|
|
float readSampleInterpolated (const juce::AudioBuffer<float>& buffer, double position) const;
|
|
};
|