mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-10 04:30:12 +02:00
Add dedicated IAudioProcessor/IComponent sockets
This way every relevant object instance will get its own thread for handling these calls. The alternative would be creating a full fat Vst3MessageHandler pair for all object instances, but that would be a huge waste.
This commit is contained in:
@@ -491,12 +491,14 @@ class AdHocSocketHandler {
|
|||||||
if (acceptor) {
|
if (acceptor) {
|
||||||
acceptor->accept(socket);
|
acceptor->accept(socket);
|
||||||
|
|
||||||
// As mentioned in `acceptor's` docstring, this acceptor will be
|
if constexpr (ad_hoc_sockets) {
|
||||||
// recreated in `receive_multi()` on another context, and
|
// As mentioned in `acceptor's` docstring, this acceptor will be
|
||||||
// potentially on the other side of the connection in the case
|
// recreated in `receive_multi()` on another context, and
|
||||||
// where we're handling `vst_host_callback` VST2 events
|
// potentially on the other side of the connection in the case
|
||||||
acceptor.reset();
|
// where we're handling `vst_host_callback` VST2 events
|
||||||
boost::filesystem::remove(endpoint.path());
|
acceptor.reset();
|
||||||
|
boost::filesystem::remove(endpoint.path());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
socket.connect(endpoint);
|
socket.connect(endpoint);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <future>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include "../logging/vst3.h"
|
#include "../logging/vst3.h"
|
||||||
@@ -221,6 +222,16 @@ class Vst3MessageHandler : public AdHocSocketHandler<Thread, ad_hoc_sockets> {
|
|||||||
* sockets, and the call to `connect()` will then accept any incoming
|
* sockets, and the call to `connect()` will then accept any incoming
|
||||||
* connections.
|
* connections.
|
||||||
*
|
*
|
||||||
|
* We'll have a host -> plugin connection for sending control messages (which is
|
||||||
|
* just a made up term to more easily differentiate between the two directions),
|
||||||
|
* and a plugin -> host connection to allow the plugin to make callbacks. Both
|
||||||
|
* of these connections are capable of spawning additional sockets and threads
|
||||||
|
* as needed.
|
||||||
|
*
|
||||||
|
* For audio processing (or anything that implement `IAudioProcessor` or
|
||||||
|
* `IComonent`) we'll use dedicated sockets per instance, since we don't want to
|
||||||
|
* do anything that could increase latency there.
|
||||||
|
*
|
||||||
* @tparam Thread The thread implementation to use. On the Linux side this
|
* @tparam Thread The thread implementation to use. On the Linux side this
|
||||||
* should be `std::jthread` and on the Wine side this should be `Win32Thread`.
|
* should be `std::jthread` and on the Wine side this should be `Win32Thread`.
|
||||||
*/
|
*/
|
||||||
@@ -250,7 +261,8 @@ class Vst3Sockets : public Sockets {
|
|||||||
listen),
|
listen),
|
||||||
vst_host_callback(io_context,
|
vst_host_callback(io_context,
|
||||||
(base_dir / "vst_host_callback.sock").string(),
|
(base_dir / "vst_host_callback.sock").string(),
|
||||||
listen) {}
|
listen),
|
||||||
|
io_context(io_context) {}
|
||||||
|
|
||||||
~Vst3Sockets() { close(); }
|
~Vst3Sockets() { close(); }
|
||||||
|
|
||||||
@@ -264,17 +276,113 @@ class Vst3Sockets : public Sockets {
|
|||||||
// that may still be active
|
// that may still be active
|
||||||
host_vst_control.close();
|
host_vst_control.close();
|
||||||
vst_host_callback.close();
|
vst_host_callback.close();
|
||||||
|
|
||||||
|
// This map should be empty at this point, but who knows
|
||||||
|
std::lock_guard lock(audio_processor_sockets_mutex);
|
||||||
|
for (auto& [instance_id, socket] : audio_processor_sockets) {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Since audio processing may be done completely in parallel we might
|
/**
|
||||||
// want to have a dedicated socket per processor/controller pair. For
|
* Connect to the dedicated `IAudioProcessor` and `IConnect` handling socket
|
||||||
// this we would need to figure out how to associate a plugin instance
|
* for a plugin object instance. This should be called on the plugin side
|
||||||
// with a socket.
|
* after instantiating such an object.
|
||||||
|
*
|
||||||
|
* @param instance_id The object instance identifier of the socket.
|
||||||
|
*/
|
||||||
|
void add_audio_processor_and_connect(size_t instance_id) {
|
||||||
|
std::lock_guard lock(audio_processor_sockets_mutex);
|
||||||
|
audio_processor_sockets.try_emplace(
|
||||||
|
instance_id, io_context,
|
||||||
|
(base_dir / ("host_vst_audio_processor_" +
|
||||||
|
std::to_string(instance_id) + ".sock"))
|
||||||
|
.string(),
|
||||||
|
false);
|
||||||
|
audio_processor_sockets.at(instance_id).connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and listen on a dedicated `IAudioProcessor` and `IConnect`
|
||||||
|
* handling socket for a plugin object instance. The calling thread will
|
||||||
|
* block until the socket has been closed. This should be called from the
|
||||||
|
* Wine plugin host side after instantiating such an object.
|
||||||
|
*
|
||||||
|
* @param instance_id The object instance identifier of the socket.
|
||||||
|
* @param socket_listening_latch A promise we'll set a value for once the
|
||||||
|
* socket is being listened on so we can wait for it. Otherwise it can be
|
||||||
|
* that the native plugin already tries to connect to the socket before
|
||||||
|
* Wine plugin host is even listening on it.
|
||||||
|
* @param cb An overloaded function that can take every type `T` in the
|
||||||
|
* `AudioProcessorRequest` variant and then returns `T::Response`.
|
||||||
|
*/
|
||||||
|
template <typename F>
|
||||||
|
void add_audio_processor_and_listen(
|
||||||
|
size_t instance_id,
|
||||||
|
std::promise<void>& socket_listening_latch,
|
||||||
|
F cb) {
|
||||||
|
{
|
||||||
|
std::lock_guard lock(audio_processor_sockets_mutex);
|
||||||
|
audio_processor_sockets.try_emplace(
|
||||||
|
instance_id, io_context,
|
||||||
|
(base_dir / ("host_vst_audio_processor_" +
|
||||||
|
std::to_string(instance_id) + ".sock"))
|
||||||
|
.string(),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_listening_latch.set_value();
|
||||||
|
audio_processor_sockets.at(instance_id).connect();
|
||||||
|
audio_processor_sockets.at(instance_id)
|
||||||
|
.receive_messages(std::nullopt, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `instance_id` is in `audio_processor_sockets`, then close its socket
|
||||||
|
* and remove it from the map. This is called from the destructor of
|
||||||
|
* `Vst3PluginProxyImpl` on the plugin side and when handling
|
||||||
|
* `Vst3PluginProxy::Destruct` on the Wine plugin host side.
|
||||||
|
*
|
||||||
|
* @param instance_id The object instance identifier of the socket.
|
||||||
|
*
|
||||||
|
* @return Whether the socket was closed and removed. Returns false if it
|
||||||
|
* wasn't in the map.
|
||||||
|
*/
|
||||||
|
bool remove_audio_processor(size_t instance_id) {
|
||||||
|
std::lock_guard lock(audio_processor_sockets_mutex);
|
||||||
|
if (audio_processor_sockets.contains(instance_id)) {
|
||||||
|
audio_processor_sockets.at(instance_id).close();
|
||||||
|
audio_processor_sockets.erase(instance_id);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message from the native plugin to the Wine plugin host to handle
|
||||||
|
* an `IAudioProcessor` or `IComponent` call. Since those functions are
|
||||||
|
* called from a hot loop we want every instance to have a dedicated socket
|
||||||
|
* and thread for handling those.
|
||||||
|
*
|
||||||
|
* @tparam T Some object in the `AudioProcessorRequest` variant.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
typename T::Response send_audio_processor_message(
|
||||||
|
const T& object,
|
||||||
|
std::optional<std::pair<Vst3Logger&, bool>> logging) {
|
||||||
|
// TODO: These calls should reuse buffers
|
||||||
|
return audio_processor_sockets.at(object.instance_id)
|
||||||
|
.send_message(object, logging);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For sending messages from the host to the plugin. After we have a better
|
* For sending messages from the host to the plugin. After we have a better
|
||||||
* idea of what our communication model looks like we'll probably want to
|
* idea of what our communication model looks like we'll probably want to
|
||||||
* provide an abstraction similar to `EventHandler`.
|
* provide an abstraction similar to `EventHandler`. For optimization
|
||||||
|
* reasons calls to `IAudioProcessor` or `IComponent` are handled using the
|
||||||
|
* dedicated sockets in `audio_processor_sockets`.
|
||||||
*
|
*
|
||||||
* This will be listened on by the Wine plugin host when it calls
|
* This will be listened on by the Wine plugin host when it calls
|
||||||
* `receive_multi()`.
|
* `receive_multi()`.
|
||||||
@@ -287,4 +395,22 @@ class Vst3Sockets : public Sockets {
|
|||||||
* want to provide an abstraction similar to `EventHandler`.
|
* want to provide an abstraction similar to `EventHandler`.
|
||||||
*/
|
*/
|
||||||
Vst3MessageHandler<Thread, CallbackRequest, true> vst_host_callback;
|
Vst3MessageHandler<Thread, CallbackRequest, true> vst_host_callback;
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::asio::io_context& io_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every `IAudioProcessor` or `IComponent` instance (which likely implements
|
||||||
|
* both of those) will get a dedicated socket. These functions are always
|
||||||
|
* called in a hot loop, so there should not be any waiting or additional
|
||||||
|
* thread or socket creation happening there.
|
||||||
|
*
|
||||||
|
* THe last `false` template arguments means that we'll disable all ad-hoc
|
||||||
|
* socket and thread spawning behaviour. Otherwise every plugin instance
|
||||||
|
* would have one dedicated thread for handling function calls to these
|
||||||
|
* interfaces, and then another dedicated thread just idling around.
|
||||||
|
*/
|
||||||
|
std::map<size_t, Vst3MessageHandler<Thread, AudioProcessorRequest, false>>
|
||||||
|
audio_processor_sockets;
|
||||||
|
std::mutex audio_processor_sockets_mutex;
|
||||||
};
|
};
|
||||||
|
|||||||
+273
-273
@@ -90,210 +90,6 @@ bool Vst3Logger::log_request(bool is_host_vst,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Vst3Logger::log_request(
|
|
||||||
bool is_host_vst,
|
|
||||||
const YaAudioProcessor::SetBusArrangements& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IAudioProcessor::setBusArrangements(inputs = "
|
|
||||||
"[SpeakerArrangement; "
|
|
||||||
<< request.inputs.size() << "], numIns = " << request.num_ins
|
|
||||||
<< ", outputs = [SpeakerArrangement; " << request.outputs.size()
|
|
||||||
<< "], numOuts = " << request.num_outs << ")";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(
|
|
||||||
bool is_host_vst,
|
|
||||||
const YaAudioProcessor::GetBusArrangement& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IAudioProcessor::getBusArrangement(dir = " << request.dir
|
|
||||||
<< ", index = " << request.index << ", &arr)";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(
|
|
||||||
bool is_host_vst,
|
|
||||||
const YaAudioProcessor::CanProcessSampleSize& request) {
|
|
||||||
return log_request_base(
|
|
||||||
is_host_vst, Logger::Verbosity::all_events, [&](auto& message) {
|
|
||||||
message
|
|
||||||
<< request.instance_id
|
|
||||||
<< ": IAudioProcessor::canProcessSampleSize(symbolicSampleSize "
|
|
||||||
"= "
|
|
||||||
<< request.symbolic_sample_size << ")";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(
|
|
||||||
bool is_host_vst,
|
|
||||||
const YaAudioProcessor::GetLatencySamples& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IAudioProcessor::getLatencySamples()";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::SetupProcessing& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IAudioProcessor::setupProcessing(setup = "
|
|
||||||
"<SetupProcessing with mode = "
|
|
||||||
<< request.setup.processMode << ", symbolic_sample_size = "
|
|
||||||
<< request.setup.symbolicSampleSize
|
|
||||||
<< ", max_buffer_size = " << request.setup.maxSamplesPerBlock
|
|
||||||
<< " and sample_rate = " << request.setup.sampleRate << ">)";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::SetProcessing& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IAudioProcessor::setProcessing(state = "
|
|
||||||
<< (request.state ? "true" : "false") << ")";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::Process& request) {
|
|
||||||
return log_request_base(
|
|
||||||
is_host_vst, Logger::Verbosity::all_events, [&](auto& message) {
|
|
||||||
// This is incredibly verbose, but if you're really a plugin that
|
|
||||||
// handles processing in a weird way you're going to need all of
|
|
||||||
// this
|
|
||||||
|
|
||||||
std::ostringstream num_input_channels;
|
|
||||||
num_input_channels << "[";
|
|
||||||
for (bool is_first = true;
|
|
||||||
const auto& buffers : request.data.inputs) {
|
|
||||||
num_input_channels << (is_first ? "" : ", ")
|
|
||||||
<< buffers.num_channels();
|
|
||||||
is_first = false;
|
|
||||||
}
|
|
||||||
num_input_channels << "]";
|
|
||||||
|
|
||||||
std::ostringstream num_output_channels;
|
|
||||||
num_output_channels << "[";
|
|
||||||
for (bool is_first = true;
|
|
||||||
const auto& num_channels : request.data.outputs_num_channels) {
|
|
||||||
num_output_channels << (is_first ? "" : ", ") << num_channels;
|
|
||||||
is_first = false;
|
|
||||||
}
|
|
||||||
num_output_channels << "]";
|
|
||||||
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IAudioProcessor::process(data = <ProcessData with "
|
|
||||||
"input_channels = "
|
|
||||||
<< num_input_channels.str()
|
|
||||||
<< ", output_channels = " << num_output_channels.str()
|
|
||||||
<< ", num_samples = " << request.data.process_mode
|
|
||||||
<< ", input_parameter_changes = <IParameterChanges* for "
|
|
||||||
<< request.data.input_parameter_changes.num_parameters()
|
|
||||||
<< " parameters>, output_parameter_changes = "
|
|
||||||
<< (request.data.output_parameter_changes_supported
|
|
||||||
? "<IParameterChanges*>"
|
|
||||||
: "nullptr")
|
|
||||||
<< ", input_events = ";
|
|
||||||
if (request.data.input_events) {
|
|
||||||
message << "<IEventList* with "
|
|
||||||
<< request.data.input_events->num_events()
|
|
||||||
<< " events>";
|
|
||||||
} else {
|
|
||||||
message << "nullptr";
|
|
||||||
}
|
|
||||||
message << ", output_events = "
|
|
||||||
<< (request.data.output_events_supported ? "<IEventList*>"
|
|
||||||
: "nullptr")
|
|
||||||
<< ", process_context = "
|
|
||||||
<< (request.data.process_context ? "<ProcessContext*>"
|
|
||||||
: "nullptr")
|
|
||||||
<< ", process_mode = " << request.data.process_mode
|
|
||||||
<< ", symbolic_sample_size = "
|
|
||||||
<< request.data.symbolic_sample_size << ">)";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::GetTailSamples& request) {
|
|
||||||
return log_request_base(
|
|
||||||
is_host_vst, Logger::Verbosity::all_events, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IAudioProcessor::getTailSamples()";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaComponent::GetControllerClassId& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IComponent::getControllerClassId(&classId)";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaComponent::SetIoMode& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IComponent::setIoMode(mode = " << request.mode << ")";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaComponent::GetBusCount& request) {
|
|
||||||
// JUCE-based hosts will call this every processing cycle, for some reason
|
|
||||||
// (it shouldn't be allwoed to change during processing, right?)
|
|
||||||
return log_request_base(
|
|
||||||
is_host_vst, Logger::Verbosity::all_events, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IComponent::getBusCount(type = " << request.type
|
|
||||||
<< ", dir = " << request.dir << ")";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaComponent::GetBusInfo& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IComponent::getBusInfo(type = " << request.type
|
|
||||||
<< ", dir = " << request.dir << ", index = " << request.index
|
|
||||||
<< ", &bus)";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaComponent::GetRoutingInfo& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message
|
|
||||||
<< request.instance_id
|
|
||||||
<< ": IComponent::getRoutingInfo(inInfo = <RoutingInfo& for bus "
|
|
||||||
<< request.in_info.busIndex << " and channel "
|
|
||||||
<< request.in_info.channel << ">, outInfo = <RoutingInfo& for bus "
|
|
||||||
<< request.out_info.busIndex << " and channel "
|
|
||||||
<< request.out_info.channel << ">)";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaComponent::ActivateBus& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id
|
|
||||||
<< ": IComponent::activateBus(type = " << request.type
|
|
||||||
<< ", dir = " << request.dir << ", index = " << request.index
|
|
||||||
<< ", state = " << (request.state ? "true" : "false") << ")";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
|
||||||
const YaComponent::SetActive& request) {
|
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << request.instance_id << ": IComponent::setActive(state = "
|
|
||||||
<< (request.state ? "true" : "false") << ")";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst,
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
const YaConnectionPoint::Connect& request) {
|
const YaConnectionPoint::Connect& request) {
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
@@ -508,6 +304,210 @@ bool Vst3Logger::log_request(bool is_host_vst,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(
|
||||||
|
bool is_host_vst,
|
||||||
|
const YaAudioProcessor::SetBusArrangements& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IAudioProcessor::setBusArrangements(inputs = "
|
||||||
|
"[SpeakerArrangement; "
|
||||||
|
<< request.inputs.size() << "], numIns = " << request.num_ins
|
||||||
|
<< ", outputs = [SpeakerArrangement; " << request.outputs.size()
|
||||||
|
<< "], numOuts = " << request.num_outs << ")";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(
|
||||||
|
bool is_host_vst,
|
||||||
|
const YaAudioProcessor::GetBusArrangement& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IAudioProcessor::getBusArrangement(dir = " << request.dir
|
||||||
|
<< ", index = " << request.index << ", &arr)";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(
|
||||||
|
bool is_host_vst,
|
||||||
|
const YaAudioProcessor::CanProcessSampleSize& request) {
|
||||||
|
return log_request_base(
|
||||||
|
is_host_vst, Logger::Verbosity::all_events, [&](auto& message) {
|
||||||
|
message
|
||||||
|
<< request.instance_id
|
||||||
|
<< ": IAudioProcessor::canProcessSampleSize(symbolicSampleSize "
|
||||||
|
"= "
|
||||||
|
<< request.symbolic_sample_size << ")";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(
|
||||||
|
bool is_host_vst,
|
||||||
|
const YaAudioProcessor::GetLatencySamples& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IAudioProcessor::getLatencySamples()";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::SetupProcessing& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IAudioProcessor::setupProcessing(setup = "
|
||||||
|
"<SetupProcessing with mode = "
|
||||||
|
<< request.setup.processMode << ", symbolic_sample_size = "
|
||||||
|
<< request.setup.symbolicSampleSize
|
||||||
|
<< ", max_buffer_size = " << request.setup.maxSamplesPerBlock
|
||||||
|
<< " and sample_rate = " << request.setup.sampleRate << ">)";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::SetProcessing& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IAudioProcessor::setProcessing(state = "
|
||||||
|
<< (request.state ? "true" : "false") << ")";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::Process& request) {
|
||||||
|
return log_request_base(
|
||||||
|
is_host_vst, Logger::Verbosity::all_events, [&](auto& message) {
|
||||||
|
// This is incredibly verbose, but if you're really a plugin that
|
||||||
|
// handles processing in a weird way you're going to need all of
|
||||||
|
// this
|
||||||
|
|
||||||
|
std::ostringstream num_input_channels;
|
||||||
|
num_input_channels << "[";
|
||||||
|
for (bool is_first = true;
|
||||||
|
const auto& buffers : request.data.inputs) {
|
||||||
|
num_input_channels << (is_first ? "" : ", ")
|
||||||
|
<< buffers.num_channels();
|
||||||
|
is_first = false;
|
||||||
|
}
|
||||||
|
num_input_channels << "]";
|
||||||
|
|
||||||
|
std::ostringstream num_output_channels;
|
||||||
|
num_output_channels << "[";
|
||||||
|
for (bool is_first = true;
|
||||||
|
const auto& num_channels : request.data.outputs_num_channels) {
|
||||||
|
num_output_channels << (is_first ? "" : ", ") << num_channels;
|
||||||
|
is_first = false;
|
||||||
|
}
|
||||||
|
num_output_channels << "]";
|
||||||
|
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IAudioProcessor::process(data = <ProcessData with "
|
||||||
|
"input_channels = "
|
||||||
|
<< num_input_channels.str()
|
||||||
|
<< ", output_channels = " << num_output_channels.str()
|
||||||
|
<< ", num_samples = " << request.data.process_mode
|
||||||
|
<< ", input_parameter_changes = <IParameterChanges* for "
|
||||||
|
<< request.data.input_parameter_changes.num_parameters()
|
||||||
|
<< " parameters>, output_parameter_changes = "
|
||||||
|
<< (request.data.output_parameter_changes_supported
|
||||||
|
? "<IParameterChanges*>"
|
||||||
|
: "nullptr")
|
||||||
|
<< ", input_events = ";
|
||||||
|
if (request.data.input_events) {
|
||||||
|
message << "<IEventList* with "
|
||||||
|
<< request.data.input_events->num_events()
|
||||||
|
<< " events>";
|
||||||
|
} else {
|
||||||
|
message << "nullptr";
|
||||||
|
}
|
||||||
|
message << ", output_events = "
|
||||||
|
<< (request.data.output_events_supported ? "<IEventList*>"
|
||||||
|
: "nullptr")
|
||||||
|
<< ", process_context = "
|
||||||
|
<< (request.data.process_context ? "<ProcessContext*>"
|
||||||
|
: "nullptr")
|
||||||
|
<< ", process_mode = " << request.data.process_mode
|
||||||
|
<< ", symbolic_sample_size = "
|
||||||
|
<< request.data.symbolic_sample_size << ">)";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::GetTailSamples& request) {
|
||||||
|
return log_request_base(
|
||||||
|
is_host_vst, Logger::Verbosity::all_events, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IAudioProcessor::getTailSamples()";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaComponent::GetControllerClassId& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IComponent::getControllerClassId(&classId)";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaComponent::SetIoMode& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IComponent::setIoMode(mode = " << request.mode << ")";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaComponent::GetBusCount& request) {
|
||||||
|
// JUCE-based hosts will call this every processing cycle, for some reason
|
||||||
|
// (it shouldn't be allwoed to change during processing, right?)
|
||||||
|
return log_request_base(
|
||||||
|
is_host_vst, Logger::Verbosity::all_events, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IComponent::getBusCount(type = " << request.type
|
||||||
|
<< ", dir = " << request.dir << ")";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaComponent::GetBusInfo& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IComponent::getBusInfo(type = " << request.type
|
||||||
|
<< ", dir = " << request.dir << ", index = " << request.index
|
||||||
|
<< ", &bus)";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaComponent::GetRoutingInfo& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message
|
||||||
|
<< request.instance_id
|
||||||
|
<< ": IComponent::getRoutingInfo(inInfo = <RoutingInfo& for bus "
|
||||||
|
<< request.in_info.busIndex << " and channel "
|
||||||
|
<< request.in_info.channel << ">, outInfo = <RoutingInfo& for bus "
|
||||||
|
<< request.out_info.busIndex << " and channel "
|
||||||
|
<< request.out_info.channel << ">)";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaComponent::ActivateBus& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id
|
||||||
|
<< ": IComponent::activateBus(type = " << request.type
|
||||||
|
<< ", dir = " << request.dir << ", index = " << request.index
|
||||||
|
<< ", state = " << (request.state ? "true" : "false") << ")";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst3Logger::log_request(bool is_host_vst,
|
||||||
|
const YaComponent::SetActive& request) {
|
||||||
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << request.instance_id << ": IComponent::setActive(state = "
|
||||||
|
<< (request.state ? "true" : "false") << ")";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool Vst3Logger::log_request(bool is_host_vst, const WantsConfiguration&) {
|
bool Vst3Logger::log_request(bool is_host_vst, const WantsConfiguration&) {
|
||||||
return log_request_base(is_host_vst, [&](auto& message) {
|
return log_request_base(is_host_vst, [&](auto& message) {
|
||||||
message << "Requesting <Configuration>";
|
message << "Requesting <Configuration>";
|
||||||
@@ -593,6 +593,75 @@ void Vst3Logger::log_response(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Vst3Logger::log_response(
|
||||||
|
bool is_host_vst,
|
||||||
|
const YaEditController::GetParameterInfoResponse& response) {
|
||||||
|
log_response_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << response.result.string();
|
||||||
|
if (response.result == Steinberg::kResultOk) {
|
||||||
|
std::string param_title =
|
||||||
|
VST3::StringConvert::convert(response.updated_info.title);
|
||||||
|
message << ", <ParameterInfo for '" << param_title << "'>";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst3Logger::log_response(
|
||||||
|
bool is_host_vst,
|
||||||
|
const YaEditController::GetParamStringByValueResponse& response) {
|
||||||
|
log_response_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << response.result.string();
|
||||||
|
if (response.result == Steinberg::kResultOk) {
|
||||||
|
std::string value = VST3::StringConvert::convert(response.string);
|
||||||
|
message << ", \"" << value << "\"";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst3Logger::log_response(
|
||||||
|
bool is_host_vst,
|
||||||
|
const YaEditController::GetParamValueByStringResponse& response) {
|
||||||
|
log_response_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << response.result.string();
|
||||||
|
if (response.result == Steinberg::kResultOk) {
|
||||||
|
message << ", " << response.value_normalized;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst3Logger::log_response(
|
||||||
|
bool is_host_vst,
|
||||||
|
const YaEditController::CreateViewResponse& response) {
|
||||||
|
log_response_base(is_host_vst, [&](auto& message) {
|
||||||
|
if (response.plug_view_args) {
|
||||||
|
message << "<IPlugView*>";
|
||||||
|
} else {
|
||||||
|
message << "<nullptr>";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst3Logger::log_response(bool is_host_vst,
|
||||||
|
const YaPlugView::GetSizeResponse& response) {
|
||||||
|
log_response_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << response.result.string();
|
||||||
|
if (response.result == Steinberg::kResultOk) {
|
||||||
|
message << ", <ViewRect* with left = " << response.updated_size.left
|
||||||
|
<< ", top = " << response.updated_size.top
|
||||||
|
<< ", right = " << response.updated_size.right
|
||||||
|
<< ", bottom = " << response.updated_size.bottom << ">";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst3Logger::log_response(bool is_host_vst,
|
||||||
|
const YaPluginFactory::ConstructArgs& args) {
|
||||||
|
log_response_base(is_host_vst, [&](auto& message) {
|
||||||
|
message << "<IPluginFactory*> with " << args.num_classes
|
||||||
|
<< " registered classes";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Vst3Logger::log_response(
|
void Vst3Logger::log_response(
|
||||||
bool is_host_vst,
|
bool is_host_vst,
|
||||||
const YaAudioProcessor::GetBusArrangementResponse& response) {
|
const YaAudioProcessor::GetBusArrangementResponse& response) {
|
||||||
@@ -684,75 +753,6 @@ void Vst3Logger::log_response(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vst3Logger::log_response(
|
|
||||||
bool is_host_vst,
|
|
||||||
const YaEditController::GetParameterInfoResponse& response) {
|
|
||||||
log_response_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << response.result.string();
|
|
||||||
if (response.result == Steinberg::kResultOk) {
|
|
||||||
std::string param_title =
|
|
||||||
VST3::StringConvert::convert(response.updated_info.title);
|
|
||||||
message << ", <ParameterInfo for '" << param_title << "'>";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Vst3Logger::log_response(
|
|
||||||
bool is_host_vst,
|
|
||||||
const YaEditController::GetParamStringByValueResponse& response) {
|
|
||||||
log_response_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << response.result.string();
|
|
||||||
if (response.result == Steinberg::kResultOk) {
|
|
||||||
std::string value = VST3::StringConvert::convert(response.string);
|
|
||||||
message << ", \"" << value << "\"";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Vst3Logger::log_response(
|
|
||||||
bool is_host_vst,
|
|
||||||
const YaEditController::GetParamValueByStringResponse& response) {
|
|
||||||
log_response_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << response.result.string();
|
|
||||||
if (response.result == Steinberg::kResultOk) {
|
|
||||||
message << ", " << response.value_normalized;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Vst3Logger::log_response(
|
|
||||||
bool is_host_vst,
|
|
||||||
const YaEditController::CreateViewResponse& response) {
|
|
||||||
log_response_base(is_host_vst, [&](auto& message) {
|
|
||||||
if (response.plug_view_args) {
|
|
||||||
message << "<IPlugView*>";
|
|
||||||
} else {
|
|
||||||
message << "<nullptr>";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Vst3Logger::log_response(bool is_host_vst,
|
|
||||||
const YaPlugView::GetSizeResponse& response) {
|
|
||||||
log_response_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << response.result.string();
|
|
||||||
if (response.result == Steinberg::kResultOk) {
|
|
||||||
message << ", <ViewRect* with left = " << response.updated_size.left
|
|
||||||
<< ", top = " << response.updated_size.top
|
|
||||||
<< ", right = " << response.updated_size.right
|
|
||||||
<< ", bottom = " << response.updated_size.bottom << ">";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Vst3Logger::log_response(bool is_host_vst,
|
|
||||||
const YaPluginFactory::ConstructArgs& args) {
|
|
||||||
log_response_base(is_host_vst, [&](auto& message) {
|
|
||||||
message << "<IPluginFactory*> with " << args.num_classes
|
|
||||||
<< " registered classes";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Vst3Logger::log_response(bool is_host_vst, const Configuration&) {
|
void Vst3Logger::log_response(bool is_host_vst, const Configuration&) {
|
||||||
log_response_base(is_host_vst,
|
log_response_base(is_host_vst,
|
||||||
[&](auto& message) { message << "<Configuration>"; });
|
[&](auto& message) { message << "<Configuration>"; });
|
||||||
|
|||||||
+32
-30
@@ -64,27 +64,6 @@ class Vst3Logger {
|
|||||||
bool log_request(bool is_host_vst, const Vst3PluginProxy::Destruct&);
|
bool log_request(bool is_host_vst, const Vst3PluginProxy::Destruct&);
|
||||||
bool log_request(bool is_host_vst, const Vst3PluginProxy::SetState&);
|
bool log_request(bool is_host_vst, const Vst3PluginProxy::SetState&);
|
||||||
bool log_request(bool is_host_vst, const Vst3PluginProxy::GetState&);
|
bool log_request(bool is_host_vst, const Vst3PluginProxy::GetState&);
|
||||||
bool log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::SetBusArrangements&);
|
|
||||||
bool log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::GetBusArrangement&);
|
|
||||||
bool log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::CanProcessSampleSize&);
|
|
||||||
bool log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::GetLatencySamples&);
|
|
||||||
bool log_request(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::SetupProcessing&);
|
|
||||||
bool log_request(bool is_host_vst, const YaAudioProcessor::SetProcessing&);
|
|
||||||
bool log_request(bool is_host_vst, const YaAudioProcessor::Process&);
|
|
||||||
bool log_request(bool is_host_vst, const YaAudioProcessor::GetTailSamples&);
|
|
||||||
bool log_request(bool is_host_vst,
|
|
||||||
const YaComponent::GetControllerClassId&);
|
|
||||||
bool log_request(bool is_host_vst, const YaComponent::SetIoMode&);
|
|
||||||
bool log_request(bool is_host_vst, const YaComponent::GetBusCount&);
|
|
||||||
bool log_request(bool is_host_vst, const YaComponent::GetBusInfo&);
|
|
||||||
bool log_request(bool is_host_vst, const YaComponent::GetRoutingInfo&);
|
|
||||||
bool log_request(bool is_host_vst, const YaComponent::ActivateBus&);
|
|
||||||
bool log_request(bool is_host_vst, const YaComponent::SetActive&);
|
|
||||||
bool log_request(bool is_host_vst, const YaConnectionPoint::Connect&);
|
bool log_request(bool is_host_vst, const YaConnectionPoint::Connect&);
|
||||||
bool log_request(bool is_host_vst, const YaConnectionPoint::Disconnect&);
|
bool log_request(bool is_host_vst, const YaConnectionPoint::Disconnect&);
|
||||||
bool log_request(bool is_host_vst,
|
bool log_request(bool is_host_vst,
|
||||||
@@ -117,6 +96,28 @@ class Vst3Logger {
|
|||||||
bool log_request(bool is_host_vst, const YaPluginFactory::Construct&);
|
bool log_request(bool is_host_vst, const YaPluginFactory::Construct&);
|
||||||
bool log_request(bool is_host_vst, const YaPluginFactory::SetHostContext&);
|
bool log_request(bool is_host_vst, const YaPluginFactory::SetHostContext&);
|
||||||
|
|
||||||
|
bool log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::SetBusArrangements&);
|
||||||
|
bool log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::GetBusArrangement&);
|
||||||
|
bool log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::CanProcessSampleSize&);
|
||||||
|
bool log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::GetLatencySamples&);
|
||||||
|
bool log_request(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::SetupProcessing&);
|
||||||
|
bool log_request(bool is_host_vst, const YaAudioProcessor::SetProcessing&);
|
||||||
|
bool log_request(bool is_host_vst, const YaAudioProcessor::Process&);
|
||||||
|
bool log_request(bool is_host_vst, const YaAudioProcessor::GetTailSamples&);
|
||||||
|
bool log_request(bool is_host_vst,
|
||||||
|
const YaComponent::GetControllerClassId&);
|
||||||
|
bool log_request(bool is_host_vst, const YaComponent::SetIoMode&);
|
||||||
|
bool log_request(bool is_host_vst, const YaComponent::GetBusCount&);
|
||||||
|
bool log_request(bool is_host_vst, const YaComponent::GetBusInfo&);
|
||||||
|
bool log_request(bool is_host_vst, const YaComponent::GetRoutingInfo&);
|
||||||
|
bool log_request(bool is_host_vst, const YaComponent::ActivateBus&);
|
||||||
|
bool log_request(bool is_host_vst, const YaComponent::SetActive&);
|
||||||
|
|
||||||
bool log_request(bool is_host_vst, const WantsConfiguration&);
|
bool log_request(bool is_host_vst, const WantsConfiguration&);
|
||||||
bool log_request(bool is_host_vst, const YaComponentHandler::BeginEdit&);
|
bool log_request(bool is_host_vst, const YaComponentHandler::BeginEdit&);
|
||||||
bool log_request(bool is_host_vst, const YaComponentHandler::PerformEdit&);
|
bool log_request(bool is_host_vst, const YaComponentHandler::PerformEdit&);
|
||||||
@@ -131,15 +132,6 @@ class Vst3Logger {
|
|||||||
const std::variant<Vst3PluginProxy::ConstructArgs, UniversalTResult>&);
|
const std::variant<Vst3PluginProxy::ConstructArgs, UniversalTResult>&);
|
||||||
void log_response(bool is_host_vst,
|
void log_response(bool is_host_vst,
|
||||||
const Vst3PluginProxy::GetStateResponse&);
|
const Vst3PluginProxy::GetStateResponse&);
|
||||||
void log_response(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::GetBusArrangementResponse&);
|
|
||||||
void log_response(bool is_host_vst,
|
|
||||||
const YaAudioProcessor::ProcessResponse&);
|
|
||||||
void log_response(bool is_host_vst,
|
|
||||||
const YaComponent::GetControllerClassIdResponse&);
|
|
||||||
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,
|
void log_response(bool is_host_vst,
|
||||||
const YaEditController::GetParameterInfoResponse&);
|
const YaEditController::GetParameterInfoResponse&);
|
||||||
void log_response(bool is_host_vst,
|
void log_response(bool is_host_vst,
|
||||||
@@ -152,6 +144,16 @@ class Vst3Logger {
|
|||||||
void log_response(bool is_host_vst, const YaPluginFactory::ConstructArgs&);
|
void log_response(bool is_host_vst, const YaPluginFactory::ConstructArgs&);
|
||||||
void log_response(bool is_host_vst, const Configuration&);
|
void log_response(bool is_host_vst, const Configuration&);
|
||||||
|
|
||||||
|
void log_response(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::GetBusArrangementResponse&);
|
||||||
|
void log_response(bool is_host_vst,
|
||||||
|
const YaAudioProcessor::ProcessResponse&);
|
||||||
|
void log_response(bool is_host_vst,
|
||||||
|
const YaComponent::GetControllerClassIdResponse&);
|
||||||
|
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,
|
void log_response(bool is_host_vst,
|
||||||
const YaHostApplication::GetNameResponse&);
|
const YaHostApplication::GetNameResponse&);
|
||||||
|
|
||||||
|
|||||||
@@ -64,21 +64,6 @@ using ControlRequest = std::variant<Vst3PlugViewProxy::Destruct,
|
|||||||
Vst3PluginProxy::Destruct,
|
Vst3PluginProxy::Destruct,
|
||||||
Vst3PluginProxy::SetState,
|
Vst3PluginProxy::SetState,
|
||||||
Vst3PluginProxy::GetState,
|
Vst3PluginProxy::GetState,
|
||||||
YaAudioProcessor::SetBusArrangements,
|
|
||||||
YaAudioProcessor::GetBusArrangement,
|
|
||||||
YaAudioProcessor::CanProcessSampleSize,
|
|
||||||
YaAudioProcessor::GetLatencySamples,
|
|
||||||
YaAudioProcessor::SetupProcessing,
|
|
||||||
YaAudioProcessor::SetProcessing,
|
|
||||||
YaAudioProcessor::Process,
|
|
||||||
YaAudioProcessor::GetTailSamples,
|
|
||||||
YaComponent::GetControllerClassId,
|
|
||||||
YaComponent::SetIoMode,
|
|
||||||
YaComponent::GetBusCount,
|
|
||||||
YaComponent::GetBusInfo,
|
|
||||||
YaComponent::GetRoutingInfo,
|
|
||||||
YaComponent::ActivateBus,
|
|
||||||
YaComponent::SetActive,
|
|
||||||
YaConnectionPoint::Connect,
|
YaConnectionPoint::Connect,
|
||||||
YaConnectionPoint::Disconnect,
|
YaConnectionPoint::Disconnect,
|
||||||
YaEditController::SetComponentState,
|
YaEditController::SetComponentState,
|
||||||
@@ -107,6 +92,35 @@ void serialize(S& s, ControlRequest& payload) {
|
|||||||
s.ext(payload, bitsery::ext::StdVariant{});
|
s.ext(payload, bitsery::ext::StdVariant{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A subset of all functions a host can call on a plugin. These functions are
|
||||||
|
* called from a hot loop every processing cycle, so we want a dedicated socket
|
||||||
|
* for these for every plugin instance.
|
||||||
|
*/
|
||||||
|
using AudioProcessorRequest =
|
||||||
|
std::variant<YaAudioProcessor::SetBusArrangements,
|
||||||
|
YaAudioProcessor::GetBusArrangement,
|
||||||
|
YaAudioProcessor::CanProcessSampleSize,
|
||||||
|
YaAudioProcessor::GetLatencySamples,
|
||||||
|
YaAudioProcessor::SetupProcessing,
|
||||||
|
YaAudioProcessor::SetProcessing,
|
||||||
|
YaAudioProcessor::Process,
|
||||||
|
YaAudioProcessor::GetTailSamples,
|
||||||
|
YaComponent::GetControllerClassId,
|
||||||
|
YaComponent::SetIoMode,
|
||||||
|
YaComponent::GetBusCount,
|
||||||
|
YaComponent::GetBusInfo,
|
||||||
|
YaComponent::GetRoutingInfo,
|
||||||
|
YaComponent::ActivateBus,
|
||||||
|
YaComponent::SetActive>;
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
void serialize(S& s, AudioProcessorRequest& payload) {
|
||||||
|
// All of the objects in `AudioProcessorRequest` should have their own
|
||||||
|
// serialization function.
|
||||||
|
s.ext(payload, bitsery::ext::StdVariant{});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When we do a callback from the Wine VST host to the plugin, this encodes the
|
* When we do a callback from the Wine VST host to the plugin, this encodes the
|
||||||
* information we want or the operation we want to perform. A request of type
|
* information we want or the operation we want to perform. A request of type
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Vst3PluginProxyImpl::Vst3PluginProxyImpl(Vst3PluginBridge& bridge,
|
|||||||
Vst3PluginProxyImpl::~Vst3PluginProxyImpl() {
|
Vst3PluginProxyImpl::~Vst3PluginProxyImpl() {
|
||||||
bridge.send_message(
|
bridge.send_message(
|
||||||
Vst3PluginProxy::Destruct{.instance_id = instance_id()});
|
Vst3PluginProxy::Destruct{.instance_id = instance_id()});
|
||||||
bridge.unregister_plugin_proxy(instance_id());
|
bridge.unregister_plugin_proxy(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
tresult PLUGIN_API
|
tresult PLUGIN_API
|
||||||
@@ -49,29 +49,32 @@ tresult PLUGIN_API Vst3PluginProxyImpl::setBusArrangements(
|
|||||||
int32 numOuts) {
|
int32 numOuts) {
|
||||||
// NOTE: Ardour passes a null pointer when `numIns` or `numOuts` is 0, so we
|
// NOTE: Ardour passes a null pointer when `numIns` or `numOuts` is 0, so we
|
||||||
// need to work around that
|
// need to work around that
|
||||||
return bridge.send_message(YaAudioProcessor::SetBusArrangements{
|
return bridge.send_audio_processor_message(
|
||||||
.instance_id = instance_id(),
|
YaAudioProcessor::SetBusArrangements{
|
||||||
.inputs = (inputs ? std::vector<Steinberg::Vst::SpeakerArrangement>(
|
.instance_id = instance_id(),
|
||||||
inputs, &inputs[numIns])
|
.inputs =
|
||||||
: std::vector<Steinberg::Vst::SpeakerArrangement>()),
|
(inputs ? std::vector<Steinberg::Vst::SpeakerArrangement>(
|
||||||
.num_ins = numIns,
|
inputs, &inputs[numIns])
|
||||||
.outputs =
|
: std::vector<Steinberg::Vst::SpeakerArrangement>()),
|
||||||
(outputs ? std::vector<Steinberg::Vst::SpeakerArrangement>(
|
.num_ins = numIns,
|
||||||
outputs, &outputs[numOuts])
|
.outputs =
|
||||||
: std::vector<Steinberg::Vst::SpeakerArrangement>()),
|
(outputs ? std::vector<Steinberg::Vst::SpeakerArrangement>(
|
||||||
.num_outs = numOuts,
|
outputs, &outputs[numOuts])
|
||||||
});
|
: std::vector<Steinberg::Vst::SpeakerArrangement>()),
|
||||||
|
.num_outs = numOuts,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tresult PLUGIN_API Vst3PluginProxyImpl::getBusArrangement(
|
tresult PLUGIN_API Vst3PluginProxyImpl::getBusArrangement(
|
||||||
Steinberg::Vst::BusDirection dir,
|
Steinberg::Vst::BusDirection dir,
|
||||||
int32 index,
|
int32 index,
|
||||||
Steinberg::Vst::SpeakerArrangement& arr) {
|
Steinberg::Vst::SpeakerArrangement& arr) {
|
||||||
const GetBusArrangementResponse response = bridge.send_message(
|
const GetBusArrangementResponse response =
|
||||||
YaAudioProcessor::GetBusArrangement{.instance_id = instance_id(),
|
bridge.send_audio_processor_message(
|
||||||
.dir = dir,
|
YaAudioProcessor::GetBusArrangement{.instance_id = instance_id(),
|
||||||
.index = index,
|
.dir = dir,
|
||||||
.arr = arr});
|
.index = index,
|
||||||
|
.arr = arr});
|
||||||
|
|
||||||
arr = response.updated_arr;
|
arr = response.updated_arr;
|
||||||
|
|
||||||
@@ -80,24 +83,26 @@ tresult PLUGIN_API Vst3PluginProxyImpl::getBusArrangement(
|
|||||||
|
|
||||||
tresult PLUGIN_API
|
tresult PLUGIN_API
|
||||||
Vst3PluginProxyImpl::canProcessSampleSize(int32 symbolicSampleSize) {
|
Vst3PluginProxyImpl::canProcessSampleSize(int32 symbolicSampleSize) {
|
||||||
return bridge.send_message(YaAudioProcessor::CanProcessSampleSize{
|
return bridge.send_audio_processor_message(
|
||||||
.instance_id = instance_id(),
|
YaAudioProcessor::CanProcessSampleSize{
|
||||||
.symbolic_sample_size = symbolicSampleSize});
|
.instance_id = instance_id(),
|
||||||
|
.symbolic_sample_size = symbolicSampleSize});
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 PLUGIN_API Vst3PluginProxyImpl::getLatencySamples() {
|
uint32 PLUGIN_API Vst3PluginProxyImpl::getLatencySamples() {
|
||||||
return bridge.send_message(
|
return bridge.send_audio_processor_message(
|
||||||
YaAudioProcessor::GetLatencySamples{.instance_id = instance_id()});
|
YaAudioProcessor::GetLatencySamples{.instance_id = instance_id()});
|
||||||
}
|
}
|
||||||
|
|
||||||
tresult PLUGIN_API
|
tresult PLUGIN_API
|
||||||
Vst3PluginProxyImpl::setupProcessing(Steinberg::Vst::ProcessSetup& setup) {
|
Vst3PluginProxyImpl::setupProcessing(Steinberg::Vst::ProcessSetup& setup) {
|
||||||
return bridge.send_message(YaAudioProcessor::SetupProcessing{
|
return bridge.send_audio_processor_message(
|
||||||
.instance_id = instance_id(), .setup = setup});
|
YaAudioProcessor::SetupProcessing{.instance_id = instance_id(),
|
||||||
|
.setup = setup});
|
||||||
}
|
}
|
||||||
|
|
||||||
tresult PLUGIN_API Vst3PluginProxyImpl::setProcessing(TBool state) {
|
tresult PLUGIN_API Vst3PluginProxyImpl::setProcessing(TBool state) {
|
||||||
return bridge.send_message(YaAudioProcessor::SetProcessing{
|
return bridge.send_audio_processor_message(YaAudioProcessor::SetProcessing{
|
||||||
.instance_id = instance_id(), .state = state});
|
.instance_id = instance_id(), .state = state});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +110,7 @@ tresult PLUGIN_API
|
|||||||
Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) {
|
Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) {
|
||||||
// TODO: Check whether reusing a `YaProcessData` object make a difference in
|
// TODO: Check whether reusing a `YaProcessData` object make a difference in
|
||||||
// terms of performance
|
// terms of performance
|
||||||
ProcessResponse response = bridge.send_message(
|
ProcessResponse response = bridge.send_audio_processor_message(
|
||||||
YaAudioProcessor::Process{.instance_id = instance_id(), .data = data});
|
YaAudioProcessor::Process{.instance_id = instance_id(), .data = data});
|
||||||
|
|
||||||
response.output_data.write_back_outputs(data);
|
response.output_data.write_back_outputs(data);
|
||||||
@@ -114,14 +119,15 @@ Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32 PLUGIN_API Vst3PluginProxyImpl::getTailSamples() {
|
uint32 PLUGIN_API Vst3PluginProxyImpl::getTailSamples() {
|
||||||
return bridge.send_message(
|
return bridge.send_audio_processor_message(
|
||||||
YaAudioProcessor::GetTailSamples{.instance_id = instance_id()});
|
YaAudioProcessor::GetTailSamples{.instance_id = instance_id()});
|
||||||
}
|
}
|
||||||
|
|
||||||
tresult PLUGIN_API
|
tresult PLUGIN_API
|
||||||
Vst3PluginProxyImpl::getControllerClassId(Steinberg::TUID classId) {
|
Vst3PluginProxyImpl::getControllerClassId(Steinberg::TUID classId) {
|
||||||
const GetControllerClassIdResponse response = bridge.send_message(
|
const GetControllerClassIdResponse response =
|
||||||
YaComponent::GetControllerClassId{.instance_id = instance_id()});
|
bridge.send_audio_processor_message(
|
||||||
|
YaComponent::GetControllerClassId{.instance_id = instance_id()});
|
||||||
|
|
||||||
std::copy(response.editor_cid.begin(), response.editor_cid.end(), classId);
|
std::copy(response.editor_cid.begin(), response.editor_cid.end(), classId);
|
||||||
|
|
||||||
@@ -129,14 +135,14 @@ Vst3PluginProxyImpl::getControllerClassId(Steinberg::TUID classId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tresult PLUGIN_API Vst3PluginProxyImpl::setIoMode(Steinberg::Vst::IoMode mode) {
|
tresult PLUGIN_API Vst3PluginProxyImpl::setIoMode(Steinberg::Vst::IoMode mode) {
|
||||||
return bridge.send_message(
|
return bridge.send_audio_processor_message(
|
||||||
YaComponent::SetIoMode{.instance_id = instance_id(), .mode = mode});
|
YaComponent::SetIoMode{.instance_id = instance_id(), .mode = mode});
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 PLUGIN_API
|
int32 PLUGIN_API
|
||||||
Vst3PluginProxyImpl::getBusCount(Steinberg::Vst::MediaType type,
|
Vst3PluginProxyImpl::getBusCount(Steinberg::Vst::MediaType type,
|
||||||
Steinberg::Vst::BusDirection dir) {
|
Steinberg::Vst::BusDirection dir) {
|
||||||
return bridge.send_message(YaComponent::GetBusCount{
|
return bridge.send_audio_processor_message(YaComponent::GetBusCount{
|
||||||
.instance_id = instance_id(), .type = type, .dir = dir});
|
.instance_id = instance_id(), .type = type, .dir = dir});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +151,7 @@ Vst3PluginProxyImpl::getBusInfo(Steinberg::Vst::MediaType type,
|
|||||||
Steinberg::Vst::BusDirection dir,
|
Steinberg::Vst::BusDirection dir,
|
||||||
int32 index,
|
int32 index,
|
||||||
Steinberg::Vst::BusInfo& bus /*out*/) {
|
Steinberg::Vst::BusInfo& bus /*out*/) {
|
||||||
const GetBusInfoResponse response = bridge.send_message(
|
const GetBusInfoResponse response = bridge.send_audio_processor_message(
|
||||||
YaComponent::GetBusInfo{.instance_id = instance_id(),
|
YaComponent::GetBusInfo{.instance_id = instance_id(),
|
||||||
.type = type,
|
.type = type,
|
||||||
.dir = dir,
|
.dir = dir,
|
||||||
@@ -159,7 +165,7 @@ Vst3PluginProxyImpl::getBusInfo(Steinberg::Vst::MediaType type,
|
|||||||
tresult PLUGIN_API Vst3PluginProxyImpl::getRoutingInfo(
|
tresult PLUGIN_API Vst3PluginProxyImpl::getRoutingInfo(
|
||||||
Steinberg::Vst::RoutingInfo& inInfo,
|
Steinberg::Vst::RoutingInfo& inInfo,
|
||||||
Steinberg::Vst::RoutingInfo& outInfo /*out*/) {
|
Steinberg::Vst::RoutingInfo& outInfo /*out*/) {
|
||||||
const GetRoutingInfoResponse response = bridge.send_message(
|
const GetRoutingInfoResponse response = bridge.send_audio_processor_message(
|
||||||
YaComponent::GetRoutingInfo{.instance_id = instance_id(),
|
YaComponent::GetRoutingInfo{.instance_id = instance_id(),
|
||||||
.in_info = inInfo,
|
.in_info = inInfo,
|
||||||
.out_info = outInfo});
|
.out_info = outInfo});
|
||||||
@@ -174,7 +180,7 @@ Vst3PluginProxyImpl::activateBus(Steinberg::Vst::MediaType type,
|
|||||||
Steinberg::Vst::BusDirection dir,
|
Steinberg::Vst::BusDirection dir,
|
||||||
int32 index,
|
int32 index,
|
||||||
TBool state) {
|
TBool state) {
|
||||||
return bridge.send_message(
|
return bridge.send_audio_processor_message(
|
||||||
YaComponent::ActivateBus{.instance_id = instance_id(),
|
YaComponent::ActivateBus{.instance_id = instance_id(),
|
||||||
.type = type,
|
.type = type,
|
||||||
.dir = dir,
|
.dir = dir,
|
||||||
@@ -183,7 +189,7 @@ Vst3PluginProxyImpl::activateBus(Steinberg::Vst::MediaType type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tresult PLUGIN_API Vst3PluginProxyImpl::setActive(TBool state) {
|
tresult PLUGIN_API Vst3PluginProxyImpl::setActive(TBool state) {
|
||||||
return bridge.send_message(
|
return bridge.send_audio_processor_message(
|
||||||
YaComponent::SetActive{.instance_id = instance_id(), .state = state});
|
YaComponent::SetActive{.instance_id = instance_id(), .state = state});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,13 +161,28 @@ Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() {
|
|||||||
return plugin_factory;
|
return plugin_factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vst3PluginBridge::register_plugin_proxy(Vst3PluginProxyImpl& component) {
|
void Vst3PluginBridge::register_plugin_proxy(
|
||||||
|
Vst3PluginProxyImpl& proxy_object) {
|
||||||
std::lock_guard lock(plugin_proxies_mutex);
|
std::lock_guard lock(plugin_proxies_mutex);
|
||||||
plugin_proxies.emplace(component.instance_id(),
|
|
||||||
std::ref<Vst3PluginProxyImpl>(component));
|
plugin_proxies.emplace(proxy_object.instance_id(),
|
||||||
|
std::ref<Vst3PluginProxyImpl>(proxy_object));
|
||||||
|
|
||||||
|
// For optimization reaons we use dedicated sockets for functions that will
|
||||||
|
// be run in the audio processing loop
|
||||||
|
if (proxy_object.YaAudioProcessor::supported() ||
|
||||||
|
proxy_object.YaComponent::supported()) {
|
||||||
|
sockets.add_audio_processor_and_connect(proxy_object.instance_id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vst3PluginBridge::unregister_plugin_proxy(size_t instance_id) {
|
void Vst3PluginBridge::unregister_plugin_proxy(
|
||||||
|
Vst3PluginProxyImpl& proxy_object) {
|
||||||
std::lock_guard lock(plugin_proxies_mutex);
|
std::lock_guard lock(plugin_proxies_mutex);
|
||||||
plugin_proxies.erase(instance_id);
|
|
||||||
|
plugin_proxies.erase(proxy_object.instance_id());
|
||||||
|
if (proxy_object.YaAudioProcessor::supported() ||
|
||||||
|
proxy_object.YaComponent::supported()) {
|
||||||
|
sockets.remove_audio_processor(proxy_object.instance_id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-10
@@ -76,13 +76,12 @@ class Vst3PluginBridge : PluginBridge<Vst3Sockets<std::jthread>> {
|
|||||||
/**
|
/**
|
||||||
* Add a `Vst3PluginProxyImpl` to the list of registered proxy objects so we
|
* Add a `Vst3PluginProxyImpl` to the list of registered proxy objects so we
|
||||||
* can handle host callbacks. This function is called in
|
* can handle host callbacks. This function is called in
|
||||||
* `Vst3PluginProxyImpl`'s constructor.
|
* `Vst3PluginProxyImpl`'s constructor. If the plugin supports the
|
||||||
|
* `IAudioProcessor` or `IComponent` interfaces, then we'll also connect to
|
||||||
|
* a dedicated audio processing socket.
|
||||||
*
|
*
|
||||||
* @param instance_id The instance ID generated by the plugin host when
|
* @param proxy_object The proxy object so we can access its host context
|
||||||
* instantiating the `IComponent`. Used as a stable name to refer to
|
* and unique instance identifier.
|
||||||
* these.
|
|
||||||
* @param plugin_proxy The actual proxy object we can access its host
|
|
||||||
* context.
|
|
||||||
*
|
*
|
||||||
* @see plugin_proxies
|
* @see plugin_proxies
|
||||||
*/
|
*/
|
||||||
@@ -93,13 +92,12 @@ class Vst3PluginBridge : PluginBridge<Vst3Sockets<std::jthread>> {
|
|||||||
* registered proxy objects. Called during the object's destructor after
|
* registered proxy objects. Called during the object's destructor after
|
||||||
* asking the Wine plugin host to destroy the component on its side.
|
* asking the Wine plugin host to destroy the component on its side.
|
||||||
*
|
*
|
||||||
* @param instance_id The instance ID generated by the plugin host when
|
* @param proxy_object The proxy object so we can access its unique instance
|
||||||
* instantiating the `IComponent`. Used as a stable name to refer to
|
* identifier.
|
||||||
* these.
|
|
||||||
*
|
*
|
||||||
* @see plugin_proxies
|
* @see plugin_proxies
|
||||||
*/
|
*/
|
||||||
void unregister_plugin_proxy(size_t instance_id);
|
void unregister_plugin_proxy(Vst3PluginProxyImpl& proxy_object);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a control message to the Wine plugin host return the response. This
|
* Send a control message to the Wine plugin host return the response. This
|
||||||
@@ -112,6 +110,18 @@ class Vst3PluginBridge : PluginBridge<Vst3Sockets<std::jthread>> {
|
|||||||
object, std::pair<Vst3Logger&, bool>(logger, true));
|
object, std::pair<Vst3Logger&, bool>(logger, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an `IAudioProcessor` or `IComponent` control message to a specific
|
||||||
|
* plugin instance. This is separated from the above `send_message()` for
|
||||||
|
* performance reasons, as this way every instance has its own dedicated
|
||||||
|
* socket and thread.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
typename T::Response send_audio_processor_message(const T& object) {
|
||||||
|
return sockets.send_audio_processor_message(
|
||||||
|
object, std::pair<Vst3Logger&, bool>(logger, true));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logging facility used for this instance of yabridge. Wraps around
|
* The logging facility used for this instance of yabridge. Wraps around
|
||||||
* `PluginBridge::generic_logger`.
|
* `PluginBridge::generic_logger`.
|
||||||
|
|||||||
+202
-120
@@ -116,28 +116,215 @@ void Vst3Bridge::run() {
|
|||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
if (object) {
|
if (!object) {
|
||||||
std::lock_guard lock(object_instances_mutex);
|
|
||||||
|
|
||||||
const size_t instance_id = generate_instance_id();
|
|
||||||
object_instances.emplace(instance_id, std::move(object));
|
|
||||||
|
|
||||||
// This is where the magic happens. Here we deduce which
|
|
||||||
// interfaces are supported by this object so we can create
|
|
||||||
// a one-to-one proxy of it.
|
|
||||||
return Vst3PluginProxy::ConstructArgs(
|
|
||||||
object_instances[instance_id].object, instance_id);
|
|
||||||
} else {
|
|
||||||
return UniversalTResult(Steinberg::kResultFalse);
|
return UniversalTResult(Steinberg::kResultFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::lock_guard lock(object_instances_mutex);
|
||||||
|
|
||||||
|
const size_t instance_id = generate_instance_id();
|
||||||
|
object_instances.emplace(instance_id, std::move(object));
|
||||||
|
|
||||||
|
// If the object supports `IComponent` or `IAudioProcessor`,
|
||||||
|
// then we'll set up a dedicated thread for function calls for
|
||||||
|
// those interfaces.
|
||||||
|
if (object_instances[instance_id].audio_processor ||
|
||||||
|
object_instances[instance_id].component) {
|
||||||
|
std::promise<void> socket_listening_latch;
|
||||||
|
object_instances[instance_id]
|
||||||
|
.audio_processor_handler = Win32Thread([&,
|
||||||
|
instance_id]() {
|
||||||
|
// TODO: Move this somewhere else, because this is
|
||||||
|
// obviously ridiculous
|
||||||
|
sockets.add_audio_processor_and_listen(
|
||||||
|
instance_id, socket_listening_latch,
|
||||||
|
overload{
|
||||||
|
[&](YaAudioProcessor::SetBusArrangements&
|
||||||
|
request)
|
||||||
|
-> YaAudioProcessor::SetBusArrangements::
|
||||||
|
Response {
|
||||||
|
return object_instances
|
||||||
|
[request.instance_id]
|
||||||
|
.audio_processor
|
||||||
|
->setBusArrangements(
|
||||||
|
request.inputs.data(),
|
||||||
|
request.num_ins,
|
||||||
|
request.outputs.data(),
|
||||||
|
request.num_outs);
|
||||||
|
},
|
||||||
|
[&](YaAudioProcessor::GetBusArrangement&
|
||||||
|
request)
|
||||||
|
-> YaAudioProcessor::GetBusArrangement::
|
||||||
|
Response {
|
||||||
|
const tresult result =
|
||||||
|
object_instances
|
||||||
|
[request.instance_id]
|
||||||
|
.audio_processor
|
||||||
|
->getBusArrangement(
|
||||||
|
request.dir,
|
||||||
|
request.index,
|
||||||
|
request.arr);
|
||||||
|
|
||||||
|
return YaAudioProcessor::
|
||||||
|
GetBusArrangementResponse{
|
||||||
|
.result = result,
|
||||||
|
.updated_arr = request.arr};
|
||||||
|
},
|
||||||
|
[&](const YaAudioProcessor::
|
||||||
|
CanProcessSampleSize& request)
|
||||||
|
-> YaAudioProcessor::CanProcessSampleSize::
|
||||||
|
Response {
|
||||||
|
return object_instances
|
||||||
|
[request.instance_id]
|
||||||
|
.audio_processor
|
||||||
|
->canProcessSampleSize(
|
||||||
|
request
|
||||||
|
.symbolic_sample_size);
|
||||||
|
},
|
||||||
|
[&](const YaAudioProcessor::GetLatencySamples&
|
||||||
|
request)
|
||||||
|
-> YaAudioProcessor::GetLatencySamples::
|
||||||
|
Response {
|
||||||
|
return object_instances
|
||||||
|
[request.instance_id]
|
||||||
|
.audio_processor
|
||||||
|
->getLatencySamples();
|
||||||
|
},
|
||||||
|
[&](YaAudioProcessor::SetupProcessing& request)
|
||||||
|
-> YaAudioProcessor::SetupProcessing::
|
||||||
|
Response {
|
||||||
|
return object_instances
|
||||||
|
[request.instance_id]
|
||||||
|
.audio_processor
|
||||||
|
->setupProcessing(
|
||||||
|
request.setup);
|
||||||
|
},
|
||||||
|
[&](const YaAudioProcessor::SetProcessing&
|
||||||
|
request)
|
||||||
|
-> YaAudioProcessor::SetProcessing::
|
||||||
|
Response {
|
||||||
|
return object_instances
|
||||||
|
[request.instance_id]
|
||||||
|
.audio_processor
|
||||||
|
->setProcessing(
|
||||||
|
request.state);
|
||||||
|
},
|
||||||
|
[&](YaAudioProcessor::Process& request)
|
||||||
|
-> YaAudioProcessor::Process::Response {
|
||||||
|
const tresult result =
|
||||||
|
object_instances[request.instance_id]
|
||||||
|
.audio_processor->process(
|
||||||
|
request.data.get());
|
||||||
|
|
||||||
|
return YaAudioProcessor::ProcessResponse{
|
||||||
|
.result = result,
|
||||||
|
.output_data =
|
||||||
|
request.data
|
||||||
|
.move_outputs_to_response()};
|
||||||
|
},
|
||||||
|
[&](const YaAudioProcessor::GetTailSamples&
|
||||||
|
request)
|
||||||
|
-> YaAudioProcessor::GetTailSamples::
|
||||||
|
Response {
|
||||||
|
return object_instances
|
||||||
|
[request.instance_id]
|
||||||
|
.audio_processor
|
||||||
|
->getTailSamples();
|
||||||
|
},
|
||||||
|
[&](const YaComponent::GetControllerClassId&
|
||||||
|
request)
|
||||||
|
-> YaComponent::GetControllerClassId::
|
||||||
|
Response {
|
||||||
|
Steinberg::TUID cid;
|
||||||
|
const tresult result =
|
||||||
|
object_instances
|
||||||
|
[request.instance_id]
|
||||||
|
.component
|
||||||
|
->getControllerClassId(
|
||||||
|
cid);
|
||||||
|
|
||||||
|
return YaComponent::
|
||||||
|
GetControllerClassIdResponse{
|
||||||
|
.result = result,
|
||||||
|
.editor_cid =
|
||||||
|
std::to_array(cid)};
|
||||||
|
},
|
||||||
|
[&](const YaComponent::SetIoMode& request)
|
||||||
|
-> YaComponent::SetIoMode::Response {
|
||||||
|
return object_instances[request.instance_id]
|
||||||
|
.component->setIoMode(request.mode);
|
||||||
|
},
|
||||||
|
[&](const YaComponent::GetBusCount& request)
|
||||||
|
-> YaComponent::GetBusCount::Response {
|
||||||
|
return object_instances[request.instance_id]
|
||||||
|
.component->getBusCount(request.type,
|
||||||
|
request.dir);
|
||||||
|
},
|
||||||
|
[&](YaComponent::GetBusInfo& request)
|
||||||
|
-> YaComponent::GetBusInfo::Response {
|
||||||
|
const tresult result =
|
||||||
|
object_instances[request.instance_id]
|
||||||
|
.component->getBusInfo(
|
||||||
|
request.type, request.dir,
|
||||||
|
request.index, request.bus);
|
||||||
|
|
||||||
|
return YaComponent::GetBusInfoResponse{
|
||||||
|
.result = result,
|
||||||
|
.updated_bus = request.bus};
|
||||||
|
},
|
||||||
|
[&](YaComponent::GetRoutingInfo& request)
|
||||||
|
-> YaComponent::GetRoutingInfo::Response {
|
||||||
|
const tresult result =
|
||||||
|
object_instances[request.instance_id]
|
||||||
|
.component->getRoutingInfo(
|
||||||
|
request.in_info,
|
||||||
|
request.out_info);
|
||||||
|
|
||||||
|
return YaComponent::GetRoutingInfoResponse{
|
||||||
|
.result = result,
|
||||||
|
.updated_in_info = request.in_info,
|
||||||
|
.updated_out_info = request.out_info};
|
||||||
|
},
|
||||||
|
[&](const YaComponent::ActivateBus& request)
|
||||||
|
-> YaComponent::ActivateBus::Response {
|
||||||
|
return object_instances[request.instance_id]
|
||||||
|
.component->activateBus(
|
||||||
|
request.type, request.dir,
|
||||||
|
request.index, request.state);
|
||||||
|
},
|
||||||
|
[&](const YaComponent::SetActive& request)
|
||||||
|
-> YaComponent::SetActive::Response {
|
||||||
|
return object_instances[request.instance_id]
|
||||||
|
.component->setActive(request.state);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the new socket to be listening on before
|
||||||
|
// continuing. Otherwise the native plugin may try to
|
||||||
|
// connect to it before our thread is up and running.
|
||||||
|
socket_listening_latch.get_future().wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is where the magic happens. Here we deduce which
|
||||||
|
// interfaces are supported by this object so we can create
|
||||||
|
// a one-to-one proxy of it.
|
||||||
|
return Vst3PluginProxy::ConstructArgs(
|
||||||
|
object_instances[instance_id].object, instance_id);
|
||||||
},
|
},
|
||||||
[&](const Vst3PluginProxy::Destruct& request)
|
[&](const Vst3PluginProxy::Destruct& request)
|
||||||
-> Vst3PluginProxy::Destruct::Response {
|
-> Vst3PluginProxy::Destruct::Response {
|
||||||
|
// Tear the dedicated audio processing socket down again if we
|
||||||
|
// created one while handling `Vst3PluginProxy::Construct`
|
||||||
|
if (object_instances[request.instance_id].audio_processor ||
|
||||||
|
object_instances[request.instance_id].component) {
|
||||||
|
sockets.remove_audio_processor(request.instance_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the instance from within the main IO context so
|
||||||
|
// removing it doesn't interfere with the Win32 message loop
|
||||||
main_context
|
main_context
|
||||||
.run_in_context([&]() {
|
.run_in_context([&]() {
|
||||||
// Remove the instance from within the main IO context
|
|
||||||
// so removing it doesn't interfere with the Win32
|
|
||||||
// message loop
|
|
||||||
std::lock_guard lock(object_instances_mutex);
|
std::lock_guard lock(object_instances_mutex);
|
||||||
object_instances.erase(request.instance_id);
|
object_instances.erase(request.instance_id);
|
||||||
})
|
})
|
||||||
@@ -181,111 +368,6 @@ void Vst3Bridge::run() {
|
|||||||
return Vst3PluginProxy::GetStateResponse{
|
return Vst3PluginProxy::GetStateResponse{
|
||||||
.result = result, .updated_state = std::move(stream)};
|
.result = result, .updated_state = std::move(stream)};
|
||||||
},
|
},
|
||||||
[&](YaAudioProcessor::SetBusArrangements& request)
|
|
||||||
-> YaAudioProcessor::SetBusArrangements::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.audio_processor->setBusArrangements(
|
|
||||||
request.inputs.data(), request.num_ins,
|
|
||||||
request.outputs.data(), request.num_outs);
|
|
||||||
},
|
|
||||||
[&](YaAudioProcessor::GetBusArrangement& request)
|
|
||||||
-> YaAudioProcessor::GetBusArrangement::Response {
|
|
||||||
const tresult result =
|
|
||||||
object_instances[request.instance_id]
|
|
||||||
.audio_processor->getBusArrangement(
|
|
||||||
request.dir, request.index, request.arr);
|
|
||||||
|
|
||||||
return YaAudioProcessor::GetBusArrangementResponse{
|
|
||||||
.result = result, .updated_arr = request.arr};
|
|
||||||
},
|
|
||||||
[&](const YaAudioProcessor::CanProcessSampleSize& request)
|
|
||||||
-> YaAudioProcessor::CanProcessSampleSize::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.audio_processor->canProcessSampleSize(
|
|
||||||
request.symbolic_sample_size);
|
|
||||||
},
|
|
||||||
[&](const YaAudioProcessor::GetLatencySamples& request)
|
|
||||||
-> YaAudioProcessor::GetLatencySamples::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.audio_processor->getLatencySamples();
|
|
||||||
},
|
|
||||||
[&](YaAudioProcessor::SetupProcessing& request)
|
|
||||||
-> YaAudioProcessor::SetupProcessing::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.audio_processor->setupProcessing(request.setup);
|
|
||||||
},
|
|
||||||
[&](const YaAudioProcessor::SetProcessing& request)
|
|
||||||
-> YaAudioProcessor::SetProcessing::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.audio_processor->setProcessing(request.state);
|
|
||||||
},
|
|
||||||
[&](YaAudioProcessor::Process& request)
|
|
||||||
-> YaAudioProcessor::Process::Response {
|
|
||||||
const tresult result =
|
|
||||||
object_instances[request.instance_id]
|
|
||||||
.audio_processor->process(request.data.get());
|
|
||||||
|
|
||||||
return YaAudioProcessor::ProcessResponse{
|
|
||||||
.result = result,
|
|
||||||
.output_data = request.data.move_outputs_to_response()};
|
|
||||||
},
|
|
||||||
[&](const YaAudioProcessor::GetTailSamples& request)
|
|
||||||
-> YaAudioProcessor::GetTailSamples::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.audio_processor->getTailSamples();
|
|
||||||
},
|
|
||||||
[&](const YaComponent::GetControllerClassId& request)
|
|
||||||
-> YaComponent::GetControllerClassId::Response {
|
|
||||||
Steinberg::TUID cid;
|
|
||||||
const tresult result =
|
|
||||||
object_instances[request.instance_id]
|
|
||||||
.component->getControllerClassId(cid);
|
|
||||||
|
|
||||||
return YaComponent::GetControllerClassIdResponse{
|
|
||||||
.result = result, .editor_cid = std::to_array(cid)};
|
|
||||||
},
|
|
||||||
[&](const YaComponent::SetIoMode& request)
|
|
||||||
-> YaComponent::SetIoMode::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.component->setIoMode(request.mode);
|
|
||||||
},
|
|
||||||
[&](const YaComponent::GetBusCount& request)
|
|
||||||
-> YaComponent::GetBusCount::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.component->getBusCount(request.type, request.dir);
|
|
||||||
},
|
|
||||||
[&](YaComponent::GetBusInfo& request)
|
|
||||||
-> YaComponent::GetBusInfo::Response {
|
|
||||||
const tresult result =
|
|
||||||
object_instances[request.instance_id].component->getBusInfo(
|
|
||||||
request.type, request.dir, request.index, request.bus);
|
|
||||||
|
|
||||||
return YaComponent::GetBusInfoResponse{
|
|
||||||
.result = result, .updated_bus = request.bus};
|
|
||||||
},
|
|
||||||
[&](YaComponent::GetRoutingInfo& request)
|
|
||||||
-> YaComponent::GetRoutingInfo::Response {
|
|
||||||
const tresult result =
|
|
||||||
object_instances[request.instance_id]
|
|
||||||
.component->getRoutingInfo(request.in_info,
|
|
||||||
request.out_info);
|
|
||||||
|
|
||||||
return YaComponent::GetRoutingInfoResponse{
|
|
||||||
.result = result,
|
|
||||||
.updated_in_info = request.in_info,
|
|
||||||
.updated_out_info = request.out_info};
|
|
||||||
},
|
|
||||||
[&](const YaComponent::ActivateBus& request)
|
|
||||||
-> YaComponent::ActivateBus::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.component->activateBus(request.type, request.dir,
|
|
||||||
request.index, request.state);
|
|
||||||
},
|
|
||||||
[&](const YaComponent::SetActive& request)
|
|
||||||
-> YaComponent::SetActive::Response {
|
|
||||||
return object_instances[request.instance_id]
|
|
||||||
.component->setActive(request.state);
|
|
||||||
},
|
|
||||||
[&](const YaConnectionPoint::Connect& request)
|
[&](const YaConnectionPoint::Connect& request)
|
||||||
-> YaConnectionPoint::Connect::Response {
|
-> YaConnectionPoint::Connect::Response {
|
||||||
// We can directly connect the underlying objects
|
// We can directly connect the underlying objects
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ struct InstanceInterfaces {
|
|||||||
|
|
||||||
InstanceInterfaces(Steinberg::IPtr<Steinberg::FUnknown> object);
|
InstanceInterfaces(Steinberg::IPtr<Steinberg::FUnknown> object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dedicated thread for handling incoming `IAudioProcessor` and
|
||||||
|
* `IComponent` calls. Will be instantiated if `object` supports either of
|
||||||
|
* those interfaces.
|
||||||
|
*/
|
||||||
|
Win32Thread audio_processor_handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the host passes a host context object during
|
* If the host passes a host context object during
|
||||||
* `IPluginBase::initialize()`, we'll store a proxy object here and then
|
* `IPluginBase::initialize()`, we'll store a proxy object here and then
|
||||||
|
|||||||
Reference in New Issue
Block a user