Experiments with light
Semester 1 / Week 3 - 4
I want to experiment with DMX lighting and how it works. I know lighting is an important aspect of installation environments.
DMX + Processing + Ableton
I borrowed a DMX light and a USB ENTTEC adapter from the studio and played around with how it works. I made a Processing sketch that control the light with a nice system I made. I can send commands that can lerp between colours throughout a specified “life time” with any easing/curve I want. I also made it so multiple of these can be sent and overlapped, with the colours being mixed into one output on the light. For example, a pulsing light linked to a midi note can be played whilst another command is running a gradual change from one colour to another.
import themidibus.*;
import dmxP512.*;
import processing.serial.*;
MidiBus bus;
DmxP512 dmxOutput;
String dmxPort = "/dev/tty.usbserial-EN268160";
int dmxBaudrate = 115000;
void setup() {
size(100, 100);
setupSources();
MidiBus.list();
bus = new MidiBus(new java.lang.Object(), "Virtual MIDI", "Virtual MIDI");
dmxOutput = new DmxP512(this, 5, false);
dmxOutput.setupDmxPro(dmxPort, dmxBaudrate);
dmxOutput.set(0, 0);
}
void draw() {
frameRate(abs(sin(millis() / 4000.0 * TWO_PI)) * 200 + 20);
updateLights();
updateSources();
if (frameCount % 60 == 0) {
Light newLight = new Light(200, 1, color(255, 0, 0), color(0, 0, 0), 0);
bus.sendNoteOn(0, 32, 127); // Send a Midi noteOn
}
if (frameCount % 15 == 0 && frameCount % 30 == 0) {
Light newLight = new Light(30, 1, color(0, 0, 0), color(100, 100, 100), 0);
bus.sendNoteOn(1, 32, 127); // Send a Midi noteOn
}
if (frameCount % 240 == 0) {
Light newLight = new Light(4000, 1, color(50, 0, 0), color(50, 50, 0), 0);
}
}
void noteOn(int channel, int pitch, int velocity) {
println(channel);
}
ArrayList<Light> lights = new ArrayList<Light>();
final int lightSources = 1;
ArrayList<ArrayList<Light>> sources = new ArrayList<>();
void setupSources() {
for (int i = 0; i < lightSources; i++) {
sources.add(new ArrayList<Light>());
}
}
class Light {
int born, lifeTime, curveType, sourceNumber;
color startColour, endColour;
color currentColour;
Light(int lifeTime, int curveType, color startColour, color endColour, int sourceNumber) {
this.lifeTime = lifeTime;
this.curveType = curveType;
this.sourceNumber = sourceNumber;
this.born = millis();
this.startColour = startColour;
this.endColour = endColour;
lights.add(this);
sources.get(sourceNumber).add(this);
}
boolean update() {
int elapsed = millis() - this.born;
if (elapsed > this.lifeTime) {
return false;
}
float percent = 0;
if (curveType == 1) {
percent = easeInSine(elapsed / float(lifeTime));
}
this.currentColour = lerpColor(startColour, endColour, percent);
return true;
}
}
float easeInSine(float number) {
return 1 - cos((number * PI) / 2);
}
void updateLights() {
for (int i = 0; i < lights.size(); i++) {
Light currentLight = lights.get(i);
if (currentLight.update() == false) {
sources.get(currentLight.sourceNumber).remove(currentLight);
lights.remove(i);
i--;
}
}
}
void updateSources() {
for (int i = 0; i < lightSources; i++) {
int red = 0;
int green = 0;
int blue = 0;
for (int j = 0; j < sources.get(i).size(); j++) {
Light currentLight = sources.get(i).get(j);
color currentColour = currentLight.currentColour;
red += red(currentColour);
green += green(currentColour);
blue += blue(currentColour);
}
red = constrain(red, 0, 255);
green = constrain(green, 0, 255);
blue = constrain(blue, 0, 255);
dmxOutput.set(4 * i + 2, new int[]{red, green, blue, 255});
}
}
I connected Processing to Ableton using the “IAC Driver” in Mac’s Audio MIDI Setup. I had difficulties making Ableton react to messages received by Processing. I knew it was working because the “MIDI Track In Indicator” at the top right of Ableton was flashing showing it received. I had to restart my computer for it work. I think this is an Ableton issue.
In Ableton, I simply set up a couple of instruments with it receiving midi from “Virtual MIDI”, referenced in the code, this is what I labelled the IAC Driver. It worked effectively!
Next to explore is adding another light and seeing if the system I made in mind for multiple lights will work. I am not sure how addressing works with multiple lights but we’ll see.
DMX Pro + Processing + Ableton
I borrowed another DMX light that can pan around and rotate upwards. This is quite powerful and it seems magical for your code to move it! Though, a problem with this light is that I cannot do custom RGB colours, they are set to discrete options. I experimented with it and connected it to VCV Rack (I tried Ableton but it wasn’t having it, I figured VCV Rack is just as good for quick tests!).
import dmxP512.*;
import processing.serial.*;
import themidibus.*;
DmxP512 dmxOutput;
MidiBus bus;
String dmxPort = "/dev/tty.usbserial-EN268160";
int dmxBaudrate = 115000;
int time = 500;
void setup() {
size(100, 100);
noiseDetail(3, 0.5);
MidiBus.list();
bus = new MidiBus(new java.lang.Object(), -1, "Virtual MIDI");
dmxOutput = new DmxP512(this, 128, false);
dmxOutput.setupDmxPro(dmxPort, dmxBaudrate);
dmxOutput.set(7, 0); // close shutter
dmxOutput.set(8, 0); // set dimmer 0
dmxOutput.set(1, 0); // set rotation
dmxOutput.set(2, 0); // set inclination
dmxOutput.set(5, 0); // set speed
dmxOutput.set(9, 10);
dmxOutput.set(9, 99);
dmxOutput.set(10, 191);
dmxOutput.set(12,0);
dmxOutput.set(14, 15);
dmxOutput.set(6, 32);
frameRate(60);
}
float rotateValue = 0;
void draw() {
float noise1 = noise(millis() * 0.001);
float noise2 = noise(millis() * 0.001, 100);
int cc1 = floor(map(noise1, 0, 1, 0, 127));
int cc2 = floor(map(noise2, 0, 1, 0, 127));
rotateValue += pow(noise2, 4) * QUARTER_PI * 0.5;
bus.sendControllerChange(2, 1, cc2);
bus.sendControllerChange(2, 2, cc2);
dmxOutput.set(14, floor(map(noise2, 0, 1, 0, 239))); // prism
if (noise2 < 0.5) {
dmxOutput.set(14, 0);
dmxOutput.set(12, 127);
} else {
dmxOutput.set(14, floor(map(noise2, 0.5, 1, 16, 239))); // prism
dmxOutput.set(12, 0);
}
dmxOutput.set(8, floor(map(noise2, 0, 1, 0, 255))); // brightness
dmxOutput.set(10, floor(map(noise1, 0, 1, 128, 255))); // gobo rotate
dmxOutput.set(1, int(sin(frameCount / float(time) * TWO_PI) * 85 + 85)); // rotation
dmxOutput.set(2, int(cos(frameCount / float(time) * TWO_PI) * 20 + 127)); // inclination
dmxOutput.set(7, 8); // open shutter
}
The DMX Pro has a lot of options that can be addressed, such as rotation, inclination, speed, brightness and numerous different gobo options. This was shown all in the instruction manual for the light.
Thoughts
I enjoyed experimenting with the lights and find it quite simple how they are controlled with Processing. During my exploration of the lights, I was also exploring into my essay on sound. This made me realise I want to focus more on sound for now. The DMX Pro isn’t suitable for what I want to achieve overall, it doesn’t offer nuance to colours. The first DMX light could be useful, but I want to carefully think about how I want to use them.
October 2024