VDJPedia

Ingresar:     



 VDJScript_2026_tutorial_pt3

Bracketed Thread Concurrency & Scope



We've seen brackets used to contain queries, yes||no replies into a separate script thread, and we've seen brackets used to contain the implicit, a created implicit only lives as long as the thread lives.

There remains a question

Are threads concurrent?

Are threads concurrent they both run at exactly the same time or are threads performed in left to right order? Let's answer that.

set a 1 & ( set a +1 ) & set a +1 & set b `get_var a`

If the were concurrent the bit inside the brackets would see that 'a' is equal to 1 and add 1 and save to 'a'
And the bit after the brackets would also see that 'a' is equal to 1 because they both would have got there at the same time [a race condition]
We can var_list to inspect b and we see it is == 3

So scripts are acted on in a left to right order, even bracketed script threads.

However consider this
set a 1 & ( wait 500ms & set a +1 ) & set a +2 & set a `get_var a & param_multiply 2`


we have applied a wait at the start of the bracketed thread, now there's a question, if scripts are applied left to right what happens?
Is it
a 1 + 1 + 2, set a `a * 2` var a finally == 8
or is it
a 1 + 2, set a `a * 2` [ and just the bracket bit waits] a + 1 var a finally == 7

it's the second case,
var 'a' will == 7,
if inside a thread and the script engine is told to wait it will go off do any other task it can do outside the script thread if the logic allows it.

Scripts like this can be error prone and used wrong can lead to race conditions but can have uses when used correctly, here is an example of correct use.

( quantize_setcue on ? : quantize_setcue on & wait 200ms & quantize_setcue off) & has_cue 1 ? goto_cue 1 & set_cue 1 & has_cue 2 ? goto_cue 2 & set_cue 2 & has_cue 3 ? goto_cue 3 & set_cue 3


Say if I notice my first 3 cues are fractionally off beat and I want to correct them,
in a bracket thread, I check if quantize_setcue is on ? if it is - all good, I terminate the bracket thread with an empty reply : if quantize_setcue is off, turn it on and then apply a wait, we'll come back to this in a moment.
the script engine now jumps out the bracket thread, checks if cue 1 exists, goes to the cue position, Sets the cue again but because quantize_setcue is now on, the cue will be on beat, this is near enough instant, it's so fast I don't know how [or really want to] to measure it.
So back to the wait, we got here by quantize_setcue being queried as off, so we best turn it off again.

This is a reasonably safe use of applying a wait in a bracketed thread


Brackets can also contain a deck specifier
Imagine we're on deck 2
play & ( set_deck `get_deck & param_invert & param_add 3` & set a 10 ) & set a 5

specified deck for a deck 2 button is deck 2 by default, inside the brackets we use set_deck which allows us to specify a deck by script query. the query we do some maths to get the number 1 if calling deck is 2, and or the number 2 if calling deck is 1,
follow the maths, get_deck will return an of the deck specified at that time as an int,
int fed into param invert becomes the negative of that number, then we then add 3
if calling deck is 2, becomes -2 + 3 = 1
if calling deck is 1, becomes -1 + 3 = 2

this has made the other deck the specified deck (not the original calling deck) only inside the brackets, then we make a local variable == 10, then jumping out the brackets and setting the local variable to 5
and you can check var_list deck 1 var a == 10 , deck 2 var a == 5
we swapped the specified deck only in the brackets


Brackets to contain deck all

I've said it before and it's worth saying again, deck all used incorrectly is dangerous. And I've seen it used very dangerously.
I'm going to show you why
imagine a 4 deck set up

set $a 0 & deck all set $a +1

obviously all 4 decks will each increment var $a by 1

var $a will == 4
further proving that threads are not concurrent.

Now consider this, bad use of deck all
set $a 0 & deck all set $a +1 & deck all set $a +1

var $a will now == 20
the first deck all will create 4 threads and add 1 for each thread to var $a, these second deck all will create more 4 threads for each of the first 4 threads so we will add 1 to var $a 16 more times.

Whenever you're about to call deck all always always open bracket containment first, and if you're going to call another deck while in containment for a deck all is open, close the containment first.

set $a 0 & deck all set $a +1 & deck all set $a +1
for the usual intention with this bad script here (increment $a twice per deck
ideal would be this
set $a 0 & ( deck all set $a +2 )

not as neat but good enough would be this
set $a 0 & ( deck all set $a +1 & set $a +1 )

not sure why you want to spec deck all twice like this but still safe
set $a 0 & ( deck all set $a +1) & ( deck all set $a +1 )



RSIs vdj's equivalent of the forLoop(;;)
repeat_start
repeat_start_instant

params for these two verbs
repeat_start MANDATORY_NAME, MANDATORY_REPEAT_LENGTH (can be ms, bt, or result from `action query`), OPTIONAL_MAX_REPEAT_COUNT (this can be a number or a number via action)

repeat_start_instant MANDATORY_NAME, MANDATORY_REPEAT_LENGTH (can be ms, bt, or result from `action query`), OPTIONAL_MAX_REPEAT_COUNT (this can be a number or a number via action)



if no value or zero or < 0 is used as repeat count the RSI will repeat forever or until stopped by a repeat_stop call )

