/********** Originale Dokumentation von G Baier, see translationin TaDat_EEG

Attached 5 Ascii-Files, die wie folgt organisiert sind.

Jede Zahl ist ein elektrisches Potential, abgegriffen an der Kopfhaut,ausgedrueckt in Mikrovolt.
Jede Zeile enthaelt alle Potentiale, die zu einem bestimmten Zeitpunktabgegriffen wurden.
Pro Zeile sind die Potentiale aller gewaehlten Elektroden hintereinandergeschrieben, separiert durch Kommas. Die Zeilenfolge gibt die Zeitreihe, dasheisst die zeitliche Sequenz der Potentiale aller Elektroden bei einerkonstanten Sampling Rate.

Files  GBalpha.csv und MLTalpha.csv:
Normale erwachsene Versuchspersonen. Kanaele: P3, P4, Pz, O1, O2.
Referenz: Gemittelete Ohrlaeppchen-Elektroden (A1+A2)/2. Sampling rate: 250 proSekunde.

Files RhythmWave1.csv, RHythmWave2.csv und RhythmSeizure.csv:

15 jaehriger Patient mit partiellen epileptischen Anfaellen, frontaler Focus. 
Kanaele: FP2-*SD F10-*SD T10-*SD P10-*SD FP2-*SD F8-*SD T4-*SD
T6-*SD FP2-*SD F4-*SD C4-*SD P4-*SD FPZ-*SD FZ-*SD CZ-*SD FP1-*SD F3-*SD
C3-*SD P3-*SD FP1-*SD F7-*SD T3-*SD T5-*SD FP1-*SD F9-*SD T9-*SD P9-*SD.
Referenz: Source density, d.h. gemittelte Nachbarelektroden. Sampling
rate: 500 pro Sekunde.

(Kanalnamen sind entsprechend der 10-20 bzw 10-10 EEG Konvention. )

Tasks: 
Es wird eine Real-time-Sonification gesucht, die die Datenzeit in Hoerzeituebersetzt.
Rhythmische Ereignisse treten zwischen 1 und 20 Hz auf.  In allen Faellen trittein besonderer EEG-Rhythmus im Frequenzbereich 8-13 Hz (alpha-Band) auf, der vonbesonderem Interesse ist. Er soll als hörbarer Rhythmus dargestellt werdenum: sein transientes Auftreten in der Einzelelektrode
verfolgen zu koennen; die Korrelationen des gleichen Rhythmus in verschiedenenElektroden verfolgen zu koennen.

Task Gruppe 1: eine Sonifikation der Kanaele 4 und 5 (Elektroden O1 und O2) desFiles MLTalpha.csv zu entwickeln und dann damit das File GBalpha.csv abzuspielenum die Unterschiede des gleichen physiologischen Rhythmus zwischen zweiVersuchspersonen zu beschreiben.

Task Gruppe 2 und 3: Eine Sonifikation der kurzen alpha-Transienten der Kanaele14 und 15 des Files RhythmWave1.csv (Zeitpunkte 20000-20600, Gruppe 2) undRhythmWave2.csv (Zeitpunkte 18200-18900, Gruppe 3) zu entwickeln und dann damitdas File RhythmSeizure (beide Gruppen)
abzuspielen, um die darin auftretenden rhythmischen Veraenderungen zubeschreiben.
 *************/
(
q = q ? ();		// read two 5chan files, write them assoundfiles.

q.localDir = Document.current.path.dirname; 
q.filenames = ["/Graz_EEG/GBalpha.csv", "/Graz_EEG/MLTalpha.csv"]; 

q.vectorsGB = CSVFileReader.readInterpret(q.localDir ++q.filenames[0], true, true);
q.vectorsMLT = CSVFileReader.readInterpret(q.localDir ++q.filenames[1], true, true);
)
								// channelsare P3, P4, Pz, O1, O2.
q.vectorsGB.maxItem(_.maxItem).maxItem;		// range isca +- 30 microvolts.
q.vectorsGB.minItem(_.minItem).minItem;	

								// channelsare P3, P4, Pz, O1, O2.
