451 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
			
		
		
	
	
			451 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
/*
 | 
						|
	This file is part of "Interface Fractures III - Silicon".
 | 
						|
	Copyright (c) 2015 Luka Prinčič, All rights reserved.
 | 
						|
	This program is free software distributed under
 | 
						|
	GNU General Public Licence. See COPYING for more info.
 | 
						|
	- - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
 | 
						|
	snd_lines.scd - deals with converting spectral lines
 | 
						|
	of silicon into sound in time...
 | 
						|
	
 | 
						|
********************************************************** */
 | 
						|
 | 
						|
 | 
						|
// function procLines: process lines and store/return List
 | 
						|
postln("~~~ function ~procLinesFunc ...");
 | 
						|
~procLinesFunc = { // process lines, return na array
 | 
						|
	arg location = PathName(thisProcess.nowExecutingPath).pathOnly +/+ "../dat/silicon_lines.txt";
 | 
						|
	var siLines = FileReader.read(path: location, skipBlanks:true, skipEmptyLines:true); 
 | 
						|
	var intensity, minutes, seconds, freq1, freq2, midi1, midi2, red, green, blue;
 | 
						|
	var threshold = 0;
 | 
						|
    var linewidth = 3;
 | 
						|
	var spectrumheight = 750;
 | 
						|
	var colorpenlen = 40;
 | 
						|
	var siLinesData, processItem;
 | 
						|
	var colors = [ // these are taken from http://astro.u-strasbg.fr/~koppen/discharge/discharge.html
 | 
						|
		[ 3800.0,        0,   0,   0],  
 | 
						|
		[ 4000.0,      150,   0, 150],  
 | 
						|
		[ 4400.0,      120,   0, 255],  // violet
 | 
						|
		[ 4500.0,        0,   0, 255],  // blue
 | 
						|
		[ 4800.0,        0, 255, 255],  // cyan
 | 
						|
		[ 5200.0,        0, 255,   0],  // green
 | 
						|
		[ 5800.0,      255, 255,   0],  // yellow
 | 
						|
		[ 6500.0,      255,   0,   0],  // red
 | 
						|
		[ 7000.0,       80,   0,   0],
 | 
						|
		[ 7300.0,        0,   0,   0] ];
 | 
						|
 | 
						|
	siLinesData = List.newClear(0);
 | 
						|
 | 
						|
	processItem = { |item, i, reverse=false, layer=0, tscale=1, toffset=0|
 | 
						|
 | 
						|
		if((item[1].asInt > threshold) && (item[0].asInt < 6741) && (item[0].asInt > 3950), {
 | 
						|
			var color;
 | 
						|
			var time, time_end = 60*37+5;
 | 
						|
			var alpha = item[1].asFloat.linlin(0, 1000, 0, 255);
 | 
						|
 | 
						|
			intensity = item[1].asInt;
 | 
						|
			
 | 
						|
			// time
 | 
						|
			if(reverse == false,
 | 
						|
				// then
 | 
						|
				{ time = (item[0].asFloat.linlin(3950, 6741, 0, time_end)); },
 | 
						|
				// else:
 | 
						|
				{ time = (item[0].asFloat.linlin(3950, 6741, time_end, 0)); } );
 | 
						|
			time = time * tscale ;
 | 
						|
			time = time + (toffset * time_end);
 | 
						|
 | 
						|
			minutes = (time / 60).round(1);
 | 
						|
			seconds = (time % 60).round(1);
 | 
						|
			freq1 = item[0].asFloat.linexp(3900, 7200, 16000, 40 ).asInt;
 | 
						|
			freq2 = item[0].asFloat.linexp(3900, 7200, 40, 16000 ).asInt;
 | 
						|
			midi1 = item[0].asFloat.linlin(3900, 7200, 0, 12 ).round(0.01);
 | 
						|
			midi2 = item[0].asFloat.linlin(3900, 7200, 12, 0 ).round(0.01);
 | 
						|
 | 
						|
			colors.do({ |colordb, i|
 | 
						|
				var thisboundary = colors[i][0];
 | 
						|
				if (i+1 < colors.size, {
 | 
						|
					var nextboundary = colors[i+1][0];
 | 
						|
					if ((item[0].asFloat > thisboundary) && (item[0].asFloat < nextboundary), {
 | 
						|
 | 
						|
						var red   = colors[i][1] + ( ( (colors[i+1][1] - colors[i][1]) / (colors[i+1][0] - colors[i][0]) )
 | 
						|
							* (item[0].asFloat - colors[i][0]) );
 | 
						|
						var green = colors[i][2] + ( ( (colors[i+1][2] - colors[i][2]) / (colors[i+1][0] - colors[i][0]) )
 | 
						|
							* (item[0].asFloat - colors[i][0]) );
 | 
						|
						var blue  = colors[i][3] + ( ( (colors[i+1][3] - colors[i][3]) / (colors[i+1][0] - colors[i][0]) )
 | 
						|
							* (item[0].asFloat - colors[i][0]) );
 | 
						|
						var color = Color.new255(red.round(1),green.round(1),blue.round(1), alpha);
 | 
						|
						var colorHSV = color.asHSV;
 | 
						|
 | 
						|
						// add line data as a List to the siLinesData List
 | 
						|
						siLinesData.add(List[
 | 
						|
							time, // [0]
 | 
						|
							layer, // [1]
 | 
						|
							item[0], // [2]
 | 
						|
							intensity,	// [3]
 | 
						|
							freq1, freq2, // [4], [5]
 | 
						|
							midi1, midi2, // [6], [7]
 | 
						|
							// R, G, B, [8] [9] [10]
 | 
						|
							red.round(1), green.round(1), blue.round(1),
 | 
						|
							// H, S, V, Alpha [11][12][13][14]
 | 
						|
							(colorHSV[0] * 360).round(1), // hue
 | 
						|
							(colorHSV[1] * 100).round(1), // saturation
 | 
						|
							(colorHSV[2] * 100).round(1), // value
 | 
						|
							(colorHSV[3] * 100).round(1) // ALPHA
 | 
						|
						]); // end of siLinesData.add
 | 
						|
					}); // endif wavelength inside this boundary
 | 
						|
				}); // endif below last item (prevents error going beyond List's boundary)
 | 
						|
			}); // end colors.do
 | 
						|
		}); // endif threshold and inside min/max in the spectrum
 | 
						|
	}; // end of function processItem
 | 
						|
 | 
						|
	// process lines four times with offsets and scales with golden ratios
 | 
						|
	siLines.do({ |item, i| processItem.value(item, i, layer:0); });
 | 
						|
	
 | 
						|
	siLines.do({ | item, i| processItem.value(item, i, layer:1, reverse:true,
 | 
						|
		tscale:0.618); });
 | 
						|
	
 | 
						|
	siLines.do({ | item, i| processItem.value(item, i, layer:1, reverse:true,
 | 
						|
		tscale: 0.618.squared, toffset:0.618); 	});
 | 
						|
	
 | 
						|
	siLines.do({ | item, i| processItem.value(item, i, layer:2, reverse:false,
 | 
						|
		tscale: 0.618.cubed, toffset:(0.618.squared-0.618.cubed)+0.618); });
 | 
						|
	
 | 
						|
	// return ?
 | 
						|
	siLinesData;
 | 
						|
	
 | 
						|
};
 | 
						|
 | 
						|
