TouchDesigner | Python and the Subprocess Module

I can has Subprocess?

At the TouchDesigner Summit in Montreal we’ll be taking some time to talk about working with external Python Modules in TouchDesigner. While we’ll have time to cover lots of information about how to incorporate external modules in Touch, we won’t have a lot of time to talk through the wobbles that you might run into when working with operations that might be slow, or otherwise unwieldy to run in Touch.

“What do you mean Matt?”

The types of pieces that usually fall into this category are blocking operations. For example, let’s say that you want to upload an image to the web somewhere. Many of the libraries that you might find will have an approach that’s probably blocking – as in it will appear as if TouchDesigner has frozen while the whole operation completes. While this is fine outside of Touch, we don’t typically like it when our applications appear to freeze – especially in installations or live performances. You might be able to move that process to another thread, though that might be a little more hassle that you really want it to be in the long run.

Enter the Python Subprocess module.

Subprocess

The subprocess module allows you to run a python script as a parallel execution that doesn’t touch your TouchDesigner application. You could use this for all sorts of interesting an powerful applications – from starting media syncing between machines, running a process that talks to the internet, or any number of solutions that execute outside of TouchDesigner. In the past I’ve used this for things like sending emails, or uploading images to Instagram – there’s lots you can do with this approach, it’s just a matter of wrangling python and the subprocess module.

What exactly is happening when we use the subprocess module?! Well, we can think of this as a situation where we write a python script in a text file, and then ask your operating system to run that file. There are great ways to pass in arguments into those situations, and if you really need data there are ways to get a response before the process quits. This can be a very flexible solution for a number of situations, and worth looking into if you want something that’s non-blocking and can be run outside of TouchDesigner.

Subprocess calls can be infuriating if you’re not familiar with them, so let’s look at some simple anatomy of making this work from Touch.


Scenario 1 – Execute this Script

Let’s start with the most basic of scenarios. Here we have some Python script that normally takes a long time to run, that we just want to kick off from TouchDesigner. For this example let’s just look at something that will print to a shell – nothing fancy, just a place to get our bearings. Our python script might look something like this:

Pure Python

import time
import sys

# a variable a divider that we're going to use
divider = '- ' * 10

# a for loop to print all of the paths in our sys.path
for each in sys.path:
    print(each)

# our divider
print(divider)

# a for loop that prints numbers 
for each in range(10):
    print(each)

# a call to time.sleep to keep our terminal open so we can see what's happening
time.sleep(120)

This works just the way that we might expect if we run it in our OS. But how can we run this script from TouchDesigner?

In TouchDesigner

In TouchDesigner we’d add a DAT that has the following contents. Here we assume that the script above has been saved in a folder called scripts that’s in the same folder as our project file, and the name of the script is cmd_line_python.py.

import subprocess

# point to our script that we're going to execute
cmd_python_script = '{}/scripts/cmd_line_python.py'.format(project.folder)

# quick debug print
print(cmd_python_script)

# call our script with subprocess
subprocess.Popen(['python', cmd_python_script], shell=False)

This is great, but this will actually execute with the version of Python that’s packaged with TouchDesigner. In some cases that’s exactly what we want… in other’s we might want to use a different version of python that’s installed on our OS. How can we do that?


Scenario 2 – Execute this Script with a Specific Python

This is very similar to our first situation, but here we want to run the python that’s installed on our OS, not the python that’s packaged with Touch. In this case we can use the exact same python script we saw above.

Pure Python

import time
import sys

# a variable a divider that we're going to use
divider = '- ' * 10

# a for loop to print all of the paths in our sys.path
for each in sys.path:
    print(each)

# our divider
print(divider)

# a for loop that prints numbers 
for each in range(10):
    print(each)

# a call to time.sleep to keep our terminal open so we can see what's happening
time.sleep(120)

Our real changes come when we’re issuing the subprocess call in TouchDesigner.

In TouchDesigner

Again, we add a DAT that has the following contents. Here we assume that the script above has been saved in a folder called scripts that’s in the same folder as our project file, and the name of the script is cmd_line_python.py. The additional wrinkle this time, is that we also need to specify which python.exe we want to use for this process.

import subprocess

# point to our script that we're going to execute
cmd_python_script = '{}/scripts/cmd_line_python.py'.format(project.folder)

# point to the specific version of python that we want to use
python_exe = 'C:/Program Files/Python35/python.exe'

# quick debug print
print(cmd_python_script)

# call our script with subprocess
subprocess.Popen([python_exe, cmd_python_script], shell=False)

If we look closely at the example above, we can see that we’ve been very specific about where our python_exe lives. This approach runs the same script, only this time with the python.exe that we’ve specifically pointed to.


Scenario 3 – Passing Over Args

There are several ways to approach this challenge. One that will line up with the format of many pure pythonic approaches here would be to use the argparse library. We find this in lots of stand-alone scripts, and it allows us the flexibility of setting default arguments, and creating some relatively clean inputs when calling a script form the command line. In this approach we set up a function that we’ll call, and pass arguments into – in the example below that’s our My_python_method(). By using ArgumentParser we can pass in command line arguments that we can in turn pass through to our function. Notice the syntax at the bottom to see how this works. ArgumentParser returns keyword arguments, which is why we use kwargs as the mechanism for sending args into our simple for loop.

Pure Python

import time
import sys
import time
from argparse import ArgumentParser

def My_python_method(kwargs):

    disp_str = 'key: {} | value: {} | type: {}'
    for each_key, each_value in kwargs.items():
        formatted_str = disp_str.format(each_key, each_value, type(each_value))
        print(formatted_str)

    # keep the shell open so we can debug
    time.sleep(int(kwargs.get('delay')))

