First steps - a patch which will load a file into a buffer and let you play through it at different rate

(
var s, b, w, serverbut, openDialog, playbut, ratesl;

s = Server.local;
b = Buffer.read(s, "sounds/break2.wav");

// A synthdef - using PlayBuf to play the contents of the buffer "b"
SynthDef("fplayer", { arg rate;
var file;
file = PlayBuf.ar(2, b.bufnum, rate);
Out.ar(0, file);
}).writeDefFile;
s.sendSynthDef("fplayer");

// Create a window. When it is closed, the buffer b will be freed
w = SCWindow("Granular Synthesis", Rect(100, 400, 600, 600));
w.onClose = {b.free};
w.front;

// A button to start and stop the server
serverbut = SCButton(w, Rect(10, 30, 100, 25));
serverbut.states = [
		["Start Server", Color.black, Color.white],
		["Stop Server", Color.white, Color.black],
];
serverbut.action = {
		if (serverbut.value == 1, {s.boot;},{s.quit;});
};

// A button to bring up a file dialog. Whenever a file is selected, buffer
// b is cleared and the new file is read into it.
openDialog = SCButton(w, Rect(10, 60, 100, 25));
openDialog.states = [
	["Open File", Color.black, Color.new(0.8,0.8,0.8)]
];
openDialog.action = {
	CocoaDialog.getPaths({ arg paths;
		if (b != nil, {b.free});
		b = Buffer.read(s, paths.at(0));
	},{
		"Cancelled".postln;
	});
};

// A button to play back the contents of the buffer. Note the shortcuts!
// Instead of using s.sendMsg(blahblahblah) I used the Synth ugen instead.
// I can send values to the synths arguments by using .set, and I can free
// whatever node it is sent to by doing .free
playbut = SCButton(w, Rect(10, 90, 100, 25));
playbut.states = [
	["Play", Color.black, Color.new(0.8,0.8,0.8)],
	["Stop", Color.black, Color.new(0.8,0.8,0.8)],
];
playbut.action = {
	if (playbut.value ==1, {
			y = Synth.new("fplayer");
			y.set("rate", (8*ratesl.value)-4);
		},{
			y.free;
		});
};

// A slider to determine the rate of playback. It will produce values
// between +/- 4 - remember a minus value will play through the file backwards
ratesl = SCSlider(w, Rect(10, 120, 25, 100));
ratesl.value = 0.5;
ratesl.action = {
		y.set("rate", (8*ratesl.value)-4);
};

)

So for granular synthesis, we would control the various parameters in the following way:

Grain size: Create an envelope - the envelope duration will then be the grain size
Grain amplitude: Change the maximum value of the envelope mentioned above
Grain amplitude dispersion: Add a random factor to the above amplitude
Pitch: Change the rate value of the PlayBuf
Pitch Dispersion: Add a random factor to the Pitch value
Density: Use some sort of signal (e.g. Pulse) to trigger the envelope - if you use Pulse, then a higher frequency 
			will generate a higher density, a lower frequency a lower density.
Time Dispersion: Add a random factor to the frequency of your Pulse trigger signal
No. of Grains: Create/destroy more instances of the synth

Step 1: Creating an envelope
add the variable env

