mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-08 20:40:11 +02:00
Move event handling logic to a dedicated class
Now all pieces are in place to allow handling events over multiple socket connections.
This commit is contained in:
@@ -263,7 +263,5 @@ void GroupHost::terminate() {
|
||||
// There's no need to manually terminate group host processes as they will
|
||||
// shut down automatically after all plugins have exited. Manually closing
|
||||
// the dispatch socket will cause the associated plugin to exit.
|
||||
sockets.host_vst_dispatch.shutdown(
|
||||
boost::asio::local::stream_protocol::socket::shutdown_both);
|
||||
sockets.host_vst_dispatch.close();
|
||||
}
|
||||
|
||||
@@ -121,41 +121,31 @@ PluginBridge::PluginBridge(audioMasterCallback host_callback)
|
||||
// instead of asynchronous IO since communication has to be handled in
|
||||
// lockstep anyway
|
||||
host_callback_handler = std::jthread([&]() {
|
||||
while (true) {
|
||||
try {
|
||||
// TODO: Think of a nicer way to structure this and the similar
|
||||
// handler in `Vst2Bridge::handle_dispatch_midi_events`
|
||||
receive_event(
|
||||
sockets.vst_host_callback,
|
||||
std::pair<Logger&, bool>(logger, false), [&](Event& event) {
|
||||
// MIDI events sent from the plugin back to the host are
|
||||
// a special case here. They have to sent during the
|
||||
// `processReplacing()` function or else the host will
|
||||
// ignore them. Because of this we'll temporarily save
|
||||
// any MIDI events we receive here, and then we'll
|
||||
// actually send them to the host at the end of the
|
||||
// `process_replacing()` function.
|
||||
if (event.opcode == audioMasterProcessEvents) {
|
||||
std::lock_guard lock(incoming_midi_events_mutex);
|
||||
// TODO: Think of a nicer way to structure this and the similar
|
||||
// handler in `Vst2Bridge::handle_dispatch_midi_events`
|
||||
sockets.vst_host_callback.receive(
|
||||
std::pair<Logger&, bool>(logger, false), [&](Event& event) {
|
||||
// MIDI events sent from the plugin back to the host are a
|
||||
// special case here. They have to sent during the
|
||||
// `processReplacing()` function or else the host will ignore
|
||||
// them. Because of this we'll temporarily save any MIDI events
|
||||
// we receive here, and then we'll actually send them to the
|
||||
// host at the end of the `process_replacing()` function.
|
||||
if (event.opcode == audioMasterProcessEvents) {
|
||||
std::lock_guard lock(incoming_midi_events_mutex);
|
||||
|
||||
incoming_midi_events.push_back(
|
||||
std::get<DynamicVstEvents>(event.payload));
|
||||
EventResult response{.return_value = 1,
|
||||
.payload = nullptr,
|
||||
.value_payload = std::nullopt};
|
||||
incoming_midi_events.push_back(
|
||||
std::get<DynamicVstEvents>(event.payload));
|
||||
EventResult response{.return_value = 1,
|
||||
.payload = nullptr,
|
||||
.value_payload = std::nullopt};
|
||||
|
||||
return response;
|
||||
} else {
|
||||
return passthrough_event(
|
||||
&plugin, host_callback_function)(event);
|
||||
}
|
||||
});
|
||||
} catch (const boost::system::system_error&) {
|
||||
// This happens when the sockets got closed because the plugin
|
||||
// is being shut down
|
||||
break;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
} else {
|
||||
return passthrough_event(&plugin,
|
||||
host_callback_function)(event);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Read the plugin's information from the Wine process. This can only be
|
||||
@@ -435,10 +425,9 @@ intptr_t PluginBridge::dispatch(AEffect* /*plugin*/,
|
||||
intptr_t return_value = 0;
|
||||
try {
|
||||
// TODO: Add some kind of timeout?
|
||||
return_value = send_event(
|
||||
sockets.host_vst_dispatch, dispatch_mutex, converter,
|
||||
std::pair<Logger&, bool>(logger, true), opcode, index,
|
||||
value, data, option);
|
||||
return_value = sockets.host_vst_dispatch.send(
|
||||
converter, std::pair<Logger&, bool>(logger, true), opcode,
|
||||
index, value, data, option);
|
||||
} catch (const boost::system::system_error& a) {
|
||||
// Thrown when the socket gets closed because the VST plugin
|
||||
// loaded into the Wine process crashed during shutdown
|
||||
@@ -461,10 +450,9 @@ intptr_t PluginBridge::dispatch(AEffect* /*plugin*/,
|
||||
// thread and socket to pass MIDI events. Otherwise plugins will
|
||||
// stop receiving MIDI data when they have an open dropdowns or
|
||||
// message box.
|
||||
return send_event(sockets.host_vst_dispatch_midi_events,
|
||||
dispatch_midi_events_mutex, converter,
|
||||
std::pair<Logger&, bool>(logger, true), opcode,
|
||||
index, value, data, option);
|
||||
return sockets.host_vst_dispatch_midi_events.send(
|
||||
converter, std::pair<Logger&, bool>(logger, true), opcode,
|
||||
index, value, data, option);
|
||||
break;
|
||||
case effCanDo: {
|
||||
const std::string query(static_cast<const char*>(data));
|
||||
@@ -521,9 +509,9 @@ intptr_t PluginBridge::dispatch(AEffect* /*plugin*/,
|
||||
// and loading plugin state it's much better to have bitsery or our
|
||||
// receiving function temporarily allocate a large enough buffer rather than
|
||||
// to have a bunch of allocated memory sitting around doing nothing.
|
||||
return send_event(sockets.host_vst_dispatch, dispatch_mutex, converter,
|
||||
std::pair<Logger&, bool>(logger, true), opcode, index,
|
||||
value, data, option);
|
||||
return sockets.host_vst_dispatch.send(
|
||||
converter, std::pair<Logger&, bool>(logger, true), opcode, index, value,
|
||||
data, option);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "../common/communication.h"
|
||||
#include "../common/configuration.h"
|
||||
#include "../common/logging.h"
|
||||
#include "../common/communication.h"
|
||||
#include "host-process.h"
|
||||
|
||||
/**
|
||||
@@ -132,16 +132,10 @@ class PluginBridge {
|
||||
std::jthread host_callback_handler;
|
||||
|
||||
/**
|
||||
* A binary semaphore to prevent race conditions from the dispatch function
|
||||
* being called by two threads at once. See `send_event()` for more
|
||||
* information.
|
||||
*/
|
||||
std::mutex dispatch_mutex;
|
||||
std::mutex dispatch_midi_events_mutex;
|
||||
/**
|
||||
* A similar semaphore as the `dispatch_*` semaphores in the rare case that
|
||||
* `getParameter()` and `setParameter()` are being called at the same time
|
||||
* since they use the same socket.
|
||||
* A mutex to prevent multiple simultaneous calls to `getParameter()` and
|
||||
* `setParameter()`. This likely won't happen, but better safe than sorry.
|
||||
* For `dispatch()` and `audioMaster()` there's some more complex logic for
|
||||
* this in `EventHandler`.
|
||||
*/
|
||||
std::mutex parameters_mutex;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user