q.vectorsMLT.maxItem(_.maxItem).maxItem;	// range is ca +-80 microvolts.
q.vectorsMLT.minItem(_.minItem).minItem;	

// read the 3 files for task2 - this can take 2 minutes!
(
var filenames = [ 
	"/Graz_EEG/RhythmSeizure.csv", 
	"/Graz_EEG/RhythmWave1.csv", 
	"/Graz_EEG/RhythmWave2.csv"
];
q.rhythms = filenames.collect({ |filename, i|
	CSVFileReader.readInterpret(q.localDir ++ filename, true, true);
}); 
)
	// file amp ranges are:
[ /Graz_EEG/RhythmSeizure.csv, 264.38, -123.68]
[ /Graz_EEG/RhythmWave1.csv, 142.45, -122.18 ]
[ /Graz_EEG/RhythmWave2.csv, 123.1, -133.46 ]

// 	the names are q.vectorsMLT, q.vectorsGB
p.clear;
(
q.sampleRate = 250; 
			// voltages control frequencies of 5tones

~sound2.setn(\voltages, q.data.first[[3,4]]);
~sound2.play; 

~sound2 = { |pulseRatio=1.15|
	var sound, voltages, amps, freqs;
	
	voltages = Control.names([\voltages]).kr(0.1 ! 2);
	amps = Control.names([\amps]).kr(1 ! 2);
	
			// ca 30 for GB, ca 80 for MLT;
	freqs = voltages.lag(0.01) * 10 + 500;	// linear into 200 -800
	
	sound = SinOsc.ar(freqs, 0, AmpComp.kr(freqs.max(50)));
	
	Splay.ar(sound * (amps * 0.2));
};
)

~sound2.setn(\voltages, [0,0]);

~sound2.setn(\voltages, q.data[0]);
~sound2.setn(\voltages, q.data[10]);
~sound2.setn(\voltages, q.data[30]);

~sound2.setn(\amps, [1,1]);
~sound2.setn(\amps, [1,1]);

(
	// play 250 values per sec:
	// 
Tdef(\week, { 
	~sound2.play;
	q.vectorsGB.do { |vals, i| 
		if (i % q.sampleRate == 0) { 
			("sec" + (i div: q.sampleRate) + ",index" + i).postln 
		};
		~sound2.setn(\voltages, vals[[3,4]]);
		(q.sampleRate.reciprocal * 1).wait;
	};
	~sound2.stop;
}).stop.play(quant: 0);
)

q.vectorsGB.flat.plot(numChannels: 5);

(
~sound2.play; 

~sound2 = { |pulseRatio=1.15|
	var sound, voltages, amps, freqs;
	
	voltages = Control.names([\voltages]).kr(0.1 ! 2);
	amps = Control.names([\amps]).kr(1 ! 2);
	
			// ca 30 for GB, ca 80 for MLT;
	freqs = voltages.lag(0.01) * 10 + 500;	// linear into 200 -800
	
	sound = SinOsc.ar(freqs, 0, AmpComp.kr(freqs.max(50)));
	
				// only positive half-waves?
	Splay.ar(sound * (amps * 0.2) * voltages.sign.max(0));
};
)

		// quick and dirty
(
q.buf1 = Buffer.read(s, q.localDir ++ "/GrazEEG_aifs/alpha_aifs/GBalpha_O1.aif");
q.buf2 = Buffer.read(s, q.localDir ++ "/GrazEEG_aifs/alpha_aifs/GBalpha_O2.aif");
)

(
q.buf1.read(q.localDir ++ "/GrazEEG_aifs/alpha_aifs/MLTalpha_O1.aif");
q.buf2.read(q.localDir ++ "/GrazEEG_aifs/alpha_aifs/MLTalpha_O2.aif");
)

(
q.buf1.read(q.localDir ++ "/GrazEEG_aifs/alpha_aifs/GBalpha_O1.aif");
q.buf2.read(q.localDir ++ "/GrazEEG_aifs/alpha_aifs/GBalpha_O2.aif");
)

