Teleport - Strangest discovery of Rack VST so far....

Ah ok. I didn’t mean a Java style garbage collection, more if the DAW gets to free things up itself on deletion, but from what you are saying it sounds like the plugins really are completely self contained so that’s reassuring,

Hi, dev of LittleUtils here!

To be honest, I didn’t expect Teleport to work across VST Instances! It’s kind of cool but also scary at the same time. The list of existing inputs is stored in a static std::map<string, TeleportIn*> that is shared by all Teleport Input and Output module instances, I guess even across threads.

It feels like it’s a bit of a coincidence or implementation detail that all VST instances are running in the same process, so I wouldn’t rely it in my patches.

I’m a bit surprised that Teleport works at all with multiple threads without crashing or glitching, because there isn’t really any sort of cross-thread synchronization. Let me know if you encounter any problems.

5 Likes

It’s amazing stuff haha - I’ve had an instance running on and off all afternoon/evening that has no clock in at all - all clocks are teleported from another instance and it’s been solid so far.

Maybe you could have 2 options in the right click menu: Teleport (this universe) and Quantum Teleport (other universes) :slight_smile:

I’ll keep playing with it and give it a proper workout and let you know if any issues. This is my clock setup that Teleport makes possible - you can see its getting a good workout.

2 Likes

Yes, probably a right-click menu like this would be the right UI to do it. I suspect that actually having the “local” option would be more difficult to implement than the global one, but maybe I’ll look into it at some point.

I don’t really understand your post.

If Teleports are sharing a global map in a way that isn’t thread-safe, people are already running into that with v1. v2 and VST aren’t bringing anything new to the table.

Also, it’s not a coincidence that all the VST are running in the same process, it’s the default way VSTs run in all programs, afaik. Yes, you can force them into their own process on Reaper, and perhaps some others… well, if users do, then they can’t use this feature.

Ah yes that rings a bell. Bitwig runs every plugin in its own sandbox by default IIRC so a plugin crash shouldn’t crash the DAW. Most DAWs with that feature permit turning it off though.

1 Like

You are right, thread safety problems that cause a segfault would have probably surfaced by now. std::map should be thread safe from what I understand.

I’m still not entirely convinced that audio glitching is not possible. Say a teleport input is in thread A and teleport output is in thread B. If now the threads happen to execute the process() functions in the order ABBA, the output would read the same value from the map twice in a row. But I haven’t come across this myself and I haven’t heard anyone complaining about it either.

Related to the VST - I guess Bitwig is a good example of implementation specific behavior (or is the sandboxing still done inside a single process?). Who knows if all DAWs start doing something similar in 5 years.

Yes, bitwig is like reaper, as far as I can determine. One can optionally sandbox plugins in a separate process.

Obviously the decision is yours to make. If it were mine (and it isn’t), I would choose to ignore the sandboxing issue. And anyway, the worst case is that some cool (undocumented) feature stops working. In five year??

Clearly you can try to find a solution that will work on all three OS’s and has a chance of working five years from now. It seems awfully difficult.

From Bitwig

32-bit and 64-bit plug-ins (VST2.4 and VST3) are natively supported, no third-party bridging necessary.

Here are the 5 modes explained:

Within Bitwig. Plug-ins are loaded along with the audio engine. This requires the least memory, but any single plug-in can crash all audio.

Together. Plug-ins are sandboxed together, separating them from the audio engine.

By manufacturer. Individual sandboxes are created for each plug-in manufacturer. (This can be necessary when plug-ins need to communicate with one another.)

By plug-in. Individual sandboxes are created for each plug-in used. When a plug-in is used multiple times, its instances are sandboxed together, sometimes reducing the required memory.

Individually. Individual sandboxes are created for each plug-in used. This is the most memory-intensive option, but the safest.

1 Like

Yeah, I will leave the behavior as it is for now.

I would like my software to work in five years. It’s already almost three years old with fairly minor changes when it was ported to v1. Maybe I’m weird but I sometimes like to open up old Ableton project files from five or more years ago and they work fine. I’d hope to have the same with VCV Rack, and I try to make my plugins in such a way.

3 Likes

Not just clocks…

1 Like

:exploding_head:
totally forgot about this discovery that you made,
I gotta try some freaky stuff with it haha

Does this work in Bitwig with:

  • Individually-hosted VCV instances?
  • Per-manufacturer/Per-plugin hosted VCV instances?
1 Like

