b = Buffer.read(s, "/home/lcoogan/snd/demos/desolation.wav");
(
{
    PlayBuf.ar(2, b, 1, loop: 1) * 0.3
}.play;
)

/*add springverb and dubecho
split break and pad*/


(
SynthDef(\grainFMPad, {
    |out=0, bufnum=0, rate=1, centerFreq=200, dur=6, amp=0.3, pan=0|
    var trigRate = 20; // how many grains per second
    var grainDur = 0.1; // duration of each grain
    var snd;

    snd = GrainFM.ar(
        numChannels: 2,
        trigger: Impulse.kr(trigRate),
        dur: grainDur,
        carfreq: LFNoise1.kr(0.2).range(centerFreq * 0.5, centerFreq * 1.5),
        modfreq: LFNoise1.kr(0.1).range(100, 300),
        index: LFNoise1.kr(0.05).range(1, 10),
        pan: LFNoise1.kr(0.5),
        envbufnum: -1,
        sndbuf: bufnum,
        rate: rate
    );

    // Smoothing the pad
    snd = snd * EnvGen.kr(Env.linen(2, dur-4, 2), doneAction: 2) * amp;
    Out.ar(out, snd);
}).add;
)

(
// play it with your buffer b
x = Synth(\grainFMPad, [
    \bufnum, b,
    \centerFreq, 250,
    \dur, 12,
    \amp, 0.3
]);
)

(
~midiToFreq = { |note| note.midicps };
)


(
t = TempoClock(86/60);

Pbind(
    \instrument, \grainFMPad,
    \bufnum, b, // your loaded buffer
    \dur, 2, // time between notes (longer since your grains are pad-like)
    \centerFreq, Pseq([60, 62, 65, 67, 69, 72].collect(~midiToFreq), inf),
    \amp, 0.05,
    \rate,1,
    \pan, 0,
).play(t);
)


(
SynthDef(\grainFMPad, {
    |out=0, bufnum=0, rate=1, centerFreq=200, dur=6, amp=0.3, pan=0|
    var trigRate = 20;
    var grainDur = 0.1;
    var snd;

    // Subtle detuning of carrier freq (optional)
    var carfreq = centerFreq * LFNoise1.kr(0.1).range(0.98, 1.02);

    snd = GrainFM.ar(
        numChannels: 2,
        trigger: Impulse.kr(trigRate),
        dur: grainDur,
        carfreq: carfreq, // More stable, but still a little alive
        modfreq: LFNoise1.kr(0.1).range(100, 300),
        index: LFNoise1.kr(0.05).range(1, 10),
        pan: LFNoise1.kr(0.5),
        envbufnum: -1,
        sndbuf: bufnum,
        rate: rate
    );

    snd = snd * EnvGen.kr(Env.linen(2, dur - 4, 2), doneAction: 2) * amp;
    Out.ar(out, snd);
}).add;
)


(
SynthDef(\grainFMPadBlended, {
    |out=0, bufnum=0, rate=1, centerFreq=500, dur=6, amp=0.3, pan=0, toneMix=1|
    var trigRate = 20;
    var grainDur = 0.1;
    var snd, tone, blend;

    // GrainFM layer
    snd = GrainFM.ar(
        numChannels: 2,
        trigger: Impulse.kr(trigRate),
        dur: grainDur,
        carfreq: centerFreq,
        modfreq: centerFreq * 2,
        index: 1.0,
        pan: pan,
        envbufnum: -1,
        sndbuf: bufnum,
        rate: rate
    );

    // Clean tone layer (can also try Saw or Pulse for edge)
    tone = SinOsc.ar(centerFreq ! 2); // stereo

    // Blend between grainy texture and clean tone
    blend = XFade2.ar(snd, tone, (toneMix * 2 - 1)); // toneMix: 0 = all grains, 1 = all tone

    // Envelope
    blend = blend * EnvGen.kr(Env.linen(2, dur - 4, 2), doneAction: 2) * amp;

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


(
SynthDef(\grainFMPadShifted, {
    |out=0, bufnum=0, rate=1, centerFreq=200, dur=6, amp=0.3, pan=0, pitchRatio=20.0|
    var trigRate = 20;
    var grainDur = 0.1;
    var snd, shifted;

    snd = GrainFM.ar(
        numChannels: 2,
        trigger: Impulse.kr(trigRate),
        dur: grainDur,
        carfreq: centerFreq,
        modfreq: centerFreq * 2,
        index: 1.0,
        pan: pan,
        envbufnum: -1,
        sndbuf: bufnum,
        rate: rate
    );

    // Pitch shift output toward stable tone
    shifted = PitchShift.ar(snd, windowSize: 0.2, pitchRatio: pitchRatio, pitchDisp: 0.0);

    shifted = shifted * EnvGen.kr(Env.linen(2, dur - 4, 2), doneAction: 2) * amp;

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




(
SynthDef(\grainFMPadPV, {
    |out=0, bufnum=0, rate=1, centerFreq=1, dur=1, amp=0.3, pan=0, shiftBins=20, gate 1, env|
    var trigRate = 20;
    var grainDur = 0.1;
    var snd, chain, shifted;

    snd = GrainFM.ar(
        numChannels: 1, // FFT works on mono
        trigger: Impulse.kr(trigRate),
        dur: grainDur,
        carfreq: centerFreq,
        modfreq: centerFreq * 1,
        index: 1.0,
        pan: 0,
        envbufnum: -1,
        sndbuf: b,
        rate: rate
    );

	env = EnvGen.kr(Env.asr(0.1, 1.0, 0.1, -4), gate, doneAction:2);

    // FFT and PV shift
    chain = FFT(LocalBuf(2048), snd);
	// chain = PV_MagShift(chain, shiftBins, 0); // shifts bins upward
	chain = PV_BinScramble(chain, 1, 1, 0);
	chain = PV_BinDelay(chain, 1, 1, 1, 0.5);
	chain = PV_PitchShift(chain, -2000);
	chain = PV_BrickWall(chain, -20000);
	chain = PV_NoiseSynthF(chain, 80, 2, 0);


    shifted = IFFT(chain);
    shifted = Pan2.ar(shifted, pan); // stereo output

	shifted = RLPF.ar(shifted, 800, 0.1);
	shifted = CombL.ar(shifted);


	// shifted = shifted * EnvGen.kr(Env.linen(2, dur - 4, 2), doneAction: 2) * amp;
	shifted = shifted * amp;
    Out.ar(out, shifted);
}).add;
)


(
~midiToFreq = { |note| note.midicps };
)


(
t = TempoClock(86/60);

Pbind(
    \instrument, \grainFMPad,
    \bufnum, b, // your loaded buffer
    \dur, 2, // time between notes (longer since your grains are pad-like)
    \centerFreq, Pseq([60].collect(~midiToFreq), inf),
    \amp, 0.05,
    \rate,1,
    \pan, 0,
).play(t);
)

