Mapping Touch UI Sliders/Buttons to a Midi Device

I am suffering from an inability to connect the logic between two tutorials. I’ve been following along with Matthew Ragan’s fabulous tutorial series, and since hundreds of others are as well… maybe someone else might have had the same question and solved it.

The Task:

I would like to Map the UI Sliders/Buttons to a Midi Device like the one below for example the “Oxygen 25.”

Specifically, I want to map Sliders that I built in touch (following Matthew Ragan’s tutorial [url]Day 1 - Your First Movie Player 6/6 - YouTube ) that control Invert, Contrast, Hue Offset, Etc. to the knobs, keys, buttons to the above Midi Device.

So I understand this : [url]TouchDesigner | Working with Midi 1/4 - YouTube
which is to say that I understood the idea of mapping out particular Sliders/Buttons in The Midi Device Mapper Dialog to the respective physical dodad on the midi device.

I understand that you can theoretically map out your device once and then in “Local” plop the .tox file into a new project and point the base of the project to the .tox file with all those fine mappings that you just did. So this could save you time using your midi map on various projects.

But!

Now what?
I’m guessing now one would need a way to tell the Midi Mapper sliders/buttons in which you just assigned the proper Midi Channel/Controller that “hey you, s1 are going to control this UI slider— let’s say the “Invert” slider in the Touch Interface.”

I feel that I need another step here because I haven’t connected the UI sliders with the Midi Mapped button/sliders… but how on earth does one do that?

With a table? Or some swanky python script? Or… with a drag and drop that I just could simply not common sense my way upon??

Is it correct to think of this as a circle that needs to be complete?

Thanks in advance for helping me complete my circle!
Very Best, Nesli

Good questions!

Looking specifically at the back and forth between your controller and your UI

This is the kind of principle we’re chasing… it’s an old post, but the idea is we want an outside control to override our UI, and our UI to override our outside control:
matthewragan.com/2014/04/11/osc … hdesigner/

I would probably do this with a script to control panel vals. That gets a little tricksy, but the idea is you’d come up with a correspondence table - maybe the input midi control, and the target ui element, and the val to change (is it u, v, etc). Then write a simple value change script that checks the name of the channel that’s changed, find’s that in the correspondence table, and then changes the target ui element’s target parameter.

You could also organize this with an override CHOP, but those can get a little wonky so I’d practice small before you go big.

I’ll see if I can put together an example tonight - I know those are usually helpful for these kinds of things.

Sorry it’s taken me all day to get an example up here.

This is a small test, so you’ll have to do a bit more leg work to get it up and configured the way you want, but this should give you a good push.

The big idea is that the operator “table_lookup” contains 4 columns:

  • the incoming midi channel
  • the panel element it should target
  • the panel val that should be targeted (u, v, state)
  • if that value should be inverted

A chop execute does all of the leg work of making that happen:

[code]lookup = op( ‘table_lookup’ )

def valueChange(channel, sampleIndex, val, prev):
# general set-up
# on value change we set these variables dynamically
# based on the contents of our lookup table
target_panel = lookup[ channel.name, ‘target_panel’ ].val
panel_val = lookup[ channel.name, ‘val’ ]
invert = lookup[ channel.name, ‘invert’ ]

# check to see if we're working with a slider
if "s" in target_panel:
	
	# check to see if we're targeting a u panel par (horizontal slider)
	if panel_val == "u":
		op( target_panel ).panel.u			= abs( val - invert )

	# if we're targeting a v panel par (vertical slider)
	elif panel_val == "v":
		op( target_panel ).panel.v		 	= abs( val - invert )

# check to see if we're targeting a button
elif "b" in target_panel:

	# check to see if we're targeting state 
	if panel_val == "state":
		op( target_panel ).panel.state		= abs( val - invert )

	# in case you wanted to target something other than state
	else:
		pass

# empty else statement in case there are other possible ui elements
else:
	pass

return[/code]

Our first step is to create a few variables on value change - this uses the name of the channel that’s changed to look up the other target values - if the channel named “s1” has changed we know that we want to look at that row in the lookup table. Next we grab all of the other elements we need - the target panel element, the panel val we want to update, and if we want that value to be inverted.