Mine is set up as per manufacturer and it works with that. Don’t really want to change that setting right now so can’t say for sure as to the other options.

If I had to guess I would say it would work for Per Plugin (as multiple instances of same plugin are sandboxed together), but not for individually hosted (as the instances would be in different sandboxes).

But hey - we’re talking Teleportation! who’s to say the walls of a mere box will stand in the way? You might need a sandbox with quantum shielding or something like that…

1 Like

No, that’s fine, that’s good enough to know…

I’m going to assume that if Rack instances are individually hosted then it won’t…

That’s how I have mine set at the moment - as I like to restrict core affinity and farm out certain plugins to groups of cores using Process Lasso.

But until Rack VST has access to more than 1 CPU thread, there’s not much point in doing that, to be fair - so I’ll probably change Rack to the Bitwig default

Can’t wait for the full release of this module!!

I am waiting patiently as well. This will hopefully be the solution to route one patch to different midi-channels in Ableton.

I just did a quick test on this which suggests it would work. (I’m in Bitwig but principle should hopefully work in Live).

In first Rack instance, I had a NoteSeq 16 sending V/Oct and Gate out by Teleport

In second instance I had Teleport receiving the V/Oct and Gate and connected those Teleport outputs to CV > Midi

On a third track I had Serum set up to receive midi from the second Rack instance. Serum seems to be playing things in tune and in time.

1 Like

interesting this came up in another topic

I had a quick look at the code and I say it is not thread-safe…

first I should say, its common for threading bugs to lurk for really long periods of time, and not cause any issue - simply because they require certain pre-conditions to be triggered, and also often very ‘unfortunate’ timing. also, there can be other things in play e.g. timing constraints that are in play that are unintentional.

sure std::map is ok for const access… but not for being modified.

I’ll just give one example… so the processing code has this in it.

	void process(const ProcessArgs &args) override {

		if(sourceExists(label)){
			TeleportInModule *src = sources[label];
			for(int i = 0; i < NUM_TELEPORT_INPUTS; i++) {
				Input input = src->inputs[TeleportInModule::INPUT_1 + i];

theres a couple of issues I believe here:

first the divisibility of sourceExists (which is find) and then the access. in a multi-threaded environment (esp with multi cores), there is nothing to stop the source existing for the IF statement (so true), but then for the source to disappear before sources[label] is executed.

even if this was ok, another thread (Id assume the UI thread) could delete the object that was refer to in the map whilst we have a local copy of the pointer . i.e. its not just the map that needs to be safe, but also the thing it contains.

I could go on… but you probably get the picture…

“But it doesn’t crash” - well lucky you :slight_smile:

there are quite a lot of pre-conditions at play here… obviously, its only going to occur if you use these objects in your patch. next. I think its most likely to occur with multi dsp threads (vcv standalone defaults to one, but in daw, we are likely be using more)

the other reason is the ‘danger time window’ is very small… if we look at above, we can see it quickly access the pointer, and just sets a few floats … this is going to be very few cpu cycles in which to get it wrong… also this is only an issue when the map changes, and in particular when the source is removed. so it’s extremely unlikely that this would occur at the same time. (but importantly, not impossible)

also you’d need to look at the vcv rack ui code, it may be that it is some how protecting this module with additional timing constraints. e.g. if it suspended processing of all modules whilst it removed modules or something similar.

as I said, in multi threaded coding, it is not unusual to have code that can run for days/months and be perfectly happy… then one bad day, it just crashes out of the blue.

so you’ll almost certainly be fine… but id not want to risk it in a live performance, or have unsaved work, and Id be cautious in recommending it to others in multi threaded environment.

4 Likes

Yep, you speak the truth. I’ve seen a lot of threading issues in source code I’ve looked at.

And, as always, you can’t just use a mutex from the audio thread or badness will happen.

You are right, there are likely several thread-safety issues with Teleport, and it’s probably not suitable for live performance. Basically I got the idea and just tried to see if it works, and so far I don’t know of it causing crashes.

It would be good to verify how the Rack engine handles deletions, to see if the TOCTOU race condition you mention can cause problems in practice, and perhaps document it in the code.

I’m happy to accept a PR that makes the module thread-safe! I have basically zero experience with lock-free multi-threaded programming, which is what one would want for audio I guess. In prinicple the architecture should be okay for multithreading, there is always only one input that can write to the shared map, and multiple teleport outputs can read from it.

4 Likes