diff --git a/README.md b/README.md index 0e64360..110c62a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,31 @@ -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 +# Whistling in the Wind -And get a tolken in return: -{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJPbjJGUXVKOFktOTA5dUpHV1FFRGtiekctR1JObU1jNDNIc2xFZ1Z2X1ZRIn0.eyJleHAiOjE2OTYzNDk0NzUsImlhdCI6MTY5NjMzMTQ3NSwianRpIjoiODg0ZTg5ZTctOGE2Zi00YWIzLWIwNjMtYjlmZDg5MTEyMDkxIiwiaXNzIjoiaHR0cHM6Ly9waGVub2RlLWxpbmsuY29tOjg0NDMvcmVhbG1zL2dyYWZhbmEiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiZGYzMzBhNjItOGNmYS00ZWY0LWEzYzgtZTE5OTY4NzE2YTViIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoicGhlbm9kZSIsInNlc3Npb25fc3RhdGUiOiI2YWE1OTg3ZC1hMjc5LTQ4NzItYmRlNS02YzdmZDc1ODkzNDgiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL3BoZW5vZGUtbGluay5jb206MzAwMiIsImh0dHA6Ly93d3cucGhlbm9kZS1saW5rLmNvbTozMDAyIiwiaHR0cHM6Ly93d3cucGhlbm9kZS1saW5rLmNvbTozMDAyIiwiaHR0cHM6Ly9sb2NhaG9zdDozMDAyIiwiaHR0cHM6Ly93d3cucGhlbm9kZS1saW5rLmNvbSIsImh0dHBzOi8vMy4xMzkuMTkxLjgwLjMwMDIiLCJodHRwOi8vbG9jYWhvc3Q6MzAwMiIsImh0dHA6Ly93d3cucGhlbm9kZS1saW5rLmNvbSIsImh0dHA6Ly8zLjEzOS4xOTEuODAuMzAwMiIsImh0dHBzOi8vbG9jYWxob3N0OjMwMDIiLCJodHRwczovL3BoZW5vZGUtbGluay5jb206MzAwMiIsImh0dHBzOi8vMy4xMzkuMTkxLjgwIiwiaHR0cDovL3BoZW5vZGUtbGluay5jb20iLCJodHRwczovL3BoZW5vZGUtbGluay5jb20iLCJodHRwOi8vMy4xMzkuMTkxLjgwIl0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJzaWQiOiI2YWE1OTg3ZC1hMjc5LTQ4NzItYmRlNS02YzdmZDc1ODkzNDgiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInJvbGVzIjpbInZpZXdlciIsIm9mZmxpbmVfYWNjZXNzIiwiZGVmYXVsdC1yb2xlcy1ncmFmYW5hIiwidW1hX2F1dGhvcml6YXRpb24iXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGF0YS1hcGktdXNlciIsImdpdmVuX25hbWUiOiIiLCJmYW1pbHlfbmFtZSI6IiJ9.PrEaqR0f5v4KtJlrDegHPGsw8-RLJUB0y3D22BYDZgAVeVBu823vRBuyoOsmG1paE-Q46M_RtBUMEOLd62mjOZEOaVJ9-gQC7f2Guc26ji02U1Glf6AVMtR9K-Se_M8Pq8nhHjDouuSpvLvcyP3YolkT3iGkXEsoRhd7cjFuiK3hiJU2y7iSKhEinKbw6K_engCEtBN-V_r21gDeCt_xIgI_bGkMXKWHQWasj4h5AixwIJtqpHPKmI6OUYah0xR2KhZiqKV0aWFQZAOy8ZP80ksYG5AKDVbJ491UjVAPG8acmFsPV5FumJIPG8hdENEA4vBxgFPk_b_6TzBlLaSWdg","expires_in":18000,"refresh_expires_in":31536000,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiYjY3ODY2NS1lNjk0LTQzNWEtYjViYi04YzExZTQ3MjdjMWMifQ.eyJleHAiOjE3Mjc4Njc0NzUsImlhdCI6MTY5NjMzMTQ3NSwianRpIjoiMDNjNWI1NTUtNzlhMi00NWQ0LWJiY2ItZmIxODcyMmZiZThlIiwiaXNzIjoiaHR0cHM6Ly9waGVub2RlLWxpbmsuY29tOjg0NDMvcmVhbG1zL2dyYWZhbmEiLCJhdWQiOiJodHRwczovL3BoZW5vZGUtbGluay5jb206ODQ0My9yZWFsbXMvZ3JhZmFuYSIsInN1YiI6ImRmMzMwYTYyLThjZmEtNGVmNC1hM2M4LWUxOTk2ODcxNmE1YiIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJwaGVub2RlIiwic2Vzc2lvbl9zdGF0ZSI6IjZhYTU5ODdkLWEyNzktNDg3Mi1iZGU1LTZjN2ZkNzU4OTM0OCIsInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsInNpZCI6IjZhYTU5ODdkLWEyNzktNDg3Mi1iZGU1LTZjN2ZkNzU4OTM0OCJ9.17Hxv-n8jiUTbHGjXiEu-E0zBUV6UCz2cDGku-8e05M","token_type":"Bearer","not-before-policy":1662482026,"session_state":"6aa5987d-a279-4872-bde5-6c7fd7589348","scope":"profile email"} -curl --insecure -X POST https://phenode-link.com:2537/devices/D7:80:BE:2C:63:BD/all-data/2023-04-10T16:52:21Z -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJPbjJGUXVKOFktOTA5dUpHV1FFRGtiekctR1JObU1jNDNIc2xFZ1Z2X1ZRIn0.eyJleHAiOjE2OTYzNDk0NzUsImlhdCI6MTY5NjMzMTQ3NSwianRpIjoiODg0ZTg5ZTctOGE2Zi00YWIzLWIwNjMtYjlmZDg5MTEyMDkxIiwiaXNzIjoiaHR0cHM6Ly9waGVub2RlLWxpbmsuY29tOjg0NDMvcmVhbG1zL2dyYWZhbmEiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiZGYzMzBhNjItOGNmYS00ZWY0LWEzYzgtZTE5OTY4NzE2YTViIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoicGhlbm9kZSIsInNlc3Npb25fc3RhdGUiOiI2YWE1OTg3ZC1hMjc5LTQ4NzItYmRlNS02YzdmZDc1ODkzNDgiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL3BoZW5vZGUtbGluay5jb206MzAwMiIsImh0dHA6Ly93d3cucGhlbm9kZS1saW5rLmNvbTozMDAyIiwiaHR0cHM6Ly93d3cucGhlbm9kZS1saW5rLmNvbTozMDAyIiwiaHR0cHM6Ly9sb2NhaG9zdDozMDAyIiwiaHR0cHM6Ly93d3cucGhlbm9kZS1saW5rLmNvbSIsImh0dHBzOi8vMy4xMzkuMTkxLjgwLjMwMDIiLCJodHRwOi8vbG9jYWhvc3Q6MzAwMiIsImh0dHA6Ly93d3cucGhlbm9kZS1saW5rLmNvbSIsImh0dHA6Ly8zLjEzOS4xOTEuODAuMzAwMiIsImh0dHBzOi8vbG9jYWxob3N0OjMwMDIiLCJodHRwczovL3BoZW5vZGUtbGluay5jb206MzAwMiIsImh0dHBzOi8vMy4xMzkuMTkxLjgwIiwiaHR0cDovL3BoZW5vZGUtbGluay5jb20iLCJodHRwczovL3BoZW5vZGUtbGluay5jb20iLCJodHRwOi8vMy4xMzkuMTkxLjgwIl0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJzaWQiOiI2YWE1OTg3ZC1hMjc5LTQ4NzItYmRlNS02YzdmZDc1ODkzNDgiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInJvbGVzIjpbInZpZXdlciIsIm9mZmxpbmVfYWNjZXNzIiwiZGVmYXVsdC1yb2xlcy1ncmFmYW5hIiwidW1hX2F1dGhvcml6YXRpb24iXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGF0YS1hcGktdXNlciIsImdpdmVuX25hbWUiOiIiLCJmYW1pbHlfbmFtZSI6IiJ9.PrEaqR0f5v4KtJlrDegHPGsw8-RLJUB0y3D22BYDZgAVeVBu823vRBuyoOsmG1paE-Q46M_RtBUMEOLd62mjOZEOaVJ9-gQC7f2Guc26ji02U1Glf6AVMtR9K-Se_M8Pq8nhHjDouuSpvLvcyP3YolkT3iGkXEsoRhd7cjFuiK3hiJU2y7iSKhEinKbw6K_engCEtBN-V_r21gDeCt_xIgI_bGkMXKWHQWasj4h5AixwIJtqpHPKmI6OUYah0xR2KhZiqKV0aWFQZAOy8ZP80ksYG5AKDVbJ491UjVAPG8acmFsPV5FumJIPG8hdENEA4vBxgFPk_b_6TzBlLaSWdg" --output D7-80-BE-2C-63-BD.zip +Whistling in the Wind is a hybrid data-sonification / electronic music composition. The piece can be thought of as a 'data-guided' generative music composition. It uses live and histoic data from environmental monitoring stations located around the city of Maribor in Slovenia as its data inputs. This data influence musical change, in real-ttime, within the composition's own generative logic. + +The installation can be thought of as similar to wind chimes in that one system (the collection of tuned pipes) is exposed to another (the wind speed and direction), but a little more complex. The first system is the musical composition, described in software, where some parameters are variable and open to external influence while other element are fixed and more deliberatly composed. + +The composition can be installed in a physical location such as a gallery or public space as well as existing as a live streaming Internet radio station. + +## Live Stream +[http://rizom.si:8000/whistling_in_the_wind.mp3]() + +## Credits +*Whistling in the Wind* was commissioned through the EU funded KonS Platform for Contemporary Investigative Arts as a creative response within the city{making}sense project directed by urban planner and architect Andrej Žižek. + +[https://kons-platforma.org/dogodki/andrej-zizek-citymakingsense/()]() + +## Technologies +The composition uses Supercollider in conjuntion with a set of Python and Bash scripts which gather data from the environmental monitoring stations via an API. The composition is then streamed as an online radio using Liquidsoap and Icecast. Everything runs headless on a Debian 12 server requiring minimal long term maintenance. + +### Code +The code lives in a git reposity publicly hosted by kompot.si, a collective of Slovenia's finest autonomous infrastructure and free software advocates. +- https://git.kompot.si/rob/witw + +### System Requirments + +Debian 12 OS, Jack2, Supercollider 3.13.0, Python3, Bash, Liquidsoap, Icecast2 Streaming Server + +---- -A ZIP file is created in the folder, named D7-80-BE-2C-63-BD.zip -(3) For the second sensor set the command is adopted using the F1:CC:C3:0B:7F:5C adress and F1-CC-C3-0B-7F-5C.zip name. diff --git a/ardour/witw/instant.xml b/ardour/witw/instant.xml index fcc553f..526a840 100644 --- a/ardour/witw/instant.xml +++ b/ardour/witw/instant.xml @@ -1,6 +1,18 @@ +
+ + + + + + + + + + + @@ -24,25 +36,10 @@ - - + + - - - - - - - - - - - - - - - diff --git a/ardour/witw/witw.ardour b/ardour/witw/witw.ardour index 83681fb..1ed6931 100644 --- a/ardour/witw/witw.ardour +++ b/ardour/witw/witw.ardour @@ -1,5 +1,5 @@ - + @@ -73,10 +73,7 @@ - - - - + @@ -105,10 +102,12 @@ + + @@ -149,7 +148,7 @@ - + @@ -248,8 +247,8 @@ - - + + @@ -325,7 +324,7 @@ - + @@ -400,10 +399,10 @@ - - - - + + + + @@ -417,9 +416,7 @@ - - - + @@ -508,9 +505,7 @@ - - - + @@ -599,9 +594,7 @@ - - - + @@ -690,9 +683,7 @@ - - - + diff --git a/ardour/witw/witw.ardour.bak b/ardour/witw/witw.ardour.bak index 7390cff..83681fb 100644 --- a/ardour/witw/witw.ardour.bak +++ b/ardour/witw/witw.ardour.bak @@ -1,5 +1,5 @@ - + @@ -784,7 +784,7 @@ - @@ -868,7 +868,7 @@ - + diff --git a/sc/witw.scd b/sc/witw.scd index e16f626..7172dd2 100644 --- a/sc/witw.scd +++ b/sc/witw.scd @@ -2,18 +2,27 @@ // initial settings ..................................... -s.options.numInputBusChannels = 4; -s.options.numOutputBusChannels = 4; +s.options.numInputBusChannels = 2; // 4 for installation 2 for webstream +s.options.numOutputBusChannels = 2; -~dataPath = "/home/rizoma/witw/data/"; // CHANGE THIS TO RELATIVE PATH +// create 8 control busses to pass data between synths +~ctrlBus = 8.collect({arg i; Bus.control(s,1); }); + +//~dataPath = "/home/rob/witw/data/"; // laptop +~dataPath = "/home/rizoma/witw/data/"; // installation computer ~devices = ["D7:80:BE:2C:63:BD", "F1:CC:C3:0B:7F:5C"]; +// load and process the data source ///////////////////////////////// +~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 ).collect({ arg itt; + Array.fill( ~csvFile.size-1,{ arg i; + ~csvFile.at(i+1).asArray.at(itt)}); // +1 to skip the column name +}); + s.waitForBoot{ - // create 8 control busses to pass data between synths - ~ctrlBus = 8.collect({arg i; Bus.control(s,1); }); - - // initial settings ..................................... // define synths SynthDef(\sgrain, { | out=0, atk=0.01, dcy=0.01, freq=100, pan=0, amp=1| var sig, env; @@ -36,48 +45,20 @@ s.waitForBoot{ }).add; SynthDef.new(\sine, { - arg freq=440, modfreq=6, pmindex=3, modphase=0, panfreq=1.3, panphase=0.5, rel=0.5, gate=0, amp=0.0001; + arg freq=440, modfreq=6, pmindex=3, modphase=0, + panfreq=1.3, panphase=0.5, rel=0.5, gate=0, amp=0.0001; var sig, env; sig = PMOsc.ar(freq, modfreq, pmindex, modphase); //env = Env.perc(0.04,rel); env = Env.new([ 0, 1, 0.3, 0], [ 0.01, rel ,1], [1,-1]); sig = sig * EnvGen.kr(env, doneAction:2); - //sig = Pan2.ar(sig, FSinOsc.kr(panfreq, panphase)); - sig = PanAz.ar(4, sig, LFSaw.kr(panfreq, modphase), width: 1, orientation: 0); + sig = Pan2.ar(sig, FSinOsc.kr(panfreq, modphase)); + //sig = PanAz.ar(4, sig, LFSaw.kr(panfreq, modphase), width: 1, orientation: 0); sig = sig * amp; Out.ar(0, sig); }).add; - // initial settings ..................................... - - // load and process the data source ///////////////////////////////// - ~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 ).collect({ arg itt; - Array.fill( ~csvFile.size-1,{ arg i; - ~csvFile.at(i+1).asArray.at(itt)}); // +1 to skip the column name - }); - - ~data[2]; // Temperature C - ~data[3]; // F - ~data[10]; // wind speed MPH - ~data[11]; // wind direction - ~data[13]; // wind gusts MPH - ~data[5]; // rain bucket capacity - ~data[6]; // rain bucket tips per minute? - ~data[20]; // LON - ~data[21]; // LAT - - // normalize data ranges ////// - - ~date=~data[0]; - ~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.1, 0.1); - ~level=~data[2].asFloat.normalize(0, 0); //start the slewing synth ///////////////////////////// @@ -117,7 +98,7 @@ s.waitForBoot{ ~sca = PatternProxy.new; // scale ~rel = PatternProxy.new; // release - ~dur.source = Pseq(Array.geom(30, rrand(1,1.5), rrand(0.98,0.99)).mirror,inf); + ~dur.source = Pseq(Array.geom(30, rrand(2,2.5), rrand(0.98,0.99)).mirror,inf); ~deg.source = Prand([0,5,7],inf); // carrier frequency ~mfr.source = Pexprand(0.1,3, inf); // modulation frequency ~pmi.source = Pexprand(0.5,3, inf); // phase modulation index @@ -126,13 +107,13 @@ s.waitForBoot{ ~oct.source = Prand([2,3,4],inf); ~voc.source = 4; - ~amp.source = Pwhite(0.001, 0.1,inf); + ~amp.source = Pwhite(0.001, 0.02,inf); ~sca.source = Scale.harmonicMinor; ~rel.source = Pexprand(1.5,3.35, inf); // initial settings ..................................... - Pdef(\c, Pspawner({ | sp | 4.do { | i | sp.par( + Pdef(\c, Pspawner({ | sp | 3.do { | i | sp.par( // 4 do for installation version Pbind( *[ \instrument, \sine, \dur, ~dur, @@ -151,106 +132,128 @@ s.waitForBoot{ ]); ); sp.wait(10); }}); ).play; -}; // closes s.waitForBoot ..................................... -( ///////////////////////////////////////////////////////// - // temporal structure of wind controled layer /////////// - // ..................................... + s.sync; -~temperature=~data[2];//.asFloat; //.normalize(0, 11); -~dateTime=~data[0]; + ( // normalize data ranges or not /////////////////////////// -~windDirection=~data[13]; -~windGust=~data[14]; // m/s + ~temperature=~data[2];//.asFloat; //.normalize(0, 11); + ~dateTime=~data[0]; + ~windDirection=~data[13]; + ~windGust=~data[14]; // m/s + ~windNorth=~data[16]; // m/s + ~windEast=~data[18]; // m/s -~windNorth=~data[16]; // m/s -~windEast=~data[18]; // m/s + // data player //////////////////////////////////////////// -~global_t = 0; // temperature C -~global_wD = 0; // wind direction 360degrees + ~time = Routine { + arg inval; var t = 0; + // itterate through data at a fixed rate // data point every 15mins + // 4sec = 1 hr 24 * 96seconds = 1 day // 9.6 seconds = 1 day @ 0.1.wait + loop { + t = (t + 1) % (~csvFile.size - 1); + postln( t + + " " + ~dateTime[t] + + "C:" ++ ~temperature[t] + + "Wind Dir: " + ~windDirection[t] + + "Gust:" ++ ~windGust[t] + + "North: " + ~windNorth[t] + + "East: " + ~windEast[t]); + 0.1.wait; + }}.play(); -~time.stop; + // temporal structure of wind controled layer /////////// + // ...................................................... + // conditional logic goes here ////////////////////////// -~time = Routine { - arg inval; var t = 0; - // itterate through data at a fixed rate // data point every 15mins - // 4sec = 1 hr 24 * 96seconds = 1 day // 9.6 seconds = 1 day @ 0.1.wait - loop { - t = (t + 1) % (~csvFile.size - 1) ; - ~global_t = ~temperature[t]; - ~global_wD = ~windDirection[t]; - postln( t + " " + ~dateTime[t] + " C:" ++ ~temperature[t] + " Wind Dir: " + ~windDirection[t] + " Gust: " ++ ~windGust[t] + "North: " + ~windNorth[t] + "East: " + ~windEast[t]); - 0.1.wait; -}}.play(); + r = Routine { arg inval; var i = 0; -r = Routine { arg inval; var i = 0; + loop { + i = i + 1; // this loop itterator is not used? + postln(t); // only t the ~time counter - loop { + postf("beats: % seconds: % time: % \n", + thisThread.beats, thisThread.seconds, Main.elapsedTime ); - postln(t); + ~sca.source = Scale.harmonicMinor; + ~deg.source = Prand([0,1,2,3,5,7],inf); + ~oct.source = Prand([4,5],inf); + ~dur.source = Pseq(Array.geom(30, rrand(2,4), rrand(0.96,0.97)).mirror,inf); + ~rel.source = Pexprand(2.1,5.5, inf); + ~amp.source = Pwhite(0.05, 0.2,inf); - i = i + 1; + 50.wait; + postln("line 2"); + ~deg.source = Prand([0,3,5,7],inf); + ~oct.source = Prand([3,4,5],inf); + ~dur.source = Pseq(Array.geom(30, rrand(1,2.5), rrand(0.96,0.97)).mirror,inf); - postln(~temperature[i]); postf("beats: % seconds: % time: % \n", - thisThread.beats, thisThread.seconds, Main.elapsedTime ); + 50.wait; - ~sca.source = Scale.harmonicMinor; - ~deg.source = Prand([0,1,2,3,5,7],inf); - ~oct.source = Prand([4,5],inf); - ~dur.source = Pseq(Array.geom(30, rrand(2,4), rrand(0.96,0.97)).mirror,inf); - ~rel.source = Pexprand(2.1,5.5, inf); - ~amp.source = Pwhite(0.001, 0.05,inf); + postln("line 3"); + ~deg.source = Prand([0,3,5],inf); + ~oct.source = Prand([3,4,5],inf); + ~rel.source = Pexprand(1,3, inf); + ~dur.source = Pseq(Array.geom(30, rrand(1,1.5), rrand(0.96,0.97)).mirror,inf); - 30.wait; - postln("line 2"); - ~deg.source = Prand([0,3,5,7],inf); - ~oct.source = Prand([3,4,5],inf); - ~dur.source = Pseq(Array.geom(30, rrand(1,2.5), rrand(0.96,0.97)).mirror,inf); + 50.wait; - 30.wait; + postln("line 4"); + ~sca.source = Scale.chromatic; + ~deg.source = Prand([0,2,4,6,8,10],inf); + ~oct.source = Prand([3,4,5],inf); - postln("line 3"); - ~deg.source = Prand([0,3,5],inf); - ~oct.source = Prand([3,4,5],inf); - ~rel.source = Pexprand(1,3, inf); - ~dur.source = Pseq(Array.geom(30, rrand(1,1.5), rrand(0.96,0.97)).mirror,inf); + 50.wait; - 30.wait; + postln("line 5"); + ~deg.source = Prand([0,2,4,6,8,10],inf); + ~oct.source = Prand([3,4,5],inf); + ~dur.source = Pseq(Array.geom(30, rrand(0.5,0.6), rrand(0.98,0.99)).mirror,inf); + ~rel.source = Pexprand(0.5,3, inf); - postln("line 4"); - ~sca.source = Scale.chromatic; - ~deg.source = Prand([0,2,4,6,8,10],inf); - ~oct.source = Prand([3,4,5],inf); + 50.wait; - 20.wait; + postln("line 6"); + ~deg.source = Prand([0,7,5],inf); + ~oct.source = Prand([2,3,4,5],inf); + ~dur.source = Pseq(Array.geom(30, rrand(1.5,3.6), rrand(0.98,0.99)).mirror,inf); + ~rel.source = Pexprand(2,4, inf); - postln("line 5"); - ~deg.source = Prand([0,2,4,6,8,10],inf); - ~oct.source = Prand([3,4,5],inf); - ~dur.source = Pseq(Array.geom(30, rrand(0.5,0.6), rrand(0.98,0.99)).mirror,inf); - ~rel.source = Pexprand(0.5,3, inf); + 50.wait; - 30.wait; + ~sca.source = Scale.harmonicMinor; - postln("line 6"); - ~deg.source = Prand([0,7,5],inf); - ~oct.source = Prand([2,3,4,5],inf); - ~dur.source = Pseq(Array.geom(30, rrand(1.5,3.6), rrand(0.98,0.99)).mirror,inf); - ~rel.source = Pexprand(2,4, inf); + postln("line 7"); + ~deg.source = Prand([0,7,5],inf); + ~oct.source = Prand([2,3,4,5],inf); + ~dur.source = Pseq(Array.geom(30, rrand(1,1.5), rrand(0.98,0.99)).mirror,inf); + ~rel.source = Pexprand(2,6, inf); - 30.wait; + 50.wait; - postln("line 7"); - ~deg.source = Prand([0,7,5],inf); - ~oct.source = Prand([2,3,4,5],inf); - ~dur.source = Pseq(Array.geom(30, rrand(1,1.5), rrand(0.98,0.99)).mirror,inf); - ~rel.source = Pexprand(2,6, inf); - 30.wait; - }; -}.play; + postln("line 8"); + + ~deg.source = Prand([0,5,7,9],inf); + ~oct.source = Prand([4,5,6],inf); + ~dur.source = Pseq(Array.geom(30, rrand(2,3.5), rrand(0.98,0.99)).mirror,inf); + ~rel.source = Pexprand(6,12, inf); + + 50.wait; + + postln("line 9"); + ~deg.source = Prand([1,6,8,10],inf); + ~oct.source = Prand([3, 4,5],inf); + ~dur.source = Pseq(Array.geom(30, rrand(3,4.5), rrand(0.98,0.99)).mirror,inf); + ~rel.source = Pexprand(4,12, inf); + + 50.wait; + + }; + }.play; ); -r.stop; +}; // closes s.waitForBoot ..................................... -~time.pause; +r.stop; +~time.stop; diff --git a/witw.liq b/witw.liq new file mode 100644 index 0000000..3d7395f --- /dev/null +++ b/witw.liq @@ -0,0 +1,44 @@ +#!/usr/bin/liquidsoap +# Log dir +log.file.path.set("/tmp/basic-radio.log") + +# Music +#myplaylist = playlist("~/radio/music.m3u") +# Some jingles +#jingles = playlist("~/radio/jingles.m3u") +# If something goes wrong, we'll play this +#security = single("~/radio/sounds/default.ogg") + +# Start building the feed with music +#radio = myplaylist +# Now add some jingles +#radio = random(weights = [1, 4],[jingles, radio]) +# And finally the security +#radio = fallback(track_sensitive = false, [radio, security]) + +radio = input.jack(); + +# Stream it out +output.icecast(%vorbis, + host = "rizom.si", port = 8000, + password = "hackmeheklab", mount = "whistling_in_the_wind.ogg", + genre= "Ambient", + url= "https://kons-platforma.org/" , + description = "Sound Installation / Data Sonification", + id="WITW", + name="Whistling in the Wind", + + radio) + +output.icecast(%mp3(bitrate=256), + host = "rizom.si", port = 8000, + password = "hackmeheklab", mount = "whistling_in_the_wind.mp3", + genre= "Ambient", + url= "https://kons-platforma.org/" , + description = "Sound Installation / Data Sonification", + id="WITW", + name="Whistling in the Wind", + radio) + + +