Properties update and Client desync

Hi !

Question 1 : I use OSC{ } or VAR{ } for many widget properties subject to updates. In some cases, I would need to update a widget property with both OSC and VAR functions. Is that possible? If so, what would be the syntax?

Question 2: Let's say I need 2 clients (2 iPads, for instance). Sending and receiving the same OSC messages. However, desynchronized from each other and from a GUI perspective. I tried unsuccessfully the client option "desyncCanvas = 1" but any actions on any client, even not involving OSC messages, remains replicated. Basically if I hit a button or turn a knob on a client which does not involve an OSC message, I'd like this action not to show up on the other clients.

Question 3: Nobody works for free. What is the best way to sponsor you, even with a small amount?

Thanks !

Use VAR and add a script widget as osc receiver that will call setVar().

I tried unsuccessfully the client option "desyncCanvas = 1" but any actions on any client, even not involving OSC messages, remains replicated. Basically if I hit a button or turn a knob on a client which does not involve an OSC message, I'd like this action not to show up on the other clients.

Just in case the synchronization mechanism is explained here, you can prevent it by enabling the bypass property (but then you'll need to use scripting to make it send messages)

What is the best way to sponsor you, even with a small amount?

There is a patreon page here, any amount is welcome :),

There is a patreon page here , any amount is welcome :slight_smile:

Done :ok_hand: To be renewed from time to time :smiley:

Just in case the synchronization mechanism is explained here , you can prevent it by enabling the bypass property (but then you'll need to use scripting to make it send messages)

Perfect ! Just bypassed my navigation buttons and I can now use client devices independently from each other :star_struck: :ok_hand: Bad news is, I will have to invest in more tablets :sweat_smile:

Use VAR and add a script widget as osc receiver that will call setVar().

Not sure I got this one right. Let's say I'd like to update the label of a button, by clicking on it. Then in the Label properties of that button, I'll write for instance VAR{button_label, "Default label"}. In the Scripting/OnValue field : if(value) { setVar('button_id', 'button_label', "ON" } else { setVar('button_id', 'button_label', "OFF"}. Fine.

Now the label could also be updated by an external OSC messages. I cannot use the OSC{} advanced syntax since the label property field is already used by the VAR{} function. So where would you place a script which includes this OSC receiver, and how would it look like?

May sound like a newbie question, but I feel a bit confused :roll_eyes: Thanks !

Thanks a lot !

I'll write for instance VAR{button_label, "Default label"}. In the Scripting/OnValue field : if(value) { setVar('button_id', 'button_label', "ON" } else { setVar('button_id', 'button_label', "OFF"}. Fine.

Note that you can write "this" instead of "button_id" in this case.

Now the label could also be updated by an external OSC messages.

Create a script widget (it's only visible in the project tree), set its addresss property so that it receives the appropriate messages and use its onValue script to call setVar when it does.

Note that you can write "this" instead of "button_id" in this case.

Sure. Most of the time such functions are called from other widgets though.

Create a script widget (it's only visible in the project tree)

Brilliant !! One more thing I missed... These script and variable widgets will be a game changer. Cool stuff ! :star_struck:

Side question: Are there any o-stage-c tutorial repositories available out there? It is always great to see what others did, and I could understand better the full potential of your platform. Also it would limit the amount of messages I post on a daily basis :sweat_smile:

Enjoy the week-end !

I told my friend @BenRio about Open Stage Control and he jumped on it =D

Very interesting the possibility of using widget scripts to manipulate variables. Regarding this, instead of opening a new topic, I thought it wise to piggyback on this one.

Ben helped me write a python script that updates Ableton Live's clip list. This way I can get the name of any Ableton clip. For example: at the address "/clipname_tr0_0" I get the name of the first clip of the first track... And so on.

In my template I use a 4x4 session box (with 16 widgets ranging from clip_/0 to clip_/15).

In addition to a standard button to show the first 4x4 set of clips and tracks, I have "grid down" and "grid up" buttons.

As a starting point, I'll bring only the case of the clip_/0 widget (to later replicate to the others).

I'm trying to change the label property of the clip_/0 widget to toggle it between "/clipname_tr0_0" and "/clipname_tr0_4" in response to the "down grid" and "up grid" buttons.

For that, I have in clip 0:

id: clip_/0
label: @{cl_0_name}

And to make the switch I created the following widget script:

id: cl_0_name
address: /clipname_tr0_0

id: cl_4_name
address: /clipname_tr0_4

In the "down grid" button, I put it in scripting > onValue:

set("cl_0_name", get("cl_4_name"))

When I press "down grid", the widget clip_/0 successfully receives the name of the clip referring to /clipname_tr0_4, but the name lasts only a few milliseconds and returns the name of /clipname_tr0_0.

I have the impression that it is something very simple to do (without the need to write a module). I've tried other combinations with set, setVar... but I also got it wrong. I wonder if @jean-emmanuel has any suggestions.

I suspect this fails because cl_0_name keeps receiving /clipname_tr0_0. You could do it like so:

id: clip_/0
label: VAR{name}

id: cl_0_name
address: /clipname_tr0_0

id: cl_4_name
address: /clipname_tr0_4

# grid down onValue
setVar('clip_/0', 'name', get('cl_4_name'))

@rimasinc once you will resolve your problem, it would be kind to share a working session file to help one day maybe the others.
Cheers

Hello Jean! Thanks a lot for the guidance. I'm getting the visual feedback when I press "down grid" and "up grid".

However, I see that I need to figure out a way to assign the OSC listener of "clip_/0" to act dynamically. The variables work great, but the update with the name of the clip (which can be an existing clip, or a newly created one, or a recorded one, or even the empty slot - when deleted) only happens when I press:

# grid down onValue
setVar('clip_/0', 'name', get('cl_0_name')
or
# grid up onValue
setVar('clip_/0', 'name', get('cl_4_name')

The python script works perfectly by looping updating the different states the clip can have by constantly sending messages to /clipname_tr0_0 and /clipname_tr0_4.

I tried using it on clip_/0:

id: clip_/0
label: VAR{cl_0_name, cl_4_name}
# VAR{variableName, default}

But this returns the problem from the previous message.

I didn't use OSC{address, default) because I believe it doesn't apply to variables.

Thanking you again, I ask: do you have any other suggestions?

Certainly! I'm starting to refactor all the code, which is currently all done in ClyphX Pro (I'll upgrade to Python). So this is going to take a while. However, here I do a demo of the first version TOCA Osc & Midi for Ableton - Open Stage Control + ClyphX Pro - By Clécio Rimas (aka Rimas Inc) - YouTube

1 Like

I was specially talking about the topic of this post not the whole software you made (by the way congratulations !)

Ah yes! Certainly. I've been trying to discover this magic for a few days haha.

I also tried this increment, but it doesn't work.

id: clip_/0
label: JS{{
var nameOsc = VAR{name};
if (nameOsc.includes("slots[0")) {
nameOsc = 'OSC{/clipname_tr0_0}';
} else if (nameOsc.includes("slots[4")) {
nameOsc = 'OSC{/clipname_tr0_4}';
} else {
return nameOsc;
}
}}

This way, when I press:

# grid down button
setVar('clip_/0', 'name', get('cl_4_name'))
  # result: clip slot 4 name appears correctly.

And

# grid up button
setVar('clip_/1', 'name', get('cl_0_name'))
# result: clip slot name 0 appears, takes a few milliseconds, 
# then goes back to displaying clip slot 4 name

I added "includes(slots[0)" and "includes("slots[4")" because this is how Python sends them:

song.tracks[0].clip_slots[0].clip.name
song.tracks[0].clip_slots[4].clip.name