# execution order matters -this puppy has to be at the bottom as our functions are defined above
if __name__ == '__main__':
    parser = ArgumentParser(description='A simple argument input example')
    parser.add_argument("-i", "--input", dest="in", help="an input string", required=True)
    parser.add_argument("-i2", "--input2", dest="in2", help="another input", required=True)    
    parser.add_argument("-d", "--delay", dest="delay", help="how long our terminal stays up", required=False, default=10)
    
    args = parser.parse_args()
    My_python_method(vars(args))
    pass

# example
# python .\cmd_line_python_args.py -i="a string" -i2="another string" -d=15

Where this becomes more interesting is when we look at what’s happening on the TouchDesigner side of this equation.

In TouchDesigner

A DAT in TouchDesigner needs to follow the same rules we established so far – we need to know what executable we’re using, which file we’re running, and finally we now need to send along some arguments that will be passed to that file. In Touch, our script this time should look something like this:

import subprocess

# point to our script that we're going to execute
cmd_python_script = '{}/scripts/cmd_line_python_args.py'.format(project.folder)

# construct a list of arguments for out external script
script_args = ['-i', 'Hello', '-i2', 'TouchDesigner']

# join our python instructions with our scirpt args
command_list = ['python', cmd_python_script] + script_args

# call our script with subprocess
subprocess.Popen(command_list, shell=False)

Scenario 4 – I Want a Message Back

Like all things Touch, and all things Python there are LOTS of ways to accomplish this task. One way we might want to consider, however, is using UDP messages. Touch happens to have a handy UDPIn DAT that’s ready to accept messages, and the other benefit here is that we could potentially target another machine on our network as the target for these messages. For this first exploration let’s imagine that we’re only sending a message locally, and that all of our variables are defined in the python script we’re running. We’ll need to use the socket library to help with the communication elements, and you’ll notice that we import that at the top of our script. This silly example just creates a UDP connection, and sends messages at a regular interval.

Pure Python

import time
import sys
import socket

upd_ip = "127.0.0.1"
udp_port = 7000
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

num_iters = 11
sleep_interval = 2

def msg_to_bytes(msg):
    return msg.encode('utf-8')

starting_msg = "Sending messages at an interval of {} seconds".format(sleep_interval)
sock.sendto(msg_to_bytes(starting_msg), (upd_ip, udp_port))

for each in range(num_iters):
    msg = "{} of {}".format(each, num_iters-1)
    sock.sendto(msg_to_bytes(msg), (upd_ip, udp_port))
    time.sleep(sleep_interval)

ending_msg = "All messages sent"
sock.sendto(msg_to_bytes(ending_msg), (upd_ip, udp_port))

In TouchDesigner

For this simple execution in TouchDesigner we only need to worry about kicking off the script. That looks almost exactly like the other pieces we’ve set up so far.

import subprocess

# point to our script that we're going to execute
cmd_python_script = '{}/scripts/cmd_line_python_udp_msg.py'.format(project.folder)

# print our script path - quick debug
print(cmd_python_script)

# clear the last entries from the UDPin DAT
op('udpin1').par.clear.pulse()

# call our script with subprocess
subprocess.Popen(['python', cmd_python_script], shell=True)

Our catch this time is that we need to use a UDPIn DAT to receive those messages. Let’s also make sure the Row/Callback Format parameter is set to One Per Message. With this all set up we should see something like this when we kick off the script.


Scenario 5 – Messages, I can has args?!

That all seems mighty fine… but, what happens when I want to combine what we’ve done with passing along arguments, and messages? I’m so glad you asked. With a little extra work we can make exactly that happen. We do need to do a little more heavy lifting on the python front, but that work gives us some extra flexibility. You’ll notice below that we’re now passing along which port we want to use, how many iterations of our for loop, and the interval between repetitions.

Pure Python

import time
import sys
import socket
from argparse import ArgumentParser

def msg_to_bytes(msg):
    return msg.encode('utf-8')

def msg_loop(port, interval, loop):
    # localhost
    upd_ip = "127.0.0.1"

    # set udp port with input val and initialize socket connection
    udp_port = int(port)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # set additional variables with input vals
    num_iters = int(loop)
    sleep_interval = int(interval)

    # send message that we're starting
    starting_msg = "Sending messages at an interval of {} seconds".format(sleep_interval)
    sock.sendto(msg_to_bytes(starting_msg), (upd_ip, udp_port))

    # run message loop
    for each in range(num_iters):
        msg = "{} of {}".format(each, num_iters-1)
        sock.sendto(msg_to_bytes(msg), (upd_ip, udp_port))
        time.sleep(sleep_interval)

    # send message that we're ending
    ending_msg = "All messages sent"
    sock.sendto(msg_to_bytes(ending_msg), (upd_ip, udp_port))

# execution order matters - this puppy has to be at the bottom as our functions are defined above
if __name__ == '__main__':
    parser = ArgumentParser(description='A simple UDP example')
    parser.add_argument("-p", "--port", dest="port", help="UDP port", required=True, default=1234)
    parser.add_argument("-i", "--interval", dest="interval", help="loop interval", required=True, default=5)
    parser.add_argument("-l", "--loop", dest="loop", help="number of repetitions", required=True, default=10)
    args = parser.parse_args()

    msg_loop(args.port, args.interval, args.loop)
    pass

# example
# python .\cmd_line_python_udp_msg_args.py -p=5000 -i=2 -l=10

In TouchDesigner

Over in TouchDesigner, our subprocess script looks very similar to what we’ve done so far with just a few modifications.

import subprocess

# set up our variables for our subprocess call
port = str(op('udpin2').par.port.val)
interval = '1'
loop = '15'

# point to our script that we're going to execute
cmd_python_script = '{}/scripts/cmd_line_python_udp_msg_args.py'.format(project.folder)

# construct a list of our python args - which python and which script
python_args = ['python', cmd_python_script]