Next we have a few branches to ensure that we perform the right operations - for example if “s” is int he channel name we know we have a slider. If we have a slider we’ll probably want to change either u or v depending on if the slider is horizontal or vertical. Next we can take the absolute value of the channel val less our invert amount to determine if we flip invert the behavior of our slider. That’s a little goofy, but check it out - if the invert value is 0, nothing changes. If the invert value is 1 our we subtract our value from one, which would be a negative number - but if we take the absolute value of that operation we get a positive value. That means that decreasing vals now have a rising slope, and increasing vals now have a falling slope. If that’s a little wonky for you, try it out with a math CHOP and a tail to see it in action.

Because this script changes the panel vals of the ui elements, our TD panel will update with the changes from our controller - but we’ll also still be able to use our TD panel to make changes. It’s the best of both worlds.

Finally, the select CHOP that’s after the container1 COMP would be the CHOP you’d want to use to drive any changes in your network.

Hopefully that makes sense. :slight_smile:
base_midi_to_ui_example.tox (2.58 KB)

1 Like

Wow!! Thanks for the incredible response Matthew Ragan.

I didn’t have luck with the “Your First Movie Player” tutorial example, I will go back to it and try to figure out where I went wrong. Meanwhile, I switched examples and tried to simplify it as much as I could. I used “Your First VJ Mixer.” [url]Day 2 Your First VJ Mixer 1/14 - YouTube Since there is only one slider in question in that Tutorial… maybe, I thought, that would be a better jumping off point?


VJMixer_Midi_Testing.3.toe (10.4 KB)container_deck_ctrl1.tox (3.24 KB)

Nice work! This is very close to what you’re after.

In your table_lookup try this - change “container1/slider1” to just “slider1”.

In that lookup table, the target_panel column represents the path to the target panel element. In your case, since the chop execute and the slider are in the same part of the network you don’t need any more than this.

Hope that helps!

It did help thank you! However, I tried to do it over again, this time with a different midi control called Hercules DJ Control Instinct and now it doesn’t work. I’m overlooking something for sure, I just can’t tell what! Thank you tremendously in advanced for anyone that posts a reply here! You have no idea how appreciative I am. Thank you!

[url]Slider to Midi Mapping - YouTube
HerculesDJControlInstinct_midiBase.tox (2.08 KB)
SecondTry_container_deck_ctrl.tox (2.84 KB)

Hey Nesli,

The issue is really coming from line 10:

lookup = op( 'table_lookup' )

The look-up table in your sample tox is called “table1” rather than “table_lookup”.

If you change the name of the table, or the execute it should work as expected. Hope that helps!

You are so wonderful, you have no idea. Thank you sincerely for your help! Respectfully, Nesli

Hi! I’ve been working on the same VJ set-up and I am running into similar MIDI mapping issues, connecting the dots between Matthew’s great tutorials (thank you so much for them!) I am new to TD and coding in general but here’s what I have so far…

FIG.1


UI in performance mode. (Ctrl and FX only affect final output).

FIG.2


Midi module mapped to Novation LaunchControl. Buttons/sliders respond as they should. Using Matthew’s example tox, I managed to map a device slider to the Volume (gain) UI slider and it works! So far, so good!

I then tried applying this example to other parts of my network but without much luck…

FIG.3


How do I apply this method to a slider with a replicator?
Eg. the CTRL panel housing brightness, contrast and opacity sliders. My table’s target_panel values are wrong… how do I reference a replicator’s items (1-3) in the look-up table?

FIG.4


I tried applying this method to the same example as Nesli (ctrl deck, slider, 2 buttons) and didn’t have much luck either…
A/B Buttons
I can click the A/B buttons with the device buttons and see on/off value changes but the slider doesn’t move from deck to deck (as it does when mouse-clicked).
Slider
I can move the slider with the assigned device knob but it doesn’t actually cross-fade the clips. BUT if I mouse-click once on the slider first, and THEN use the midi knob, it works as it should! Odd…

FIG.5


Input Switch - Live In/Audio Input -
Here the device buttons toggle both UI buttons on and off as they should but… if I press Button 2 (audio file in), for example, I hear no audio. (they work fine with mouse clicks). I also tried using Overwrite and Select chops on the Switch but with limited success.

Any help would be very much appreciated, thank you… :slight_smile: