/**
Simulated data of proton-proton collisions of the TPC,
one set of tracks is given,
with single measured events of electron clouds reaching one of the two read-out chambers after a certain time with a certain charge
written down by jrh
*/

(
q = ();
q.dataFolder = Document.current.dir ++ "/TPC_m_data_96/";
q.myfileName = "m_data_96";

// get all tracks including [tracknumber, # of data associated with track]:
q.headerArchive = ZArchive.read(q.dataFolder +/+ q.myfileName ++ "_tracks.zar");
q.trackInfos = q.headerArchive.readItem;

	// read and post data for ONE track:
q.readTPC = { |q, index = 0|
	var trackID = q.trackInfos[index][0];
	var trackArchive = ZArchive.read(q.dataFolder +/+ q.myfileName ++ "_" ++ trackID ++ ".zar");
	var data = trackArchive.readItem;
	trackArchive.close; 
	
	data.do { |track, i| 
		track[3] = (track[4].abs)/2.6 * 100 
	}; // correct time! 
 	data
};
	// q.readTPC(14);

q.allTPCdata = q.trackInfos.size.collect { |i| 
	var track = q.readTPC(i);
	"read track %.\n".postf(i);
	track
};

/**
	// [units are in cm]
	q.track = q.allTPCdata[8];
	i = q.track[0] 	// track id, 			
	r = q.track[1]		// radius 	r,		[0..250] cm 
	p = q.track.flop[2] 	// angle 		phi,		[-pi, pi]
	t = q.track.flop[3]	// time 		t,		[0, 100] microsec, 
											= (2.6-(z.abs))/2.58 (2.58=drift velocity)
											BUT sometimes negative, therefore corrected!
	z = q.track.flop[4] 	// coordinate	z,		[-2.6, 2.6] // in meter: total size is 5m!
	x = q.track.flop[5] 	// coordinate	x,		[-250, 250] cm		
	y = q.track.flop[6] 	// coordinate	y, 		[-200, 225] cm
	c = q.track.flop[7] 	// charge 	q,  		in out.dat: [0, 272] nb. of electrons
	k = q.track.flop[8]		// kind of particle that produced the track, see TPCmontecarlorpp.pdf
	
	q.track.flop.do { |x| x.plot }; // plot all.
	q.track.flop.plot2; // plot all.
**/

q.loadBuffer = { |q, index, dimension|
	var array = 	q.allTPCdata[index].flop[dimension];
	Buffer.loadCollection(s, array);
};

q.buffers = q.allTPCdata.collect { |tuple|
		tuple.flop.collect { |data|
			Buffer.loadCollection(s, data);
			//data.postln;
		}
};

q.allCharges = q.buffers.collect(_[7]);

)

(
SynthDef(\TPC, { |out, chargeBuf, phiBuf, rate = 1|
	var snd, freq;
	snd = PlayBuf.ar(1, chargeBuf, rate, doneAction: 2);
	Out.ar(out, snd * 0.1)
	
}).memStore
)

// just the charges "audified"
// note that time axis is not audification time axis
(
Tdef(\x, {
	q.allCharges.do { |buf|
		var e = (instrument: \TPC, chargeBuf: buf, rate: 1).play;
		e.dur.wait;
	}
}).play
)

// charge as exciter for filter, modulated with angle
(
SynthDef(\TPC, { |out, chargeBuf, phiBuf, rate = 1|
	var snd, charge, freq;
	var phi = PlayBuf.ar(1, phiBuf, rate);
	charge = PlayBuf.ar(1, chargeBuf, rate, doneAction: 2);
	freq =  phi.cos.linexp(-1, 1, 300, 8000);
	snd = Ringz.ar(charge, freq, 0.01);
	
	Out.ar(out, Pan2.ar(snd, phi) * 0.1)
	
}).memStore;
)

(
Tdef(\x, {
	q.allCharges.do { |buf, eventIndex|
		(
			instrument: \TPC, 
			chargeBuf: buf, 
			rate: 0.5,
			phiBuf: q.buffers[eventIndex][2]
		).play;
		1.wait;
	}
}).play
)

