diff --git a/src/common/events.h b/src/common/events.h index ba9a203b..150158c7 100644 --- a/src/common/events.h +++ b/src/common/events.h @@ -135,6 +135,7 @@ intptr_t send_event(boost::asio::local::stream_protocol::socket& socket, const std::optional payload = data_converter.read(opcode, index, value, data); if (!payload.has_value()) { + // A 1 usually means that the event was processed succesfully return 1; } @@ -217,7 +218,8 @@ void passthrough_event(boost::asio::local::stream_protocol::socket& socket, return &events.as_c_events(); }, [&](WantsChunkBuffer&) -> void* { return string_buffer.data(); }, - [&](const WantsVstRect&) -> void* { return string_buffer.data(); }, + [&](VstIOProperties& props) -> void* { return &props; }, + [&](WantsVstRect&) -> void* { return string_buffer.data(); }, [&](const WantsVstTimeInfo&) -> void* { return nullptr; }, [&](WantsString&) -> void* { return string_buffer.data(); }}, event.payload); @@ -265,6 +267,11 @@ void passthrough_event(boost::asio::local::stream_protocol::socket& socket, return std::string(*static_cast(data), return_value); }, + [&](VstIOProperties& props) -> EventResposnePayload { + // The plugin has written a pointer to a VstRect struct + // into the data poitner + return props; + }, [&](WantsVstRect&) -> EventResposnePayload { // The plugin has written a pointer to a VstRect struct // into the data poitner diff --git a/src/common/logging.cpp b/src/common/logging.cpp index 42837d79..554cc9c2 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -177,6 +177,7 @@ void Logger::log_event(bool is_dispatch, [&](const WantsChunkBuffer&) { message << ""; }, + [&](const VstIOProperties&) { message << ""; }, [&](const WantsVstRect&) { message << ""; }, [&](const WantsVstTimeInfo&) { message << ""; }, [&](const WantsString&) { message << ""; }}, @@ -202,23 +203,25 @@ void Logger::log_event_response(bool is_dispatch, message << return_value; std::visit( - overload{[&](const std::monostate&) {}, - [&](const std::string& s) { - if (s.size() < 32) { - message << ", \"" << s << "\""; - } else { - // Long strings contain binary data that we - // probably don't want to print - message << ", <" << s.size() << " bytes>"; - } - }, - [&](const AEffect&) { message << ", "; }, - [&](const VstRect& rect) { - message << ", {l: " << rect.left << ", t: " << rect.top - << ", r: " << rect.right - << ", b: " << rect.bottom << "}"; - }, - [&](const VstTimeInfo&) { message << ", "; }}, + overload{ + [&](const std::monostate&) {}, + [&](const std::string& s) { + if (s.size() < 32) { + message << ", \"" << s << "\""; + } else { + // Long strings contain binary data that we probably + // don't want to print + message << ", <" << s.size() << " bytes>"; + } + }, + [&](const AEffect&) { message << ", "; }, + [&](const VstIOProperties&) { message << ", "; }, + [&](const VstRect& rect) { + message << ", {l: " << rect.left << ", t: " << rect.top + << ", r: " << rect.right << ", b: " << rect.bottom + << "}"; + }, + [&](const VstTimeInfo&) { message << ", "; }}, payload); log(message.str()); diff --git a/src/common/serialization.h b/src/common/serialization.h index a82cee57..433b638b 100644 --- a/src/common/serialization.h +++ b/src/common/serialization.h @@ -27,6 +27,8 @@ #include +#include "vst24.h" + // These constants are limits used by bitsery /** @@ -83,6 +85,11 @@ void serialize(S& s, AEffect& plugin) { s.value4b(plugin.version); } +template +void serialize(S& s, VstIOProperties& props) { + s.container1b(props.data); +} + template void serialize(S& s, VstRect& rect) { s.value2b(rect.top); @@ -212,6 +219,7 @@ using EventPayload = std::variant; @@ -233,6 +241,7 @@ void serialize(S& s, EventPayload& payload) { events.events, max_midi_events, [](S& s, VstEvent& event) { s.container1b(event.dump); }); }, + [](S& s, VstIOProperties& props) { s.object(props); }, [](S&, WantsChunkBuffer&) {}, [](S&, WantsVstRect&) {}, [](S&, WantsVstTimeInfo&) {}, [](S&, WantsString&) {}}); } @@ -289,8 +298,12 @@ struct Event { * `audioMasterIOChanged`. * - An X11 window pointer for the editor window. */ -using EventResposnePayload = - std::variant; +using EventResposnePayload = std::variant; template void serialize(S& s, EventResposnePayload& payload) { @@ -304,6 +317,7 @@ void serialize(S& s, EventResposnePayload& payload) { s.text1b(string, binary_buffer_size); }, [](S& s, AEffect& effect) { s.object(effect); }, + [](S& s, VstIOProperties& props) { s.object(props); }, [](S& s, VstRect& rect) { s.object(rect); }, [](S& s, VstTimeInfo& time_info) { s.object(time_info); }}); } diff --git a/src/plugin/host-bridge.cpp b/src/plugin/host-bridge.cpp index 93f649c3..818993fa 100644 --- a/src/plugin/host-bridge.cpp +++ b/src/plugin/host-bridge.cpp @@ -206,6 +206,13 @@ class DispatchDataConverter : DefaultDataConverter { case effProcessEvents: return DynamicVstEvents(*static_cast(data)); break; + case effGetInputProperties: + case effGetOutputProperties: + // In this case we can't simply pass an empty marker struct + // because the host can have already populated this field with + // data (or at least Bitwig does this) + return *static_cast(data); + break; default: return DefaultDataConverter::read(opcode, index, value, data); break; @@ -232,11 +239,21 @@ class DispatchDataConverter : DefaultDataConverter { // `HostBridge` and write a pointer to that struct to the data // pointer - std::string buffer = std::get(response.payload); + const auto buffer = std::get(response.payload); chunk.assign(buffer.begin(), buffer.end()); *static_cast(data) = chunk.data(); } break; + case effGetInputProperties: + case effGetOutputProperties: { + // These opcodes pass the plugin some empty struct through the + // data parameter that the plugin then fills with flags and + // other data to describe an input or output channel. + const auto properties = + std::get(response.payload); + + *static_cast(data) = properties; + } break; default: DefaultDataConverter::write(opcode, data, response); break;