# construct a list of arguments for out external script
script_args = ['-p', port, '-i', interval, '-l', loop]

# join our two lists - python args and scirpt args
cmd_args = python_args + script_args

# quick debug print
print(cmd_args)

# clear the last entries from the UDPin DAT
op('udpin2').par.clear.pulse()

# call our script with subprocess
subprocess.Popen(cmd_args, shell=True)

Here the resulting messages look very similar, only we’ve not gotten to specify all the qualities about the for loop from our script.


What does this Matter?

Well, there are lots of things you might do with this, but especially interesting might be considering how you can use otherwise very costly and slow operations in Python with this approach. For example, a recent set of Style Transfer experiments I was working on used this style of approach to essentially create a TouchDesigner front end / UI for a pytorch style transfer backend. This let me pass along arguments from the UI over to a pure python execution that didn’t block or freeze touch while it was running. There are lots of ways you might get into mischief with this kind of work, and it’s worth pointing out that while all this is focused on python, there’s no reason you couldn’t instead think of other applications you want to run with a particular file and a set of command line arguments.

Happy Programming!


What to follow along? Download the sample code from github

TouchDesigner | Stoner Tricks

There was a great question that recently popped up on the Forum about using the Stoner component from the Palette.

Every time I use the stoner tool I delete these ops first thing.

For some reason the locked TOP doesn’t seem to have anything to do with the real output, yet it saves that data with the TOE and it’s easy for the toe to be huge for no reason.

I had 3 4K stoners and the file was 150 mb. Remove these ops and the toe goes to 140KB

Stoner throws errors when moving points after deleting these, however doesn’t seem to impact the functionality of the stoner, it still outputs the correct UV and warp texture. It still persists the data after a save.

Can someone explain why those ops are even there? it looks only like it’s saving the demo image before you start using it.

Read the whole thread

Long story short, what looks like a ramp is actually a displacement map. The idea here is that you can actually get all of the benefits of the stoner’s displacement, without running the whole component. Unless your mapping is changing dynamically, you can instead use this texture to drive a remap TOP which in turn handles your distortion. Richard Burns wrote a lovely little piece about this on Visualesque.

I wrote about what these ops are good for in a post a few years ago when working on a short installation that was in Argentina – Building a Calibration UI. Sadly, I never got to the second part of that post to dig into how we could actually use this feature of the stoner. Fast forward a few years and when collaborating with Zoe Sandoval on their thesis project (which featured four channels of projection) – { remnants } of a { ritual } – I used a very similar approach to leveraging Stoner’s flexibility to use a single UI for multiple displacement maps.

So… how do we actually use it?!

Well, I finally had some time to knock out a walk through of how to make this work in your projects, some python to help you get it moving and organized quickly, and ways to keep your calibration data out of your project file. Hope this sheds some light on some of the ways you can better take advantage of the Stoner.

Check out a sample project here.


YouTube Playlist


Individual Vids

TouchDesigner | Start-up Configuration with Environment Variables

Environment Variables

Environment Variables can be a handy way of passing in information to Touch without setting up a complicated file opening process. Some approaches benefit from using external files to indicate configuration, and at other times setting an environment variable is a better approach. One caution here is that working with Environment Variables can be invisible to the user – so in some cases while this is highly convenient, it can make trouble shooting slightly more complicated. A consideration for working around this challenge would be to set your environment variable at start programmatically. On Windows you might use a .bat or .cmd file. You can do the same operations with Python – of course this requires that you have Python installed on your machine, but it does provide for handy cross platform solution that’s easier to read.

The bit that’s worth thinking about is if you’re going to be running on systems with multiple GPUs. On those systems you have to set your GPU affinity at start. Derivative recommends doing this with a .bat or .cmd file. The trick for us here is that our schema of using a separate python file to indicate our indication will break – in the case of using a system with multiple GPUs, you likely want those two networks configured slightly differently. We can address this by using environment variables instead of a stand alone .json file. Depending on your workflow you might want to move this direction generally, but it’s a little more advanced than we have time to cover in this workshop.

At the 2019 TouchDesigner Summit in Montreal, Zoe and I are going to talk through a number of pieces about large system design and architecture. There’s always more to cover than there are hours in a day, and this little tid-bit, while very handy isn’t one that we have a lot of time to talk about at the workshop. Instead, I thought it would be handy to can leave this little reference here so you can come back to this part when you’re ready to push a little harder on start-up configuration. The big idea is that rather than using that outputlist.json file to tell us how to configure our project, we can instead use environment variables. Touch will read environment variables that are called before the application starts with the Python syntax:

var.("my_var_name")

We’d have to re-arrange a little logic in our project, but once we did that we’d be able to set our project’s configuration from another script at start-up. You could do this either with a .cmd script or with Python script. For the more advanced users, if you have another watcher application keeping tabs on your Touch project you’d want to add a mechanism to set an environment variable before starting the target application.

Here’s a quick run down of what this might look like if you’re running a batch script or a python script.

Setting environment variables in a windows batch script

Sample Batch Script

Looking closer a the syntax here, we can see that we point to the directory where our TouchDesigner executable is located (the appliaction we want to use), and then point to the file we want to open. But, what is %~dp0?! A little browsing through stack overflow can help illustrate what’s going on here:

The %~dp0 Variable

The %~dp0 (that’s a zero) variable when referenced within a Windows batch file will expand to the drive letter and path of that batch file.

The variables %0-%9 refer to the command line parameters of the batch file. %1-%9 refer to command line arguments after the batch file name. %0 refers to the batch file itself.

If you follow the percent character (%) with a tilde character (~), you can insert a modifier(s) before the parameter number to alter the way the variable is expanded. The d modifier expands to the drive letter and the p modifier expands to the path of the parameter.

