Allow midi events to be handled during interaction

This commit is contained in:
Robbert van der Helm
2020-03-28 17:00:12 +01:00
parent 629fa72e0c
commit d52989acc5
5 changed files with 52 additions and 16 deletions
+12 -3
View File
@@ -81,6 +81,7 @@ HostBridge::HostBridge(audioMasterCallback host_callback)
socket_endpoint(generate_endpoint_name().string()),
socket_acceptor(io_context, socket_endpoint),
host_vst_dispatch(io_context),
host_vst_dispatch_midi_events(io_context),
vst_host_callback(io_context),
host_vst_parameters(io_context),
host_vst_process_replacing(io_context),
@@ -127,6 +128,7 @@ HostBridge::HostBridge(audioMasterCallback host_callback)
// It's very important that these sockets are connected to in the same
// order in the Wine VST host
socket_acceptor.accept(host_vst_dispatch);
socket_acceptor.accept(host_vst_dispatch_midi_events);
socket_acceptor.accept(vst_host_callback);
socket_acceptor.accept(host_vst_parameters);
socket_acceptor.accept(host_vst_process_replacing);
@@ -281,10 +283,7 @@ intptr_t HostBridge::dispatch(AEffect* /*plugin*/,
float option) {
DispatchDataConverter converter(chunk_data, editor_rectangle);
// Some events need some extra handling
// TODO: Handle GUI closing?
switch (opcode) {
break;
case effClose: {
// TODO: Gracefully close the editor?
// TODO: Check whether the sockets and the endpoint are closed
@@ -333,6 +332,16 @@ intptr_t HostBridge::dispatch(AEffect* /*plugin*/,
return return_value;
}; break;
case effProcessEvents:
// Because of limitations of the Win32 API we have to use a seperate
// 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(host_vst_dispatch_midi_events,
dispatch_midi_events_semaphore, converter,
std::pair<Logger&, bool>(logger, true), opcode,
index, value, data, option);
break;
}
// TODO: Maybe reuse buffers here when dealing with chunk data
+8
View File
@@ -139,6 +139,13 @@ class HostBridge {
// `AEffect.dispatch()` calls from the native VST host to the Windows VST
// plugin (through the Wine VST host).
boost::asio::local::stream_protocol::socket host_vst_dispatch;
/**
* Used specifically for the `effProcessEvents` opcode. This is needed
* because the Win32 API is designed to block during certain GUI
* interactions such as resizing a window or opening a dropdown. Without
* this midi input would just stop working at times.
*/
boost::asio::local::stream_protocol::socket host_vst_dispatch_midi_events;
boost::asio::local::stream_protocol::socket vst_host_callback;
/**
* Used for both `getParameter` and `setParameter` since they mostly
@@ -168,6 +175,7 @@ class HostBridge {
* information.
*/
std::mutex dispatch_semaphore;
std::mutex dispatch_midi_events_semaphore;
/**
* The callback function passed by the host to the VST plugin instance.
+13
View File
@@ -62,6 +62,7 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
io_context(),
socket_endpoint(socket_endpoint_path),
host_vst_dispatch(io_context),
host_vst_dispatch_midi_events(io_context),
vst_host_callback(io_context),
host_vst_parameters(io_context),
host_vst_process_replacing(io_context),
@@ -94,6 +95,7 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
// It's very important that these sockets are accepted to in the same order
// in the Linus plugin
host_vst_dispatch.connect(socket_endpoint);
host_vst_dispatch_midi_events.connect(socket_endpoint);
vst_host_callback.connect(socket_endpoint);
host_vst_parameters.connect(socket_endpoint);
host_vst_process_replacing.connect(socket_endpoint);
@@ -118,6 +120,16 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
current_bridge_isntance = nullptr;
plugin->ptr1 = this;
// This works functionally identically to the `handle_dispatch()` function
// below, but this socket will only handle midi events. This is needed
// because of Win32 API limitations.
dispatch_midi_events_handler = std::thread([&]() {
while (true) {
passthrough_event(host_vst_dispatch_midi_events, std::nullopt,
plugin, plugin->dispatcher);
}
});
parameters_handler = std::thread([&]() {
while (true) {
// Both `getParameter` and `setParameter` functions are passed
@@ -191,6 +203,7 @@ void PluginBridge::handle_dispatch() {
} catch (const boost::system::system_error&) {
// This happens when the sockets got closed because the plugin is being
// shut down. In that case we can just let the whole host terminate.
dispatch_midi_events_handler.detach();
parameters_handler.detach();
process_replacing_handler.detach();
}
+13
View File
@@ -104,6 +104,13 @@ class PluginBridge {
// `AEffect.dispatch()` calls from the native VST host to the Windows VST
// plugin (through the Wine VST host).
boost::asio::local::stream_protocol::socket host_vst_dispatch;
/**
* Used specifically for the `effProcessEvents` opcode. This is needed
* because the Win32 API is designed to block during certain GUI
* interactions such as resizing a window or opening a dropdown. Without
* this midi input would just stop working at times.
*/
boost::asio::local::stream_protocol::socket host_vst_dispatch_midi_events;
boost::asio::local::stream_protocol::socket vst_host_callback;
/**
* Used for both `getParameter` and `setParameter` since they mostly
@@ -119,6 +126,12 @@ class PluginBridge {
*/
boost::asio::local::stream_protocol::socket vst_host_aeffect;
/**
* The thread that specifically handles `effProcessEvents` opcodes so the
* plugin can still receive midi during GUI interaction to work around Win32
* API limitations.
*/
std::thread dispatch_midi_events_handler;
/**
* The thread that responds to `getParameter` and `setParameter` requests.
*/