Implement the plugin side if IComponentHandler3

This commit is contained in:
Robbert van der Helm
2021-01-06 22:25:23 +01:00
parent 79319413f5
commit 9e3c57476c
5 changed files with 101 additions and 1 deletions
@@ -39,6 +39,26 @@ Vst3PluginProxyImpl::queryInterface(const Steinberg::TUID _iid, void** obj) {
return result;
}
size_t Vst3PluginProxyImpl::register_context_menu(
Steinberg::IPtr<Steinberg::Vst::IContextMenu> menu) {
std::lock_guard lock(context_menus_mutex);
const size_t context_menu_id = current_context_menu_id.fetch_add(1);
context_menus.emplace(context_menu_id, std::move(menu));
return context_menu_id;
}
/**
* Unregister a context menu using the ID generated by a previous call to
* `register_context_menu()`. This will release the context menu object
* returned by the host.
*/
bool Vst3PluginProxyImpl::unregister_context_menu(size_t context_menu_id) {
std::lock_guard lock(context_menus_mutex);
return context_menus.erase(context_menu_id);
}
tresult PLUGIN_API Vst3PluginProxyImpl::setAudioPresentationLatencySamples(
Steinberg::Vst::BusDirection dir,
int32 busIndex,
@@ -373,6 +393,7 @@ tresult PLUGIN_API Vst3PluginProxyImpl::setComponentHandler(
// Automatically converted smart pointers for when the plugin performs a
// callback later
component_handler_2 = component_handler;
component_handler_3 = component_handler;
unit_handler = component_handler;
return bridge.send_message(YaEditController::SetComponentHandler{
@@ -38,6 +38,22 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy {
tresult PLUGIN_API queryInterface(const Steinberg::TUID _iid,
void** obj) override;
/**
* Add a context menu created by a call to
* `IComponentHandler3::createContextMenu` to our list of registered cotnext
* menus. This way we can refer to it later when the plugin calls a function
* on the proxy object we'll create for it.
*/
size_t register_context_menu(
Steinberg::IPtr<Steinberg::Vst::IContextMenu> menu);
/**
* Unregister a context menu using the ID generated by a previous call to
* `register_context_menu()`. This will release the context menu object
* returned by the host.
*/
bool unregister_context_menu(size_t context_menu_id);
// From `IAudioPresentationLatency`
tresult PLUGIN_API
setAudioPresentationLatencySamples(Steinberg::Vst::BusDirection dir,
@@ -242,6 +258,21 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy {
*/
Vst3PlugViewProxyImpl* last_created_plug_view = nullptr;
/**
* All context menus created by this object through
* `IComponentHandler3::createContextMenu()`. We'll generate a unique
* identifier for each context menu just like we do for plugin objects. When
* the plugin drops the context menu object, we'll also remove the
* corresponding entry for this map causing the original pointer returned by
* the host to get dropped a well.
*
* @see Vst3PluginProxyImpl::register_context_menu
* @see Vst3PluginProxyImpl::unregister_context_menu
*/
std::map<size_t, Steinberg::IPtr<Steinberg::Vst::IContextMenu>>
context_menus;
std::mutex context_menus_mutex;
// The following pointers are cast from `host_context` if
// `IPluginBase::initialize()` has been called
@@ -252,6 +283,8 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy {
Steinberg::FUnknownPtr<Steinberg::Vst::IComponentHandler2>
component_handler_2;
Steinberg::FUnknownPtr<Steinberg::Vst::IComponentHandler3>
component_handler_3;
Steinberg::FUnknownPtr<Steinberg::Vst::IUnitHandler> unit_handler;
private:
@@ -265,4 +298,12 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy {
* but for the sake of correctness we will.
*/
Steinberg::IPtr<Steinberg::FUnknown> host_context;
/**
* Used to assign unique identifiers to context menus created by
* `IComponentHandler3::CreateContextMenu`.
*
* @related Vst3PluginProxyImpl::register_context_menu
*/
std::atomic_size_t current_context_menu_id;
};
+37
View File
@@ -102,6 +102,43 @@ Vst3PluginBridge::Vst3PluginBridge()
.get()
.component_handler_2->finishGroupEdit();
},
[&](const YaComponentHandler3::CreateContextMenu& request)
-> YaComponentHandler3::CreateContextMenu::Response {
// XXX: As mentioned elsewhere, since VST3 only supports a
// single plug view type at the moment we'll just
// assume that this function is called from the last
// (and only) `IPlugView*` instance returned by the
// plugin.
Vst3PlugViewProxyImpl* plug_view =
plugin_proxies.at(request.owner_instance_id)
.get()
.last_created_plug_view;
Steinberg::IPtr<Steinberg::Vst::IContextMenu> context_menu =
Steinberg::owned(
plugin_proxies.at(request.owner_instance_id)
.get()
.component_handler_3->createContextMenu(
plug_view, request.param_id
? &*request.param_id
: nullptr));
if (context_menu) {
const size_t context_menu_id =
plugin_proxies.at(request.owner_instance_id)
.get()
.register_context_menu(std::move(context_menu));
return YaComponentHandler3::CreateContextMenuResponse{
.context_menu_args =
Vst3ContextMenuProxy::ConstructArgs(
context_menu, request.owner_instance_id,
context_menu_id)};
} else {
return YaComponentHandler3::CreateContextMenuResponse{
.context_menu_args = std::nullopt};
}
},
[&](YaConnectionPoint::Notify& request)
-> YaConnectionPoint::Notify::Response {
return plugin_proxies.at(request.instance_id)