Example: Let’s say you have a directory on C: called bat_files, and in that directory is a file called example.bat. In this case, %~dp0 (combining the d and p modifiers) will expand to C:\bat_files.

Read the Thread on stackoverflow

In other words, that little bit says that file we want to open is at the same location as the script we’re running.

Setting environment variables with Python

Simple Python Script to set Env Vars


Learn More about Environment Variables

TouchDesigner | Previs for Moving Lights

I got an interesting question a few weeks ago about how to use tracking data to control moving lights. If you work with Touch long enough, at some point you’ll almost always end up wanting to drive some object in the real world with information derived from calculations in Touch. Where / how can you get started with that process?! It’s often temping to straight away jump into just driving the physical object. After all you know what you’re trying to do, and you might have a sense of how to get there – so what’s the harm?

That’s not a bad instinct, but I almost always like to start with some form of previs. You won’t always have access to all the equipment you want to use, and more importantly it’s often better to make sure you understand the problem you’re trying to solve before you start driving motors. The additional bonus here is that solid previs will create some opportunities for testing, and planning that you might not other wise have.

This post is going to look at:

  • Planning / mapping out some simple previs for using tracking data on some moving lights
  • Using the Object CHOP to calculate bearings for rotation information
  • Some simple use of custom parameters and bindings
  • Pattern matching for renaming
  • Using the CHOP export method Channel Name is Path:Parameter
Top level look at our setup

As a disclaimer, this is not a great approach for LOTS of lights – but is a great way to get started and make sure you understand what you’re trying to accomplish.

Workspace Setup

I like a workspace where it’s easy to see multiple perspectives at the same time. In this case I’d like to see the the network editor (your typical Touch workspace), the geometry viewer, and a rendered view. We can split our workspace with the icon that looks like a little down arrow in the upper right corner of the pane bar:

Split the network with the drop down menu in the upper right

In this case I’m going to split the workspace left/right, and then once top/bottom. In the pane on the top right I’m going to change the Pane Type to geometry.

Change the pane type to geometry

On the Bottom I’m going to change the pane type to Panel. If we’re working with container COMPs this can be very handy as it lets us see the panel for the container. If you’ve created an interface, that means you can also interact with your controls from here, without having to open a floating window.

A clean project set up like this looks like:

Our blank network

Our last step here is going to be adding a Container COMP to our network. We also need to rename it, and make sure our two new windows on the right correctly reference our net container. Our network bar is path based, so we just need to make sure both of them have the address: /project1/container_previs

Container COMP with our correct addresses

Custom Parameters

I want to control the elements of my previs container with a set of custom parameters. This will help me reduce the places I have to look for making changes, and helps save me the step of building a UI to control this visualization. I already happen to know what pieces I want to add here:

  • Transform controls for a tracked object
  • Transform Controls for 3 lights
  • Color Controls for 3 lights
  • Dimmer Controls for 3 lights
  • All of these should live on a page called “Settings”

In the end, our custom parameters should look like this:

Our Custom Parameters

I’m not going to go into huge detail here about how to set up the custom parameters here, but you can learn more about using custom parameters:

There is, however, one quick thing to point out. The addition of bindings in the Spring update comes along with a handy way to take quick advantage of them. We can use the drag and drop trick to add a set of custom parameters from another operator, and we can also auto assign all of our bindings in the process. Let’s take a look at that process.

Inside of /project1/conatiner_previs I’m going to add a light COMP. I’m going to first open the custom parameters dialog, and then add a page to my previs container called Settings. Next I’m going to grab the parameter Translate from my light comp, and drag it right onto the Parameter column in the customize dialogue. Here’s where the magic happens. Next I’ll select Bind New Par as Master from the drop-down, and ta-da – now your bindings are already set up for you:

Auto-assign our bindings by dragging and dropping

Scene Set-up

To set up this scene I’m going to use a few simple tricks. First I’m going to use a camera and a few pieces of geometry to get started. For something like the stage, I like a single top level Geo, with separate pieces nested inside. The benefit here is that if we scale or transform our top level Geo those changes will propagate to our nested elements:

Inside out stage

You’ll notice a separate wire-frame version of the stage inside of our stage – this is to give us some nice grid lines. geo2 is also transformed ever so slightly above geo as well, so we’ve got some nice clean rendering. Looking at the phong material for the primary stage, it’s got a slight gray emit color – so we can see it even when there’s no light on it’s surface.

We’ll also use a little trick with our camera. I’ve set my camera to look at a null COMP in our scene. This gives us some better handles for adjusting where our camera is looking without needing to manually set the rotation and transformation values. This is often a very helpful and easy way to get better camera controls by thinking spatially, rather than as transformation values.

Finally, I’m going to add another geo and change it to be a sphere. In this case I want some object to represent a moving object on my stage. I’m going to bind this object to my parent’s custom parameters that I already set-up for transformation. This means I can change the position of this geo either from the parent’s custom ops, or from the parameters on the geo.

Light Set-up

Depending on the order you’ve done this, you may have already created lights to set-up your custom parameters. If you haven’t done that yet, now’s a good time to add some lights to your scene. I’m going to use three for now. I’m also going to use a table to hold the transformation information for our lights. I’m using a table here because I’m thinking of a situation where my lights aren’t going to move – theatrical lights are usually transformationaly stable, and instead just rotate. If you’re lights are going to move in xyz position, this isn’t the most optimal set-up. Next I’m going to convert my table of positions to CHOP data. In my Dat to CHOP I want to make sure that I’m using a channel per column, and that my fist row and first column are marked as names.

Convert from DAT to CHOP

Next I’m going to use an object CHOP to find the position data for my target (that sphere we set-up in our scene). I’m going to plug my datto1 into that a second object CHOP, and my first object CHOP into the second input. Next I’ll make sure that I’m computing bearing, and on the channel page I want to change the output range to be start/end. I want to change that to samples instead of seconds, and then make sure that I start at sample 0 and end at sample 2.