// charge as exciter for filter, modulated with angle.
// pan modulated by angle
// trying to loop to normalise length
(
SynthDef(\TPC, { |out, chargeBuf, phiBuf, rate = 1, sustain = 1|
	var snd, charge, freq, env;
	var phi = PlayBuf.ar(1, phiBuf, rate, loop:1);
	charge = PlayBuf.ar(1, chargeBuf, rate, loop:1);
	freq =  phi.cos.linexp(-1, 1, 300, 8000);
	snd = Ringz.ar(charge, freq, 0.01);
	env = EnvGen.kr(Env.linen(0, sustain, 0.1), doneAction: 2);
	
	Out.ar(out, Pan2.ar(snd, phi) * 0.1 * env)
	
}).memStore;
)

(
Tdef(\x, {
	q.allCharges.do { |buf, eventIndex|
		(
			instrument: \TPC, 
			chargeBuf: buf, 
			rate: 1,
			sustain: 2,
			phiBuf: q.buffers[eventIndex][2]
		).play;
		(0.1 + 2).wait;
	}
}).play
)

// charge as exciter for filter, modulated with angle
// pan modulated by angle
// radius is resonance and pan strength
(
SynthDef(\TPC, { |out, chargeBuf, phiBuf, radiusBuf, rate = 1|
	var snd, freq, res;
	var phi = PlayBuf.ar(1, phiBuf, rate);
	var radius = PlayBuf.ar(1, radiusBuf, rate);
	var charge = PlayBuf.ar(1, chargeBuf, rate, doneAction: 2);
	freq =  phi.cos.linexp(-1, 1, 300, 8000);
	res = radius.linlin(0, 250, 0.0001, 0.05);
	snd = Ringz.ar(charge, freq, res);
	
	Out.ar(out, Pan2.ar(snd, phi) * 0.1)
	
}).memStore;
)

(
Tdef(\x, {
	q.allCharges.do { |buf, eventIndex|
		(
			instrument: \TPC, 
			chargeBuf: buf, 
			rate: 1,
			sustain: 2,
			phiBuf: q.buffers[eventIndex][2],
			radiusBuf: q.buffers[eventIndex][1]
		).play;
		(0.1 + 2).wait;
	}
}).play
)

// a possibility: sort data according to z axis
/*
q.allTPCdataSortZ = q.allTPCdata.collect { |tuple|
	var order;
	tuple = tuple.flop;
	order = tuple[4].order;
	tuple.collect(_[order]).flop;	
};
q.allTPCdataSortZ[0].flop.plot2;

(
q.buffers = q.allTPCdataSortZ.collect { |tuple|
		tuple.flop.collect { |data|
			Buffer.loadCollection(s, data);
			//data.postln;
		}
};
)

q.buffers[0].flop[0][2].plot2;
*/

// charge as exciter for filter, modulated with angle
// pan modulated by angle
// radius is resonance and pan strength
(
SynthDef(\TPC, { |out, chargeBuf, phiBuf, radiusBuf, rate = 1|
	var snd, freq, res, pan;
	var phi = PlayBuf.ar(1, phiBuf, rate);
	var radius = PlayBuf.ar(1, radiusBuf, rate);
	var charge = PlayBuf.ar(1, chargeBuf, rate, doneAction: 2);
	freq =  phi.cos.linexp(-1, 1, 300, 8000);
	res = radius.linlin(83.65, 254.5, 0.0001, 0.05);
	snd = Ringz.ar(charge, freq, res);
	pan = phi / pi * radius.linlin(83.65, 254.5, 0.1, 1);
	Out.ar(out, Pan2.ar(snd, pan) * 0.1)
	
}).memStore;
)

(
Tdef(\x, {
	q.allCharges.do { |buf, eventIndex|
		var event = (
			instrument: \TPC, 
			chargeBuf: buf, 
			rate: 0.5,
			sustain: 2,
			phiBuf: q.buffers[eventIndex][2],
			radiusBuf: q.buffers[eventIndex][1]
		).play;
		(event.dur + 0.5).wait;
	}
}).play
)

// all at once
(
q.allCharges.do { |buf, eventIndex|
		var event = (
			instrument: \TPC, 
			chargeBuf: buf, 
			rate: 0.5,
			sustain: 2,
			phiBuf: q.buffers[eventIndex][2],
			radiusBuf: q.buffers[eventIndex][1]
		).play;
	};
)