env = EnvGen.kr(Env.new([0,1,1,0], [1,1,1]), trigger, grainamplitude, 0, grainsize);
 So, how do we work out the trigger, grainamplitude and grainsize?
 
 Trigger:
 
 trigger = LFPulse.kr(density+timedispersion)
 grainamplitude = Grain Amplitude + Grain Amplitude Dispersion
 grainsize = Grain Size + random factor if wanted
 
 Once this is done, you can multiply the output of the synthdef by env
 
 (
var s, b, w, serverbut, openDialog, playbut, ratesl;
var densl, timedispsl, grainampsl, grainampdispsl, grainsizesl;

s = Server.local;
b = Buffer.read(s, "sounds/break2.wav");

// A synthdef - using PlayBuf to play the contents of the buffer "b"
SynthDef("fplayer", { arg rate, density=1, timedispersion=0, grainamp=1, grainampdisp=0, grainsize=1;
var file, env, trigger, grainamplitude;
trigger = LFPulse.kr(density+(LFNoise1.kr(10, 0.5, 0.5) * timedispersion));
grainamplitude = TRand.kr(grainamp, grainampdisp, trigger);
env = EnvGen.kr(Env.new([0,1,1,0], [1,1,1]), trigger, grainamplitude, 0, grainsize);
file = PlayBuf.ar(2, b.bufnum, rate);
Out.ar(0, file*env);
}).writeDefFile;
s.sendSynthDef("fplayer");

// Create a window. When it is closed, the buffer b will be freed
w = SCWindow("Granular Synthesis", Rect(100, 400, 600, 600));
w.onClose = {b.free};
w.front;

// A button to start and stop the server
serverbut = SCButton(w, Rect(10, 30, 100, 25));
serverbut.states = [
		["Start Server", Color.black, Color.white],
		["Stop Server", Color.white, Color.black],
];
serverbut.action = {
		if (serverbut.value == 1, {s.boot;},{s.quit;});
};

// A button to bring up a file dialog. Whenever a file is selected, buffer
// b is cleared and the new file is read into it.
openDialog = SCButton(w, Rect(10, 60, 100, 25));
openDialog.states = [
	["Open File", Color.black, Color.new(0.8,0.8,0.8)]
];
openDialog.action = {
	CocoaDialog.getPaths({ arg paths;
		if (b != nil, {b.free});
		b = Buffer.read(s, paths.at(0));
	},{
		"Cancelled".postln;
	});
};

// A button to play back the contents of the buffer. Note the shortcuts!
// Instead of using s.sendMsg(blahblahblah) I used the Synth ugen instead.
// I can send values to the synths arguments by using .set, and I can free
// whatever node it is sent to by doing .free
playbut = SCButton(w, Rect(10, 90, 100, 25));
playbut.states = [
	["Play", Color.black, Color.new(0.8,0.8,0.8)],
	["Stop", Color.black, Color.new(0.8,0.8,0.8)],
];
playbut.action = {
	if (playbut.value ==1, {
			y = Synth.new("fplayer");
			y.set("rate", (8*ratesl.value)-4);
		},{
			y.free;
		});
};

// A slider to determine the rate of playback. It will produce values
// between +/- 4 - remember a minus value will play through the file backwards
ratesl = SCSlider(w, Rect(10, 120, 25, 300));
ratesl.value = 0.5;
ratesl.action = {
		y.set("rate", (8*ratesl.value)-4);
};

densl = SCSlider(w, Rect(40, 120, 25, 300));
densl.action = {
		y.set("density", 40*densl.value); // The number set here will be the maximum possible density
};

timedispsl = SCSlider(w, Rect(70, 120, 25, 300));
timedispsl.action = {
		y.set("timedispersion", 0.2*timedispsl.value); //The number set here will be the maximum deviation from the density
};

grainampsl = SCSlider(w, Rect(100, 120, 25, 300));
grainampsl.action = {
		y.set("grainamp", grainampsl.value);
};

grainampdispsl = SCSlider(w, Rect(130, 120, 25, 300));
grainampdispsl.action = {
		y.set("grainampdisp", 0.5*grainampdispsl.value);
};

grainsizesl = SCSlider(w, Rect(160, 120, 25, 300));
grainsizesl.action = {
		y.set("grainsize", 0.25*grainsizesl.value);
};

)

So now we have very basic granular synthesis, using only one grain at a time. What we want to do now is find a way of adding and killing new instances of the Synth. To do this, we add and remove instances of the Synth in an array and assign them to a group. Now we use the .set command on the group instead of individual synths.
var grainarray;
grainarray = Array.new;
create an add and remove button. The add button action will do
grainarray = grainarray.add(Synth("fplayer", [array of arguments], groupname));

And the remove button action will do
grainarray.pop.free;