Object CHOP -bearing calculations

So what’s this all about? What we’re doing with this second object CHOP is calculating the rotational values that will tell us the how to look at our target with each of our lights. We can then use this to set the rotation of our lights so they follow our target object. We could also do this with a chain of Math CHOPs… but having done it both ways, they’re almost computationally identical, and this you can do with fewer operators. So now we know the rotation values we need to set our on lights to make sure they’re looking at our target.

Now, we could certainly write some complex references for these values, but we can also learn a handy trick that I don’t see used too many places. Here we’re going to look at another CHOP export configuration. Before we get there, we need to flatten out our CHOP data. To do this we can use a shuffle CHOP set to split all samples:

Flatten out our CHOP data

This is swell, but if we don’t want to go through the process of exporting these one by one to our lights, what can we do? Well, it’s handy to know that there’s another way to use CHOP exports. There happens to be an export method called Channel Name is Path:Parameter. What that means is that if we change the name of our channel to be formatted so it’s the path to the operator followed by a colon and ending with the target parameter the exports will happen for us without any extra work.

Let’s take a quick detour to see how that works in isolation first. Let’s first add a constant CHOP, connected to a null CHOP. Finally let’s add another geo COMP to see how this works.

First steps to understanding another export method

Next let’s name some channels in our constant. I want to add the following:

  • geo1:tx
  • geo1:ty
  • geo1:tz

Next on my null CHOP I’m going to go the common page and change the export method to Channel Name is Path:Parameter. Finally, I’m going to turn on the export flag for the null CHOP, and ta-da. You’ve not exported values for tx, ty, and tz to your geo.

Exporting CHOPs with Path and Parameter

Okay, now if we go back to our flattened rotation info, we can imagine that if we just change the names of our channels we won’t have to do lots of dragging and dropping to get our exports sorted.

Let’s add a rename CHOP, and we can use some fancy pattern matching to do the renaming for us. In the From parameter we want r*[0-2]. What on earth does that mean? Well, any channel that starts with r, then has any character next, and then has a value of 0, 1, then 2. This happens sequentially, so we do all the r0s first, then the r1s and so on. That matters because our shuffled data is all rx values, then ry, and finally rz. We have to make a pattern matching schema that works works with that pattern.

Okay, so in our To parameter we want to use the pattern light[1-3]:r[xyz]. This means we’ll change our name space to be something like light1:rx. Again, this happens sequentially, so we’ll do all the 1s, then 2s, then 3s. What we end up with changes our original names like this:

Next we should be able to connect our null CHOP, set it to export as Channel Name is Path:Parameter, and we should be off to the races with all of our exports set up.

Our Container

By the end of all of this we should have a handy little container that’s set-up so we can change the position of a target geometry, and have our lights automatically follow it around our stage. If you’ve gotten stuck along the way, check the bottom of the page for a link to a repo where you can download just a tox of the finished Container, or a whole toe file with our workspace setup.

Our little follow spots

Other Considerations

What we haven’t talked about is getting your measurements and scaling right, or how to convert our rotational values into pan and tilt measurements, or how to convert that for controlling something with a protocol like DMX. Those are big concerns in their own right, but with a solid visualization you will at least have something to compare the real world against so you can start pulling apart those challenges.

Happy programming!


If you want to download this and look through the set-up you can find it on GitHub here.

TouchDesigner | Virtual MIDI Devices

In the past week I’ve found myself in multiple conversations about working with MIDI in TouchDesigner. Specifically, how you might pass a MIDI signal from one application to another on the same computer. So far, all of the conversations I’ve been involved in have been related to working with Windows – which means that this particular post is focused on that operating system, though the same idea should transfer to macOS if that’s your current platform.

So what’s the problem exactly?

All of my conversations about this topic have been centered around sending messages from TouchDesigner to WATCHOUT. For those unfamiliar, WATCHOUT is a media server application that’s used in Theatrical and live events contexts for controlling or sequencing media playback. It’s in the same family of tools as Disguise, GreenHippo, and Pandora’s Box. You may well be asking – “why not just use OSC?” That’s a great question, some versions of WATCHOUT don’t support OSC, though they do support MIDI. While this is the specific challenge, the more general idea that we can push against here is:

How can I locally (on the same machine) test a MIDI signal flow without adding extra hardware?

To get there we need to add in a virtual device to allow us to loopback. At it’s simplest, a loopback is just a way of capturing a signal that you’d other wise be sending somewhere else. Imagine using a cable from the headphone port on your laptop, and connecting it to the microphone in on your laptop (don’t actually do that, just imagine it). Why? Well, using actual interfaces often have different requirements, or set-up than just faking it – you’ll also likely find that operating systems don’t have an implicit knowledge of a particular signal or transfer format. Just because your computer is making noises doesn’t automatically mean that it can capture that noise locally.

How do we make this work then?

Enter the Virtual Device. A Virtual Device provides drivers that act as though it’s sending your signal to a dedicated piece of hardware, but instead allows you to rout it back to your machine. There are lots of examples of this in the audio world, and it just so happens that there’s a Virtual MIDI device we can install to pass around MIDI signals as well.

Doing a bit of googling I found LoobBe1. It has a free evaluation license, which is what we’ll use below. If you decide that this needs to be part of your commercial workflow, I’d encourage you purchase a license. It’s less than $15 US, and supporting folks that make useful tools is something we should all do more. As a disclaimer, I don’t have any affiliation or connection to LoopBe1 – I just found them after doing some internet searching.

We’re going to set-up a simple loopback test for a MIDI signal from TouchDesigner, and see if we can read that signal back. I don’t have a copy of WATCHOUT to work with, but if we can trouble shoot within TouchDesigner, we should at least know that it’s working.

