s.boot;
b = Buffer.read(s, "/home/lcoogan/Misc/grave.wav");

(
SynthDef("tonal_grain_sample", {
	arg freq = 220, gate = 1, outBus = 0, gain = 0.1;
	var env, t, grainDur, pos, rate, sig, baseFreq;

	// Envelope to shape amplitude
	env = EnvGen.kr(
		Env.adsr(0.01, 0.1, 0.6, 1.5, curve: -4),
		gate,
		doneAction: 2
	);

	// Trigger for grains
	t = Impulse.ar(freq);

	// Duration of each grain
	grainDur = 0.1;

	// Playback rate controls pitch: freq / base pitch of sample
	baseFreq = 220; // You can adjust this depending on your sample
	rate = freq / baseFreq;

	// Position in buffer: random or LFO modulation
	pos = LFNoise1.kr(1).range(0, 0.3); // pick random spots in the buffer

	// Granulate the sample buffer tonally
	sig = GrainBuf.ar(
		numChannels: 2,
		trigger: t,
		dur: grainDur,
		sndbuf: b, // use your sample buffer
		rate: rate,
		pos: pos,
		interp: 2
	);

	sig = sig * env;
	sig = FreeVerb.ar(sig, 0.3, 0.9);
	sig = LeakDC.ar(sig);

	Out.ar(outBus, sig * gain);
}).add;
)

Synth(\tonal_grain_sample, [ \grainDur, 0.3, \freq, [50].midicps]);
