Polysaccharides - Made by Nature
	
	Molecule Geometry / Symmetries 
	
	Transitions between symmetries
	trees of same kind will be different because of environment; 

Material Scientists 

Are 4 datasets (should be the same) different? 

Supermolecular Structures in Aqueous Media

Very few of these molecules structurize lots of water!!!

Water Cluster may be millimeters! 

Molecules are nanometers -> 6 scales of magnitude

// data are sorted by fraction: 
	left is big mols, right is small ones;

30 bins is conventionally considered sufficiently precise 
	(industry and science!)
(for which measurements); 

//	Brainstorming: 
	
	FFT - Convolution? 
	Klank resonator with e.g. 150 bands,
	maybe detuned from harmonic series? 
	
	wish list: get real impulse responses, raw data, audif (FD)
	
	do 1-2 seconds signature by param mapping...
	
	e.g. 15-20 dimensions; 
	
	try 2 beacons binaurally 

////// reading taken from Materials_Start file provided:
(
q = q ? ();		// a place to store things by name

				// mac and linux only, on win, please set this by hand.
q.localDir = Document.current.path.dirname;

	// do not know what these are yet:
	// sorting_criterium, observed_phys_property
q.chanNames = [ 
	\raw_mass1, \delta_refrac_index, 
	\raw_mass2, \fluorescence, 
	\r_5, \dispersion
];

(				// read all data in;
q.allMats = 
[ \beech, \birch, \oat, \rice ].collect { |name| 
	var path = q.localDir ++ ("/materials_txt/materials_" ++ name ++ ".txt");
	var lines = TabFileReader.read(path.postcs, true, true);

	lines = lines.drop(4).collect({ |line|
		line = line.collect(_.asFloat); // nil -> 0
		if (line.size < 6, { line = line ++ 0.dup(6 - line.size) }, line)
	});
	
	q[name] = lines;
	lines;
};
);
)
		// look at the different measurements
q.beech.flat.plot(numChannels: 6);	// all channels, channel 1 is clipped in the center.
q.beech.collect(_[0]).plot;			// a kind of index?
q.beech.collect(_[1]).plot;			// looks like it went out of range
q.beech.collect(_[2]).plot;			// index?
q.beech.collect(_[3]).plot;			// peak in the middle
q.beech.collect(_[4]).plot;			// index, ends early
q.beech.collect(_[5]).plot;			// 2-3 resonance peaks?

	// index lines seem to be identical
(q.beech.collect(_[0]) - q.birch.collect(_[0])).plot;

q.beech.collect(_[1]).plot;			// looks like it went out of range
q.birch.collect(_[1]).plot;			// slightly different
q.oat.collect(_[1]).plot;			// slightly different
q.rice.collect(_[1]).plot;			// slightly different

//	compare 2 against each other, e.g. with mouse? 

q.beech.collect(_[3]).plot;			// looks like it went out of range
q.birch.collect(_[3]).plot;			// slightly different
q.oat.collect(_[3]).plot;			// slightly different
q.rice.collect(_[3]).plot;			// slightly different

////////////// sound examples made in workshop session:

p = ProxySpace.push(s.boot);

		// the plan: take the undistorted part of channel1, 
		// downsample it to e.g. 50 zones, make these 50 resonators ->
		// these will ring differently for the different materials when excited 
(
q.numResos = 50;
q.cutNum = 680;	// where to cut the distorted

		// undistorted part
q.allMats.first.collect(_[1]).keep(q.cutNum).plot;

q.myVals = q.allMats.first.collect(_[1]).keep(q.cutNum).resamp1(q.numResos);

q.myRingtimes = q.myVals / 100 + 1;		// rescale to 0.4 - 1.8; 

	// index chan goes from 3 to 38, which corresponds to 10000 to 2-3 nanometers. 
	// convert indexhan to nanometers:
q.nanometers = q.allMats.first.collect(_[0]).linexp(3, 38, 10000, 2.5);
q.nanometers.plot; 

	// a function to convert data segment to ringtimes
q.dataToRingtimes = { |q, dataIndex=0, measureIndex=1| 
	var datavals = q.allMats[dataIndex].collect(_[measureIndex])
		.keep(q.cutNum)
		.resamp1(q.numResos);
	datavals.plot;
	q.myRingtimes = datavals / 100 + 1;	// 0.4 - 1.8; 
	q.myRingtimes;
};

)

	// simpler case: scale only ringtimes from data
(
~resos = { 
	var freqs, amps, ringtimes; 
			// generate freqs from k / nanometers 
	freqs = (500000 / q.nanometers.keep(q.cutNum).resamp1(q.numResos));
	amps = 0.3.dup(q.numResos);
	ringtimes = q.myRingtimes ** 2;
	Klank.ar(`[ freqs, amps, ringtimes * 2], Impulse.ar(0.5)) * 0.5;
};
~resos.play;
)
		// measurement 1, 4 types
q.dataToRingtimes(0);	~resos.rebuild;	// beech,
q.dataToRingtimes(1);	~resos.rebuild;	// birch,
q.dataToRingtimes(2);	~resos.rebuild;	// oat
q.dataToRingtimes(3);	~resos.rebuild;	// rice

~resos.stop;

// more sophisticated: separate exciter and resonator, 
// allow for different measurements channels.
(
q.dataToRingtimes = { |q, dataIndex=0, measureIndex=1| 
	var datavals = q.allMats[dataIndex].collect(_[measureIndex])
		.keep(q.cutNum)
		.resamp1(q.numResos);
	
				// optiocal density compared to 'empty' water 
	if (measureIndex == 1, { q.myRingtimes = datavals / 100 + 1 }); // 0.4 - 1.8; 
	
				// intensity of response to 350nm laser excitement, 
				// measured at 380 nm, relative to water background; 
	if (measureIndex == 3, { q.myRingtimes = (datavals + 1).sqrt * 0.5 }); // 0.4 - 1.8; 
	
				// dispersion: laser light, detected total intensity 
				// at 5 degrees angles; all polarizable electrons ...
	if (measureIndex == 5, { q.myRingtimes = datavals }); // 0.4 - 1.8; 
	q.myRingtimes;
};
)
q.dataToRingtimes(0, 1).plot;		// [-0.8, 15];
q.dataToRingtimes(0, 3).plot;		// [-0.8, 15];
q.dataToRingtimes(0, 5).plot;		// [0, 9e-5];

	// two different exciters, try both.
~exciter = { PinkNoise.ar(0.01) };
~exciter = { Impulse.ar(0.5, 0.99, 0.3) };

(
~resos = { 
	var freqs, amps, ringtimes; 
	freqs = (500000 / q.nanometers.keep(q.cutNum).resamp1(q.numResos));
	amps = q.myRingtimes ** 2 * 0.1;
	ringtimes = q.myRingtimes ** 2;
	Klank.ar(`[ freqs, amps, ringtimes * 2], ~exciter.ar) * 0.5 ! 2;
};
~resos.play;
)

q.dataToRingtimes(0);	~resos.rebuild;	// beech,
q.dataToRingtimes(1);	~resos.rebuild;	// birch,
q.dataToRingtimes(2);	~resos.rebuild;	// oat
q.dataToRingtimes(3);	~resos.rebuild;	// rice

		// measurement 2, 4 types
q.dataToRingtimes(0, 3);	~resos.rebuild;	// beech,
q.dataToRingtimes(1, 3);	~resos.rebuild;	// birch,
q.dataToRingtimes(2, 3);	~resos.rebuild;	// oat,
q.dataToRingtimes(3, 3);	~resos.rebuild;	// rice