Getting a MIDI Loopback Working

Ingredients

Windows 10 v1809
TouchDesigner 099 2019.15230
LoobBe1

To get started you’ll need to download and install LoobBe1. I like to limit what starts up automatically on my computer, so I’d recommend also turning off the automatic start-up of this application once you have it installed.

From there we can start up TouchDesigner and begin our configuration process. We’re going to start by opening the MIDI Mapper dialogue. You can open that with alt + d or you can find it from the Dialogues drop down:

Open the MIDI Mapper dialogue from the Dialogs drop-down

You should now see the MIDI Mapper:

The MIDI Mapper Dialog window

We’re going to test our output right in TouchDesigner. To do that let’s click on the Create New Mapping button in the middle left of the dialogue window. That will add a row to our Device Mapping where we can specify that both our In and Out Device will be LoopBe Internal MIDI.

The MIDI Mapper with an added Device

Before we can move forward here it’s important to recognize that the naming of MIDI channels matters. MIDI (Music Instrument Digital Interface) has a detailed specification that ensures continuity across devices and manufactures, so it shouldn’t be a surprise that there’s lots of detail here. You can read the whole spec by here, or get a summary from Wikipedia. What we really care about today is that we need to format our TouchDesigner channel names in a way that’s compatible with Derivative’s implementation. To figure all of that out, we need to head over to the wiki for a quick read. Let’s take a look at the MIDI Out CHOP page. Here we see that:

Naming the CHOP channels: Channels are mapped to events by their name. Events like notes, controllers and velocities must be followed by the note/controller number (n65, c7). If the number is left off a note event, the note number is the value of the channel. Other events, which are sent to the entire channel, do not need a trailing number (pc, pw). The channel prefix can be used to identify the MIDI channel the event should be sent on (i.e. “ch1n45” assigns that TouchDesigner channel to note 45 messages on MIDI channel 1). Channels can always be renamed with a Rename CHOP before entering the MIDI Out CHOP.

The MIDI Out CHOP sends MIDI velocity as well. The values of the channels entering the MIDI Out CHOPs are sent as the velocity of the note. If Normalize is “None”, the channel needs to be 0 to 127. If Normalize is “0 to 1”, channel values between 0 and 1 are scaled to be MIDI 0 to 127.

The “Cook Every Frame” option cooks the CHOP every frame, even if the CHOP isn’t being displayed. All Volume Off and All Volume On flags are new and emit events for Controller 7 of all 16 channels. MIDI output go in a separate thread to allow output that slows TouchDesigner less. It now works in Time Slice mode for note events and controller events. (Not for Program Change or Sysex messages yet) Note channels only trigger anew Note On when the input channel goes from 0 or less to a value greater than zero. Similar for Note Off events.The channel name determines how it is interpreted.

Derivative’s MIDI Out CHOP Wiki Page

What does that even mean?! Well, let’s set up a few pieces in a network to see if we can make sense of this.

I’m going to add a Noise CHOP to my network, and turn on the time-slice parameter so we have some constantly changing values. I’m going to change the Channel name parameter to be ch1c1. This would be Channel 1, Control 1.

By default our Noise CHOP will have values between -1 and 1. Based on what’s in the wiki, we’ll either need to normalize our values (change them to be in a range of 0-1) or we’ll need to change our values to be in a range of 0-127. We can do either of these with a Math CHOP so let’s add one of those in line and change our range parameters:

Now we can finish this off by adding a MIDI Out CHOP to our network:

So how do we make sure this is working?

Well, let’s first check with Touch. Since we added our LoopBe Internal MIDI as our input device, we should now be able to drop in a MIDI In CHOP to see our midi values:

Great – so we can see our values… only they’re expressed as whole numbers rather than as a floating point value. Why? MIDI works with 127 steps, so our MIDI Out CHOP is converting our 0-1 set of values into a range of 0-127. What this means is that you, dear developer-artist, have to make a choice. This approach works perfectly fine, but it may mean that at some point you’ll be doing some mental gymnastics in understanding how values in Touch correspond to values in your other application. If that’s too much to think about all the time, then you may want to change the math CHOP to be in a range of 0-127, with the values rounded either up or down (depending on your preference). This kind of change would let you see exactly what value you’re expected to be transmitted from Touch. If you’re working on a high profile AV installation, this kind of specificity might be worth having – if only so you can say with complete confidence that you’re transmitting a value of x on channelxyz.

Okay, so it works in Touch… but can we be sure? Of course. I’m going to use Isadora by Troikatronix to help us validate that we’re sending this correctly. I’m not going to go into too many of the details for how we set-this up in Izzy, just enough so we can validate what we’re seeing here.

To start I’m going to open up Isadora, go to the Communications drop down, and select MIDI Setup:

Like Touch, I’m going to set the Input Port to be LoopBe Internal MIDI:

To see if we’re actually transmitting values, let’s open up the Izzy Status monitor:

Sure enough, we should see a blinking Green light on Channel 1 and the value associated with it:

TADA! You’re passing data around locally from one application to another using MIDI.

Takeaways

Okay, so what exactly did we do? Well, we added a virtual MIDI interface that let us send MIDI encoded data between applications on a single computer. We then verified that this works by first looking at the data transmission in Touch, then further validated that this works working by looking outside of Touch with another application.

Why on earth do any of this? Well, that’s really a question for you. If MIDI is a core part of your work flow, and passing data between applications on the same computer has an important role for you, then the answers might seem obvious. For those still scratching their heads, imagine that you have raw sensor data that’s not MIDI friendly, but you’d like to get it into an application that does speak MIDI. This kind of workflow is great for that. Working with a Kinect but want to turn that data into MIDI, easy. What about a Leap – sure. Can I do my mouse – you betcha.

