(

// Define the bus to send the audio to the filter
~bus = Bus.audio(s, 2);
~fxBus = Bus.audio(s, 2);
~synthGroup = Group.head(s);             // synths go here
~filterGroup = Group.after(~synthGroup); // filter comes after

~lfoBus = Bus.control(s, 1);       // 1-channel control bus for the LFO
~filterEnvBus = Bus.control(s, 1); // 1-channel control bus for the filter envelope


// Low Frequency Oscillator for parameter modulation
SynthDef(\lfo, { |out=0, freq=2, min=(-0.5), max=0.5, waveform=0|
    var lfo;

    // Select waveform based on parameter
    lfo = Select.kr(waveform, [
        SinOsc.kr(freq),         // Sine wave (waveform=0)
        LFTri.kr(freq),          // Triangle wave (waveform=1)
        LFSaw.kr(freq, 0, -1),   // Decreasing sawtooth wave (waveform=2)
        LFPulse.kr(freq, 0, 0.5) // Square wave (waveform=3)
    ]);

    // Scale to range
    lfo = lfo.range(min, max);

    // Output to control bus
    Out.kr(out, lfo);
}).add;



// RGB-controlled synthesizer with amplitude envelope
SynthDef(\rgbSynth, { |out=0, freq=440, amp=1, ampAttack=0.01, ampRelease=1,
	pitchAttack=0, pitchDecay=0, pitchRatio=1,
	redAmt=1, greenAmt=1, blueAmt=1,
	lfoBus=(-1), lfoDepth=0|

    var env, gate, pitchEnv, red, green, blue, sig, modFreq, lfo;

	gate = \gate.kr(0);

    // Amplitude envelope
    env = EnvGen.kr(Env.adsr(ampAttack, 0, 1, ampRelease), gate);

    // Pitch envelope
    pitchEnv = EnvGen.kr(Env.adsr(pitchAttack, pitchDecay, 0, pitchDecay), gate);

	 // If lfoBus < 0, read from bus 0 (assumed silent)
	lfo = In.kr(lfoBus.max(0));
	lfo.postln();

    // Calculate modulated frequency
    modFreq = freq * (1 + (pitchEnv * (pitchRatio - 1))) * (1 + (lfo * lfoDepth));

    // Different waveforms for RGB components
    red = SinOsc.ar(modFreq) * redAmt;
    green = Saw.ar(modFreq) * greenAmt;
    blue = Pulse.ar(modFreq, 0.5) * blueAmt;

    // Mix the waveforms
    sig = (red + green + blue) / 3;

    // Apply envelope and output
    sig = sig * env * amp;
    Out.ar(out, sig!2);
}).add;


SynthDef(\filterEnv, {
    |out=0, gate=1, attack=0.001, decay=0|

    var env = EnvGen.kr(Env.adsr(attack, decay, 0, decay), gate);
    Out.kr(out, env);
}).add;


// The sound goes into a LPF
SynthDef(\lpf, { |in=0, out=0, cutoff=18000, resonance=1,
	lfoBus=(-1), lfoDepth=0, envBus=(-1), envDepth=0|

	var sig, lfo, env, modCutoff, rq;

	// Read audio and control signals from buses
    sig = In.ar(in, 2);
    lfo = In.kr(lfoBus.max(0));
    env = In.kr(envBus.max(0));

	modCutoff = cutoff * (1 + (lfo * lfoDepth)) * (1 + (env * envDepth));
	modCutoff = modCutoff.clip(20, 18000);  // safety

	rq = resonance.linexp(0, 1, 1, 0.07); // Transforms resonance amount to rq with exp interpolation

    sig = RLPF.ar(sig, modCutoff, rq); // low-pass filter

    Out.ar(out, sig);
}).add;



// Create a SynthDef with the VSTPlugin UGen
SynthDef(\juceVST, { |in, out|

	var sound = In.ar(in, 2);
	ReplaceOut.ar(out, VSTPlugin.ar(sound, 2))

}).add;



"RGB-controlled synthesizer loaded".postln;
)





