# Continuous MIDI Encoders to increase and decrease a value

Hi all,

So I’m stumped.

I have an Ableton Push Mk1 and the encoders are continuous.

I need to convert these values to integers within a range so that if CC value is between 1 and I think 7 it will increase by that many and if it’s 127 to 120 then it will decrease by the difference between 127 and 120.

I have the values in chops or dats whatever works more efficiently I think dats but I’m not sure where to start the maths, in what type of dat to write it in python etc.

Inevitably I imagine a constant chop to drive a slider in a fixed range

Ok I’ve made some progress of course and i’m almost done.

I can’t work out how to extract the row number of the table that my datexecute op provides in the cells variable:

Here’s my code
EDIT: I’ve made my code simpler and it works perfectly with tab[0,0] = cells[0] I just need the location to be dynamic

``````def onCellChange(dat, cells, prev):
print (dat)
print (cells)
print (prev)
tab = op('table1')
loc = cells[0][1]
print(loc)
if cells[0] < 8:
tab[loc,0] = cells[0]
pass
else:
if cells[0]>119:
tab[loc,0] = cells[0]-127
pass
return
``````

In the image below you can see this and the texport which gives me this from a single signal:

``` /project1/mainWords/controls/selectValues [type:Cell cell:(0, 0) owner:/project1/mainWords/controls/selectValues value:2] ['1'] Traceback (most recent call last): File "/project1/mainWords/controls/datexec1", line 6, in onCellChange TypeError: list indices must be integers or slices, not tuple```

So loc = cells[0,1][1] this is my bain.

print (cells) can be seen above to give this:

``[type:Cell cell:(0, 0) owner:/project1/mainWords/controls/selectValues value:2]``

[… cell:(0, 0)…] is the bit I want and is obviously the tuple, but really I only want the 1st number as the column will always be 0. So if you look in my code you will see I have tab[loc,0] = -2 where loc is the number i want.

I’ve tried a lot of syntax variations and I can’t seem to split this tuple and get it to cast to an int.

Thanks again

Robbie

Hey Robbie,

The DAT execute can be a real brain buster. I never know how much python a person has experience with, so please excuse me if any of the below feels too explicit.

The value of ‘cells’ is actual a list of all of the cell objects that have changed. In your case you might find inconsistent results if you’re not careful. Take a look at this example:

base_dat_execute.tox (2.51 KB)

Notice that you can use a toggle to print either the results from noise 1 changing, or from table 1 changing.

Noise1 one has several values that change at a regular interval. You’ll notice that more than just printing the value of cells we need to run a for loop over the list of values:

[code]def onCellChange(dat, cells, prev):
print_string = “the cell row is {row}, the cell col is {col}, the cell val is {val}”

``````print("Noise 1 Changing")
print("- "*10)

for each_cell in cells:
formatted_str = print_string.format(row=each_cell.row, col=each_cell.col, val=each_cell.val)
print(formatted_str)

return[/code]
``````

This will return a result like:

[code]Noise 1 Changing

the cell row is 0, the cell col is 0, the cell val is -0.06780897
the cell row is 1, the cell col is 0, the cell val is -0.04219285
the cell row is 2, the cell col is 0, the cell val is -0.02128557[/code]

The result from our for loop tells us which cells have changed, their row and col, as well as the value of the cell.

Compare this to table1. Here a pulse CHOP triggers a script that only updates a single cell at a time, cycling through all cells. This uses nearly an identical script, but our output should look like:

[code]Table 1 Changing

the cell row is 2, the cell col is 0, the cell val is 0.021346164867281914[/code]

Here we only get a single value that’s changed even though there are three cells in the table.

I bring all this up as you want to make sure you know which cell’s values you care about changing when working with a DAT execute - otherwise you can end up with values that change in ways that seem confusing.

Hi Raganmd

Boom winning!

Exactly what was required. Thanks for the explanation!

Full Code to change a continuous MIDI encoder into a ± table below:

```def onCellChange(dat, cells, prev): tab = op('table1') for each_cell in cells: loc = each_cell.row if cells[0] < 8: tab[loc,0] = cells[0] pass else: if cells[0]>119: tab[loc,0] = cells[0]-128 pass return ```

Cool so that’s fine but…