It might not be what you need today, but maybe it’ll inspire you to think about some mischief you could get yourself into.

Happy Programming.

Guest Post with Elburz Sorkhabi | Two TouchDesigner Beginner Tricks

If you’re reading this, you’re probably a fan of Elburz Sorkhabi and his work. That makes two of us! Elburz and I are always trying to find ways to collaborate and get into trouble, but we’re often on other sides of the world from one another. We thought it would be fun to do some guest blog posts for each other’s readers. So today you’re in for a treat with a guest post from Elburz himself! If you like a little variety in life, give Elburz blog a read over at Elburz.io.


TouchDesigner is a feature-rich software. It can be daunting for new users what they should be learning and what they’re missing in their toolbox. I thought it would be nice to share two TouchDesigner tricks that are easy to learn and will provide you a lot of value over your career. Some of these things can even evade experienced users as they come quickly in new updates and over time it can be hard to keep track of them all. With that said, let’s dive in!

Custom parameters

Custom parameters are one of the best features to come to TouchDesigner in the last few years. I use them all the time. Sometimes I use them to wrap complex functionality inside of a component while providing easy to use controls. Otherwise I use them for more architectural elements of a project, such as creating internal APIs. The great thing is that any kind of parameter type already available in TouchDesigner can be used for your own custom components. One thing to note is that you can only add Custom Parameters to COMP operators. The first step is to make a COMP, which usually will be a Container COMP or Base COMP, and then right click on it and select Customize Component…

This will open the Component Editor. In this window you can do things like make new extensions, and more importantly for us, this is a visual way to create Custom Parameters. The next step is type a name in to the top-left string field that will be used to name the new parameter page. Then go ahead and click Add Page. I use names like Settings or Controls for my parameter pages. You can confirm everything worked by checking the parameters of your COMP and looking for your new parameter page. It’ll be blank for now.

The next step is to start adding parameters to our new parameter page. Click on the parameter page you just created on the left side of the Component Editor. Now you can enter a name for the parameter you’re about to create in the second string field. Then we’ll go ahead and use the drop down menu to choose the type of parameter you’d like to create. Like I mentioned earlier, you can create any of the existing types of parameters including pulse buttons, toggles, colour pickers, file/folder selectors, and more. The drop down menu to the right of the parameter type has numbers from 1 to 4. These numbers represent the amount of value parts for parameters such as floats and integers. Parts can be thought of as the “amount” of values, for example if you make an integer with 3 selected, you’ll get an integer parameter with 3 separate integers, similar to an RGB parameter field. For this example, let’s select Toggle, name it Toggle Button, and click Add Par. You’ll immediately see the parameter appear in your parameter window as well as the component editor.

That’s it! That’s all there is to making custom parameters. The process is the same for any type of parameter, you just have to choose what you want from the drop down menu. How to use the values is our final step here, but it’s also quite easy.
The quickest way to access the parameter values of a COMP are to use the Parameter CHOP. When you drop one inside of the COMP, by default it’ll already be setup to show you only the values of your custom parameters. For most parameter types, it isn’t any more complicated than using these CHOP channels as you would any other channels for referencing.

For the parameters that hold non-numeric data, such as the file/folder selectors or string fields, you’ll need to access the data through some simple Python scripting. In this case, we can place a Parameter DAT right next to our Parameter CHOP. In the OP parameter enter .. which will select the parent container, for the Parameters enter *, and finally turn off the Built-In button. The Parameter DAT has callbacks like many of the other Execute type of DATs in TouchDesigner. This means that it has different functions where you add your code based on triggers. To access our same toggle button via the Parameter DAT we could add this under the onValueChange() callback:

if par.name == "Togglebutton":
    print(par.val)

This would parse the different customer parameters by name (par.name), find the toggle parameter by it’s scripting name (Togglename – the name you see when you click on a parameter and see it’s second name in the expanded area), and then prints it’s value (val).

Operator snippets

I’m still surprised to this day by how Operator Snippets isn’t talked about every day by new users. It’s the most helpful resource added that can help you learn how to use just about any operator. Operator Snippets is a project file that is built into TouchDesigner that contains tons and tons of examples of how to use operators. It’s similar to Max MSP’s examples per node.
There are two ways to access them. The first is to click Help in the top menu and then select Operator Snippets. This will open up a new window. The left side of the screen looks similar to the OP Create Dialogue (the menu when you double click on the network background) and allows you to choose which operator you want to find examples for. Underneath the operator selection area are a handful of big buttons with different names. Click on one of these changes between the different examples for the operator you’ve selected. On the right hand side of the window is the network area with the example in action.
The great thing about Operator Snippets is that the example is a live network running in real-time! You can copy the example, paste it into your project, and then tweak it to your needs. How useful it that?

Wrap up

These two tricks may sound simple but they are game changing. Being able to make your own custom parameters quickly and easily is game changing. You can make complex components that can be easily used by anyone or implemented into your own projects and controlled easily. Operator Snippets give you the greatest documentation you could ever ask for: live networks running in real-time. I bet if you spent a little bit of time just browsing the snippets, you’d find awesome little examples you’ll be eager to copy and paste into your next project. With that said, enjoy these two beginner tricks and happy programming! And if you’re interested in more content like this, check out elburz.io

TouchDesigner | New Features | Bindings

Spring time is lots of things – flowers, holidays, vigorous allergies, and the TouchDesigner Spring Update. For the second year running this is the time of year that features graduate from just being in experimental to being full fledged stable release features. Wowza.

This spring we’re seeing a feature that’s flat out amazing, and likely a bit of a sleeper. Bindings. Elburz has a great shout out to bindings on a recent blog, and I wanted to take some time to dig in and step through an example of both why they’re important, the paradigm they’re built on, and why they matter.

So what are parameter bindings anyway? The Derivative wiki has a great segment describing bindings:

