I would like to vote for this feature too.
Achieving smooth color fades with LED fixtures and 8-bit color depth per channel is only possible by using a DMX controlled LED driver with interpolation capability. I am using several EldoLED PowerDrive DC and LinearDrive DC LED drivers, which provide very smooth fades thanks to interpolation. Recently I bought some less expensive EldoLED EcoDrive 45D drivers, which to my surprise lack interpolation. They do support 16-bit resolution though.
I have written a 16-bit colour fader which works quite well. There is a tiny bit of flickering sometimes but the fading is much smoother than the 8-bit fader.
In my opinion there is no need to increase the precision of the parameters that control the fader. I would be happy to still use 8-bit values as input for the resulting intensity levels of the channels at the end of the fade. The problem is with the steps between consecutive frames, which are too coarse.
Here is my script:
<?php
/**
* Created by PhpStorm.
* User: femme
* Date: 01/06/15
* Time: 19:08
*/
/** Provides a dmx fader with deep colour depth and exponential fade curve using two 8-bit dmx channels per colour
*/
class DmxDeepColorFader
{
private $frameRate = 40; // Number of dmx frames per second
/** Converts 24-bit true colour integer to 8-bit rgb channel values
* @param int $value: 24-bit colour value
* @return array|bool: array containing red, green and blue values, false if invalid value given
*/
public function getRgbValuesFromInt($value)
{
$rgb = false;
if (is_numeric($value))
{
$red = round($value / 256 / 256 % 256);
$green = round($value / 256 % 256);
$blue = round($value % 256);
$rgb = array('red' => $red, 'green' => $green, 'blue' => $blue);
}
return $rgb;
}
/** Converts 8-bit rgb channel values to 24-bit true colour integer
* @param int $red: 8-bit value for red channel
* @param int $green: 8-bit value for green channel
* @param int $blue : 8-bit value for blue channel
* @return int
*/
public function getIntValueFromRgb($red, $green, $blue)
{
return ($red * 256 * 256) + ($green * 256) + $blue;
}
/** Performs a dmx fade with deep colour depth using two 8-bit channels per colour
* @param int $objectId: id of IP Symcon dmx instance
* @param int $colourStart: 24-bit integer for colour at the start of the fade sequence
* @param int $colourEnd: 24-bit integer for colour at the end of the fade sequence
* @param float $duration: duration of fade in seconds
*/
public function fadeRgb($objectId, $colourStart, $colourEnd, $duration)
{
// Calculate 8-bit rgb channel values
$rgbStart = $this->getRgbValuesFromInt($colourStart);
$rgbEnd = $this->getRgbValuesFromInt($colourEnd);
// Calculate 16-bit rgb channel values
$rgbStartDeepColour = array('red' => $rgbStart['red'] * 256,
'green' => $rgbStart['green'] * 256,
'blue' => $rgbStart['blue'] * 256);
$rgbEndDeepColour = array('red' => $rgbEnd['red'] * 256,
'green' => $rgbEnd['green'] * 256,
'blue' => $rgbEnd['blue'] * 256);
$rgbDiffDeepColour = array('red' => $rgbEndDeepColour['red'] - $rgbStartDeepColour['red'],
'green' => $rgbEndDeepColour['green'] - $rgbStartDeepColour['green'],
'blue' => $rgbEndDeepColour['blue'] - $rgbStartDeepColour['blue']);
// Calculate frame duration in milliseconds
$frameDuration = 1000 / $this->frameRate;
$frameCount = $duration * $this->frameRate;
for ($frameNumber = 1; $frameNumber <= $frameCount; $frameNumber++)
{
$red = $this->getFrameValue($frameNumber, $frameCount, $rgbStartDeepColour['red'], $rgbDiffDeepColour['red'], true);
$green = $this->getFrameValue($frameNumber, $frameCount, $rgbStartDeepColour['green'], $rgbDiffDeepColour['green'], true);
$blue = $this->getFrameValue($frameNumber, $frameCount, $rgbStartDeepColour['blue'], $rgbDiffDeepColour['blue'], true);
$redSplit = $this->getDmxChannelValues($red);
$greenSplit = $this->getDmxChannelValues($green);
$blueSplit = $this->getDmxChannelValues($blue);
DMX_SetChannel($objectId, 1, $redSplit['coarse']);
DMX_SetChannel($objectId, 2, $redSplit['fine']);
DMX_SetChannel($objectId, 3, $greenSplit['coarse']);
DMX_SetChannel($objectId, 4, $greenSplit['fine']);
DMX_SetChannel($objectId, 5, $blueSplit['coarse']);
DMX_SetChannel($objectId, 6, $blueSplit['fine']);
IPS_Sleep($frameDuration);
}
}
/** Calculates channel value for specific frame in the fade sequence
* @param int $frameNumber: number of the frame in the fade sequence for which colour must be calculated
* @param int $frameCount: total number of frames in the fade sequence
* @param int $fadeStartValue: value of channel at the start of the fade sequence
* @param int $fadeEndDifference: difference between value of channel at the start and end of the fade sequence
* @param bool $exponentialCurve: use exponential fade curve if set to true, use linear curve if false
* @return int
*/
private function getFrameValue($frameNumber, $frameCount, $fadeStartValue, $fadeEndDifference, $exponentialCurve = true)
{
$valueLinear = $fadeStartValue + ($fadeEndDifference / $frameCount * $frameNumber);
return $exponentialCurve ? $this->getValueExponential($valueLinear) : round($valueLinear);
}
/** Converts 16-bit channel value for linear intensity curve to equivalent value for exponential intensity curve
* @param int $valueLinear: 16-bit linear intensity value
* @return int
*/
private function getValueExponential($valueLinear)
{
return round(65536 / pow(65536, 1.5) * pow($valueLinear, 1.5));
}
/** Returns 8-bit coarse and fine channel values for a 16-bit channel value
* @param int $value: 16-bit channel value
* @return array: array containing 8-bit values for coarse and fine channels
*/
private function getDmxChannelValues($value)
{
$coarseChannelValue = floor($value / 256);
$fineChannelValue = $value - ($coarseChannelValue * 256);
return array( 'coarse' => $coarseChannelValue,
'fine' => $fineChannelValue);
}
}
Then do something like this:
$dmxFader = new DmxDeepColorFader();
$objectId = 19150 /*[Zones\Facilitair\Schakelruimte\Dmx controllers\DMX11 Gastenverblijf slaapkamer beganegrond trekbalkspots]*/;
$valueStart = $dmxFader->getIntValueFromRgb(255, 0, 128);
$valueEnd = $dmxFader->getIntValueFromRgb(64, 0, 128);
$dmxFader->fadeRgb($objectId, $valueStart, $valueEnd, 30);
$valueStart = $dmxFader->getIntValueFromRgb(64, 0, 128);
$valueEnd = $dmxFader->getIntValueFromRgb(255, 64, 0);
$dmxFader->fadeRgb($objectId, $valueStart, $valueEnd, 30);
$valueStart = $dmxFader->getIntValueFromRgb(255, 64, 0);
$valueEnd = $dmxFader->getIntValueFromRgb(255, 0, 128);
$dmxFader->fadeRgb($objectId, $valueStart, $valueEnd, 30);
The fader doesn’t run asynchronously, you would have to call it in a seperate script using IPS_RunScriptEx() if you want to fade multiple fixtures at the same time.