Possible to trigger a VCV event in code?

How can I trigger onExpanderChange() event in my code? Or is this not possible?

It seems as though there is a bug in the VCV API that neglects to trigger onExpanderChange() when a module is deleted, and that is wreaking havoc with my Venom expander code. Thanks Dan (@soundismovement) for the bug report.

I have a crude fix that will work until VCV fixes the problem (or indefinitely if never fixed). But an even better solution would be if my Venom modules automatically trigger onExpandeChange() within onRemove() in lieu of VCV doing it.

Have you reported this to support@vcvrack.com?

Not yet, but I plan on doing so. I just want to get a workaround in place ASAP because I imagine it will be a while before VCV releases any fix.

1 Like

I have submitted an inquiry to support

1 Like

Can’t you just make an expanded change event object and call onexoanderchange on your left and right neighbor directly?

I don’t know, is it that easy? Makes sense… I will try it.

It’s just a function and an object. Make the object and call the function is what the rack engine does!

So it should be. But you will get a double call if rack fixes it

But also I could be totally wrong!

It is an override, so I don’t think the override onRemove() will double trigger upon VCV fix unless I explicitly call the parent onRemove() from within my override.

I don’t think that works because if I make the call within onRemove(), then onExpanderChange() does not see any change because the module has not been deleted yet - get[Left/Right]Expander() still returns the module that is going to be deleted. I need VCV to call the neighbor module’s onExpanderChange() after the module has actually been deleted. :frowning:

Maybe I am misunderstanding what you want to do, but it sounds like you are describing something that is impossible; once a module has been deleted you cannot call its methods.

Though, if this is what you are trying to do, perhaps there is a solution where you call the module before it is deleted and it sets a flag, and then you can do the work you need in the modules destructor if the flag is set?

Yeah - I really need VCV to properly call onExpanderChange after the module has been deleted. Maybe I could do something in the destructor, but something tells me I run into the same problem - the module is not really gone while the destructor is running, right? Either way, I don’t think I want to go down that road.

I have a hack that works. When one of my modules is deleted, my onRemove increments a plugin global venomModuleDeleteCount variable. All of my modules that rely on cached pointers to Venom expander modules maintain their own venomModuleDeleteCount, and if it does not match the global value, then I update my cached pointers using get[Left/Right]Expander, and then set the local del count to match the global value.

The hack works without any noticeable increase in CPU time.

If I simply abandon the use of cached pointers and always call get[Left/Right]Expander, then CPU usage skyrockets. My mixers support expander chains of arbitrary length, so the performance degradation can be a real problem.

Get…Expander should be an inlined dereference of a member, so shouldn’t consume much cpu. On the other hand, if you’re using dynamic_cast on the result, then that can be slow.

Bingo - thanks. That is exactly what I am doing.

So, if you must use dynamic_cast, you can cache your resolved interface, but check for a null expander (without the cast) for invalidation in the absence of the notification.

just keep a Module *lastLeft;VenomModule *lastVenomLeft and only dynamic cast if the lastLeft changes.

Or just check pointer equality to look for change. The dynamic cast will change the type and do an rtti check but won’t change the pointer address in practice.

That is the whole point of using onExpanderChange - to cache and mintain the VenomModule* pointers. It naturally only does dynamic cast when there has been a change.

When I wrote the code I naively thought the get[LeftRight]Expander was slow, until @pachde set me straight that it is the dynamic_cast slowing things down. But either way, the design saves CPU.

Yeah I get it it is a gross workaround and calling it I process is a bummer but if you don’t cast probably not that bad a bummer

So the question I thought you were asking is: when you are deleted can you call on expander changed on your neighbors

Which call is missing?

I think when a module is deleted, VCV should automatically update the neighbors’ expander pointer and trigger onExpanderChange. But the trigger is not happening (and I reported this to VCV). VCV must be updating the neighbors’ left/right expander pointers, because if my code calls get[Left/Right]Expander I get the correct values. VCV is simply forgetting to trigger onExpanderChange when updating the pointers after a module deletion.

I was (again naively) hoping I could solve the problem by calling the neighbors’ onExpanderChange myself within onRemove. But I believe this doesn’t work because the module still exists while onRemove is running, so the neighbor pointers have not been updated yet.

So I have abandoned this entire concept, and fallen back to a different hack that reduces the number of times I call dynamic_cast. The hack is working just fine.

1 Like

Well I ended up discovering how to update the expander information myself before calling onExpanderChange, and it works!

See VCV API module deletion / onExpanderChange() bug and work around for more info.