Bound parameters keep their values in sync and will respond to changes from either parameter. For each parameter that is a bind master, it will have one or more bind reference parameters.
The bind master holds the current value. It can have exports and expressions and generally works like any other parameter, but its value can be also changed indirectly by the bind references.
A bind reference holds the location of the bind master. A bind reference is in a fourth “Bind” Parameter Mode, and will show up as purple text in parameter dialogs. It can only be changed via its its bind master, its UI, and its val property.

Derivative Wiki article on Binding

Model View Controller – MVC

Errm. Okay, so what does that mean exactly? Bindings are based on an interface architecture paradigm called Model – View – Controller, or MVC. Wikipedia has a nice starter debrief on the idea for us, but it’s easy to understand if you’ve spent much time working in Touch either for live set, or for a client application. Let’s consider a live set to help us get our footing here. Suppose you have parameter that can be updated by multiple touch points both in your own UI and in the TD UI. We all know this game, as soon as you export a CHOP to a parameter, you can no longer change that parameter except through the exported CHOP.

Fine.

So maybe instead of exporting from a single CHOP you instead write a bunch of scripts to handle this operation – only now you’re in a real pickle. Why? Well, because your script changes the parameter, but doesn’t update all of the UI elements that reflect the state of that parameter. So you write another script to update the UI. But now you’ve managed to save your project in a state where the UI and the parameters are not aligned. As soon as you change the UI everything is in sync – so you save over a few things, commit your changes, and now everything should be great. Until you need to load a saved preset state from disk. Now you’ve gotta write another set of scripts to do all of that updating, or hunker down for a more generalized solution – which probably means a code refactor. Who wanted to make some more sweet visuals anyway? There goes your night off. There goes your margin. Sigh.

The real world example of this is light switches. If you’ve ever lived in an apartment where multiple light switches control the same light / outlet, you understand this issue intimately. How do you know if the light is on or off? Only by looking at the light, because once the states of the light switches are out of phase they perform the opposite action.

The Model – View – Controller paradigm is a design architecture that’s intended to help resolve this issue. The MVC approach decouples the control of a UI element from the data it is manipulating. You could do this in touch before, you were just on the hook for doing all the set-up. This probably meant you had a master table or storage dictionary somewhere that was updated whenever a parameter was changed, that in turn would update all the other touch points. That’s a huge hassle, but it was the only way to solve this problem. It’s also the kind of silly thing you could really have a strangely strong opinion about – and consequently be convinced that your collaborators were doing it all wrong.

Enter Bindings

Okay, so as a refresher, Bindings are a new parameter mode – that’s the little multi-colored set of dots next to any parameter. This new mode is purple – one of the many colors of awesome. At the end of all of this, we’ll take a peek at the new widgets – and the UI redesign they offer, but to get started let’s build a use case for bindings so we can get a sense of what they’re good for.

Slider

We’re going to start with a good old fashioned slider. Why a slider?! Well, this is the kind of parameter we end up using all the time, and the fundamental nature of this UI piece should be foundational enough that if we can get a handle on this one, the jump to more abstract ideas should be a little easier.

Let’s get started by first adding a slider from the Op Create dialogue. We’re just going to add a run of the mill slider for now.

adding a slider

From here we’re going to customize our slider – let’s add a page called “Settings” and then a float custom parameter that we call “Slider” for now.

customizing our slider

So far so good. The next step is where it’s gonna get a little weird, and where it’ll get different than before. From here, let’s dive into our slider. We’re going to delete our Panel CHOP, and add our own Constant CHOP.

changing slider internals

Okay. Now here’s the wild part. On our new Constant CHOP we’ll use the new bindings parameter mode to write parent().par.Slider – that’s the reference to our newly created custom parameter.

write our binding expressing directly

If you’re not into that whole writing expressions exercise, you can also do this with a little drag-and-drop action:

drag and drop binding

Okay… so why is this interesting. Well, let’s see what happens when we move our new custom parameter, or move our Constant CHOP:

binding in action

Slick. Okay. That’s fly. So if we update the our parameter or our CHOP both changes are reflected in the other operator. Now let’s make a few final changes so that when we interact with the sliders panel we update both of these values. We can do this with a Panel Execute DAT. Let’s add our DAT and modify the contents with the following:

def onValueChange(panelValue):
     parent().par.Slider = panelValue
     return
adding our panel execute DAT

We should now see that if we move the slider that our Slider parameter updates, and our Constant CHOP updates.

panel and parameter binding

We’re very close now. All we need to do is to update the knob component in our slider. We need to change the expression there to be:

parent().par.Slider*parent().width-me.par.panelw/2
updated panel script

There we have it. Now we can change our custom parameter, our Constant CHOP, or the slider and all three stay in sync. MAGIC.

binding all around

Widgets?

Early on I mentioned that we find this same behavior in Widgets. What exactly are widgets you ask – currently Widgets are rolling out as a huge overhaul to the TUIK interface building kit that was relatively ubiquitous in TouchDesigner networks. Widgets are more modern take on UI building, and offer significant advances to UI building approaches for Touch. There’s too much to cover about widgets here, but it’s worth pointing out that the same binding approach you see above is a fundamental element of the widget system. It allows for bidirectional control of both user interaction elements and parameters – the core principle we just explored. You can dig in and learn a little more about widgets by reading through the article on the Derivative Wiki.

Why Bind…

You might be looking at this and feeling like it’s outside of your wheelhouse, or your workflow.

A reasonable reflection.

Regardless, I’d encourage you to think about the times when you’ve wanted to both control from more than one location – the parameter itself, as well as some other control interface. If nothing else, give them a try to see where they might fit – if they’re no good for you, don’t use them… though I suspect you’ll find they have all sorts of exciting uses.

Happy Programming!