// evaluate: process lines, store to a List
 | 
						|
postln("~~~ process lines, store to a list: ~siLinesData, sort ...");
 | 
						|
~siLinesData = ~procLinesFunc.value;
 | 
						|
 | 
						|
// sort 2D
 | 
						|
~siLinesData = ~siLinesData.sortBy(0);
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
// FUNCTION: display linesData list in a view/window
 | 
						|
postln("~~~ function ~viewLinesFunc ...");
 | 
						|
~viewLinesFunc = {
 | 
						|
	arg siLinesData = ~siLinesData; // all we need is a List of data
 | 
						|
 | 
						|
	var intensity, layer, alpha, peny, penx, color, time, swin;
 | 
						|
	var threshold = 0;
 | 
						|
    var linewidth = 3;
 | 
						|
	var spectrumheight = 750;
 | 
						|
	var colorpenlen = 40;
 | 
						|
	var alphamin = 10;
 | 
						|
	var time_end = 60*37+5;
 | 
						|
	
 | 
						|
	// View/Window starts here
 | 
						|
	swin = Window("TempSpectre", Rect(600, 5, width:560, height:spectrumheight));
 | 
						|
 | 
						|
	swin.view.background_(Color.black);
 | 
						|
	swin.drawFunc = {
 | 
						|
 | 
						|
		Pen.smoothing_(false);
 | 
						|
		Pen.translate(0,0);
 | 
						|
 | 
						|
		Pen.fillColor = Color.white;
 | 
						|
		Pen.fillRect(Rect(colorpenlen * 3, 0, w.bounds.width - (colorpenlen * 3), spectrumheight));
 | 
						|
 | 
						|
		siLinesData.do({ |ldata, i|
 | 
						|
 | 
						|
			alpha = ldata[14].asFloat.linlin(0, 100, alphamin, 255);
 | 
						|
			layer = ldata[1].asInt;
 | 
						|
			spectrumheight = w.bounds.height;
 | 
						|
			intensity = ldata[3].asInt;
 | 
						|
			time = ldata[0];
 | 
						|
			color = Color.new255(ldata[8], ldata[9], ldata[10], alpha);
 | 
						|
			peny = time.linlin(0, time_end, 0, spectrumheight);
 | 
						|
			penx = 2 - layer * colorpenlen;
 | 
						|
 | 
						|
			// colored lines on black
 | 
						|
			Pen.fillColor = color;
 | 
						|
			Pen.fillRect(Rect(penx, peny, colorpenlen, alpha.linlin(0,255,1,linewidth)));
 | 
						|
 | 
						|
			// black/gray lines on white
 | 
						|
			Pen.fillColor = Color.black.alpha_(alpha.linlin(0,255,0,1));
 | 
						|
			Pen.fillRect(Rect( colorpenlen*3, peny,
 | 
						|
				w.bounds.width - (colorpenlen * 3) * intensity.linlin(0,1000,0,1),
 | 
						|
				alpha.linlin(0,255,1,linewidth)));
 | 
						|
			
 | 
						|
			Pen.stroke; // draw the path
 | 
						|
 | 
						|
		}); // end of siLinesData.do
 | 
						|
	}; // end of drawFunc{}
 | 
						|
	swin.refresh;
 | 
						|
	swin.front;
 | 
						|
}; // end of viewLines function
 | 
						|
