diff --git a/arduino/remembering_clive_wearing_arduino.ino b/arduino/remembering_clive_wearing_arduino.ino new file mode 100644 index 0000000..e531b26 --- /dev/null +++ b/arduino/remembering_clive_wearing_arduino.ino @@ -0,0 +1,50 @@ + +#include // Include Timer1 library +#include // Include SimpleMessageSystem library + +// This is programmed for an Arduino Mega controlling lights from outs 22+ +int AC_pin_offset = 22; // lowest out for lights +int dims[18]; // dimmer values +unsigned char clock_tick; // variable for Timer1 +unsigned int delay_time = 50; + +void setup() { + Serial.begin(115200); + for(int i = 0; i < 18; i++){ + dims[i] = 110; + // Set the pins to the triacs as outputs (using outs 0 - 17) + pinMode(AC_pin_offset + i, OUTPUT); + }; + attachInterrupt(0, zero_crosss_int, RISING); + Timer1.initialize(65); // set a timer of length 100 microseconds for 50Hz or 83 microseconds for 60Hz; + Timer1.attachInterrupt( timerIsr ); // attach the service routine here +} + +// this is the dimmer +void timerIsr() { + clock_tick++; + for(int i = 0; i < 18; i++) { + if (dims[i] == clock_tick) { + digitalWrite(AC_pin_offset + i, HIGH); // triac on + } + }; +} + +// function to be fired at the zero crossing to dim the light +void zero_crosss_int() { + clock_tick=0; + for(int i = 0; i < 18; i++){ + digitalWrite(AC_pin_offset + i, LOW); // triac Off + } +} + +void loop(){ + int light = 0; + int val = 0; + // Checks to see if the message is complete and erases any previous messages + if (messageBuild() > 0) { + light = messageGetInt(); + val = messageGetInt(); + dims[light] = val; + } +} diff --git a/remembering_clive_wearing_score.pdf b/remembering_clive_wearing_score.pdf index f8c23c9..ce71cf0 100644 Binary files a/remembering_clive_wearing_score.pdf and b/remembering_clive_wearing_score.pdf differ diff --git a/supercollider/remembering_clive_wearing_main.scd b/supercollider/remembering_clive_wearing_main.scd index 1b9d96e..faa89e9 100644 --- a/supercollider/remembering_clive_wearing_main.scd +++ b/supercollider/remembering_clive_wearing_main.scd @@ -9,14 +9,18 @@ No GUI, just keycodes: = run synth, = pause synth = trigger start / fade in, = trigger end / fade out, = trigger wake +When ~arduino == 1 (true), the app assumes that an arduino is reachable, otherwise errors will be thrown + When automate == 1 (true), the trigger keys are disabled and the following lists in the SynthDef are used: startTimes, wakeTimes, and endTimes This launches the synth in a paused state to give the user time to put the visuals in full screen. To start the synth, must be executed */ -var automate = 1; + var dir = thisProcess.nowExecutingPath.dirname; +var automate = 1; +~arduino = 1; ~fadeInTrigBus = Bus.control(s); ~wakeTrigBus = Bus.control(s); ~fadeOutTrigBus = Bus.control(s); "remembering_clive_wearing_visuals.scd".loadRelative(true, { "remembering_clive_wearing_synthdef.scd".loadRelative(true, { diff --git a/supercollider/remembering_clive_wearing_visuals.scd b/supercollider/remembering_clive_wearing_visuals.scd index c1d2e9c..f75df02 100644 --- a/supercollider/remembering_clive_wearing_visuals.scd +++ b/supercollider/remembering_clive_wearing_visuals.scd @@ -1,7 +1,7 @@ ( // VISUALS // Init vars and window -var projectionWin, scoreWin, osc_func, run = true, blend = {0} ! 27; +var projectionWin, arduino_port, osc_func, brightness = {0} ! 27, refresh_func; projectionWin = Window.new("Lamentations I: Remembering Clive Wearing", Rect(500, 500, 750, 500)).front; projectionWin.background = Color.black; @@ -13,7 +13,7 @@ projectionWin.view.keyDownAction = { |doc, char, mod, unicode, keycode, key| // = exit full screen {mod == 0 && key == 16777216} {projectionWin.endFullScreen} // = run synth - {mod == 262144 && key == 82} {~flicker.run} + {mod == 262144 && key == 82} {refresh_func.fork(AppClock); ~flicker.run} // = pause synth {mod == 262144 && key == 80} {~flicker.run(false)} // = start / fade in @@ -24,8 +24,11 @@ projectionWin.view.keyDownAction = { |doc, char, mod, unicode, keycode, key| {mod == 262144 && key == 84} {~wakeTrigBus.set(1)} }; +// Connect arduino; edit first arg / port to match index or name of port: SerialPort.listDevices +if(~arduino == 1, { arduino_port = SerialPort( 0, 115200) }, {}); + // Get control signals from SynthDef -osc_func = OSCFunc.new({arg msg, time; blend[msg[2]] = msg[3]},'/tr', s.addr); +osc_func = OSCFunc.new({arg msg, time; brightness[msg[2]] = msg[3]; },'/tr', s.addr); // Draw the window projectionWin.drawFunc = { @@ -43,12 +46,27 @@ projectionWin.drawFunc = { Pen.addOval(innerSquare); Pen.fillRadialGradient(innerSquare.center, innerSquare.center, (innerSquare.width / 16), (innerSquare.width / 2), - Color.black.blend(Color.new255(255, 214, 170, 255), pow(blend[(i * 9) + j], 0.5)), + Color.black.blend(Color.new255(255, 214, 170, 255), pow(brightness[(i * 9) + j], 0.5)), Color.black); } ! 9 } ! 2 }; projectionWin.refresh; // Refresh function -{ while { run } { projectionWin.refresh; 30.reciprocal.wait; } }.fork(AppClock); +refresh_func = { while { true } { + // updateProjection + projectionWin.refresh; + + // updateArduino + if(~arduino == 1, { + {|i| + arduino_port.putAll(i.asString); + arduino_port.put(Char.space); + arduino_port.putAll(((brightness[i] - 1).abs * 110).trunc.asString); + arduino_port.put(Char.space); + arduino_port.put(13); + } ! 18 }, {}); + + // delay + 30.reciprocal.wait; } }; ) \ No newline at end of file