~terrain = Buffer.alloc(s, 1024, 1);
~terrain.sine1([1, 0.5, 0.3, 0.2, 0.1], true); // You can sculpt this more chaotically
~terrain.postln;

(
// Generate a terrain table
~terrain = Buffer.alloc(s, 1024, 1);
~terrain.sine1([1, 0.3, 0.3, 0.2, 0.1], true); // You can sculpt this more chaotically

SynthDef("fm_pulsar_terrain", {
	arg a, e, f, d;
	var t, overlap, carfreq, modfreq, mInd, vel, vel_, tblPos, sig;

	f = \freq.kr(100);

	vel = \kel.kr(0.5);
	vel_ = vel.clip(0,1.0).linlin( 0, 1, 2, 0.7);

	e = EnvGen.kr(
		Env.adsr(
			\att.kr(0.025) * vel_,
			\dec.kr(0.02) * vel_,
			\susl.kr(0.7),
			\rel.kr(4),
			curve: \curve.kr(-4)
		),
		gate: \gate.kr(1),
		doneAction:2
	) * vel;

	carfreq = f * \cf.kr(2) + LFNoise1.kr(3).range(0,50);
	modfreq = carfreq * \mf.kr(2) + LFNoise1.kr(3).range(0,100);

	t = Impulse.ar(f);

	mInd = e.pow(3.3); // use envelope shape to shift table pos
	overlap = 1.1 - e.pow(0.5);
	d = overlap / f;

	// convert modfreq to index between 0 and 1 for VOsc
	tblPos = modfreq.linlin(0, 8000, 0, 1).wrap(0, 1); // safer than clip for edge cases

	a = Mix([
		SinOsc.ar(f),
		// GrainBuf.ar(1, t, d, ~terrain, tblPos, carfreq, 0, 2)
		GrainBuf.ar(1, t, d, ~terrain, tblPos, carfreq);
		// GrainBuf.ar(numChannels:1, trigger:0, dur:1, ~terrain, rate:1, pos:0, interp:2)
	]);

	a = LeakDC.ar(a * e);

	a = FreeVerb.ar(a, 0.33, 1);

	Out.ar(\outBus.kr(0), a.dup * \gain.kr(0.1));

}).add;


Synth(\fm_pulsar_terrain);
)



(
// MIDI
// EMF: one major issue here is that ~notes is never actually initialized as an array, so it's nil. when you try to store a Synth at index nn, SC throws an error, because you can't put an item into nil. So, we first initialize ~notes as an array of size 128. After I add this line, your polyphonic MIDI code seems to work fine (no stuck notes)

~notes = Array.newClear(128);

MIDIdef.noteOn(\noteOnTest, {
	arg vel, nn, chan, src;
	[vel, nn].postln;

	if (chan == 0, {
		~notes[nn] = Synth.new(
			\fm_pulsar_terrain,
			[
				\freq, nn.midicps,
				\amp, vel.linexp(1,127,0.01,0.3),
				// \gate, 1,

			]
		);
	});
});

MIDIdef.noteOff(\noteOffTest, {
	arg vel, nn, chan;
	[vel, nn].postln;

	if (chan == 0, {
		~notes[nn].set(\gate, 0);
		~notes[nn] = nil;
	});
});

[
	[\f0ratio, 0, 1],
	[\f1ratio, 0, 1],
	[\f2ratio, 0, 1],
	[\modInd0, 0, 1],
	[\modInd1, 0, 1],
	[\modInd2, 0, 1],
].do { |spec|
	var param, cc, min, max;
	#param, cc, min, max = spec;

	MIDIdef.cc(param.asSymbol, { |val, num, chan, src|
		if (chan == 0) {
			var mapped = val.linlin(0, 127, min, max);
			\fm3mc_perc.set(param, mapped);
		}
	}, cc);
};
)



MIDIClient.init;
MIDIIn.connectAll;
