From 34982655447172f874d0e173f2bc9b61bb2c6d42 Mon Sep 17 00:00:00 2001 From: Rob Canning Date: Thu, 19 Oct 2023 23:04:42 +0200 Subject: [PATCH] get_data automate token etc --- data/get_data.sh | 46 +++++++++---- sc/witw.scd | 176 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 177 insertions(+), 45 deletions(-) diff --git a/data/get_data.sh b/data/get_data.sh index 3065090..d6c1351 100755 --- a/data/get_data.sh +++ b/data/get_data.sh @@ -1,37 +1,55 @@ #!/bin/bash +# /////////////////////////////////////////////// +# Whistling in the Wind +# Data Sonification with Supercollider +# Rob Canning 2023 +# /////////////////////////////////////////////// -STATION_A='D7:80:BE:2C:63:BD' -STATION_B='F1:CC:C3:0B:7F:5C' +# Array of weather station MAC addresses -STATIONS=($STATION_A $STATION_B) +STATIONS=( 'D7:80:BE:2C:63:BD' 'F1:CC:C3:0B:7F:5C' ) + +# Request API token (JSON) and parse for access_token string with Python3 TOKEN=$(curl --insecure --data \ "username=data-api-user&password=jBD0CD1wGOKoTVtC&grant_type=password&client_id=phenode" \ https://phenode-link.com:8443/realms/grafana/protocol/openid-connect/token \ | python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])") -#rm -r all-data *.zip +echo $TOKEN; + +# pull down the data and clean it up with sed and awk for data in "${STATIONS[@]}" + do - if [ -d $data ] - then echo "removing old data directories" ; rm -r $data - else echo "nothing to remove" - fi ## if data dir exists then remove it + if [ -d $data ] ## if data dir exists then remove it + then echo "removing old data directories" ; rm -r $data + else echo "nothing to remove" + fi + echo "downloading data from device with MAC: $data" - curl --insecure \ - -X POST https://phenode-link.com:2537/devices/$data/all-data/2023-04-10T16:52:21Z \ - -H "Authorization: Bearer $TOKEN" \ - --output $data.zip + + # curl --insecure \ + # -X POST https://phenode-link.com:2537/devices/$data/all-data/2023-04-10T16:52:21Z \ + # -H \"Authorization: Bearer $TOKEN\" \ + # --output $data.zip unzip $data.zip && mv all-data $data && rm $data.zip && cd $data + # backup unfiltered / raw data + cp sensor_data.csv sensor_data_ORIG.csv + # remove the null data and replace with 0 - sed -i 's/^,/0,/; :a;s/,,/,0,/g;ta' sensor_data.csv + sed -i 's/^,/0,/; :a;s/,,/,0,/g;ta' sensor_data.csv # clear the ugly rows from Growing Degree Days - awk -F, 'NR==1{print} NR>1 && $2=="0" {gsub(/[)(\]\[]/,"",$0);print}' sensor_data.csv > tmp && mv tmp sensor_data_clean.csv + awk -F, 'NR==1{print} NR>1 && $2=="0" {gsub(/[)(\]\[]/,"",$0);print}' sensor_data.csv > tmp && mv tmp sensor_data.csv cd ../ + +# sensor_data.csv is the final file to be used by supercollider +# sensor_data_ORIG.csv is the backup original data + done diff --git a/sc/witw.scd b/sc/witw.scd index 15b1899..a826987 100644 --- a/sc/witw.scd +++ b/sc/witw.scd @@ -1,11 +1,10 @@ /*RUN*/ - +( s.options.numInputBusChannels = 4; s.options.numOutputBusChannels = 4; -~dataPath = "/home/rizoma/witw/data/D7:80:BE:2C:63:BD/"; // CHANGE THIS TO RELATIVE PATH - -"echo curl -v -X POST http://3.139.191.80:2537/devices/dev:864475040526732/all-data/2023-09-20T16:52:21Z -H 'Authorization: Bearer token' --output dev:864475040526732.zip".unixCmd; +~dataPath = "/home/rizoma/witw/data/"; // CHANGE THIS TO RELATIVE PATH +~devices = ["D7:80:BE:2C:63:BD", "F1:CC:C3:0B:7F:5C"]; s.waitForBoot{ @@ -13,7 +12,7 @@ s.waitForBoot{ ~ctrlBus = 8.collect({arg i; Bus.control(s,1); }); // define synths - SynthDef(\sgrain, { | out=0, atk=0.01, dcy=0.01, freq=100, pan=0, amp=0.5| + SynthDef(\sgrain, { | out=0, atk=0.01, dcy=0.01, freq=100, pan=0, amp=1| var sig, env; env = EnvGen.ar(Env.perc(atk, dcy), doneAction: 2); sig = FSinOsc.ar(freq); @@ -24,26 +23,28 @@ s.waitForBoot{ }).add; SynthDef(\sslew, { - | out = 0, freq=100, amp = 0.05, slewrate = 1| + | out = 0, freq=100, amp = 0.7, slewrate = 1| var sig, z; // add slew rate on frequency z = Slew.kr(freq, slewrate, slewrate); - sig = Blip.ar(z, 5, amp).dup; + sig = BPF.ar(PinkNoise.ar(), z, 6 ); + //sig = Blip.ar(z, 5, amp).dup; Out.ar(out, sig) }).add; + SynthDef.new(\sine, { + arg freq=440, panfreq=0.3, panphase=0.5, rel=0.5, gate=0, amp=0.0001; + var sig; + sig = SinOsc.ar(freq); + sig = sig * EnvGen.kr(Env.perc(0.04,rel), doneAction:2); + sig = Pan2.ar(sig, FSinOsc.kr(panfreq, panphase)); + sig = sig * amp; + Out.ar(0, sig); + }).add; + // load and process the data source ///////////////////////////////// - // need to strip the header and the date // or the : from datetime and the header - // strip first 6 rows after header to stop gps data spilling - // todo preprocess file with Sed - // growing degree days causes nil in other fields - filter these out - - //~csvFile=CSVFileReader.readInterpret(~dataPath ++ "sensor_data-notime-noheader-cutrows1.csv",true,true); - - ~csvFile=CSVFileReader.read(~dataPath ++ "sensor_data.csv",true,true); - + ~csvFile=CSVFileReader.read(~dataPath ++ ~devices[0] ++ "/" ++ "sensor_data.csv",true,true); // flatten ~data from 2D Array to regular array (per column); - // ~data = ( ~csvFile[0].size-1 ).collect({ arg itt; ~data = ( ~csvFile[0].size ).collect({ arg itt; Array.fill( ~csvFile.size-1,{ arg i; ~csvFile.at(i+1).asArray.at(itt)}); // +1 to skip the column name @@ -60,32 +61,145 @@ s.waitForBoot{ ~data[21]; // LAT // normalize data ranges ////// + ~date=~data[0]; - ~freq=~data[2].asFloat.normalize(20, 1000); - ~atk=~data[2].asFloat.normalize(0.02, 0.04); + ~freq=~data[2].asFloat.normalize(0, 400); + ~atk=~data[4].asFloat.normalize(0.02, 0.04); ~dcy=~data[2].asFloat.normalize(0.05, 0.1); - ~dur=~data[2].asFloat.normalize(0.03, 0.3); - ~level=~data[2].asFloat.normalize(0.01, 0.1); + ~dur=~data[2].asFloat.normalize(0.1, 0.1); + ~level=~data[2].asFloat.normalize(0, 0); //start the slewing synth ///////////////////////////// - //~sslew1 = Synth(\sslew,[\out,0,\freq,220,\amp,0.01,\slewrate,1000]); + + //~sslew1 = Synth(\sslew,[\out,0,\freq,220,\amp,0,\slewrate,1000]); //~sslew1.map(\freq, ~ctrlBus[0]); // map control bus to freq parameter //o = OSCFunc({ |msg| msg.postln }, '/tr', s.addr); + + ~ce = Array.new(maxSize: 20); // perform the data sonification ///////////////////// - ( p = Pbind(\instrument, \sgrain, - \freq, Pseq(~freq.round(100),1), - \atk, Pseq(~atk,1), + +/* ( p = Pbind(\instrument, \sgrain, + \freq, Pseq(~freq.round(30),1), + \atk, Pseq(~atk,1).poll, \dcy, Pseq(~dcy,1), \pan, Pseq([0,1], inf), \dur, Pseq(~dur,1), - \amp, Pseq(~level,1), - //\renoise, Pfunc({|e| e.use { ~date.postln } }) - ).play; - ); + \amp, Pseq(~level, 1), + \date, Pseq(~date, 1 ) + ).collect{ arg i; i.postln; });*/ + ~gr = Group.new; + ~pitchset = [20,40,60,80].midicps; + + Pdef(\c, + Pspawner({ | sp | + 8.do { | i | + sp.par( + // Pdefn (~ce[i], + Pbind( *[ + \instrument, \sine, + \dur, Pseq(Array.geom(30, rrand(1,1.5), rrand(0.98,0.99)).mirror,1), + \freq, exprand(~pitchset[0],~pitchset[0]*100).round(~pitchset[0]), + \panfreq, rrand(0.1, 2.2), + \amp, 0.05, + \panphase, rrand(-1.0,1.0), + \rel, exprand(1.5,3.35), + //\gate, 0, + \group, ~gr + ]); + //) + ); + sp.wait(1); + }; + }); + ).play; + + + + //Pdefn (\c, Pbind( \freq, exprand(~pitchset[0],~pitchset[0]*100).round(~pitchset[0]))) + + ~dur = PatternProxy.new; + ~deg = PatternProxy.new; + ~oct = PatternProxy.new; + ~voc = PatternProxy.new; + ~amp = PatternProxy.new; + ~sca = PatternProxy.new; + ~rel = PatternProxy.new; + + ~dur.source = Pseq(Array.geom(30, rrand(1,1.5), rrand(0.98,0.99)).mirror,inf); + ~deg.source = Prand([0,5,7],inf); + ~oct.source = Prand([2,3,4],inf); + ~voc.source = 4; + ~amp.source = Pwhite(0.001, 0.1,inf); + ~sca.source = Scale.harmonicMinor; + ~rel.source = Pexprand(1.5,3.35, inf); + + Pdef(\c, Pspawner({ | sp | 8.do { | i | sp.par( + Pbind( *[ + \instrument, \sine, + \dur, ~dur, + \scale, ~sca, + \degree, ~deg, + \octave, ~oct, + //\freq, exprand(~pitchset[0],~pitchset[0]*80).round(100), + \panfreq, rrand(0.1, 2.2), + \amp, ~amp, + \panphase, rrand(-1.0,1.0), + \rel, ~rel, + //\rel, exprand(1.5,3.35), + + \group, ~gr + ]); + ); + sp.wait(1); + }; + }); + ).play; + + s.plotTreeView; }; // closes s.waitForBoot -//p.stop; +~dur.source = Pseq(Array.geom(30, rrand(1,1.5), rrand(0.98,0.99)).mirror,inf); +~dur.source = Pseq([1.5],inf); + +//~voc.source = 1; +~oct.source = Prand([3,4],inf); +~deg.source = Prand([0,4,7,9,11],inf); +~sca.source = Scale.chromatic; +~rel.source = Pexprand(1.1,10.5, inf); +~amp.source = Pwhite(0.001, 0.00,inf); + +( +r = Routine { + 199.yield; + 189.yield; + Routine { 100.do { |i| i.yield } }.idle(6); + 199.yield; + 189.yield; +}; +​ +fork { + loop { + r.value.postln; + 1.wait; + } +} +); + + + + + + + + +/* +c.set(\amp, 0.2);*/ + +//~gr.set(\amp, 0.001); +//~gr.set(\freq, exprand(~pitchset[0],~pitchset[0]*100).round(~pitchset[0])); + +) + -//~sslew1.stop;