Fixture Definitions
Fixture definitions tell Afterglow what capabilities a given piece of lighting hardware has, and how to control it to get the effects that are being requested.
Overview
There are a vast number of fixture types out there, and at this early stage almost none of them are built in to Afterglow, so you will probably need to create your own. You can study the existing fixture definitions for examples of how it is done. You can also ask for help on the wiki.
When you first embark on the project of creating a fixture definition, it might seem overwhelming. This page is long, and includes a great deal of complicated detail. But don’t despair! First, remember that most fixtures only do a subset of the kinds of things that the fixture definition mechanism needs to handle, so you do not need to learn and understand all of it at once. And even more helpful to beginners, realize that you do not need to finish your fixture definition before you can start using and testing it. Your fixture may be capable of many things, but start out by defining just a couple of channels that will make it at least light up, and see if you can get those working in a show. Once they are, you can already use the fixture at least at that level. And that success can be a foundation for digging deeper into other types of channels, which you can add to your definition one at a time, building on what you learn as you go along. Also, as of version 0.1.3, Afterglow can read fixture definitions from the QLC+ lighting controller and use those to create a starting point for you. Since there are far more fixtures already defined for QLC+, that can be a huge help. |
The namespace
afterglow.fixtures
has definitions for very basic one-channel generic dimmers and
switches. Looking at the source for those can illustrate the most
basic structure of a fixture definition. It also contains some helper
functions Afterglow uses in processing fixture definitions.
The namespace
afterglow.fixtures.american-dj
contains definitions for fixtures made by American DJ. Currently, only
the Hypnotic RGB laser is present.
The namespace
afterglow.fixtures.blizzard
is the most complete so far, mostly because the author lives close to
Blizzard and mostly owns fixures made by them. It includes definitions
for a full-featured moving head spot (the Torrent F3), a moving head
color-mixing LED fixture (the Blade RGBW), an LED five-color Par (the
Puck Fab5), an eight-head RGB system (the Weather System), and an RGBW
moonflower effect (the Snowball). These might be useful examples for
fixtures you want to create.
The namespace
afterglow.fixtures.chauvet
is for fixtures made by Chauvet.
Structure of a Fixture Definition
Once created, a fixture definition is simply a Clojure map with keys and values that tell Afterglow how to control it. The fixture definition functions linked to above simply create and return these maps.
Fixtures may have multiple "personalities" or modes which change the
number and meaning of the control channels they use, and the features
that are available. For such fixtures, the mode is generally given as
an argument to the fixture definition function, and tells it what
version of the map to return. For convenience, the function may let
you call it with no argument, and assume a default mode. Its
documentation should reflect this, see for example the
blade-rgbw
documentation.
When you are learning how to write fixture definitions, it can be
helpful to compare the fixture definition functions, which call helper
functions described on this page, with the actual maps that they
return. This can be facilitated by using clojure.pprint/pprint
to
pretty-print the map that you get when calling the function. For
example:
(clojure.pprint/pprint (afterglow.fixtures.blizzard/snowball))
{:name "Blizzard Snowball",
:channels
[{:offset 1,
:type :dimmer,
:functions
[{:start 0,
:end 255,
:range :variable,
:type :dimmer,
:label "Dimmer"}]}
{:offset 2,
:type :color,
:functions
[{:start 0, :end 255, :range :variable, :type :red, :label "Red"}],
:color :red}
; [...many channels omitted for brevity...]
{:offset 9,
:type :control,
:functions
[{:start 0,
:range :fixed,
:type :no-function,
:label "No function",
:end 127}
{:range :variable,
:label "Sound-active",
:type :sound-active,
:var-label "Sensitivity",
:start 128,
:end 255}]}]}
; -> nil
Even though most of the channels were cut out to shorten that example,
it is still pretty long. Still, it gives a sense of the shape of a
fixture definition. You may have noticed that there were only two
top-level keys in the returned map, :name
and :channels
. Those
are the only two that need to be there for a simple fixture. And
almost all of the information Afterglow needs is found in the
:channels
list, so that is where you will spend most of your work in
creating the fixture definition.
If you had already looked at the source for
snowball
(which you can get to by clicking the view source
button at the
bottom of all the API documentation entries), you might have noticed
that the source is a lot shorter than the resulting map. That’s
because it can take advantage of a bunch of helper functions described
on this page to help with the tedious and repetetive parts of
constructing the map. And when you patch a fixture into a show using
afterglow.show/patch-fixture!
the map gets much bigger again, as Afterglow annotates it with
information you provided during the patching process, assigning the
actual universes and DMX channels for each logical channel in the
fixture definition, and figuring out the location in space and aiming
direction, potentially of several heads of a multi-head fixture.
So, let’s look at the fixture definition map contents in detail.
Key | Purpose |
---|---|
:name |
A string which identifies the manufacturer and model of fixture. |
:channels |
A list of channel specifications which tell Afterglow about the DMX channels that the fixture responds to, and how to make it do different things. This is the meat of the fixture definition, and is described in detail below. |
:mode |
If present, identifies the fixture mode in which this definition map
was created. As desrcibed above, some fixtures can be configured to
have different “personalities” which use a different
number of DMX channels and provide a different set of features. Their
fixture definition functions will use a |
:heads |
If a fixture has multiple independent heads, which can be controlled
individually, the channels which control the heads are grouped into a
list under this key. Each entry in the list is a map which explains a
single head. It will contain its own |
:pan-center |
If this fixture is a moving head capable of pan movements, this entry
tells afterglow the DMX value to send the fixture to pan it directly
at the audience when the fixture is hung at its standard orientation.
(The documentation you create for your fixture definition needs to
explain what this default orientation is, so that people patching
your fixture can figure out the proper angle information to tell
Afterglow if they hung it in a different orientation, as explained in
Show Space.) The Many fixtures can pan more than once around a full circle, so you may have a choice of values to supply here, all of which pan the fixture directly towards the audience in your default hanging orientation. If so, pick one towards the middle of the DMX range, giving Afterglow room to maneuver without having to flip to the opposite end of the pan range regardless of how the fixture has been hung. If the fixture cannot pan far enough to aim directly at the audience when it is hung in its default orientation, you may be better off choosing a different default hanging orientation. But if you do not want to do that, you can set this to the closest value outside the legal DMX range which would cause the fixture to pan that far if it were legal and possible, and Afterglow will still be able to figure out and use the legal movements that the fixture is capable of. |
:pan-half-circle |
If this fixture is a moving head capable of pan movements, this entry tells Afterglow the amount it needs to add to the DMX value sent on the fixture’s Pan channel to pan it halfway around a circle in a counterclockwise direction. Afterglow uses this to figure out how to aim the head exactly where you want it. If your fixture is not capable of panning that far, this value may be larger than a legal DMX value. That is fine, Afterglow will figure that out. Simply always give it the value which, when added to some legal Pan channel value, would cause the fixture to rotate counterclockwise halfway around a circle if it could rotate that far. (This number could be negative if the fixture turns clockwise when the pan value is increased in its default hanging orientation.) The Show Space page explains how to figure out which rotations are clockwise or counterclockwise with respect to different axes. Pan motions are rotations around the fixture Y axis. |
:tilt-center |
If this fixture is a moving head capable of tilt movements, this
entry tells afterglow the DMX value to send the fixture to tilt it
directly at the audience when the fixture is hung at its standard
orientation. (The documentation you create for your fixture
definition needs to explain what this default orientation is, so that
people patching your fixture can figure out the proper angle
information to tell Afterglow if they hung it in a different
orientation, as explained in Show Space.) The
Some fixtures can tilt more than once around a full circle, so you may have a choice of values to supply here, all of which tilt the fixture directly towards the audience in your default hanging orientation. If so, pick one towards the middle of the DMX range, giving Afterglow room to maneuver without having to flip to the opposite end of the tilt range regardless of how the fixture has been hung. If the fixture cannot tilt far enough to aim directly at the audience when it is hung in its default orientation, you may be better off choosing a different default hanging orientation. But if you do not want to do that, you can set this to the closest value outside the legal DMX range which would cause the fixture to tilt that far if it were legal and possible, and Afterglow will still be able to figure out and use the legal movements that the fixture is capable of. |
:tilt-half-circle |
If this fixture is a moving head capable of tilt movements, this entry tells Afterglow the amount it needs to add to the DMX value sent on the fixture’s Tilt channel to tilt it halfway around a circle in a counterclockwise direction. Afterglow uses this to figure out how to aim the head exactly where you want it. If your fixture is not capable of tilting that far, this value may be larger than a legal DMX value. That is fine, Afterglow will figure that out. Simply always give it the value which, when added to some legal Tilt channel value, would cause the fixture to rotate counterclockwise halfway around a circle if it could rotate that far. (This number could be negative if the fixture turns clockwise when the tilt value is increased in its default hanging orientation.) The Show Space page explains how to figure out which rotations are clockwise or counterclockwise with respect to different axes. Tilt motions are rotations around the fixture X axis. |
Channel Specifications
The :channels
entry for a fixture or head definition map tells
Afterglow the control channels that can be used to make that fixture
or head do things. It is a list of maps, each of which describes the
nature and capabilities of a single channel that the fixture or head
responds to.
Although there is a lot of detail in this table, you don’t necessarily need to understand it all to create fixture definitions, because Afterglow provides channel creation functions to create these maps for you. |
Each channel specification map has the following content:
Key | Purpose |
---|---|
:offset |
The number that identifies the channel. Each
fixture listens to one or more channels, and is itself configured to
a partcular DMX channel number (DMX channels range from 1 to 512).
That configuration defines the first channel the fixture
listens to. The Although it might seem more natural (at least to a programmer) to
start the offset with The offsets for all the channel specifications in a fixture definition should form a continuous series of integers starting from 1 and going up to the number of channels the fixture supports. It is an error if more than one channel specification in the fixture definition uses the same offset value, and if there are any gaps it probably means that you have missed a channel specification (except for multi-byte channels, as described in the next row). You don’t need to define the channels in the same order as their offsets in your fixture definition, although that is a reasonable practice, making it easier to match them up with the manual. |
:fine-offset |
There is one circumstance in which there will be gaps in the
|
:type |
Tells afterglow the kind of channel this is. Special values include
|
:color |
When the channel |
:hue |
When the channel If you don’t want Afterglow to mix colors using this channel, leave
out the |
:functions |
A list of Function Specifications which identify ranges of DMX values that can be sent to the channel, and which perform particular functions. Fixture manufacturers often use a single DMX channel to achieve many different kinds of effects, in order to not use up the DMX address space, especially when it would not make sense to try to activate two or more of the functions at the same time. Afterglow effects and cues can work in terms of these function definitions, and it often makes sense to do so even for channels which implement only a single function, so you don’t need to worry about how a function is implemented when designing your effect or cue. Because of that, the channel creation functions add a function map even when you are creating a single-function channel. |
:inverted-from |
Head Specifications
As described above, the :heads
entry in a fixture definition map is
a list that describes each individually controllable head within that
fixture. It may be a separate moving head, or it may just be an
individually-addressable pixel. If a fixture has only one
light-emitting head, it does not need a head specification list at
all; everthing Afterglow needs to know about it will be contained in
the main fixture definition. But if there is more than one place on
the fixture that can be controlled independently, you will want to
organize them into heads, and tell Afterglow their spatial
relationships as well as which channels control which head, using a
head specifications list. Each element of the list is a map with the
following content:
Key | Purpose |
---|---|
:channels |
A list of channel specifications which tell Afterglow about the DMX channels that this individual head responds to. These have exactly the same structure as the channel specifications for the main fixture, as described above. A channel can only be listed in one place or the other. If it affects the entire fixture, it should be in the main list; if it affects only a single head, it should be in that head’s list. |
:x |
The offset along the fixture X axis, in meters, from the geometric center of the fixture (the point at which Afterglow is told the fixture is located when patching the fixture) and the geometric center of this head. If this head is centered along the fixture X axis, you can omit this value or you can supply it with a value of 0.0. The Show Space page illustrates the axes and links to a function you can use for converting inches to meters. |
:y |
The offset along the fixture Y axis, in meters, from the geometric center of the fixture (the point at which Afterglow is told the fixture is located when patching the fixture) and the geometric center of this head. If this head is centered along the fixture Y axis, you can omit this value or you can supply it with a value of 0.0. The Show Space page illustrates the axes and links to a function you can use for converting inches to meters. |
:z |
The offset along the fixture Z axis, in meters, from the geometric center of the fixture (the point at which Afterglow is told the fixture is located when patching the fixture) and the geometric center of this head. If this head is centered along the fixture X axis, you can omit this value or you can supply it with a value of 0.0. The Show Space page illustrates the axes and links to a function you can use for converting inches to meters. |
:x-rotation |
If this head aims in a different direction than the fixture as a whole, this value tells afterglow the angle in radians it is rotated around the X axis. The Show Space page illustrates the axes, explains how to calculate the sign of a rotation, and links to a function you can use for converting degrees to radians. |
:y-rotation |
If this head aims in a different direction than the fixture as a whole, this value tells afterglow the angle in radians it is rotated around the Y axis. The Show Space page illustrates the axes, explains how to calculate the sign of a rotation, and links to a function you can use for converting degrees to radians. |
:z-rotation |
If this head aims in a different direction than the fixture as a whole, this value tells afterglow the angle in radians it is rotated around the Z axis. The Show Space page illustrates the axes, explains how to calculate the sign of a rotation, and links to a function you can use for converting degrees to radians. |
Function Specifications
Function specifications allow a single channel to be broken up into a series of value ranges which accomplish different purposes. As noted above, fixture manufacturers often do this so that they can provide a lot of functionality without taking up too much of the DMX address space. And since fixtures often have functions which cannot be activated at the same time, such as selecting a particular gobo on a gobo wheel, it makes great sense.
The :functions
entry in a channel specification map lists all the
functions that a given channel offers. In order to work well with
Function Effects and
Function Cues it is best to
provide a function list even for channels which only perform a single
function. A function list is a list of maps, each of which identifies
a range of values that do something when the channel is set to a value
within that range. Each map has the following content:
Key | Purpose |
---|---|
:start |
The beginning of the function range: the lowest DMX value which
activates this function on the channel. Must be a legal DMX value,
from |
:end |
The end of the function range: the highest DMX value which activates
this function on the channel. Must be a legal DMX value, from |
:type |
A keyword which identifies the nature of the function. This is how Function Effects and Function Cues will find the effect, so it is important to be consistent when assigning function types. The list of standard function types is a good starting point. If you feel there is a common kind of function which should be added to that list, please open an issue requesting it. |
:range |
Tells Afterglow what kind of a function range this is. Some functions
are simply either off or on, and even if multiple DMX values exist
within the function range, the result of using any of them is no
different from using another. Such functions are identified by a
|
:label |
Specifies a label that should be used when creating a user interface
that refers to this function. Function
Cues will use this as the label text in the grid cell they create
in the web interface. If omitted, a capitalzed
version of the value of the |
:var-label |
Specifies a label that should be used when creating a user interface
for adjusting the value associated with this function (so it makes
sense to set this only when |
:scale-fn |
A function that will be called to scale the function value being
requested by an effect. For functions whose If there is a reason to tweak the values on the way in, you can store
a function at this key in the function specification, and Afterglow
will call the function with the percentage value the effect requested,
and expect the function to return a modified percentage value to use
to actually pick the DMX value to send. A good example of a reason to
do this is with the |
Channel Creation Functions
The
afterglow.channels
namespace provides a number of functions to help you create channel
specifications in your fixture definitions. You will see these used
all over the place in the fixture definitions which ship with
Afterglow; here is an introduction to how they work.
Color Channels
afterglow.channels/color
returns a channel specification for a channel that controls an
individual color intensity (such as with an RGB LED fixture). Its two
mandatory arguments are the channel offset
(the channel number
reported in the fixture manual, assuming they are numbered starting
with 1
as described above), and the color
, a
keyword naming the color. The standard colors :red
, :green
,
:blue
, and :white
will automatically participate in Afterglow’s
color mixing for Color Effects. If your
fixture has other color channels, and you would like them to
participate in color mixing as well, pass the hue value of the color
channel with the optional keyword argument :hue
. (See the discussion
above for ways to determine the hue value of your color
channel.)
If your fixture supports two-byte color values for more precise color
mixing, use the most-significant byte as the offset
value, and pass
the offset of least-significant byte using the optional keyword
argument :fine-offset
.
If you want to use a label which differs from the name of the color
keyword in the user interface when
adjusting
Function Cues (for example, if the
keyword is hyphenated, and you want the label to use a space), specify
your desired label with the optional keyword argument
:function-label
.
Dimmer Channels
afterglow.channels/dimmer
returns a specification for a channel that controls the dimmer of a
fixture or head. It always takes at least one argument, the channel
offset
(as described above). If the fixture uses
two-byte values for more precise dimmer control, use the
most-significant byte as the offset
value, and pass the offset of
the least-significant byte using the optional keyword argument
:fine-offset
.
Normal dimmers are dark at zero, and get brighter as the channel value
increases, to a maximum brightness at 255. However, some fixtures have
inverted dimmers. If that is the case for the fixture you are
defining, pass the DMX value at which the inversion takes place with
:inverted-from
. For example, fixtures which are brightest at zero
and darken as the value approaches 255 would be specified as
:inverted-from 0
, while fixtures which are dark at zero, jump to
maximum brightness at 1, then dim as the value grows towards 255 would
be specified as :inverted-from 1
.
Focus Channels
afterglow.channels/focus
returns a specification for a channel that controls the focal plane of
a fixture or head, usually a moving head spot which can project gobo
(template) images. It always takes at least one argument, the channel
offset
(as described above). If the fixture uses
two-byte values for more precise focus control, pass the offset of
the channel that controls the most-significant byte as the offset
argument, and pass the offset of the channel that controls the
least-significant byte as the second argument, fine-offset
.
Frost Channels
afterglow.channels/frost
returns a specification for a channel that controls the frost effect
of a fixture or head, softening the beam of light it emits. It always
takes at least one argument, the channel offset
(as described
above). If the fixture uses two-byte values for
more precise focus control, pass the offset of the channel that
controls the most-significant byte as the offset
argument, and pass
the offset of the channel that controls the least-significant byte as
the second argument, fine-offset
.
Iris Channels
afterglow.channels/iris
returns a specification for a channel that controls the iris
(aperture) of a fixture or head, widening or narrowing the beam of
light it emits. It always takes at least one argument, the channel
offset
(as described above). If the fixture uses
two-byte values for more precise iris control, pass the offset of the
channel that controls the most-significant byte as the offset
argument, and pass the offset of the channel that controls the
least-significant byte as the second argument, fine-offset
.
Pan Channels
afterglow.channels/pan
returns a specification for a channel that controls the pan (rotation
around the Y axis) of a fixture or head. It always takes at least one
argument, the channel offset
(as described
above). If the fixture uses two-byte values for
more precise pan control, pass the offset of the channel that controls
the most-significant byte as the offset
argument, and pass the
offset of the channel that controls the least-significant byte as the
second argument, fine-offset
.
Tilt Channels
afterglow.channels/tilt
returns a specification for a channel that controls the tilt (rotation
around the X axis) of a fixture or head. It always takes at least one
argument, the channel offset
(as described
above). If the fixture uses two-byte values for
more precise tilt control, pass the offset of the channel that controls
the most-significant byte as the offset
argument, and pass the
offset of the channel that controls the least-significant byte as the
second argument, fine-offset
.
Zoom Channels
afterglow.channels/zoom
returns a specification for a channel that controls the zoom of a
fixture or head, changing how much the beam spreads as it travels from
the fixture. It always takes at least one argument, the channel
offset
(as described above). If the fixture uses
two-byte values for more precise zoom control, pass the offset of the
channel that controls the most-significant byte as the offset
argument, and pass the offset of the channel that controls the
least-significant byte as the second argument, fine-offset
.
Function Channels
afterglow.channels/functions
returns a specification for a channel that implements a list of
different functions for different ranges of DMX values. Its first two arguments are chan-type
, the keyword which identifies the type of the channel (please see the list of
standard function types below and try to
reuse one if it is appropriate, or at least create your keyword in a
way that follows their conventions), and the channel offset
(as
described above).
These are followed by a variable number of function range
specifications, which take the form of a number (which identifies the
starting DMX value for the function range) followed by the function
specification itself. This can either be a
function specification map as described
above (without the :start
and :end
keys, which will be figured out
from the starting ranges supplied to this function), or in many simple
cases you can use the shorthand of passing a keyword, which will be
expanded into a variable-range function with the a type of the keyword
you supplied, or a string, which will be expanded into a fixed-range
function with a type of a keyword made from the string you supplied.
If you pass a nil
after the number, it tells Afterglow to not create
a function at all for that part of the range.
The range specifications need to be in order of increasing starting values, and the ending values for each will be figured out by context.
The best way to understand this is to look at an example, like the specification for channel 9 of the Torrent F3:
(chan/functions :shutter 9 0 "shutter-closed" 32 "shutter-open"
64 {:type :strobe
:scale-fn (partial function-value-scaler 14 100)
:label "Strobe (1.4Hz->10Hz)"
:range :variable}
96 "shutter-open-2" 128 :pulse-strobe 160 "shutter-open-3"
192 :random-strobe
224 "shutter-open-4")
This sets up a channel of type :shutter
with offset 9
. The
remaining arguments are pairs which define function ranges.
The first two pairs use the String shortcut to set up a fixed-ranged
function of type :shutter-closed
from 0
-31
, and another fixed-range
function of type :shutter-open
from 32
-63
.
Then there is a more complex function specification, using the map
approach to set up a variable-range function of type :strobe
from
64
-95
, assign it a function label of Strobe (1.4Hz→10Hz)
, and
assign it a scaling function, which maps the values from 14 to 100
onto tenth-Hertz frequency values, to try to normalize the strobe
speed of the fixture, since :strobe
is a very common function, and
it is nice to try to get different models of fixtures to react
similarly when a given value for that function is assigned to them.
The discussion of the
:strobe
standard function below provides another example of this approach, and explains it further.
This is followed by another fixed-range function of type
:shutter-open-2
from 96
-127
set up using the String shortcut,
and a simpler variable-range function of type :pulse-strobe
from
128
-159
set up using the keyword shortcut rather than a map. That
line finishes with a fixed-range function of type :shutter-open-3
from 160
-191
created using the String shortcut. Since the
Torrent’s pulse strobe mode is not something any of the other fixtures
support, there was no need to try to use a scaling function to make it
approximate another fixture’s speed.
The last two pairs should be easily understood by now, as we have seen
their like before. The second-to-last line uses the keyword shortcut
to create a variable-range function of type :random-strobe
from
192
-223
, and the last line uses the String shortcut to create a
fixed-range function of type :shutter-open-4
from 224
to the
largest legal DMX value of 255
. Again, random strobing is a function
unique to the Torrent, so no effort was made to scale it.
The various shutter-open ranges all do the same thing, but need
to be given different names, since function names must be unique; it
is a quirk of this fixture that it has multiple ranges with the same
function. Another valid approach for handling the redundant later
ranges would have been to pass nil after the number to tell
Afterglow to not create a function for them.
|
Generic Channels
If none of the above functions match the channel you are creating, you
can use
afterglow.channels/fine-channel
to create the definition.
It always takes at least two arguments: chan-type
, a keyword
identfying the type of the channel (please see the list of
standard function types below and try to
reuse one if it is appropriate, or at least create your keyword in a
way that follows their conventions), and the channel offset
(as
described above).
If the channel uses two-byte values for more precise control, use the
most-significant byte as the offset
value, and pass the offset of
the least-significant byte using the optional keyword argument
:fine-offset
.
If for some reason the channel’s function type should differ from the
value you gave for chan-type
, you can pass a different keyword to
use when creating the function range, using the optional keyword
argument :function-type
.
If you want to use a variable label which differs from the name of the
channel’s function type keyword in the user interface when
adjusting
Function Cues (for example, if the
keyword is hyphenated, and you want the label to use a space), specify
your desired label with the optional keyword argument
:var-label
.
Function Creation Functions
There are also functions to help you create function specifications in your channel definitions.
Color Wheel Hue
afterglow.channels/color-wheel-hue
returns a function specification which ties a color wheel position to
a particular hue, so the color wheel can participate in Afterglow’s
color effects. See the
API
documentation for more details, and the
Torrent
F3 fixture definition source for an example of its use.
Standard Function Types
Function Effects and
Function Cues trigger and control
specific functions, potentially across a range of different fixture
types from different manufacturers. In order for that to work, the
Function Specifications must be created
with consistent :type
keywords. When you are creating a new fixture
definition, check to see if any of the functions that it provides are
covered by this table, and if so, use the same keywords to identify
them, so your fixture can participate with other fixtures in effects
using that function.
If your function does not fit into this list, make up a keyword that makes sense for it, following the style shown here. And also please consider (if the function type is likely to be present on other fixtures and useful to other people) opening an issue requesting that your new function type be added to this list so that when other people create definitions for similar fixtures, they can interoperate with yours.
Function Key | Description |
---|---|
:dimmer |
Controls the overall brightness of the fixture or head, independent
of any color intensity channels which might also affect it. This is
also a fundamental channel type in Afterglow, and has a category of
Dimmer Effects to work with it. Dimmer
effects can work with either fully dedicated dimmer channels (in
which case the channel itself has a |
:red :green :blue :white :amber :uv |
These identify functions (usually entire channels) which control the
intensity of a particular color, usually on LED fixtures. When you
create a channel of type |
:pan :tilt |
Rotates the fixture about its Y (in the case of |
:strobe |
Causes the fixture to flash on and off abruptly (and usually
rapidly). This is typically a variable-range function, so different
values within the function range cause the fixture to strobe at
different speeds. If possible, use a Take a look at the strobe function definitions for the existing fixtures for examples how to do this. All you need to do is measure the slowest and fastest rates at which your fixture actually strobes, as best you can, and use them like this:
In this example, the fixture’s strobe channel is at offset
|
:focus |
Adjusts the focal plane of the fixture, usually a moving-head spot with the ability to project gobos (templates). |
:frost |
Controls a frost effect, softening the beam of light. |
:iris |
Controls the iris size, widening or narrowing the beam of light. |
:zoom |
Adjusts the rate at which the beam spreads as it travels further from the fixture. |
:sound-active |
Puts the fixture in a mode where it decides what to do by listening to music in the environment, rather than being directly controlled by its DMX channels. |
Translating QLC+ Fixture Definitions
QLC+ is an established and powerful free and open-source lighting control system aimed at more traditional workflows than Afterglow. If you were not already aware of it, you should definitely take a look. And since it has been around a while, used by an increasing variety of people, it has had time to accumulate a bunch of fixture definitions for lights that you are likely to encounter or own.
Even though QLC+ does not model fixtures in as much detail as Afterglow, so their definitions are incomplete from our perspective (lacking geometry information for aim and direction cues, and explicit links between channels that pair up to control a single fixture function, among other things), Afterglow can still use them as a starting point to help you creating a fixture definition, and save a whole lot of time reading fixture manuals, and trial and error… especially when it comes to channels with a lot of functions, like gobo wheels. So when you decide to create an Afterglow fixture definition, start by looking to see if QLC+ already has one for that fixture.
You can find its current set of fixture definitions on
GitHub.
If you see one for the fixture you want, you can either click on it
and download it individually (after choosing the Raw
view for the
file in its header bar), or, if you are already using git, you can
clone the entire project to get local copies of all the fixture
definitions.
Once you have downloaded the QLC+ fixture definition file, you can invoke Afterglow from the command line, as described in the Usage section on the project page, to translate it into an Afterglow fixture definition. For example, translating the definition for the American DJ Eco UV Bar, like so:
% java -jar afterglow.jar -q American-DJ-ECO-UV-BAR-DMX.qxf
Translated fixture definition written to eco-uv-bar-dmx.clj
would result in the following Afterglow fixture definition file:
(ns afterglow.fixtures.american-dj
"Translated definition for the fixture ECO UV BAR DMX
from American DJ.
This was created by Afterglow from the QLC+ Fixture Definintion
(.qxf) file, and will almost certainly need some manual adjustment
in order to enable full Afterglow capabilities.
If you have more than one fixture definition for this manufacturer,
you can consolidate them into a single file if you like, with a
single copy of this namespace definition, since it is the same for
all fixture definitions translated by Afterglow.
Once you have completed the fixture definition, and are happy with
the way everything is being controlled by Afterglow, please consider
submitting it for inclusion with Afterglow, either as a Pull Request
at https://github.com/Deep-Symmetry/afterglow/pulls if you are
comfortable putting that together, or just on the Wiki if that's
easier for you:
https://github.com/Deep-Symmetry/afterglow/wiki/Questions#defining-fixtures
The original fixture defintition was created by Rob G.
using Q Light Controller Plus version 5.0.0 GIT.
QLC+ Fixture Type: Other"
(:require [afterglow.channels :as chan]
[afterglow.effects.channel :as chan-fx]))
(defn eco-uv-bar-dmx
"ECO UV BAR DMX.
Please flesh out this documentation if you are submitting this for
inclusion into Afterglow. See, for example, the Blizzard fixture
definitions:
http://deepsymmetry.org/afterglow/api-doc/afterglow.fixtures.blizzard.html"
[]
{:channels [(chan/color 1 :uv) ; TODO: add :hue key if you want to color mix this
(chan/fine-channel :strobing 2
:function-name "Strobing"
:var-label "Strobing (slow -> fast)")
(chan/functions :dimmer-curve 3
0 {:type :dimmer-curve-no-dimmer-curve
:label "No dimmer curve"
:range :variable}
21 {:type :dimmer-curve-dimmer-curve-1
:label "Dimmer curve 1"
:range :variable}
41 {:type :dimmer-curve-dimmer-curve-2
:label "Dimmer curve 2"
:range :variable}
61 {:type :dimmer-curve-dimmer-curve-3
:label "Dimmer curve 3"
:range :variable}
81 {:type :dimmer-curve-dimmer-curve-4
:label "Dimmer curve 4"
:range :variable}
101 {:type :dimmer-curve-delay-mode-control
:label "Delay mode control"
:range :variable})]
:name "ECO UV BAR DMX"})
Of course this is a very simple fixture, but I didn’t want to waste a ton of space on the example, and it shows the basic idea.
The new definition file will be written to the same directory as the
.qxf
file it was based on. It is not named in a way (nor placed in
the necessary directory hierarchy) that would enable it to be loaded
using a normal Clojure require
form, because it is intended to be
loaded individualy using Afterglow’s init-file mechanism, also
described in Usage, and
within
afterglow-max,
by the load-init-file
function. If you are creating definitions for
several fixtures from the same manufacturer, you are encouraged to
combine them into a single file, as described in the API documentation
at the top of the example above, using your favorite text editor. The
ns
form places the fixture definition functions in a package named
after the manufacturer, and so needs to appear only once at the top of
the file, and all the fixture definition functions themselves can be
listed after it.
Using the fixture definition from this example, once the file is
loaded, is as simple as calling
(afterglow.fixtures.american-dj/eco-uv-bar-dmx)
within
show/patch-fixture!
.
What’s Missing from Translated Fixture Definitions
As mentioned in the introduction, there are some things that Afterglow simply cannot guess from translated fixture definitions. Even in simple cases like this example, you will find things that you can make better by hand-editing the results based on your understanding of the fixture, after reading its manual or working with it for a bit.
Function Specifications
First off, all fixture function ranges are created as :variable
,
meaning that they do slightly different things along the range of
values that activate that function, because QLC+ does not distinguish
between fixed and variable functions. In the event that the function
actually has no adjustable behavior, you will want to change :range
:variable
in the corresponding function specification entry to
:range :fixed
, so that the user interface of a function cue created
for this fixture properly reflects the fixture’s behavior. I am pretty
sure that is something that should be done for all the ranges in this
example, but I don’t have the actual fixture to test it and see.
Function specifications are explained in more depth
above.
The types and labels assigned to the function ranges are derived from
the labels in the .qxf
file, and uniqueness is enforced, but they
are probably too long in many cases (especially if you want them to be
readable in the Web or Ableton Push interfaces), and in some cases
should be adjusted to match up with the
standard types so that they can
automatically work with cues. (This is especially likely to be the
case with strobe cues, for example. Compare the translated definitions
with some that ship with Afterglow as you are starting to get a feel
for these issues.)
Channel Types
Afterglow tries to guess what kinds of channels it finds, based on their name, and aspects of their structure. For simple cases it will get it right, and save you time, but it might be wrong. This is especially important to double-check for dimmer channels, to make sure they are properly detected, since only then will they participate in Dimmer Effects and the Master chain. (And you don’t want inappropriate channels to be mapped as dimmer channels for the opposite reason.)
Dimmer Channels
In addition to the possibility that a dimmer channel might be
misidentified, as described above, some fixtures have inverted
dimmer channels, which do not get brighter as the DMX value increases.
The .qxf
file does not record this information, so you will need to
manually add it to the specification.
Color Channels
Colors are fairly well represented and identified in the QLC+ format,
and if you have a channel controlling a red, green, blue, or white
channel, chances are good that it will be properly translated. If you
have an LED fixture with other colors, like amber, UV, or beyond, and
want these other channels to participate in Afterglow’s automatic
color mixing capabilities, as noted by the TODO:
comment in the
translation example above, you will need to add a :hue
key to the
color channel definition, containing the actual hue value of the LEDs
controlled by that channel. The Chauvet SlimPar Hex IRC
definition
that ships with Afterglow contains a nice example of doing this for
its amber and UV channels, and shows how to make this extended color
mixing an optional feature when using the fixture definition.
Two-Byte Channels
DMX parameter values are integers which only range from 0-255. That is
not enough to achieve precise pan and tilt movements, and some
fixtures even want to allow more precise dimming values and color
intensities. In order to achieve that, they use more than one channel
to communicate a single parameter value. QLC+ fixture definition files
reflect this to an extent, using their Group
tags which have a
Byte
value of 0 or 1. But there is no explicit link in the .qxf
file between the channels that are controlling the same value.
Afterglow is able to figure it out in simple cases, such as where
there are two channels controlling the intensity of the color red,
using bytes 0 and 1. But if there are more than two channels serving
the same purpose, it cannot figure out the relationships, and you will
have to sort that out using the fixture’s manual. Once you do, get rid
of the channel specification for the least-significant byte in the
fixture definition, and specify that channel as the fine-channel
value for the channel specification of the most-significant byte, as
documented in the Channel Creation
Functions section.
Geometric Information
If the fixture includes a Pan or Tilt channel, you will see additional
TODO:
comments telling you that you need to add information about
how the channel actually physically rotates the fixture, in order for
Afterglow to be able to accurately calculate
Direction and
Aim effects with it. The
Structure section above
describes the :pan-center
, :pan-half-circle
, :tilt-center
, and
:tilt-half-circle
values that you will need to figure out
experimentally.
We hope to someday help automate part of this process, which will make it easier for all of us!
Similarly, if the fixture has multiple heads, you will see TODO:
entries where you need to fill in their
locations relative to the origin of the
fixture itself, so that Spatial
Parameters can work properly with them.
Don’t Panic!
Even though this sounds like a lot of things that can go wrong trying to build an Afterglow fixture definition, most of the problem areas are subtle, or relate to the more advanced capabilities of Afterglow. Chances are very good that the automatically generated fixture definition will at least enable basic control of the fixture right away. So try that, and gain some confidence, as you gradually explore the areas where it isn’t quite doing what you want, and tackle those one at a time. And, as you do, remember that you can get help:
When Things Go Awry
Not all definitions have been tested with the translator, and there may be scenarios that it gets fundamentally wrong. If so, please raise an Issue, so we can see if it is something that can be fixed, or a fundamental limitation of the translation approach that should be documented here.
If you are having trouble figuring out the details of how to finish or use your fixture definition, please ask for help on the Zulip chat or Wiki. Not only will that hopefully get you going faster, but it might help others in the future, especially if it leads to improvements in the documentation or Afterglow itself.