Skip to content

Finish switching from vst3-sys to vst3#263

Open
davemollen wants to merge 11 commits intorobbert-vdh:masterfrom
davemollen:finish-vst3-pr
Open

Finish switching from vst3-sys to vst3#263
davemollen wants to merge 11 commits intorobbert-vdh:masterfrom
davemollen:finish-vst3-pr

Conversation

@davemollen
Copy link
Copy Markdown

@davemollen davemollen commented Mar 16, 2026

Switch from the vst3-sys crate to the vst3 crate. With this change VST3 plugins built with NIH-plug no longer depend on the GPLv3 license.

Changes:

  • This PR continues on the work from this draft PR: switch from vst3-sys to vst3 #243. This draft had some build issues on Linux and Windows that were fixed in this PR
  • This PR also handles the recent breaking change in Rust nightly where simd LaneCount was removed in favor of the #[rustc_simd_monomorphize_lane_limit] attribute: rust-lang/portable-simd@8ce88bc.

@davemollen davemollen changed the title Finish vst3 pr finish switching from vst3-sys to vst3 Mar 16, 2026
@davemollen davemollen changed the title finish switching from vst3-sys to vst3 Finish switching from vst3-sys to vst3 Mar 16, 2026
.spawn(parent_handle, self.inner.clone().make_gui_context()),
);
*self.inner.plug_view.write() = Some(ObjectPtr::from(self));
// *self.inner.plug_view.write() = Some(ObjectPtr::from(self));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A solution still needs to be found for this line. A direct equivalent of ObjectPtr::from(self) is not possible with the vst3 crate.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really know how this should be handled. So I will keep this open.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have taken a look. And I think I have found a working solution.

I think the plug_view field on the WrapperInner struct doesn't have to be set and cleared in the attached and removed function on the IPlugViewTrait. As far as I can tell it merely functions as a way to tell if the editor is open or not. So I store an is_editor_open atomic bool on WrapperInner instead and set that in the attached and removed function. The plug_view field can then be set when createView is called on IEditController.

I know you're short on time @micahrj, but greatly appreciated if you could take a look.

.map(|run_loop| RunLoopEventHandler::new(self.inner.clone(), run_loop));
}
*self.plug_frame.write() = Some(VstPtr::from(frame));
// *self.plug_frame.write() = Some(ComPtr::from(frame));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another line that still needs to be updated.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was actually straightforward

tasks: ArrayQueue::new(TASK_QUEUE_CAPACITY),
});

let handler_ptr = &*handler as *const _ as *mut _;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not going to work at all. You can't just allocate a Box<RunLoopEventHandler> and then do an unsafe pointer cast to *mut IEventHandler.

The use of #[VST3(implements(IEventHandler))] above RunLoopEventHandler needs to be replaced with impl Class for RunLoopEventHandler, and the RunLoopEventHandler needs to be allocated with ComWrapper.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was afraid this wouldn't make much sense. Didn't really notice this in testing though.

Copy link
Copy Markdown
Author

@davemollen davemollen Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I applied your suggested changes here. Getting access to the IEventHandler pointer for the unregisterEventHandler call was a bit fiddly. Curious to hear if this looks right to you.

It feels a bit strange to store the ComPtr on the struct it's also pointing to, but don't know what other pattern could be used.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically the right solution, yeah. This is due to a limitation in the vst3 crate where there is no good way to get an interface pointer (e.g. *mut IEventHandler) directly from &self.

However, I have a couple points of feedback:

  1. RwLock is not necessary here. The IRunLoop and IEventHandler interfaces are restricted to being used on the main thread, so Cell should suffice.
  2. Storing an actual ComPtr will result in a reference cycle, which means that the RunLoopEventHandler will never get dropped. Instead, you should just store a raw *mut IEventHandler.

Copy link
Copy Markdown
Author

@davemollen davemollen Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed up on these instructions. Thanks for guiding me to the right solution!
I was afraid of the reference cycle. Good to know this prevents that.

@davemollen davemollen marked this pull request as draft March 31, 2026 18:16
@davemollen davemollen marked this pull request as ready for review April 9, 2026 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants