I have been playing for a while with Flamecaster’s fixture mode that allows to control a Pixelblaze with DMX.
It works quite well, and the possibilities are massive. I’m just scratching the surface but I have a LOT of ideas.
You can see below a DMX spot (connectedby an Artnet to DMX box) on the mountain synced in color with the ring driven by a Pixelblaze. Nothing fancy so far.
To make it easier to work with, I’m trying to create a framework I could copy in any pattern I have (or will) develop-ed that would allow control of a few variables directly with the DMX channels, instead of the usual UI sliders. The goal is to fully control a Pixelblaze from an Artnet output without having to connect to the UI.
I’m also trying to standardize as much as possible this framework to make it easy to work with, and as light / customizable as possible to minimize impact on actual pattern calculations.
So far I’m grabbing RGB channels as well as a dimmer successfully (with conversion of the RGB to HSV to make it easier to use). I think I won’t have much trouble to add more channels as “variables”.
My main issues are following:
-
How can I detect I’m actually in DMX mode or not ? I was thinking if all channels are at zero, all DMX calculations and calls are “not done” to save CPU and the pattern eventually runs in “standalone” like a normal pattern, for example with rotating colors, or with classic UI control. At the moment I just check if all my channels are at zero, but there is a delay at pattern start to get the channels (avg. 1 sec) which means it always starts “without DMX”… Not ideal if I want to change patterns like below.
-
How to change properly a pattern through DMX input ? I had the idea to select any pattern based on the channel[4] value (for example 0 = no change, 1 = pattern 1, 2 = pattern 2,…, 254 = previous pattern, 255 = next pattern), then only confirm the change if channel[5] is put to 255. The issue is that if it stays at 255, it’s constantly changing pattern, so I tried to create a code that requires it to be reset to 0 before registering a new “selection”, but it does not work (probably because as in 1. it seems the DMX channels are seen as zero when the pattern starts, even if Flamecaster is sending something). Maybe there’s a simpler way ?
-
Is it useful to detect if a DMX channel has been changed ? Like this we could avoid calculate HSV values before each frame for example. I’m not sure how it conflicts if DMX frames are dropped due to unstable connection ?
Once this framework is working fine, I plan to have channels sending:
- Pattern selection
- Master Dimmer
- RGB + Dedicated dimmer + Speed (BPM) in a way we can send several sets for each “segment” so the pattern can interpret it as “layers” allowing to blend effects in one pattern
As well as a sound/movement framework on top to enable sound and movement processing in-house as well: Flamecaster has too much latency to send sound data trough channels from the console, except BPM of course.
Thank you !
THE CODE:
// Framework by HOLOLIT
export var channels = array(12) //Number of channels
export var DMXActivated = 0
//convert RGB to HSV: output sets hDMX,sDMX,vDMX globals
function rgb2hsv(r, g, b) {
var rr, gg, bb, diff
r = clamp(r, 0, 1)
g = clamp(g, 0, 1)
b = clamp(b, 0, 1)
vDMX = max(r, max(g, b))
diff = vDMX - min(r, min(g, b))
if (diff == 0) {
hDMX = sDMX = 0
} else {
sDMX = diff / vDMX
rr = (vDMX - r) / 6 / diff
gg = (vDMX - g) / 6 / diff
bb = (vDMX - b) / 6 / diff
if (r == vDMX) {
hDMX = bb - gg
} else if (g == vDMX) {
hDMX = (1 / 3) + rr - bb
} else if (b == vDMX) {
hDMX = (2 / 3) + gg - rr
}
if (hDMX < 0) {
hDMX += 1
} else if (hDMX > 1) {
hDMX -= 1
}
}
}
export var DMXNext = -1 //Initializes at -1 means if DMX06 (next program if = 255) needs to be reset at 0 before being taken into account
export function beforeRender(delta) {
/* Gettng DMX Channels */ {
if (arraySum(channels)==0){
// Execute the pattern without DMX (standalone mode)
DMXActivated = 0
} else {
DMXActivated = 1
DMX01 = channels[0] / 255 // Dimmer (Segment 1)
DMX02 = channels[1] / 255 // Red (Segment 1)
DMX03 = channels[2] / 255 // Green (Segment 1)
DMX04 = channels[3] / 255 // Blue (Segment 1)
DMX05 = channels[4] // Pattern pre-selection (255 = next pattern)
DMX06 = channels[5] // Pattern confirm (selects if reset then put to 255)
DMX07 = channels[6] / 255 // Timer 3
DMX08 = channels[7] / 255
DMX09 = channels[8] / 255
DMX10 = channels[9] / 255
DMX11 = channels[10] / 255
DMX12 = channels[11] / 255 }
rgb2hsv(DMX02, DMX03, DMX04) //Calculates HSV based on RGB DMX channels
vDMX = vDMX * DMX01 //Adds dimmer on top
//Detects if DMX6 has been reset before activating it
if (DMX06 == 0){
DMXNext = 1
}
if (DMX06 == 255 && DMXNext == 1){
//New input to change program
if (DMX05 == 255) { sequencerNext() }
//We can imagine other values of DMX05 could select a specific pattern ?
}
}
}
export function render(index) {
if (DMXActivated == 0){
hsv(0,0,.2)
} else {
hsv(hDMX,sDMX,vDMX)
}
}