repeat_stop
the only param is
repeat_stop MANDATORY_NAME


the only difference between repeat_start instant & repeat_start is; repeat_start will wait one repeat size duration before acting of further scripts.

A hypothetical now, you have a want a button to call a rsi, that rsi will repeat every 15 seconds, the thing it is repeating is call a sample, wait for a few seconds for the sample to complete and have another sample play, wait for a few seconds for the sample to complete and have another sample play . And you know none of your samples are longer than 4 seconds.
[hypothetical, this all can be checked, figuring that out isn't the topic here]
You also want this button to stop the rsi if it is running

you might think this, but it's wrong

repeat_start_instant rsiName ? repeat_stop rsiName : repeat_start_instant rsiName 15000ms 0 & sampler_play 1 & wait 4000ms & sampler_play 2 & wait 4000ms & sampler_play 3

seems ok... query if rsi is running, if yes stop it, if no create rsi and give it some stuff to do, press the button, and it runs.

No not ok, Problem, try stop the rsi while sample 1 is playing, it won't stop until it has completed the whole repeat sequence it is in. the call to repeat_stop only stops another repeat from happening, not what it was currently doing.


var sampleRpt 1 ? set sampleRpt 0 & repeat_stop rsiName & sampler_stop all : set sampleRpt 1 & repeat_start_instant rsiName 15000ms 0 & sampler_play 1 & var sampleRpt 1 ? wait 4000ms & var sampleRpt 1 ? & sampler_play 2 & var sampleRpt 1 ? wait 4000ms & var sampleRpt 1 ? sampler_play 3 : : : : 


A working way to fix this problem, have the button set a variable, then query the variable to start/stop the RSI, also query the variable before and after any wait, if the query is false before a wait then the repeat will terminate right away to a no reply to nothing a [blank reply] and the repeat is finished, if you switch the variable to off during a wait, the wait completes the the var is queried again as false and the repeat terminates.

Based on real world case study.

Repeat_start scripts have a speed limit, it's around 33ms.

Common convention is if you want as fast as possible, just use 25ms, it will never achieve 25ms. Using 1ms just shows other people you have no idea how it works.

The timing of short repeats is fuzzy, for a 50ms repeat duration it may be 48ms, it maybe 52ms, it maybe 50ms. Errors mostly even out, for longer repeat lengths like 1bt [which would be 100s of ms] timing is more accurate but still can be fuzzy [say you initialise a huge VST ms before a repeat was due]

RSIs are deck dependent, several decks can have a RSI with the same name running at the same time, therefore repeat_stops are also deck dependant


If a RSI is wrote in open script [not separated into a thread] there is no escaping from the logic of the RSI, either the script complete its specified number of repeats or it completes the task it was doing and it [hopefully] stops itself. Either way the script will terminate.

For a RSI to run an action when either a condition is met or at the end of the final repeat if condition not met is up to you, you could use a variable as a counter here's an example

level 0.4 & set counter 0 & repeat_start name 100ms 50 & ( set counter +1 & level -0.01 & level 0.0 ? set counter 50 : ) & var counter 50 ? repeat_stop name & last bit of script : 



Specified deck will be the same on every repeat as the first call
deck 1 repeat_start_instant name 33ms 50 & cycle a 50 & set_deck `constant 2`

var a local to deck 1 will be the only thing touched here.

Especially cursed RSI script
With wait in rsi scripts you can do some especially cursed things
[I have this saved as 'CURSED' on a custom_button just to remind me of the horror]

set cursedX 0 & set cursedW 0 & set cursedZ 0 & repeat_start 'cursed' 25ms -1 & var cursedW 0 ? cycle cursedX 200 & var cursedX 100 ? set cursedW 1 & wait
3000ms & set cursedW 0 : : cycle cursedZ 200

yes that's a 25ms rsi with a wait 3000ms
it will reach the wait and be ready to start a wait for 3s but 25ms later the next repeat will start, the part after the wait will happen after the 3s as you told it to and will have an effect on the later repeats.


The whole script is a lovely chaotic mess that I hope to never encounter in the real world.
[When I was growing up they said I could be anything I wanted to be, I decided I wanted to be a problem]

cycle
very much like set a +1 but at some desired point the variable Loops round.
cycle MANDATORY_VARNAME MANDATORY_INT (negative or positive)

if given a positive int as the 2nd param,
add 1 once to a variable until it's just about to reach the number given as the 2nd parameter then it will set the variable back to zero

if given a negative int as the 2nd param,
add -1 once to a variable until it's about to reach < zero then it Sets the variable to number given as the 2nd parameter -1

There's actually some funky maths if your int is above you second param or below zero, I haven't found a use for it yet though.


see cycle in action on a custom_button
script
repeat_start_instant name 33ms 200 & cycle a 50
custom_button name
`get_var a

common use for cycle is to move thru a few options