Working with CHOPs in Python

From TouchDesigner 099 Wiki

The main documentation for the methods and classes you use to work with CHOPs are the CHOP Class and Channel Class articles. This article gives examples of using those methods and classes.

Getting Started

The main class type describing any Operator is the base OP Class. You will need a reference to one of these to do anything. There are two global operator objects are always available (except for in the Textport):

  • me refers to the operator that is currently being evaluated or executed. For example, when executing a script, me refers to the containing DAT. When evaluating an expression, me refers to the containing operator.
  • root refers to the top level component /.

To get references to other OPs (for example, a node named 'wave1' sitting next to the node 'constant1') the most common functions to use are: op() and ops(), for example op('wave1').

op() returns a single OP object, while ops returns a (possibly empty) list of OPs. They are described in td Module.

These functions search for operators from the current component, so both relative and absolute paths are supported. The current component is defined as: The OP that me is inside.

Note that the OP Class itself, also contains an op() and ops() method. In this case, nodes are searched from the OP.

For example: me.op('..') will always return its own parent, while op('..') will return the parent of the current component.

If you are typing a python expression in a parameter of a node 'constant1', and you wish to get a reference to 'wave1', you would type

 op('wave1')

If you are in a script you can assign this reference to a variable for easier repeated access.

 n = op('wave1')

In this case op() will search relative to the DAT that is executing the script.

An OP also has a parent() method that can be use to get the parent COMP of it.

 me.parent()

If you are putting a Python statement in a parameter of a COMP and want to refer to a child of that COMP, you can use the op() method for the OP, which is available as me in the parameters.

 me.op('achildnode')

TIP: To find out quickly what members and methods you have access to for any node, select that node and on its parameter dialog, click the Python Help icon. You will go the wiki for the python classes for that node. There you can find out what info you can get about a node, and what methods are available for it. The documentation can also be arrived at by right clicking on the node and selecting "Python Help..." from the menu.



Refer to Working with OPs in Python for more details about this seciton.

Using CHOPs in scripts

To use a CHOP in a script you would first get a reference to the CHOP(s) you are interested in using op(). Ideally this would be assigned to a variable which you can use multiple times in the script without having to re-search for the OP every time you need it. Then you can use the []s on the CHOP reference to refer to a specific channel. You can either use a channel name like this ['chan1'] or a channel index [0] to refer to a channel. For example this script gets the channel named 'chan1' from one CHOP, and the first channel of another CHOP, and adds them together.

 # get a reference to a CHOP named 'wave1'
 n1 = op('wave1')
 # get a reference to a CHOP named 'wave2'
 n2 = op('wave2') 
 
# now get references to the two channels we are interested in c1 = n1['chan1'] c2 = n2[0]
# add them together. This will add the values at the current time, not all the samples in the channels total = c1 + c2

To do an operation on every sample in a channel, you can use the [] operator on the channel. For example this script will add up all the samples in a channel:

 # get a reference to a CHOP named 'wave1'
 n = op('wave1')
 
total = 0 numSamps = n.numSamples c = n['chan1'] for i in range(0, numSamps): total = total + c[i]

Alternatively, you can use the channels vals member, which is a list of all its values:

 for v in c.vals:
   total = total + v

or more simply, using the builtin sum() expression:

  total = sum(c.vals)

You can also get references to channels using the chan() method (which is just another form of the [] operator, but with searching capabilities) or the chans() method. The chans() allows you to get a list channels from a CHOP. If no argument are given to chans() then a list of all channels in the CHOP are returned.

For example this should get a reference to a CHOP, then adds up all of the channels in it.

 # get a reference to a CHOP named 'wave1'
 n = op('wave1')
 # start our total at 0
 total = 0
 
# for each channel in the CHOP for c in n.chans(): # c is an instance of the Channel Class, and all the methods/members of that class can be used on it # add the channel's current value to the running total total = total + c print(total)

To print the name of every channel in a CHOP you can do this:

 # get a reference to 'wave1'
 n = op('wave1')
 # start our total at 0
 total = 0
 
# for each channel in the CHOP for c in n.chans(): # c is an instance of the Channel Class, and all the methods/members of that class can be used on it print(c.name)

To get a list of all the channels that start with 't' in a CHOP, you can simply do

 # get a reference to 'wave1'
 n = op('wave1')
 ts = n.chans('t*')

Casting Channels to a Value

The Channel Class implements all necessary methods to be treated as a number, which in this case evaluates its current value. Therefore, an explicit call to eval() is unnecessary when used in a parameter, or in a numeric expression.

For example, the following are equivalent in a parameter:

 (float)n['chan1']
 n['chan1'].eval()

The following are also equivalent, because the + 1 will implicitly cast the channel to a number:

 n['chan1'].eval() + 1
 n['chan1'] + 1


Using CHOPs in parameters

To reference a CHOP value in a parameter you first need to get a reference to the CHOP, and then use the CHOP Class to do something with that CHOP such as get a sample from one of its channels.

For example, this would get the current sample from the channel named 'chan1' from the CHOP named 'wave1', which is in the same network as the node whose parameters we are typing in

 op('wave1')['chan1']

We can also reference a CHOP by its channel index like this:

 op('wave1')[1] # gets the 2nd channel in the CHOP

You can get other information about the CHOP also, such as the number of channels

 op('wave1').numChans

Or the name of the 3rd channel

 op('wave1')[2].name

TScript Equivalents

For Tscript users, here are some equivalent statements to help you get started in Python.


Expressions

Python TScript
Evaluate channel chan1 at the current frame op('wave1')['chan1'].eval()
or if in parameter, simply:
op('wave1')['chan1']
chop("wave1:chan1")
Get sample 8 of channel chan1 op('wave1')['chan1'].eval(8) chopi("wave1:chan1", 8)
Get the number of CHOP Channels op('wave1').numChans chopn("wave1")
Get the CHOP length op('wave1').numSamples chopl("wave1")
Get the third sample from the first channel op('wave1')[0][2] chopc("wave1", 0, 2)
Get the name of the 2nd channel op('wave1')[1].name chopname("wave1", 1)
Get the channel index of channel chan1 op('wave1')['chan1'].index chopindex("wave1:chan1")