From 1dd575e4a7bfb62c3eaef7c34976ee46250a85e3 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Wed, 16 Dec 2020 18:38:17 +0100 Subject: [PATCH] Implement IAudioProcessor::process() With this the entire `IAudioProcessor` interface has been implemented and in theory it should now be possible to process audio and events. Logging for these requests still has to be implemented separately. --- README.md | 13 +++---- src/common/logging/vst3.cpp | 20 ++++++++++ src/common/logging/vst3.h | 2 + src/common/serialization/vst3.h | 2 +- src/common/serialization/vst3/component.h | 40 ++++++++++++++++++++ src/common/serialization/vst3/process-data.h | 4 +- src/plugin/bridges/vst3-impls/component.cpp | 9 +++-- src/wine-host/bridges/vst3.cpp | 10 +++++ 8 files changed, 87 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 7a981a79..4e53f1ff 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,6 @@ incomplete list of things that still have to be done before this can be used: - Interfaces left to implement: - `YaHostApplicationHostImpl::createComponent()` - - `IAudioProcessor::process()` along with every interface and struct involved - in `ProcessData` - `IConnectionPoint` to supplement `IComponent` - `IEditController{,2}` - All other mandatory interfaces @@ -26,11 +24,12 @@ incomplete list of things that still have to be done before this can be used: - Fully implemented: - `GetPluginFactory()` and `IPluginFactory{,2,3}` - `IPluginBase` and `IComponent` - - Everything surrounding `ProcessData`, `ProcessingContext` and - `AudioBusBuffers` - - `IParameterChanges`, `IParamValueQueue`, `IEventList`, and all event types - in VST 3.7.1 - - `IBStream` + - `IBStream` + - `IAudioProcessor` + - Everything surrounding `ProcessData`, `ProcessingContext` and + `AudioBusBuffers` + - `IParameterChanges`, `IParamValueQueue`, `IEventList`, and all event types + in VST 3.7.1 - Finalize the VST3 [design document](https://github.com/robbert-vdh/yabridge/tree/feature/vst3/src/common/serialization/vst3/README.md) and move it to `docs/`. diff --git a/src/common/logging/vst3.cpp b/src/common/logging/vst3.cpp index 7e70c58e..b3a11c15 100644 --- a/src/common/logging/vst3.cpp +++ b/src/common/logging/vst3.cpp @@ -209,6 +209,16 @@ void Vst3Logger::log_request(bool is_host_vst, }); } +void Vst3Logger::log_request(bool is_host_vst, + const YaComponent::Process& request) { + // TODO: Only log this on log level 2 + log_request_base(is_host_vst, [&](auto& message) { + // TODO: Log about the process data + message << "::process(TODO)"; + }); +} + void Vst3Logger::log_request(bool is_host_vst, const YaComponent::GetTailSamples& request) { log_request_base(is_host_vst, [&](auto& message) { @@ -303,6 +313,16 @@ void Vst3Logger::log_response( }); } +void Vst3Logger::log_response(bool is_host_vst, + const YaComponent::ProcessResponse& response) { + // TODO: Only log this on verbosity level 2 + log_response_base(is_host_vst, [&](auto& message) { + message << response.result.string(); + + // TODO: Log response + }); +} + 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 cf824906..9cab41f7 100644 --- a/src/common/logging/vst3.h +++ b/src/common/logging/vst3.h @@ -75,6 +75,7 @@ class Vst3Logger { void log_request(bool is_host_vst, const YaComponent::GetLatencySamples&); void log_request(bool is_host_vst, const YaComponent::SetupProcessing&); void log_request(bool is_host_vst, const YaComponent::SetProcessing&); + void log_request(bool is_host_vst, const YaComponent::Process&); void log_request(bool is_host_vst, const YaComponent::GetTailSamples&); void log_request(bool is_host_vst, const YaPluginFactory::Construct&); void log_request(bool is_host_vst, const YaPluginFactory::SetHostContext&); @@ -90,6 +91,7 @@ class Vst3Logger { void log_response(bool is_host_vst, const YaComponent::GetStateResponse&); void log_response(bool is_host_vst, const YaComponent::GetBusArrangementResponse&); + void log_response(bool is_host_vst, const YaComponent::ProcessResponse&); 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 c6913bf8..b9049583 100644 --- a/src/common/serialization/vst3.h +++ b/src/common/serialization/vst3.h @@ -75,7 +75,7 @@ using ControlRequest = std::variant; diff --git a/src/common/serialization/vst3/component.h b/src/common/serialization/vst3/component.h index 60b68340..a018af1a 100644 --- a/src/common/serialization/vst3/component.h +++ b/src/common/serialization/vst3/component.h @@ -581,6 +581,46 @@ class YaComponent : public Steinberg::Vst::IComponent, }; virtual tresult PLUGIN_API setProcessing(TBool state) override = 0; + + /** + * The response code and all the output data resulting from a call to + * `IAudioProcessor::process(data)`. + */ + struct ProcessResponse { + UniversalTResult result; + YaProcessDataResponse output_data; + + template + void serialize(S& s) { + s.object(result); + s.object(output_data); + } + }; + + /** + * Message to pass through a call to `IAudioProcessor::process(data)` to the + * Wine plugin host. This `YaProcessData` object wraps around all input + * audio buffers, parameter changes and events along with all context data + * provided by the host so we can send it to the Wine plugin host. We can + * then use `YaProcessData::get()` on the Wine plugin host side to + * reconstruct the original `ProcessData` object, and we then finally use + * `YaProcessData::move_outputs_to_response()` to create a response object + * that we can write back to the `ProcessData` object provided by the host. + */ + struct Process { + using Response = ProcessResponse; + + native_size_t instance_id; + + YaProcessData data; + + template + void serialize(S& s) { + s.value8b(instance_id); + s.object(data); + } + }; + virtual tresult PLUGIN_API process(Steinberg::Vst::ProcessData& data) override = 0; diff --git a/src/common/serialization/vst3/process-data.h b/src/common/serialization/vst3/process-data.h index 6216d672..2a38052b 100644 --- a/src/common/serialization/vst3/process-data.h +++ b/src/common/serialization/vst3/process-data.h @@ -357,8 +357,8 @@ void serialize(S& s, Steinberg::Vst::Chord& chord) { template void serialize(S& s, Steinberg::Vst::FrameRate& frame_rate) { - s.value1b(frame_rate.framesPerSecond); - s.value1b(frame_rate.flags); + s.value4b(frame_rate.framesPerSecond); + s.value4b(frame_rate.flags); } } // namespace Vst } // namespace Steinberg diff --git a/src/plugin/bridges/vst3-impls/component.cpp b/src/plugin/bridges/vst3-impls/component.cpp index 5fbb6fe5..2a5a4c7f 100644 --- a/src/plugin/bridges/vst3-impls/component.cpp +++ b/src/plugin/bridges/vst3-impls/component.cpp @@ -200,9 +200,12 @@ tresult PLUGIN_API YaComponentPluginImpl::setProcessing(TBool state) { tresult PLUGIN_API YaComponentPluginImpl::process(Steinberg::Vst::ProcessData& data) { - // TODO: Implement - bridge.logger.log("TODO: IAudioProcessor::process()"); - return Steinberg::kNotImplemented; + ProcessResponse response = bridge.send_message(YaComponent::Process{ + .instance_id = arguments.instance_id, .data = data}); + + response.output_data.write_back_outputs(data); + + return response.result; } uint32 PLUGIN_API YaComponentPluginImpl::getTailSamples() { diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index 3b787aeb..25c6d0af 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -205,6 +205,16 @@ void Vst3Bridge::run() { return component_instances[request.instance_id] .audio_processor->setProcessing(request.state); }, + [&](YaComponent::Process& request) + -> YaComponent::Process::Response { + const tresult result = + component_instances[request.instance_id] + .audio_processor->process(request.data.get()); + + return YaComponent::ProcessResponse{ + .result = result, + .output_data = request.data.move_outputs_to_response()}; + }, [&](const YaComponent::GetTailSamples& request) -> YaComponent::GetTailSamples::Response { return component_instances[request.instance_id]