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;
|
|
*/
|
|
|
|
|
|
|