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.
This commit is contained in:
Robbert van der Helm
2021-01-10 16:57:36 +01:00
parent 9b603a964c
commit 8971a65825
9 changed files with 65 additions and 50 deletions
+9 -7
View File
@@ -113,9 +113,9 @@ bool Vst3Logger::log_request(bool is_host_vst,
bool Vst3Logger::log_request(bool is_host_vst, bool Vst3Logger::log_request(bool is_host_vst,
const Vst3PluginProxy::GetState& request) { const Vst3PluginProxy::GetState& request) {
return log_request_base(is_host_vst, [&](auto& message) { return log_request_base(is_host_vst, [&](auto& message) {
message message << request.instance_id
<< request.instance_id << ": {IComponent,IEditController}::getState(state = "
<< ": {IComponent,IEditController}::getState(state = <IBStream*>)"; << 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) { return log_request_base(is_host_vst, [&](auto& message) {
message << "IProgramListData::getProgramData(listId = " message << "IProgramListData::getProgramData(listId = "
<< request.list_id << 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) { const YaUnitData::GetUnitData& request) {
return log_request_base(is_host_vst, [&](auto& message) { return log_request_base(is_host_vst, [&](auto& message) {
message << "IUnitData::getUnitData(listId = " << request.unit_id message << "IUnitData::getUnitData(listId = " << request.unit_id
<< ", &data)"; << ", data = " << format_bstream(request.data) << ")";
}); });
} }
@@ -774,7 +775,8 @@ bool Vst3Logger::log_request(
<< ": " << ": "
"IXmlRepresentationController::getXmlRepresentationStream(" "IXmlRepresentationController::getXmlRepresentationStream("
"info = <RepresentationInfo for \"" "info = <RepresentationInfo for \""
<< request.info.name << "\">, stream = <IBstream*>)"; << request.info.name
<< "\">, stream = " << format_bstream(request.stream) << ")";
}); });
} }
@@ -1213,7 +1215,7 @@ void Vst3Logger::log_response(
log_response_base(is_host_vst, [&](auto& message) { log_response_base(is_host_vst, [&](auto& message) {
message << response.result.string(); message << response.result.string();
if (response.result == Steinberg::kResultOk) { if (response.result == Steinberg::kResultOk) {
message << ", " << format_bstream(response.updated_state); message << ", " << format_bstream(response.state);
} }
}); });
} }
+16 -16
View File
@@ -30,25 +30,25 @@ YaBStream::YaBStream(Steinberg::IBStream* stream) {
throw std::runtime_error("Null pointer passed to YaBStream()"); 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) { Steinberg::kResultOk) {
throw std::runtime_error( // Now that we're at the end of the stream we know how large the buffer
"IBStream passed to YaBStream() does not suport seeking to end"); // 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 // Starting at VST 3.6.0 streams provided by the host may contain context
// based meta data // based meta data
if (Steinberg::FUnknownPtr<Steinberg::Vst::IStreamAttributes> if (Steinberg::FUnknownPtr<Steinberg::Vst::IStreamAttributes>
+5
View File
@@ -39,6 +39,11 @@ class YaBStream : public Steinberg::IBStream,
public Steinberg::ISizeableStream, public Steinberg::ISizeableStream,
public Steinberg::Vst::IStreamAttributes { public Steinberg::Vst::IStreamAttributes {
public: 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(); YaBStream();
/** /**
+7 -4
View File
@@ -225,31 +225,34 @@ class Vst3PluginProxy : public YaAudioPresentationLatency,
/** /**
* The response code and written state for a call to * The response code and written state for a call to
* `{IComponent,IEditController}::getState(state)`. * `{IComponent,IEditController}::getState(&state)`.
*/ */
struct GetStateResponse { struct GetStateResponse {
UniversalTResult result; UniversalTResult result;
YaBStream updated_state; YaBStream state;
template <typename S> template <typename S>
void serialize(S& s) { void serialize(S& s) {
s.object(result); s.object(result);
s.object(updated_state); s.object(state);
} }
}; };
/** /**
* Message to pass through a call to * 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 { struct GetState {
using Response = GetStateResponse; using Response = GetStateResponse;
native_size_t instance_id; native_size_t instance_id;
YaBStream state;
template <typename S> template <typename S>
void serialize(S& s) { void serialize(S& s) {
s.value8b(instance_id); s.value8b(instance_id);
s.object(state);
} }
}; };
@@ -111,12 +111,14 @@ class YaProgramListData : public Steinberg::Vst::IProgramListData {
Steinberg::Vst::ProgramListID list_id; Steinberg::Vst::ProgramListID list_id;
int32 program_index; int32 program_index;
YaBStream data;
template <typename S> template <typename S>
void serialize(S& s) { void serialize(S& s) {
s.value8b(instance_id); s.value8b(instance_id);
s.value4b(list_id); s.value4b(list_id);
s.value4b(program_index); s.value4b(program_index);
s.object(data);
} }
}; };
@@ -108,11 +108,13 @@ class YaUnitData : public Steinberg::Vst::IUnitData {
native_size_t instance_id; native_size_t instance_id;
Steinberg::Vst::UnitID unit_id; Steinberg::Vst::UnitID unit_id;
YaBStream data;
template <typename S> template <typename S>
void serialize(S& s) { void serialize(S& s) {
s.value8b(instance_id); s.value8b(instance_id);
s.value4b(unit_id); s.value4b(unit_id);
s.object(data);
} }
}; };
@@ -96,11 +96,13 @@ class YaXmlRepresentationController
native_size_t instance_id; native_size_t instance_id;
Steinberg::Vst::RepresentationInfo info; Steinberg::Vst::RepresentationInfo info;
YaBStream stream;
template <typename S> template <typename S>
void serialize(S& s) { void serialize(S& s) {
s.value8b(instance_id); s.value8b(instance_id);
s.object(info); s.object(info);
s.object(stream);
} }
}; };
@@ -253,11 +253,11 @@ tresult PLUGIN_API Vst3PluginProxyImpl::getState(Steinberg::IBStream* state) {
if (state) { if (state) {
// Since both interfaces contain this function, this is used for both // Since both interfaces contain this function, this is used for both
// `IComponent::getState()` as well as `IEditController::getState()` // `IComponent::getState()` as well as `IEditController::getState()`
const GetStateResponse response = bridge.send_message( const GetStateResponse response =
Vst3PluginProxy::GetState{.instance_id = instance_id()}); bridge.send_message(Vst3PluginProxy::GetState{
.instance_id = instance_id(), .state = state});
assert(response.updated_state.write_back(state) == assert(response.state.write_back(state) == Steinberg::kResultOk);
Steinberg::kResultOk);
return response.result; return response.result;
} else { } else {
@@ -681,7 +681,8 @@ Vst3PluginProxyImpl::getProgramData(Steinberg::Vst::ProgramListID listId,
const GetProgramDataResponse response = bridge.send_message( const GetProgramDataResponse response = bridge.send_message(
YaProgramListData::GetProgramData{.instance_id = instance_id(), YaProgramListData::GetProgramData{.instance_id = instance_id(),
.list_id = listId, .list_id = listId,
.program_index = programIndex}); .program_index = programIndex,
.data = data});
assert(response.data.write_back(data) == Steinberg::kResultOk); assert(response.data.write_back(data) == Steinberg::kResultOk);
@@ -724,7 +725,7 @@ Vst3PluginProxyImpl::getUnitData(Steinberg::Vst::UnitID unitId,
if (data) { if (data) {
const GetUnitDataResponse response = const GetUnitDataResponse response =
bridge.send_message(YaUnitData::GetUnitData{ 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); assert(response.data.write_back(data) == Steinberg::kResultOk);
@@ -914,7 +915,7 @@ tresult PLUGIN_API Vst3PluginProxyImpl::getXmlRepresentationStream(
if (stream) { if (stream) {
const GetXmlRepresentationStreamResponse response = bridge.send_message( const GetXmlRepresentationStreamResponse response = bridge.send_message(
YaXmlRepresentationController::GetXmlRepresentationStream{ YaXmlRepresentationController::GetXmlRepresentationStream{
.instance_id = instance_id(), .info = info}); .instance_id = instance_id(), .info = info, .stream = stream});
response.stream.write_back(stream); response.stream.write_back(stream);
+14 -16
View File
@@ -172,21 +172,20 @@ void Vst3Bridge::run() {
}, },
[&](Vst3PluginProxy::GetState& request) [&](Vst3PluginProxy::GetState& request)
-> Vst3PluginProxy::GetState::Response { -> Vst3PluginProxy::GetState::Response {
YaBStream stream{};
tresult result; tresult result;
// This same function is defined in both `IComponent` and // This same function is defined in both `IComponent` and
// `IEditController`, so the host is calling one or the other // `IEditController`, so the host is calling one or the other
if (object_instances[request.instance_id].component) { if (object_instances[request.instance_id].component) {
result = object_instances[request.instance_id] result = object_instances[request.instance_id]
.component->getState(&stream); .component->getState(&request.state);
} else { } else {
result = object_instances[request.instance_id] result = object_instances[request.instance_id]
.edit_controller->getState(&stream); .edit_controller->getState(&request.state);
} }
return Vst3PluginProxy::GetStateResponse{ return Vst3PluginProxy::GetStateResponse{
.result = result, .updated_state = std::move(stream)}; .result = result, .state = std::move(request.state)};
}, },
[&](YaAudioPresentationLatency::SetAudioPresentationLatencySamples& [&](YaAudioPresentationLatency::SetAudioPresentationLatencySamples&
request) request)
@@ -739,16 +738,16 @@ void Vst3Bridge::run() {
return object_instances[request.instance_id] return object_instances[request.instance_id]
.program_list_data->programDataSupported(request.list_id); .program_list_data->programDataSupported(request.list_id);
}, },
[&](const YaProgramListData::GetProgramData& request) [&](YaProgramListData::GetProgramData& request)
-> YaProgramListData::GetProgramData::Response { -> YaProgramListData::GetProgramData::Response {
YaBStream data{};
const tresult result = const tresult result =
object_instances[request.instance_id] object_instances[request.instance_id]
.program_list_data->getProgramData( .program_list_data->getProgramData(
request.list_id, request.program_index, &data); request.list_id, request.program_index,
&request.data);
return YaProgramListData::GetProgramDataResponse{ return YaProgramListData::GetProgramDataResponse{
.result = result, .data = std::move(data)}; .result = result, .data = std::move(request.data)};
}, },
[&](YaProgramListData::SetProgramData& request) [&](YaProgramListData::SetProgramData& request)
-> YaProgramListData::SetProgramData::Response { -> YaProgramListData::SetProgramData::Response {
@@ -761,15 +760,14 @@ void Vst3Bridge::run() {
return object_instances[request.instance_id] return object_instances[request.instance_id]
.unit_data->unitDataSupported(request.unit_id); .unit_data->unitDataSupported(request.unit_id);
}, },
[&](const YaUnitData::GetUnitData& request) [&](YaUnitData::GetUnitData& request)
-> YaUnitData::GetUnitData::Response { -> YaUnitData::GetUnitData::Response {
YaBStream data{};
const tresult result = const tresult result =
object_instances[request.instance_id] 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, return YaUnitData::GetUnitDataResponse{
.data = std::move(data)}; .result = result, .data = std::move(request.data)};
}, },
[&](YaUnitData::SetUnitData& request) [&](YaUnitData::SetUnitData& request)
-> YaUnitData::SetUnitData::Response { -> YaUnitData::SetUnitData::Response {
@@ -898,17 +896,17 @@ void Vst3Bridge::run() {
[&](YaXmlRepresentationController::GetXmlRepresentationStream& [&](YaXmlRepresentationController::GetXmlRepresentationStream&
request) -> YaXmlRepresentationController:: request) -> YaXmlRepresentationController::
GetXmlRepresentationStream::Response { GetXmlRepresentationStream::Response {
YaBStream stream{};
const tresult result = const tresult result =
object_instances[request.instance_id] object_instances[request.instance_id]
.xml_representation_controller .xml_representation_controller
->getXmlRepresentationStream( ->getXmlRepresentationStream(
request.info, &stream); request.info, &request.stream);
return YaXmlRepresentationController:: return YaXmlRepresentationController::
GetXmlRepresentationStreamResponse{ GetXmlRepresentationStreamResponse{
.result = result, .result = result,
.stream = std::move(stream)}; .stream =
std::move(request.stream)};
}, },
}); });
} }