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>
This commit is contained in:
hariel1985
2026-03-26 17:26:06 +01:00
commit 55b5f89ac5
34 fájl változott, egészen pontosan 2728 új sor hozzáadva és 0 régi sor törölve

86
Source/GrainEngine.h Normal file
Fájl megtekintése

@@ -0,0 +1,86 @@
#pragma once
#include <JuceHeader.h>
#include "GrainVoice.h"
class GrainEngine
{
public:
static constexpr int maxVoices = 8;
GrainEngine();
void prepare (double sampleRate, int samplesPerBlock);
void processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages);
void loadSample (const juce::File& file);
void loadSample (const void* data, size_t dataSize, const juce::String& formatName);
const juce::AudioBuffer<float>& getSampleBuffer() const { return sampleBuffer; }
double getSampleRate() const { return currentSampleRate; }
bool hasSample() const { return sampleBuffer.getNumSamples() > 0; }
juce::String getSamplePath() const { return loadedSamplePath; }
// Root note — which MIDI note the sample represents (default C4 = 60)
std::atomic<int> rootNote { 60 };
// Grain parameters (GUI → audio)
std::atomic<float> position { 0.5f };
std::atomic<float> grainSizeMs { 100.0f };
std::atomic<float> density { 10.0f };
std::atomic<float> pitchSemitones { 0.0f };
std::atomic<float> pan { 0.0f };
std::atomic<float> posScatter { 0.0f };
std::atomic<float> sizeScatter { 0.0f };
std::atomic<float> pitchScatter { 0.0f };
std::atomic<float> panScatter { 0.0f };
std::atomic<int> direction { 0 };
std::atomic<bool> freeze { false };
// ADSR
std::atomic<float> attackTime { 0.01f };
std::atomic<float> decayTime { 0.1f };
std::atomic<float> sustainLevel { 1.0f };
std::atomic<float> releaseTime { 0.3f };
// Filter
std::atomic<int> filterType { 0 }; // 0=LP, 1=HP, 2=BP
std::atomic<float> filterCutoff { 20000.0f };
std::atomic<float> filterReso { 0.707f };
// Reverb
std::atomic<float> reverbSize { 0.0f };
std::atomic<float> reverbDecay { 0.0f };
// Master
std::atomic<float> masterVolume { 1.0f };
// VU meter levels (audio → GUI)
std::atomic<float> vuLevelL { 0.0f };
std::atomic<float> vuLevelR { 0.0f };
// Grain visualization
struct ActiveGrainInfo { int startSample; int lengthSamples; float progress; };
std::vector<ActiveGrainInfo> getActiveGrainInfo() const;
private:
std::array<GrainVoice, maxVoices> voices;
juce::AudioBuffer<float> sampleBuffer;
juce::String loadedSamplePath;
double currentSampleRate = 44100.0;
double sourceSampleRate = 44100.0;
int currentBlockSize = 512;
juce::AudioFormatManager formatManager;
// Global effects
juce::dsp::StateVariableTPTFilter<float> filter;
juce::Reverb reverb;
juce::Reverb::Parameters reverbParams;
void handleMidiEvent (const juce::MidiMessage& msg);
void handleNoteOff (int note);
void syncVoiceParameters();
// Sustain pedal
bool sustainPedalDown = false;
std::array<bool, maxVoices> sustainedVoices {}; // voices held by pedal
};