From 8971a65825fa92a8fe37ef232630003062d78eee Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 10 Jan 2021 16:57:36 +0100 Subject: [PATCH] Pass through host provided IBStream objects So if the host supports IStreamAttributes, we can also provide objects that support the same itnerface to the plugin. --- src/common/logging/vst3.cpp | 16 ++++++---- src/common/serialization/vst3/bstream.cpp | 32 +++++++++---------- src/common/serialization/vst3/bstream.h | 5 +++ src/common/serialization/vst3/plugin-proxy.h | 11 ++++--- .../vst3/plugin/program-list-data.h | 2 ++ .../serialization/vst3/plugin/unit-data.h | 2 ++ .../plugin/xml-representation-controller.h | 2 ++ .../bridges/vst3-impls/plugin-proxy.cpp | 15 +++++---- src/wine-host/bridges/vst3.cpp | 30 ++++++++--------- 9 files changed, 65 insertions(+), 50 deletions(-) diff --git a/src/common/logging/vst3.cpp b/src/common/logging/vst3.cpp index 50b88d4d..8d293289 100644 --- a/src/common/logging/vst3.cpp +++ b/src/common/logging/vst3.cpp @@ -113,9 +113,9 @@ bool Vst3Logger::log_request(bool is_host_vst, bool Vst3Logger::log_request(bool is_host_vst, const Vst3PluginProxy::GetState& request) { return log_request_base(is_host_vst, [&](auto& message) { - message - << request.instance_id - << ": {IComponent,IEditController}::getState(state = )"; + message << request.instance_id + << ": {IComponent,IEditController}::getState(state = " + << format_bstream(request.state) << ")"; }); } @@ -618,7 +618,8 @@ bool Vst3Logger::log_request(bool is_host_vst, return log_request_base(is_host_vst, [&](auto& message) { message << "IProgramListData::getProgramData(listId = " << request.list_id - << ", programIndex = " << request.program_index << ", &data)"; + << ", programIndex = " << request.program_index + << ", data = " << format_bstream(request.data) << ")"; }); } @@ -643,7 +644,7 @@ bool Vst3Logger::log_request(bool is_host_vst, const YaUnitData::GetUnitData& request) { return log_request_base(is_host_vst, [&](auto& message) { message << "IUnitData::getUnitData(listId = " << request.unit_id - << ", &data)"; + << ", data = " << format_bstream(request.data) << ")"; }); } @@ -774,7 +775,8 @@ bool Vst3Logger::log_request( << ": " "IXmlRepresentationController::getXmlRepresentationStream(" "info = , stream = )"; + << request.info.name + << "\">, stream = " << format_bstream(request.stream) << ")"; }); } @@ -1213,7 +1215,7 @@ void Vst3Logger::log_response( log_response_base(is_host_vst, [&](auto& message) { message << response.result.string(); if (response.result == Steinberg::kResultOk) { - message << ", " << format_bstream(response.updated_state); + message << ", " << format_bstream(response.state); } }); } diff --git a/src/common/serialization/vst3/bstream.cpp b/src/common/serialization/vst3/bstream.cpp index 844e08a9..1795c20c 100644 --- a/src/common/serialization/vst3/bstream.cpp +++ b/src/common/serialization/vst3/bstream.cpp @@ -30,25 +30,25 @@ YaBStream::YaBStream(Steinberg::IBStream* stream) { throw std::runtime_error("Null pointer passed to YaBStream()"); } - if (stream->seek(0, Steinberg::IBStream::IStreamSeekMode::kIBSeekEnd) != + // Copy any existing contents, used for `IComponent::setState` and similar + // methods + if (stream->seek(0, Steinberg::IBStream::IStreamSeekMode::kIBSeekEnd) == Steinberg::kResultOk) { - throw std::runtime_error( - "IBStream passed to YaBStream() does not suport seeking to end"); + // Now that we're at the end of the stream we know how large the buffer + // should be + int64 size; + assert(stream->tell(&size) == Steinberg::kResultOk); + + int32 num_bytes_read = 0; + buffer.resize(size); + assert( + stream->seek(0, Steinberg::IBStream::IStreamSeekMode::kIBSeekSet) == + Steinberg::kResultOk); + assert(stream->read(buffer.data(), size, &num_bytes_read) == + Steinberg::kResultOk); + assert(num_bytes_read == 0 || num_bytes_read == size); } - // Now that we're at the end of the stream we know how large the buffer - // should be - int64 size; - assert(stream->tell(&size) == Steinberg::kResultOk); - - int32 num_bytes_read = 0; - buffer.resize(size); - assert(stream->seek(0, Steinberg::IBStream::IStreamSeekMode::kIBSeekSet) == - Steinberg::kResultOk); - assert(stream->read(buffer.data(), size, &num_bytes_read) == - Steinberg::kResultOk); - assert(num_bytes_read == 0 || num_bytes_read == size); - // Starting at VST 3.6.0 streams provided by the host may contain context // based meta data if (Steinberg::FUnknownPtr diff --git a/src/common/serialization/vst3/bstream.h b/src/common/serialization/vst3/bstream.h index cfcf67c9..c449cf50 100644 --- a/src/common/serialization/vst3/bstream.h +++ b/src/common/serialization/vst3/bstream.h @@ -39,6 +39,11 @@ class YaBStream : public Steinberg::IBStream, public Steinberg::ISizeableStream, public Steinberg::Vst::IStreamAttributes { public: + /** + * This constructor should only be used by bitsery for serialization. The + * other constructor will check whether the `IBstream*` provided by the host + * supports stream attributes and configures the object accordingly. + */ YaBStream(); /** diff --git a/src/common/serialization/vst3/plugin-proxy.h b/src/common/serialization/vst3/plugin-proxy.h index 6686db67..73104233 100644 --- a/src/common/serialization/vst3/plugin-proxy.h +++ b/src/common/serialization/vst3/plugin-proxy.h @@ -225,31 +225,34 @@ class Vst3PluginProxy : public YaAudioPresentationLatency, /** * The response code and written state for a call to - * `{IComponent,IEditController}::getState(state)`. + * `{IComponent,IEditController}::getState(&state)`. */ struct GetStateResponse { UniversalTResult result; - YaBStream updated_state; + YaBStream state; template void serialize(S& s) { s.object(result); - s.object(updated_state); + s.object(state); } }; /** * Message to pass through a call to - * `{IComponent,IEditController}::getState(state)` to the Wine plugin host. + * `{IComponent,IEditController}::getState(&state)` to the Wine plugin host. */ struct GetState { using Response = GetStateResponse; native_size_t instance_id; + YaBStream state; + template void serialize(S& s) { s.value8b(instance_id); + s.object(state); } }; diff --git a/src/common/serialization/vst3/plugin/program-list-data.h b/src/common/serialization/vst3/plugin/program-list-data.h index 5ef721ae..bf64ffc1 100644 --- a/src/common/serialization/vst3/plugin/program-list-data.h +++ b/src/common/serialization/vst3/plugin/program-list-data.h @@ -111,12 +111,14 @@ class YaProgramListData : public Steinberg::Vst::IProgramListData { Steinberg::Vst::ProgramListID list_id; int32 program_index; + YaBStream data; template void serialize(S& s) { s.value8b(instance_id); s.value4b(list_id); s.value4b(program_index); + s.object(data); } }; diff --git a/src/common/serialization/vst3/plugin/unit-data.h b/src/common/serialization/vst3/plugin/unit-data.h index 8ff7b29e..1508eca2 100644 --- a/src/common/serialization/vst3/plugin/unit-data.h +++ b/src/common/serialization/vst3/plugin/unit-data.h @@ -108,11 +108,13 @@ class YaUnitData : public Steinberg::Vst::IUnitData { native_size_t instance_id; Steinberg::Vst::UnitID unit_id; + YaBStream data; template void serialize(S& s) { s.value8b(instance_id); s.value4b(unit_id); + s.object(data); } }; diff --git a/src/common/serialization/vst3/plugin/xml-representation-controller.h b/src/common/serialization/vst3/plugin/xml-representation-controller.h index 770d44cb..13ebf766 100644 --- a/src/common/serialization/vst3/plugin/xml-representation-controller.h +++ b/src/common/serialization/vst3/plugin/xml-representation-controller.h @@ -96,11 +96,13 @@ class YaXmlRepresentationController native_size_t instance_id; Steinberg::Vst::RepresentationInfo info; + YaBStream stream; template void serialize(S& s) { s.value8b(instance_id); s.object(info); + s.object(stream); } }; diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp index ce609b29..2d6ae610 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp @@ -253,11 +253,11 @@ tresult PLUGIN_API Vst3PluginProxyImpl::getState(Steinberg::IBStream* state) { if (state) { // Since both interfaces contain this function, this is used for both // `IComponent::getState()` as well as `IEditController::getState()` - const GetStateResponse response = bridge.send_message( - Vst3PluginProxy::GetState{.instance_id = instance_id()}); + const GetStateResponse response = + bridge.send_message(Vst3PluginProxy::GetState{ + .instance_id = instance_id(), .state = state}); - assert(response.updated_state.write_back(state) == - Steinberg::kResultOk); + assert(response.state.write_back(state) == Steinberg::kResultOk); return response.result; } else { @@ -681,7 +681,8 @@ Vst3PluginProxyImpl::getProgramData(Steinberg::Vst::ProgramListID listId, const GetProgramDataResponse response = bridge.send_message( YaProgramListData::GetProgramData{.instance_id = instance_id(), .list_id = listId, - .program_index = programIndex}); + .program_index = programIndex, + .data = data}); assert(response.data.write_back(data) == Steinberg::kResultOk); @@ -724,7 +725,7 @@ Vst3PluginProxyImpl::getUnitData(Steinberg::Vst::UnitID unitId, if (data) { const GetUnitDataResponse response = bridge.send_message(YaUnitData::GetUnitData{ - .instance_id = instance_id(), .unit_id = unitId}); + .instance_id = instance_id(), .unit_id = unitId, .data = data}); assert(response.data.write_back(data) == Steinberg::kResultOk); @@ -914,7 +915,7 @@ tresult PLUGIN_API Vst3PluginProxyImpl::getXmlRepresentationStream( if (stream) { const GetXmlRepresentationStreamResponse response = bridge.send_message( YaXmlRepresentationController::GetXmlRepresentationStream{ - .instance_id = instance_id(), .info = info}); + .instance_id = instance_id(), .info = info, .stream = stream}); response.stream.write_back(stream); diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index 441e5331..9b3f2c36 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -172,21 +172,20 @@ void Vst3Bridge::run() { }, [&](Vst3PluginProxy::GetState& request) -> Vst3PluginProxy::GetState::Response { - YaBStream stream{}; tresult result; // This same function is defined in both `IComponent` and // `IEditController`, so the host is calling one or the other if (object_instances[request.instance_id].component) { result = object_instances[request.instance_id] - .component->getState(&stream); + .component->getState(&request.state); } else { result = object_instances[request.instance_id] - .edit_controller->getState(&stream); + .edit_controller->getState(&request.state); } return Vst3PluginProxy::GetStateResponse{ - .result = result, .updated_state = std::move(stream)}; + .result = result, .state = std::move(request.state)}; }, [&](YaAudioPresentationLatency::SetAudioPresentationLatencySamples& request) @@ -739,16 +738,16 @@ void Vst3Bridge::run() { return object_instances[request.instance_id] .program_list_data->programDataSupported(request.list_id); }, - [&](const YaProgramListData::GetProgramData& request) + [&](YaProgramListData::GetProgramData& request) -> YaProgramListData::GetProgramData::Response { - YaBStream data{}; const tresult result = object_instances[request.instance_id] .program_list_data->getProgramData( - request.list_id, request.program_index, &data); + request.list_id, request.program_index, + &request.data); return YaProgramListData::GetProgramDataResponse{ - .result = result, .data = std::move(data)}; + .result = result, .data = std::move(request.data)}; }, [&](YaProgramListData::SetProgramData& request) -> YaProgramListData::SetProgramData::Response { @@ -761,15 +760,14 @@ void Vst3Bridge::run() { return object_instances[request.instance_id] .unit_data->unitDataSupported(request.unit_id); }, - [&](const YaUnitData::GetUnitData& request) + [&](YaUnitData::GetUnitData& request) -> YaUnitData::GetUnitData::Response { - YaBStream data{}; const tresult result = object_instances[request.instance_id] - .unit_data->getUnitData(request.unit_id, &data); + .unit_data->getUnitData(request.unit_id, &request.data); - return YaUnitData::GetUnitDataResponse{.result = result, - .data = std::move(data)}; + return YaUnitData::GetUnitDataResponse{ + .result = result, .data = std::move(request.data)}; }, [&](YaUnitData::SetUnitData& request) -> YaUnitData::SetUnitData::Response { @@ -898,17 +896,17 @@ void Vst3Bridge::run() { [&](YaXmlRepresentationController::GetXmlRepresentationStream& request) -> YaXmlRepresentationController:: GetXmlRepresentationStream::Response { - YaBStream stream{}; const tresult result = object_instances[request.instance_id] .xml_representation_controller ->getXmlRepresentationStream( - request.info, &stream); + request.info, &request.stream); return YaXmlRepresentationController:: GetXmlRepresentationStreamResponse{ .result = result, - .stream = std::move(stream)}; + .stream = + std::move(request.stream)}; }, }); }