Get synchronous behavior from API

Post Reply New Topic
RELATED
PRODUCTS

Post

Some digging led me to the fact that Bitwig executes the script commands on multiple threads, which leads to the condition where values or callbacks are not updated on time for next task to execute properly. Is there any way to force synchronous behavior on API, for some block of code? I don't know much about concurrency in java, and with some googling I tried marking the code synchronous, but to no avail. I also tried using atomic variables as mentioned in a comment in this thread, with no success. Any pointers will be highly appreciated.

Post

Simple answer: no, don't do it.

Bitwig is highly optimized to always have audio playing without any dropouts no matter what the user does. Therefore, the API is only updated "when there is time". This means you need to deal with this fact in your code. Furthermore, you should also return as fast as possible from your code calls in flush(), synchronizing or blocking is really bad in this case.

Multi-threading is a tough topic but it is much easier nowadays in Java. Nevertheless, if you have no idea about it, just don't do it. I also touched the topic in my Youtube series in one episode.

What are you trying to achieve?

Post

Thanks for the reply moss, and excuse me for the late reply, I really wanted to make sure I'm not making any wrong assumptions.
moss wrote: Mon May 22, 2023 9:20 am This means you need to deal with this fact in your code
I really should've worded it that way, how to account for such behaviour.

Without getting into specifics of my half assed code, I was trying to make selected track move up or down with button presses:

Code: Select all

cursorTrack.selectNext();
if (cursorTrack.hasNext().get()) {
//move tracks
}
hasNext value was not getting updated in time before calling it, which lead to unwanted behaviour.

Although now I've done a much simpler implementation, which works without any shenenigans, is there any way to account for such delay, apart from host.scheduleTask(), whose delay time might get insufficient as project becomes more cpu demanding?

Post

PriyanshuKumar wrote: Tue May 23, 2023 12:52 pm Thanks for the reply moss, and excuse me for the late reply, I really wanted to make sure I'm not making any wrong assumptions.
moss wrote: Mon May 22, 2023 9:20 am This means you need to deal with this fact in your code
I really should've worded it that way, how to account for such behaviour.

Without getting into specifics of my half assed code, I was trying to make selected track move up or down with button presses:

Code: Select all

cursorTrack.selectNext();
if (cursorTrack.hasNext().get()) {
//move tracks
}
hasNext value was not getting updated in time before calling it, which lead to unwanted behaviour.

Although now I've done a much simpler implementation, which works without any shenenigans, is there any way to account for such delay, apart from host.scheduleTask(), whose delay time might get insufficient as project becomes more cpu demanding?
There are some rare occasions where you need this and then host.scheduleTask() is sadly the only way.

Post

PriyanshuKumar wrote: Tue May 23, 2023 12:52 pm Although now I've done a much simpler implementation, which works without any shenenigans, is there any way to account for such delay, apart from host.scheduleTask(), whose delay time might get insufficient as project becomes more cpu demanding?
Two more cents: in some cases there will be an observable value that tells you when it changes if you attach an observer (e.g. the cursor track position), so that's a way to get an asynchronous reply from the app. Although depending on what you're doing I wouldn't trust that that all the values update simultaneously, so I'd still be adding a delay and hoping it's long enough.

With the API most things can be written in a way that doesn't rely on synchrony. What are you trying to achieve?

Post

I was trying to replicate the multiple selection feature in bitwig (select multiple consecutive tracks). If I store the references of the selected tracks from trackBank.getItemAt(i), the references point to different tracks the instance the TrackBank scrolls pages (or when you move tracks). Afaik, there is no way to get a track reference by itself, and though there are some pointers in this thread, they do not yield usable tracks.

I tried using a arbitrarily huge TrackBank (like of size 32), so the track positions are (for less than 32 tracks) equal to their bank indices, and then tried storing their raw positions, updating them when adding/removing a track from selection, or when moving tracks. This way I can access the tracks though the hugeTrackBank.getItemAt(i), and be confident that the tracks are same, since the hugeTrackBank won't scroll (as long as I don't create 32+ tracks).

The rough implementation for updating these positions was something along the lines of, moving the cursor to next or previous, and then noting its position (and hence avoiding out of index problems, since the cursor wont move out of index). For this I did try your idea of attaching an observer, and putting the entire code in the observer with a condition as a flag.

In the end though, I ended up manually adding/removing/incrementing/decrementing track positions, than using any API object (hence avoiding any async troubles), and it ended up working successfully. :tu:

Post Reply

Return to “Controller Scripting”