I’m trying to apply the same logic to the constant chop with a datexecute so again I’m using the onCellChange method:

``````def onCellChange(dat, cells, prev):
chop = op('constant1')
loc = "value{row}"
for each_cell in cells:
loca = loc.format(row=each_cell.row)
chop = chop.par.loca
chop = chop + cells[0]
return``````

My problem is that when I try to use loca as the final value it wont work. obviously I need value0-11 here. I tried chop = chop.par.value+loc before when loc = each_cell.row was used so I moved to the formatting method and still no luck.

I also tried to put the “.” inside loca and use chop = chop.par + loca instead, nothing

thanks again

Robbie

So I’ve checked my code a bit and got a single knob to work correctly. The previous didn’t write to the chop so here is value0 hard coded to work:

``````def onCellChange(dat, cells, prev):
chop = op('constant1')
loc = ".value{row}"
for each_cell in cells:
loca = loc.format(row=each_cell.row)
chopValue = chop.par.value0
chopValue = chopValue + cells[0]
chop.par.value0 = chopValue
return``````

Where value0 is needs to be loca like this:

``````def onCellChange(dat, cells, prev):
chop = op('constant1')
loc = "value{row}"
for each_cell in cells:
loca = loc.format(row=each_cell.row)
chopValue = chop.par.loca
chopValue = chopValue + cells[0]
chop.par.loca = chopValue
return``````

Textport error is this:

``````Traceback (most recent call last):
File "/project1/mainWords/controls/datexec2", line 18, in onCellChange
td.AttributeError: 'td.ParCollection' object has no attribute 'loca' Context:/project1/mainWords/controls/constant1``````

Moving forwards

Robbie

Sadly you can’t really target a parameter by constructing it’s name this way:

```def onCellChange(dat, cells, prev): chop = op('constant1') loc = "value{row}"```

Instead you need to use pars(). Take a look at this modified example:

base_dat_execute_change_constant.tox (2.65 KB)

[code]def onCellChange(dat, cells, prev):
print_string = “the cell row is {row}, the cell col is {col}, the cell val is {val}”
target_constant = op(‘constant1’)

``````print("Noise 1 Changing")
print("- "*10)

for each_cell in cells:
formatted_str = print_string.format(row=each_cell.row, col=each_cell.col, val=each_cell.val)
print(formatted_str)

unformatted_par = "value{}"
target_constant.pars(unformatted_par.format(each_cell.row))[0].val = each_cell.val

return[/code]
``````

I think what you’re after is here:

``target_constant.pars(unformatted_par.format(each_cell.row))[0].val = each_cell.val``

docs.derivative.ca/index.php?title=OP_Class

pars() will return a list of parameters that match your provided string, you need to grab the first parameter in that list, and change it’s value to be the val from your changed cell.

Hope that helps!

Ok not quite,

I need to get the current value of the chop channel and then + each_cell.val so positive numbers increase and negatives decrease the chops channel.

this:

``````def onCellChange(dat, cells, prev):
chop = op('constant1')
loc = "value{}"
for each_cell in cells:
chop.pars(loc.format(each_cell.row))[0].val = each_cell.val
return``````

will only pass the value through.

In fact I did it. See below:

``````def onCellChange(dat, cells, prev):
chop = op('constant1')
loc = "value{}"
for each_cell in cells:
original = chop.pars(loc.format(each_cell.row))[0].val
chop.pars(loc.format(each_cell.row))[0].val = original + int(each_cell.val)
print(original)
return``````

yep - so you’d want to find the old value, add it to the new value, then set the CHOP to the new val. Something like:

[code]
def onCellChange(dat, cells, prev):
print_string = “previous val {pval} + incomming value {ival} = updated val {uval}”
target_constant = op(‘constant1’)

``````print("Noise 1 Changing")
print("- "*10)

for each_cell in cells:

unformatted_par = "value{}"
old_val = target_constant.pars(unformatted_par.format(each_cell.row))[0].val
new_val = old_val + float(each_cell.val)

target_constant.pars(unformatted_par.format(each_cell.row))[0].val = new_val

print(print_string.format(pval= old_val, ival= each_cell.val, uval=new_val))

return[/code]
``````

If you watch the textport this should give you some hints as to what’s going on in the script.