mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-10 04:30:12 +02:00
Implement the Wine side of clap_plugin::process()
This commit is contained in:
@@ -110,9 +110,16 @@ struct ClapAudioThreadControlRequest {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
ClapAudioThreadControlRequest(T request) : payload(std::move(request)) {}
|
ClapAudioThreadControlRequest(T request) : payload(std::move(request)) {}
|
||||||
|
|
||||||
using Payload = std::variant<clap::plugin::StartProcessing,
|
using Payload =
|
||||||
|
std::variant<clap::plugin::StartProcessing,
|
||||||
clap::plugin::StopProcessing,
|
clap::plugin::StopProcessing,
|
||||||
clap::plugin::Reset,
|
clap::plugin::Reset,
|
||||||
|
// The actual value for this will be stored in the
|
||||||
|
// `process_request` field on `clap_plugin_proxy`. That way
|
||||||
|
// we don't have to destroy the object (and deallocate all
|
||||||
|
// vectors in it) on the Wine side during every processing
|
||||||
|
// cycle.
|
||||||
|
MessageReference<clap::plugin::Process>,
|
||||||
clap::ext::params::plugin::Flush,
|
clap::ext::params::plugin::Flush,
|
||||||
clap::ext::tail::plugin::Get>;
|
clap::ext::tail::plugin::Get>;
|
||||||
|
|
||||||
@@ -120,38 +127,31 @@ struct ClapAudioThreadControlRequest {
|
|||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
void serialize(S& s) {
|
void serialize(S& s) {
|
||||||
s.ext(
|
s.ext(payload,
|
||||||
payload,
|
|
||||||
bitsery::ext::InPlaceVariant{
|
bitsery::ext::InPlaceVariant{
|
||||||
// TODO: Process data
|
[&](S& s,
|
||||||
// [&](S& s,
|
MessageReference<clap::plugin::Process>& request_ref) {
|
||||||
// MessageReference<YaAudioProcessor::Process>& request_ref)
|
// When serializing this reference we'll read the data
|
||||||
// {
|
// directly from the referred to object. During
|
||||||
// // When serializing this reference we'll read the data
|
// deserializing we'll deserialize into the persistent and
|
||||||
// // directly from the referred to object. During
|
// thread local `process_request` object (see
|
||||||
// // deserializing we'll deserialize into the persistent and
|
// `ClapSockets::add_audio_thread_and_listen_control`) and
|
||||||
// // thread local `process_request` object (see
|
// then reassign the reference to point to that object.
|
||||||
// // `ClapSockets::add_audio_processor_and_listen`) and then
|
s.ext(request_ref,
|
||||||
// // reassign the reference to point to that object.
|
bitsery::ext::MessageReference(process_request_));
|
||||||
// s.ext(request_ref,
|
},
|
||||||
// bitsery::ext::MessageReference(process_request_));
|
|
||||||
// },
|
|
||||||
[](S& s, auto& request) { s.object(request); }});
|
[](S& s, auto& request) { s.object(request); }});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Process data, update docstring
|
/**
|
||||||
// /**
|
* Used for deserializing the
|
||||||
// * Used for deserializing the
|
* `MessageReference<clap::plugin::process::Process>` variant. When we
|
||||||
// `MessageReference<YaAudioProcessor::Process>`
|
* encounter this variant, we'll actually deserialize the object into this
|
||||||
// * variant. When we encounter this variant, we'll actually deserialize
|
* object, and we'll then reassign the reference to point to this object.
|
||||||
// the
|
* That way we can keep it around as a thread local object to prevent
|
||||||
// * object into this object, and we'll then reassign the reference to
|
* unnecessary allocations.
|
||||||
// point
|
*/
|
||||||
// * to this object. That way we can keep it around as a thread local
|
std::optional<clap::plugin::Process> process_request_;
|
||||||
// object
|
|
||||||
// * to prevent unnecessary allocations.
|
|
||||||
// */
|
|
||||||
// std::optional<YaAudioProcessor::Process> process_request_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -899,16 +899,15 @@ void ClapBridge::register_plugin_instance(
|
|||||||
// Every plugin instance gets its own audio thread along with sockets for
|
// Every plugin instance gets its own audio thread along with sockets for
|
||||||
// host->plugin control messages and plugin->host callbacks
|
// host->plugin control messages and plugin->host callbacks
|
||||||
std::promise<void> socket_listening_latch;
|
std::promise<void> socket_listening_latch;
|
||||||
object_instances_.at(instance_id).audio_thread_handler =
|
object_instances_.at(instance_id)
|
||||||
Win32Thread([&, instance_id]() {
|
.audio_thread_handler = Win32Thread([&, instance_id]() {
|
||||||
set_realtime_priority(true);
|
set_realtime_priority(true);
|
||||||
|
|
||||||
// XXX: Like with VST2 worker threads, when using plugin groups the
|
// XXX: Like with VST2 worker threads, when using plugin groups the
|
||||||
// thread names from different plugins will clash. Not a huge
|
// thread names from different plugins will clash. Not a huge
|
||||||
// deal probably, since duplicate thread names are still more
|
// deal probably, since duplicate thread names are still more
|
||||||
// useful than no thread names.
|
// useful than no thread names.
|
||||||
const std::string thread_name =
|
const std::string thread_name = "audio-" + std::to_string(instance_id);
|
||||||
"audio-" + std::to_string(instance_id);
|
|
||||||
pthread_setname_np(pthread_self(), thread_name.c_str());
|
pthread_setname_np(pthread_self(), thread_name.c_str());
|
||||||
|
|
||||||
sockets_.add_audio_thread_and_listen_control(
|
sockets_.add_audio_thread_and_listen_control(
|
||||||
@@ -940,16 +939,55 @@ void ClapBridge::register_plugin_instance(
|
|||||||
|
|
||||||
return Ack{};
|
return Ack{};
|
||||||
},
|
},
|
||||||
|
[&](const MessageReference<clap::plugin::Process>& request_ref)
|
||||||
|
-> clap::plugin::Process::Response {
|
||||||
|
// NOTE: To prevent allocations we keep this actual
|
||||||
|
// `clap::plugin::Process` object around as part of a
|
||||||
|
// static thread local `ClapAudioThreadControlRequest`
|
||||||
|
// object, and we only store a reference to it in our
|
||||||
|
// variant (this is done during the deserialization in
|
||||||
|
// `bitsery::ext::MessageReference`)
|
||||||
|
clap::plugin::Process& request = request_ref.get();
|
||||||
|
|
||||||
|
// As suggested by Jack Winter, we'll synchronize this
|
||||||
|
// thread's audio processing priority with that of the
|
||||||
|
// host's audio thread every once in a while
|
||||||
|
if (request.new_realtime_priority) {
|
||||||
|
set_realtime_priority(true,
|
||||||
|
*request.new_realtime_priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& [instance, _] =
|
||||||
|
get_instance(request.instance_id);
|
||||||
|
|
||||||
|
// Most plugins will already enable FTZ, but there are a
|
||||||
|
// handful of plugins that don't that suffer from extreme
|
||||||
|
// DSP load increases when they start producing denormals
|
||||||
|
ScopedFlushToZero ftz_guard;
|
||||||
|
|
||||||
|
// The actual audio is stored in the shared memory
|
||||||
|
// buffers, so the reconstruction function will need to
|
||||||
|
// know where it should point the `AudioBusBuffers` to
|
||||||
// TODO: Once we add the render extension, process on the
|
// TODO: Once we add the render extension, process on the
|
||||||
// main thread when doing offline rendering
|
// main thread when doing offline rendering
|
||||||
|
auto& reconstructed = request.process.reconstruct(
|
||||||
|
instance.process_buffers_input_pointers,
|
||||||
|
instance.process_buffers_output_pointers);
|
||||||
|
clap_process_status result = instance.plugin->process(
|
||||||
|
instance.plugin.get(), &reconstructed);
|
||||||
|
|
||||||
|
return clap::plugin::ProcessResponse{
|
||||||
|
.result = result,
|
||||||
|
.output_data = request.process.create_response()};
|
||||||
|
},
|
||||||
[&](clap::ext::params::plugin::Flush& request)
|
[&](clap::ext::params::plugin::Flush& request)
|
||||||
-> clap::ext::params::plugin::Flush::Response {
|
-> clap::ext::params::plugin::Flush::Response {
|
||||||
const auto& [instance, _] =
|
const auto& [instance, _] =
|
||||||
get_instance(request.instance_id);
|
get_instance(request.instance_id);
|
||||||
|
|
||||||
clap::events::EventList out{};
|
clap::events::EventList out{};
|
||||||
instance.extensions.params->flush(
|
instance.extensions.params->flush(instance.plugin.get(),
|
||||||
instance.plugin.get(), request.in.input_events(),
|
request.in.input_events(),
|
||||||
out.output_events());
|
out.output_events());
|
||||||
|
|
||||||
return clap::ext::params::plugin::FlushResponse{
|
return clap::ext::params::plugin::FlushResponse{
|
||||||
@@ -960,8 +998,7 @@ void ClapBridge::register_plugin_instance(
|
|||||||
const auto& [instance, _] =
|
const auto& [instance, _] =
|
||||||
get_instance(request.instance_id);
|
get_instance(request.instance_id);
|
||||||
|
|
||||||
return instance.extensions.tail->get(
|
return instance.extensions.tail->get(instance.plugin.get());
|
||||||
instance.plugin.get());
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user