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:
119
Source/PluginProcessor.cpp
Normal file
119
Source/PluginProcessor.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "PluginProcessor.h"
|
||||
#include "PluginEditor.h"
|
||||
|
||||
InstaGrainProcessor::InstaGrainProcessor()
|
||||
: AudioProcessor (BusesProperties()
|
||||
.withOutput ("Output", juce::AudioChannelSet::stereo(), true))
|
||||
{
|
||||
}
|
||||
|
||||
InstaGrainProcessor::~InstaGrainProcessor() {}
|
||||
|
||||
void InstaGrainProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
|
||||
{
|
||||
engine.prepare (sampleRate, samplesPerBlock);
|
||||
}
|
||||
|
||||
void InstaGrainProcessor::releaseResources() {}
|
||||
|
||||
bool InstaGrainProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
|
||||
{
|
||||
if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstaGrainProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
|
||||
{
|
||||
juce::ScopedNoDenormals noDenormals;
|
||||
|
||||
if (bypass.load())
|
||||
{
|
||||
buffer.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
engine.processBlock (buffer, midiMessages);
|
||||
}
|
||||
|
||||
juce::AudioProcessorEditor* InstaGrainProcessor::createEditor()
|
||||
{
|
||||
return new InstaGrainEditor (*this);
|
||||
}
|
||||
|
||||
void InstaGrainProcessor::getStateInformation (juce::MemoryBlock& destData)
|
||||
{
|
||||
auto xml = std::make_unique<juce::XmlElement> ("InstaGrainState");
|
||||
|
||||
xml->setAttribute ("samplePath", engine.getSamplePath());
|
||||
xml->setAttribute ("rootNote", engine.rootNote.load());
|
||||
xml->setAttribute ("position", (double) engine.position.load());
|
||||
xml->setAttribute ("grainSize", (double) engine.grainSizeMs.load());
|
||||
xml->setAttribute ("density", (double) engine.density.load());
|
||||
xml->setAttribute ("pitch", (double) engine.pitchSemitones.load());
|
||||
xml->setAttribute ("pan", (double) engine.pan.load());
|
||||
xml->setAttribute ("posScatter", (double) engine.posScatter.load());
|
||||
xml->setAttribute ("sizeScatter", (double) engine.sizeScatter.load());
|
||||
xml->setAttribute ("pitchScatter", (double) engine.pitchScatter.load());
|
||||
xml->setAttribute ("panScatter", (double) engine.panScatter.load());
|
||||
xml->setAttribute ("direction", engine.direction.load());
|
||||
xml->setAttribute ("freeze", engine.freeze.load());
|
||||
xml->setAttribute ("attack", (double) engine.attackTime.load());
|
||||
xml->setAttribute ("decay", (double) engine.decayTime.load());
|
||||
xml->setAttribute ("sustain", (double) engine.sustainLevel.load());
|
||||
xml->setAttribute ("release", (double) engine.releaseTime.load());
|
||||
xml->setAttribute ("filterType", engine.filterType.load());
|
||||
xml->setAttribute ("filterCutoff", (double) engine.filterCutoff.load());
|
||||
xml->setAttribute ("filterReso", (double) engine.filterReso.load());
|
||||
xml->setAttribute ("reverbSize", (double) engine.reverbSize.load());
|
||||
xml->setAttribute ("reverbDecay", (double) engine.reverbDecay.load());
|
||||
xml->setAttribute ("masterVolume", (double) engine.masterVolume.load());
|
||||
xml->setAttribute ("bypass", bypass.load());
|
||||
|
||||
copyXmlToBinary (*xml, destData);
|
||||
}
|
||||
|
||||
void InstaGrainProcessor::setStateInformation (const void* data, int sizeInBytes)
|
||||
{
|
||||
auto xml = getXmlFromBinary (data, sizeInBytes);
|
||||
if (xml == nullptr || ! xml->hasTagName ("InstaGrainState"))
|
||||
return;
|
||||
|
||||
// Load sample
|
||||
juce::String samplePath = xml->getStringAttribute ("samplePath", "");
|
||||
if (samplePath.isNotEmpty())
|
||||
{
|
||||
juce::File f (samplePath);
|
||||
if (f.existsAsFile())
|
||||
engine.loadSample (f);
|
||||
}
|
||||
|
||||
engine.rootNote.store (xml->getIntAttribute ("rootNote", 60));
|
||||
engine.position.store ((float) xml->getDoubleAttribute ("position", 0.5));
|
||||
engine.grainSizeMs.store ((float) xml->getDoubleAttribute ("grainSize", 100.0));
|
||||
engine.density.store ((float) xml->getDoubleAttribute ("density", 10.0));
|
||||
engine.pitchSemitones.store ((float) xml->getDoubleAttribute ("pitch", 0.0));
|
||||
engine.pan.store ((float) xml->getDoubleAttribute ("pan", 0.0));
|
||||
engine.posScatter.store ((float) xml->getDoubleAttribute ("posScatter", 0.0));
|
||||
engine.sizeScatter.store ((float) xml->getDoubleAttribute ("sizeScatter", 0.0));
|
||||
engine.pitchScatter.store ((float) xml->getDoubleAttribute ("pitchScatter", 0.0));
|
||||
engine.panScatter.store ((float) xml->getDoubleAttribute ("panScatter", 0.0));
|
||||
engine.direction.store (xml->getIntAttribute ("direction", 0));
|
||||
engine.freeze.store (xml->getBoolAttribute ("freeze", false));
|
||||
engine.attackTime.store ((float) xml->getDoubleAttribute ("attack", 0.01));
|
||||
engine.decayTime.store ((float) xml->getDoubleAttribute ("decay", 0.1));
|
||||
engine.sustainLevel.store ((float) xml->getDoubleAttribute ("sustain", 1.0));
|
||||
engine.releaseTime.store ((float) xml->getDoubleAttribute ("release", 0.3));
|
||||
engine.filterType.store (xml->getIntAttribute ("filterType", 0));
|
||||
engine.filterCutoff.store ((float) xml->getDoubleAttribute ("filterCutoff", 20000.0));
|
||||
engine.filterReso.store ((float) xml->getDoubleAttribute ("filterReso", 0.707));
|
||||
engine.reverbSize.store ((float) xml->getDoubleAttribute ("reverbSize", 0.0));
|
||||
engine.reverbDecay.store ((float) xml->getDoubleAttribute ("reverbDecay", 0.0));
|
||||
engine.masterVolume.store ((float) xml->getDoubleAttribute ("masterVolume", 1.0));
|
||||
bypass.store (xml->getBoolAttribute ("bypass", false));
|
||||
}
|
||||
|
||||
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
||||
{
|
||||
return new InstaGrainProcessor();
|
||||
}
|
||||
Reference in New Issue
Block a user