Friday, June 12, 2020

Java Lighting Control Part 3 - The Art-Net Backbone

Thursday, May 21st, 2020

Welcome back! Today I'm going to be discussing the long awaited Art-Net backbone, an essential piece of processing for my Java projects involving stage lighting. I'll be taking a look at how it functions, the different data types and what they do, and how it all fits together to push lighting data to Art-Net.

External Libraries

Since I am not experienced enough to be writing my own Art-Net communication library from scratch, I'm building upon Artnet4J, a library written by Cansik (GitHub page here). This library is the final interface between Java and Art-Net, and what is doing the heavy lifting in terms of communicating with my lights.

What is Art-Net?

Art-Net is a protocol for sending DMX data over IP networking. An Art-Net network is built up of standard IP infrastructure like routers and switches, along with nodes, which are responsible for actually turning the Art-Net data into DMX that the lights can interpret. The Art-Net node I am using is an ELC DMXLan Buddy, which is capable of outputting 2 universes independently (a universe being a chain of 512 DMX channels).

<Photo of DMXLan Buddy>

The reason I am using Art-Net rather than something like USB to DMX conversion is because Art-Net is easier to support, since you don't have to worry about compatibility with all different USB to DMX dongles. With Art-Net, all you have to do is specify an IP address and universe, and any node that supports it will be able to read and convert the data.

Using Artnet4J

The basic thing to understand about Artnet4j is how data is packaged before being sent to Art-Net. The data takes the form of an array of 512 bytes containing values between 0 and 255. Each index position specifies a DMX channel, and each value is the value that gets pushed to that channel. From there all you have to do is create a client to handle the communications side of things, and push the array to an IP address and universe.

This is a very easy library to use, but because the software I am building is going to be relatively complex, I needed to build upon it to make things as solid as possible for use in the future. This includes creating objects for each universe to save things like IP address and universe ID, and defining different data objects for my software to work with.

Data Types

There are four main data types that my software is able to use, which are commands, frames, scenes, and stacks. These are essentially containers for each other, and the way they are encapsulated in the following way: each frame contains several commands, each scene contains several frames, and each stack contains several scenes. While I haven't yet created a project that utilizes scenes or stacks, every experiment with Art-Net in Java has extensively utilized frames.

Commands are simple, lightweight data types containing an address, universe, and data value. In essence, it is there to say "this channel at this value on this universe". By itself it simply controls a single light, but when there are many commands encapsulated in a single frame, things become more interesting.

Frames are what are actually sent to Art-Net, since they contain an array of commands which need to be read and sent out to each universe. The cool thing here is that frames are not universe specific, so you can control any lights in any universe together in a single frame.

One more step up the chain, we see that each scene contains a series of frames, much like a video contains a whole bunch of still images that it combines to create the illusion of video. This is going to be important in future projects where I need to worry about different scenes stepping through commands in sequential order, but for now it's just there for future implementation.

Finally, there is what is called a stack, which is a bunch of scenes meant to play side-by-side with each other. Once again, this is here for future implementation and isn't utilized currently.

Universes

The next thing I needed to do was to create an ArtnetUniverse object so I can reference each universe independently without worrying about specifying an IP address each time. I also store a Universe ID,  which is a unique identifier that my software can use to figure out which universe to send data to. The class also contains methods for writing data to the universe, and also for sending the universe data out to Art-Net.

Art-Net Router

The Art-Net router is an object that takes data and routes it to each universe, depending on the desired universe ID. When sending data to Art-Net, the data is encapsulated in a frame, and a router 'opens' a frame, reads each command, and sends it to the correct universe depending on the universe address in the command. This is essentially the link between the Art-Net part of Java and the rest of a program, as it serves as a hub for routing commands. However, unlike IP routers in the real world, this is merely an object in a Java program and not a physical router.

Putting it all Together

The last step is to combine all of these steps into a final project. For sake of example, I'll be explaining how I use this in my last project, the simple dimmer and color controller (see that project here).

First is to create and initialize all of the objects we need for Art-Net to work.
Initialization code
The first few lines create and start the Art-Net client on my machine, which is what will talk to all of the nodes over the network. Next, I create the router object. Then, I create two universe objects for each universe on my DMXLan buddy, which currently has the statically assigned IP address of 192.168.1.63 on my small, 2 device Art-Net network. Finally, I add references to both universes to the Art-Net router, and now the code is ready to send Art-Net.

The next step is to create a frame object. We only need one since this is a basic controller and isn't working with saved scenes and frames.
Creating and assigning the frames to the fader banks
This is a simple code to create a frame and assign it to the faders through use of the fader banks, which are explained in my last post.

Next is the code to write data to each frame. This is a simple method call for the frame object.
Code for adding a command to a frame
This code creates a command within the frame. In the context of the router, the channel is what channel the command is for, the DMXint is the data that is being sent to that channel, and the universe is what universe the command is supposed to go to. This is done within each fader when it receives a MIDI command from the Launchpads.

The last step is to send the frame to the router, which is done each cycle through the main loop.
Commands for sending Art-Net data
The first two lines send the DMX data from each fader bank to the active frame using the method we discussed above. The next line pushes the frame to the router, which sends it to each universe's data array. Finally, the last line pushes the data from each universe out to the specified node, and then to the lights.

And there you have it! This is the Art-Net framework I will be using in future projects since it offers simple functionality that builds upon existing Java Art-Net libraries. Thanks to Cansik for making the library exist so I don't have to start from scratch!

That's all for now, thanks for reading! Keep on making things!
-Will

No comments:

Post a Comment