****************Full Patch**********************
// The server needs to be booted before you execute the rest of the code
// otherwise it doesn't recognise the array of grains
s = Server.local;
s.boot;
(
var s, b, w, serverbut, openDialog, addbut, removebut, ratesl;
var densl, timedispsl, grainampsl, grainampdispsl, grainsizesl;
var grainarray, g;
s = Server.local;
b = Buffer.read(s, "sounds/break2.wav");
grainarray = Array.new;
g = Group.new;
// A synthdef - using PlayBuf to play the contents of the buffer "b"
SynthDef("fplayer", { arg rate, density=1, timedispersion=0, grainamp=1, grainampdisp=0, grainsize=1;
var file, env, trigger, grainamplitude;
trigger = LFPulse.kr(density+(LFNoise1.kr(10, 0.5, 0.5) * timedispersion));
grainamplitude = TRand.kr(grainamp, grainampdisp, trigger);
env = EnvGen.kr(Env.new([0,1,1,0], [1,1,1]), trigger, grainamplitude, 0, grainsize);
file = PlayBuf.ar(2, b.bufnum, rate);
Out.ar(0, file*env);
}).writeDefFile;
s.sendSynthDef("fplayer");

// Create a window. When it is closed, the buffer b will be freed
w = SCWindow("Granular Synthesis", Rect(100, 400, 600, 600));
w.onClose = {b.free};
w.front;

// A button to start and stop the server
serverbut = SCButton(w, Rect(10, 30, 100, 25));
serverbut.states = [
		["Stop Server", Color.white, Color.black],
];
serverbut.action = {
		s.quit;
};

// A button to bring up a file dialog. Whenever a file is selected, buffer
// b is cleared and the new file is read into it.
openDialog = SCButton(w, Rect(10, 60, 100, 25));
openDialog.states = [
	["Open File", Color.black, Color.new(0.8,0.8,0.8)]
];
openDialog.action = {
	CocoaDialog.getPaths({ arg paths;
		if (b != nil, {b.free});
		b = Buffer.read(s, paths.at(0));
	},{
		"Cancelled".postln;
	});
};

addbut = SCButton(w, Rect(10, 90, 100, 25));
addbut.states = [
	["Add grain", Color.black, Color.new(0.8,0.8,0.8)]
];
addbut.action = {
	grainarray = grainarray.add(Synth("fplayer", [
						"rate", (8*ratesl.value)-4,
						"density", 20*densl.value,
						"timedispersion", 0.2*timedispsl.value,
						"grainamp", grainampsl.value,
						"grainampdisp", 0.5*grainampdispsl.value,
						"grainsize", 0.5*grainsizesl.value
						], g));
	};

removebut = SCButton(w, Rect(120, 90, 100, 25));
removebut.states = [
	["Remove grain", Color.black, Color.new(0.8,0.8,0.8)]
];
removebut.action = {
	grainarray.pop.free;
		};
// A slider to determine the rate of playback. It will produce values
// between +/- 4 - remember a minus value will play through the file backwards
ratesl = SCSlider(w, Rect(10, 120, 25, 300));
ratesl.value = 0.5;
ratesl.action = {
		g.set("rate", (8*ratesl.value)-4);
};

densl = SCSlider(w, Rect(40, 120, 25, 300));
densl.action = {
		g.set("density", 20*densl.value); // The number set here will be the maximum possible density
};

timedispsl = SCSlider(w, Rect(70, 120, 25, 300));
timedispsl.action = {
		g.set("timedispersion", 0.2*timedispsl.value); 
};

grainampsl = SCSlider(w, Rect(100, 120, 25, 300));
grainampsl.action = {
		g.set("grainamp", grainampsl.value);
};

grainampdispsl = SCSlider(w, Rect(130, 120, 25, 300));
grainampdispsl.action = {
		g.set("grainampdisp", 0.5*grainampdispsl.value);
};

grainsizesl = SCSlider(w, Rect(160, 120, 25, 300));
grainsizesl.action = {
		g.set("grainsize", 0.5*grainsizesl.value);
};

)