~bufplay.ar(2);
~bufplay.play(0);

~bufplay = { 
	var freqs, sound;
	var bufnums = [ q.buf1.bufnum, q.buf2.bufnum];
	
	var time = Phasor.ar(0, SampleDur.ir, 0,BufDur.kr(bufnums[0])).poll;
	var voltages = BufRd.ar(1, bufnums, (time * BufSampleRate.kr(bufnums[0])));

			// ca 30 for GB, ca 80 for MLT;
	freqs = voltages.lag(0.01) * 10 + 500;	// linear into 200 -800
	
	// sound = SinOsc.ar(freqs, 0, AmpComp	// .kr(freqs.max(50)));
	
};
s.scope;

	// more possibilities:
// simple buffer audification patch with sendtrig back for timeindex; 
//	maybe with a 5chan buffer? five individual buffers?
// do simple filtering/triggering to render rhythms? 
// or some modulation approach?
// maybe do the filtering with SOS.kr filter ? it seems to be there, 
// no time yet to figure out how it works...

////// utilities: render files as soundfiles 

	// for task one, write them out as multichannel soundfiles(5chans here):
(
[ q.vectorsGB, q.vectorsMLT ].do { |vectors, i| 
	var soundfile;
	soundfile =SoundFile.new.sampleRate_(250)
		.numChannels_(vectors.first.size);
	soundfile.openWrite((q.localDir ++ q.filenames[i].splitext.first ++ "_5.aif"));
	vectors.do { |vec| soundfile.writeData(vec.as(Signal)  *0.01) };
	soundfile.close;
};
) 

	// for task one, write GBalpha and MLTalpha, all electrodesas single files:
(
var filenames = [ "/Graz_EEG/GBalpha.csv", "/Graz_EEG/MLTalpha.csv" ];
var chanNames = [ 'P3', 'P4', 'Pz', 'O1', 'O2'];
unixCmd("mkdir" + (q.localDir ++ "/Graz_EEG/alpha"));

filenames.do { |filename, i| 
	var vectors, range, channels;
	filename = q.localDir ++ filename;
	vectors = [ q.vectorsGB, q.vectorsMLT ][i];
	range = [ 
		vectors.maxItem(_.maxItem).maxItem, 
		vectors.minItem(_.minItem).minItem 
	].postln;
	channels = vectors.flop;
	chanNames.do { |chname, j| 
		var soundfile =  SoundFile.new.sampleRate_(250);
		soundfile.openWrite( 
			(q.localDir ++ "/Graz_EEG/alpha/" 
			++ filename.basename.splitext.first 
			++ "_" ++ chname ++ ".aif").postln
		);
		soundfile.writeData(channels[j].as(Signal));
		soundfile.close;
	};
};
)

// convert the other three to soundfiles too, individual channels
(
var filenames = [ 
	"/Graz_EEG/RhythmSeizure.csv", 
	"/Graz_EEG/RhythmWave1.csv", 
	"/Graz_EEG/RhythmWave2.csv"
];
unixCmd("mkdir" + (q.localDir ++ "/Graz_EEG/rhythms"));
q.rhythms = []; 

filenames.do { |filename, i| 
	var vectors, range, channels;
	filename = q.localDir ++ filename;
	vectors = CSVFileReader.readInterpret(filename, true, true);
	q.rhythms = q.rhythms.add(vectors);

	range = [ 
		vectors.maxItem(_.maxItem).maxItem, 
		vectors.minItem(_.minItem).minItem 
	].postln;
	channels = vectors.flop / 300; 	// normalize them all to the samemax, 300 microvolt;
	
	channels.do { |channel, j| 
		var soundfile =  SoundFile.new.sampleRate_(250);
		soundfile.openWrite( 
			(q.localDir ++ "/Graz_EEG/rhythms/" 
			++ filename.basename.splitext.first 
			++ "_" ++ (j + 1) ++ ".aif").postln
		);
		soundfile.writeData(channels[j].as(Signal));
		soundfile.close;
	};
};
)