[Flamecaster - Fixture Mode] WIP Framework to control Pixelblaze with DMX

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:

  1. 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.

  2. 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 ?

  3. 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)
  }
}

A couple of ideas:

  • To detect if DMX is active, initialize your channels to values that DMX can’t send, like -1; Then, if sum of the channels is negative, you know that no DMX data has been received yet.

  • The simple way to tell if variables have been changed between frames is just to keep a duplicate copy:

var lastv1 = 0;
export var v1 = 0
.
.
.
if (v1 != lastv1) {
  // do stuff with new value
  lastv1 = v1
}
else {
  // value didn't change
}

You could do this only for important channels, or since there’s not a huge amount of data, for everything. It’s not the most elegant looking approach, but it is very reliable.

I may still add an “only send data when it changes” option to Flamecaster. It’ll reduce network bandwidth when used with DMX sources that send constantly. But it will only partially solve your problem, because if any channel in a universe changes, that whole universe will be sent because of the way Art-Net works.