From e653142e458c851d0ec0ed3ef9ea1633480cfe99 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 14 Dec 2020 12:33:35 +0100 Subject: [PATCH] Implement IComponent::getState() With this the basic IComponent interface is fully implemented. Next will be `IAudioProcessor` and `IConnectionPoint` as additions to IComponent. We'll use the same `known_iids` mechanism as used in the plugin factory. --- README.md | 4 ++- src/common/logging/vst3.cpp | 19 +++++++++++++ src/common/logging/vst3.h | 2 ++ src/common/serialization/vst3.h | 1 + src/common/serialization/vst3/base.cpp | 6 ++-- src/common/serialization/vst3/base.h | 2 +- src/common/serialization/vst3/component.h | 31 +++++++++++++++++++++ src/plugin/bridges/vst3-impls/component.cpp | 9 ++++-- src/wine-host/bridges/vst3.cpp | 9 ++++++ 9 files changed, 75 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7bd354e0..769fba67 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,13 @@ imcomplete list of things that still have to be done before this can be used: - Left to implement: - `YaHostApplicationHostImpl::createComponent`. - - The rest of `IComponent`'s functions + - `IAudioProcessor` and `IConnectionPoint` to supplement `IComponent` + - `IEditController{,2}` - All other mandatory interfaces - All other optional interfaces - Fully implemented: - `GetPluginFactory()` and `IPluginFactory{,2,3}` + - `IComponent` - Update the GitHub Actions workflows. - Update yabridgectl to handle buth VST2 and VST3 plugins. - Update all documentation to refer to VST2 and VST3 support separately, and diff --git a/src/common/logging/vst3.cpp b/src/common/logging/vst3.cpp index 83ee6f7e..d77fcc49 100644 --- a/src/common/logging/vst3.cpp +++ b/src/common/logging/vst3.cpp @@ -142,6 +142,14 @@ void Vst3Logger::log_request(bool is_host_vst, }); } +void Vst3Logger::log_request(bool is_host_vst, + const YaComponent::GetState& request) { + log_request_base(is_host_vst, [&](auto& message) { + message << "::getState(state = )"; + }); +} + void Vst3Logger::log_request(bool is_host_vst, const YaPluginFactory::Construct&) { log_request_base(is_host_vst, @@ -206,6 +214,17 @@ void Vst3Logger::log_response( }); } +void Vst3Logger::log_response(bool is_host_vst, + const YaComponent::GetStateResponse& response) { + log_response_base(is_host_vst, [&](auto& message) { + message << response.result.string(); + if (response.result.native() == Steinberg::kResultOk) { + message << ", "; + } + }); +} + void Vst3Logger::log_response(bool is_host_vst, const YaPluginFactory::ConstructArgs& args) { log_response_base(is_host_vst, [&](auto& message) { diff --git a/src/common/logging/vst3.h b/src/common/logging/vst3.h index 29d45d93..951466d1 100644 --- a/src/common/logging/vst3.h +++ b/src/common/logging/vst3.h @@ -67,6 +67,7 @@ class Vst3Logger { void log_request(bool is_host_vst, const YaComponent::ActivateBus&); void log_request(bool is_host_vst, const YaComponent::SetActive&); void log_request(bool is_host_vst, const YaComponent::SetState&); + void log_request(bool is_host_vst, const YaComponent::GetState&); void log_request(bool is_host_vst, const YaPluginFactory::Construct&); void log_request(bool is_host_vst, const YaPluginFactory::SetHostContext&); void log_request(bool is_host_vst, const WantsConfiguration&); @@ -78,6 +79,7 @@ class Vst3Logger { void log_response(bool is_host_vst, const YaComponent::GetBusInfoResponse&); void log_response(bool is_host_vst, const YaComponent::GetRoutingInfoResponse&); + void log_response(bool is_host_vst, const YaComponent::GetStateResponse&); void log_response(bool is_host_vst, const YaPluginFactory::ConstructArgs&); void log_response(bool is_host_vst, const Configuration&); diff --git a/src/common/serialization/vst3.h b/src/common/serialization/vst3.h index 3d63e5ab..45ded5e4 100644 --- a/src/common/serialization/vst3.h +++ b/src/common/serialization/vst3.h @@ -68,6 +68,7 @@ using ControlRequest = std::variant; diff --git a/src/common/serialization/vst3/base.cpp b/src/common/serialization/vst3/base.cpp index ac29d4cb..88542121 100644 --- a/src/common/serialization/vst3/base.cpp +++ b/src/common/serialization/vst3/base.cpp @@ -175,15 +175,15 @@ tresult PLUGIN_API VectorStream::queryInterface(Steinberg::FIDString _iid, return Steinberg::kNoInterface; } -tresult VectorStream::write_back(Steinberg::IBStream* stream) { +tresult VectorStream::write_back(Steinberg::IBStream* stream) const { if (!stream) { return Steinberg::kInvalidArgument; } int32 num_bytes_written; assert(stream->seek(0, kIBSeekSet) == Steinberg::kResultOk); - assert(stream->write(buffer.data(), buffer.size(), &num_bytes_written) == - Steinberg::kResultOk); + assert(stream->write(const_cast(buffer.data()), buffer.size(), + &num_bytes_written) == Steinberg::kResultOk); assert(num_bytes_written == 0 || static_cast(num_bytes_written) == buffer.size()); diff --git a/src/common/serialization/vst3/base.h b/src/common/serialization/vst3/base.h index 2f50174c..2f5aef88 100644 --- a/src/common/serialization/vst3/base.h +++ b/src/common/serialization/vst3/base.h @@ -140,7 +140,7 @@ class VectorStream : public Steinberg::IBStream, * Write the vector buffer back to an IBStream. After writing the seek * position will be left at the end of the stream. */ - tresult write_back(Steinberg::IBStream* stream); + tresult write_back(Steinberg::IBStream* stream) const; /** * Return the buffer's, used in the logging messages. diff --git a/src/common/serialization/vst3/component.h b/src/common/serialization/vst3/component.h index e73dd1c2..99789178 100644 --- a/src/common/serialization/vst3/component.h +++ b/src/common/serialization/vst3/component.h @@ -371,6 +371,37 @@ class YaComponent : public Steinberg::Vst::IComponent { virtual tresult PLUGIN_API setState(Steinberg::IBStream* state) override = 0; + + /** + * The response code and written state for a call to + * `IComponent::getState(state)`. + */ + struct GetStateResponse { + UniversalTResult result; + VectorStream updated_state; + + template + void serialize(S& s) { + s.object(result); + s.object(updated_state); + } + }; + + /** + * Message to pass through a call to `IComponent::getState(state)` to the + * Wine plugin host. + */ + struct GetState { + using Response = GetStateResponse; + + native_size_t instance_id; + + template + void serialize(S& s) { + s.value8b(instance_id); + } + }; + virtual tresult PLUGIN_API getState(Steinberg::IBStream* state) override = 0; diff --git a/src/plugin/bridges/vst3-impls/component.cpp b/src/plugin/bridges/vst3-impls/component.cpp index 22800a6e..f3c22279 100644 --- a/src/plugin/bridges/vst3-impls/component.cpp +++ b/src/plugin/bridges/vst3-impls/component.cpp @@ -148,7 +148,10 @@ tresult PLUGIN_API YaComponentPluginImpl::setState(Steinberg::IBStream* state) { } tresult PLUGIN_API YaComponentPluginImpl::getState(Steinberg::IBStream* state) { - // TODO: Implement - bridge.logger.log("TODO: IComponent::getState()"); - return Steinberg::kNotImplemented; + const GetStateResponse response = bridge.send_message( + YaComponent::GetState{.instance_id = arguments.instance_id}); + + assert(response.updated_state.write_back(state) == Steinberg::kResultOk); + + return response.result.native(); } diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index b297733f..7da18669 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -158,6 +158,15 @@ void Vst3Bridge::run() { return component_instances[request.instance_id] .component->setState(&request.state); }, + [&](YaComponent::GetState& request) + -> YaComponent::GetState::Response { + VectorStream stream; + const tresult result = component_instances[request.instance_id] + .component->getState(&stream); + + return YaComponent::GetStateResponse{ + .result = result, .updated_state = std::move(stream)}; + }, [&](const YaPluginFactory::Construct&) -> YaPluginFactory::Construct::Response { return YaPluginFactory::ConstructArgs(