// this could be bound to a button,
 | 
						|
// or ideally expanded to an animated timeline
 | 
						|
// and included in main window...:
 | 
						|
 | 
						|
// evaluate: show a window/view with lines - score
 | 
						|
// ~viewLinesFunc.value;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 
 | 
						|
 | 
						|
~postLines = { // print data in post window, NICELY!
 | 
						|
 | 
						|
	// display table of all data to post window
 | 
						|
	~siLinesData.do({ |item, i|
 | 
						|
		var minutes = (item[0]/60).asInt;
 | 
						|
		var seconds = (item[0]%60).asInt;
 | 
						|
 | 
						|
		if (item[3].asInt > 199, {
 | 
						|
 | 
						|
			// post("[");
 | 
						|
			// post(i.asString.padLeft(3));
 | 
						|
			// post("] ");
 | 
						|
 | 
						|
			// time
 | 
						|
			if (minutes < 10, { minutes = "0" ++ minutes.asString;});
 | 
						|
			post(minutes);
 | 
						|
			post(":");
 | 
						|
			if (seconds < 10, { seconds = "0" ++ seconds.asString; });
 | 
						|
			post(seconds);
 | 
						|
			post(" ");
 | 
						|
 | 
						|
			// wavelength
 | 
						|
			post(item[2]);
 | 
						|
			post("Å ");
 | 
						|
 | 
						|
			
 | 
						|
			// layer
 | 
						|
			post(item[1]);
 | 
						|
			post(" ");
 | 
						|
 | 
						|
			// intensity
 | 
						|
			post(item[3].asString.padLeft(4));
 | 
						|
			post(" ");
 | 
						|
 | 
						|
 | 
						|
 | 
						|
			// frequency
 | 
						|
			post(item[4].asString.padLeft(5));
 | 
						|
			post("Hz ");
 | 
						|
			post(item[5].asString.padLeft(5));
 | 
						|
			post("Hz ");
 | 
						|
 | 
						|
			// midi/tone
 | 
						|
			post(item[6].asString.padLeft(5)); // midi1
 | 
						|
			post(" ");
 | 
						|
			post(item[7].asString.padLeft(5)); // midi2
 | 
						|
			post(" | ");
 | 
						|
 | 
						|
			// RGB
 | 
						|
			post(item[8].asString.padLeft(3));
 | 
						|
			post(" ");
 | 
						|
			post(item[9].asString.padLeft(3));
 | 
						|
			post(" ");
 | 
						|
			post(item[10].asString.padLeft(3));
 | 
						|
 | 
						|
			// HSV/B
 | 
						|
			// post(" | ");
 | 
						|
			// post(item[11].asString.padLeft(3));
 | 
						|
			// post(" ");
 | 
						|
			// post(item[12].asString.padLeft(3));
 | 
						|
			// post(" ");
 | 
						|
			// post(item[13].asString.padLeft(3));
 | 
						|
			post(" | ");
 | 
						|
			post(item[14] //.asString.padLeft(3)
 | 
						|
			);
 | 
						|
			/*
 | 
						|
			post(" |||");
 | 
						|
			
 | 
						|
			item.do({ |value, i|
 | 
						|
				//post(i);
 | 
						|
				post(Char.tab);
 | 
						|
				post(value.asFloat.round(1));
 | 
						|
				post(" ");
 | 
						|
 | 
						|
				});*/
 | 
						|
			post("\n");
 | 
						|
		});
 | 
						|
	});
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
// evaluate function
 | 
						|
//~postLines.value;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
// move to sdefs.scd at one point? --------------------------------------------
 | 
						|
SynthDef(\siliconSynth, { |freq = 440, amp = 0.2, attack = 1, release = 1|
 | 
						|
 | 
						|
	var sig, env, frequency, amply;
 | 
						|
 | 
						|
	frequency = [freq * 1.005, freq];
 | 
						|
	amply = amp * 0.3;
 | 
						|
 | 
						|
	env = EnvGen.kr(Env.perc(attack, release, 1, [10, -10]), doneAction: 2); // ENVELOPE
 | 
						|
	
 | 
						|
	sig // -----------------------------------------------------------------------------------------
 | 
						|
	= SinOsc.ar( freq: frequency, mul: amply * 0.9)
 | 
						|
	+ SinOsc.ar( freq: frequency * 0.5 * LFNoise1.kr(0.1).linlin(-1, 1, 0.998, 1.002), mul: amply)
 | 
						|
	+ SinOsc.ar( freq: frequency * 0.25 * LFNoise1.kr(0.1).linlin(-1, 1, 0.998, 1.002), mul: amply)
 | 
						|
	
 | 
						|
	+ Saw.ar( freq: frequency * LFNoise1.kr(0.1).linlin(-1, 1, 0.998, 1.002), mul: amply * 0.5)
 | 
						|
	+ Saw.ar( freq: frequency * 0.5 * LFNoise1.kr(0.1).linlin(-1, 1, 0.998, 1.002), mul: amply * 0.5)
 | 
						|
	+ Saw.ar( freq: frequency * 0.25 * LFNoise1.kr(0.1).linlin(-1, 1, 0.998, 1.002), mul: amply * 0.5)
 | 
						|
	
 | 
						|
	+ Pulse.ar( freq: frequency * LFNoise1.kr(0.1).linlin(-1, 1, 0.998, 1.002), mul: amply * 0.5)
 | 
						|
	+ Pulse.ar( freq: frequency * 0.5 * LFNoise1.kr(0.1).linlin(-1, 1, 0.998, 1.002), mul: amply * 0.5)
 | 
						|
	+ Pulse.ar( freq: frequency * 0.24 * LFNoise1.kr(0.1).linlin(-1, 1, 0.998, 1.002), mul: amply * 0.5)
 | 
						|
 | 
						|
	+ BPF.ar(BrownNoise.ar(), freq: frequency * LFNoise1.kr(0.01).linlin(-1, 1, 0.8, 1.2), rq: 0.1)
 | 
						|
	+ BPF.ar(WhiteNoise.ar(), freq: frequency * 0.5 * LFNoise1.kr(0.01).linlin(-1, 1, 0.8, 1.2), rq: 0.1)
 | 
						|
	
 | 
						|
	+ BPF.ar(Crackle.ar(SinOsc.kr(0.1).linlin(-1, 1, 0.8, 2)), frequency * LFNoise1.kr(0.01).linlin(-1, 1, 0.8, 1.2), rq:0.1, mul:2)
 | 
						|
	+ BPF.ar(Crackle.ar(SinOsc.kr(0.1).linlin(-1, 1, 0.8, 2)), frequency * 0.5 * LFNoise1.kr(0.01).linlin(-1, 1, 0.8, 1.2), rq:0.1, mul:2)
 | 
						|
 | 
						|
	; // -------------------------------------------------------------------------------------------
 | 
						|
 | 
						|
	sig = sig * env; // envlope the final sound
 | 
						|
	Out.ar(2, sig); // output
 | 
						|
	postln("\n~~~ adding SynthDef: siliconSynth ...");
 | 
						|
}).add;
 | 
						|
// -----------------------------------------------------------------------------
 | 
						|
 | 
						|
 | 
						|
postln("~~~ loading mainTimeline routine");
 | 
						|
post(" ");
 | 
						|
 | 
						|
~mainTimeline = Routine({
 | 
						|
 | 
						|
	//arg layer = 0;
 | 
						|
 | 
						|
	var delta,  playhead, frequency, amp, step=0,
 | 
						|
	nextdelta, nextplayhead, nextfrequency, nextamp,
 | 
						|
	frequency_alt, nextfrequency_alt, siLines;
 | 
						|
 | 
						|
	siLines = ~siLinesData;
 | 
						|
	postln(siLines);
 | 
						|
	postln("debug");
 | 
						|
	
 | 
						|
	while {
 | 
						|
		
 | 
						|
		step < siLines.size;
 | 
						|
		//layer == siLines[step]
 | 
						|
		
 | 
						|
	} {
 | 
						|
		// exposition
 | 
						|
		frequency = siLines[step][4].asFloat;
 | 
						|
		frequency_alt = siLines[step][5].asFloat;
 | 
						|
		playhead = siLines[step][0].asFloat;
 | 
						|
		nextfrequency = siLines[step+1][4].asFloat;
 | 
						|
		nextfrequency_alt = siLines[step+1][5].asFloat;
 | 
						|
		nextplayhead = siLines[step+1][0].asFloat;
 | 
						|
		delta = nextplayhead - playhead;
 | 
						|
		amp = siLines[step][3].asInt * 0.001;
 | 
						|
		nextamp = siLines[step+1][3].asInt * 0.001;
 | 
						|
		nextdelta = siLines[step+2][0].asFloat - nextplayhead;
 | 
						|
 | 
						|
		//action::documentation
 | 
						|
		post("\n~" + step.asString.padLeft(3));
 | 
						|
		post("|");
 | 
						|
		post(siLines[step][1]);
 | 
						|
		post("| ");
 | 
						|
		post((playhead/60).round(1).asString.padLeft(2));
 | 
						|
		post(":");
 | 
						|
		post((playhead%60).round(1).asString.padLeft(2));
 | 
						|
		post(" | ");
 | 
						|
		// post(siLines[step][2]);
 | 
						|
		// post( "nm | " );
 | 
						|
		post(frequency.round(1).asString.padLeft(5));
 | 
						|
		post("Hz | ");
 | 
						|
		post(frequency_alt.round(1).asString.padLeft(5));
 | 
						|
		post("Hz | ");
 | 
						|
		post(amp.ampdb.round(1));
 | 
						|
		post("dB \\ ");
 | 
						|
		post(delta.round(1));
 | 
						|
		postln("s");
 | 
						|
 | 
						|
		post("     |");
 | 
						|
		post(siLines[step+1][1]);
 | 
						|
		post("|   ");
 | 
						|
		post(delta.round(1));
 | 
						|
		post("s / ");
 | 
						|
		post(nextfrequency.round(1).asString.padLeft(5));
 | 
						|
		post("Hz | ");
 | 
						|
		post(nextfrequency_alt.round(1).asString.padLeft(5));
 | 
						|
		post("Hz | ");
 | 
						|
		post(nextamp.ampdb.round(1));
 | 
						|
		post("dB \\ ");
 | 
						|
		post(nextdelta.round(1));
 | 
						|
		postln("s");
 | 
						|
 | 
						|
		Synth(\siliconSynth, [
 | 
						|
			freq: nextfrequency,
 | 
						|
			amp: nextamp,
 | 
						|
			attack: delta,
 | 
						|
			release: nextdelta
 | 
						|
		]);
 | 
						|
 | 
						|
		Synth(\siliconSynth, [
 | 
						|
			freq: nextfrequency_alt,
 | 
						|
			amp: nextamp,
 | 
						|
			attack: delta,
 | 
						|
			release: nextdelta
 | 
						|
		]);
 | 
						|
 | 
						|
		// epilogue
 | 
						|
		step = step + 1;
 | 
						|
		delta.yield;
 | 
						|
		
 | 
						|
	}
 | 
						|
	
 | 
						|
});
 | 
						|
 | 
						|
 | 
						|
TempoClock.default.tempo = 1; // beats/sec /BPS
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
						|
// DEBUG
 | 
						|
//~siLines = FileReader.read(path:"../dev/silicon_lines.txt", skipBlanks:true, skipEmptyLines:true); 
 | 
						|
//~siLines[124][0].postln;
 | 
						|
//siLines.size.postln;
 | 
						|
//r.next;
 | 
						|
//r.stop;
 | 
						|
 | 
						|
		// if (siLines[step-1].notNil, {
 | 
						|
		// 	playhead = siLines[step-1][0].asFloat.linlin(3900, 7200, 0, (60*37+5)); // at the end these are seconds!
 | 
						|
		// }, { playhead = 0 });
 | 
						|
		// nextdelta = siLines[step][0].asFloat.linlin(3900, 7200, 0, (60*37+5)) - playhead;
 | 
						|
		// delta = playhead - prevplayhead;
 | 
						|
		// prevplayhead = playhead;
 | 
						|
 | 
						|
/*
 | 
						|
			post("t:" + item[0].asFloat.linlin(3900, 7200, 0, 12 ).asStringPrec(5) + Char.tab ); // tone
 | 
						|
			post("t:" + item[0].asFloat.linlin(3900, 7200, 12, 0 ).asStringPrec(5) ); // tone reverse
 | 
						|
			
 | 
						|
			//{SinOsc.ar((item[0].asFloat.linlin(3900, 7200, 0, 12)+60).midicps, mul:item[1].asInt * 0.000005)}.play;
 | 
						|
			/*{LFPar.ar((
 | 
						|
				item[0].asFloat.linlin(3900, 7200, 0, 12)
 | 
						|
				+ ( ( (i+1) % 1) * 12) + 60).midicps,
 | 
						|
				mul:(item[1].asInt.linlin(0, 1000, 0.0, 0.5) + item[1].asInt.linexp(0, 1000, 0.01, 0.5))  * [i%2,abs(i%2-1)] * 0.05)}.play;
 | 
						|
			*/
 | 
						|
			//{SinOsc.ar(item[0].asFloat.linexp(3900, 7200, 20000, 40 ).asInt, mul:item[1].asInt * 0.000005)}.play;
 | 
						|
			{SinOsc.ar(item[0].asFloat.linexp(3900, 7200, 20000, 40).asInt, mul:item[1].asInt * 0.00005)}.play;
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
 |