From 249b82f84634e42fbe051467a28247808a111232 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Fri, 22 Jan 2021 13:31:09 +0100 Subject: [PATCH] Add conversions for the garbled UIDs We'll need this to make sure the reported class IDs match up with the actual IDs. --- src/common/serialization/vst3/base.cpp | 45 ++++++++++ src/common/serialization/vst3/base.h | 86 +++++++++++++++++-- .../serialization/vst3/plugin-factory.cpp | 14 +-- .../serialization/vst3/plugin/component.h | 1 - 4 files changed, 129 insertions(+), 17 deletions(-) diff --git a/src/common/serialization/vst3/base.cpp b/src/common/serialization/vst3/base.cpp index 69ae61a5..c4df38ce 100644 --- a/src/common/serialization/vst3/base.cpp +++ b/src/common/serialization/vst3/base.cpp @@ -66,6 +66,51 @@ const Steinberg::Vst::TChar* u16string_to_tchar_pointer( #endif } +WineUID::WineUID() {} +WineUID::WineUID(const Steinberg::TUID& tuid) : uid(std::to_array(tuid)) {} + +ArrayUID WineUID::get_native_uid() const { + // We need to shuffle the first 8 bytes around to convert between the + // COM-compatible and non COM-compatible formats described by the + // `INLINE_UID` macro. See that macro as a reference for the transformations + // we're applying here. + ArrayUID converted_uid = uid; + + converted_uid[0] = uid[3]; + converted_uid[1] = uid[2]; + converted_uid[2] = uid[1]; + converted_uid[3] = uid[0]; + + converted_uid[4] = uid[5]; + converted_uid[5] = uid[4]; + converted_uid[6] = uid[7]; + converted_uid[7] = uid[6]; + + return converted_uid; +} + +NativeUID::NativeUID() {} +NativeUID::NativeUID(const Steinberg::TUID& tuid) : uid(std::to_array(tuid)) {} + +ArrayUID NativeUID::get_wine_uid() const { + // This transformation is actually the same as the one in + // `WineUID::get_native_uid()`, but we'll spell it out here in full for + // understandability's sake. + ArrayUID converted_uid = uid; + + converted_uid[0] = uid[3]; + converted_uid[1] = uid[2]; + converted_uid[2] = uid[1]; + converted_uid[3] = uid[0]; + + converted_uid[4] = uid[5]; + converted_uid[5] = uid[4]; + converted_uid[6] = uid[7]; + converted_uid[7] = uid[6]; + + return converted_uid; +} + UniversalTResult::UniversalTResult() : universal_result(Value::kResultFalse) {} UniversalTResult::UniversalTResult(tresult native_result) diff --git a/src/common/serialization/vst3/base.h b/src/common/serialization/vst3/base.h index f5781650..29ac861b 100644 --- a/src/common/serialization/vst3/base.h +++ b/src/common/serialization/vst3/base.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -31,15 +32,6 @@ using Steinberg::TBool, Steinberg::char16, Steinberg::int8, Steinberg::int16, Steinberg::int32, Steinberg::int64, Steinberg::uint8, Steinberg::uint16, Steinberg::uint32, Steinberg::uint64, Steinberg::tresult; -/** - * Both `TUID` (`int8_t[16]`) and `FIDString` (`char*`) are hard to work with - * because you can't just copy them. So when serializing/deserializing them - * we'll use `std::array`. - */ -using ArrayUID = std::array< - std::remove_reference_t()[0])>, - std::extent_v>; - /** * The maximum number of speakers or busses we support. */ @@ -86,6 +78,82 @@ struct Ack { void serialize(S&) {} }; +/** + * Both `TUID` (`int8_t[16]`) and `FIDString` (`char*`) are hard to work with + * because you can't just copy them. So when serializing/deserializing them + * we'll use `std::array`. + * + * FIXME: Replace usages of ArrayUID everywhere with either `WineUID` or + * `NativeUID` + */ +using ArrayUID = std::array< + std::remove_reference_t()[0])>, + std::extent_v>; + +/** + * Store a serializable UID in the format used on the Wine host. This then has + * to be converted to the correct native format on the plugin side. + * + * NOTE: This is crucial. The `INLINE_UID` macro from the VST3 SDK uses + * different byte ordering on Windows (with COM support) versus on other + * platforms. We need to reverse this transformation manually in order for + * projects with the Windows VST3 version of plugin X, the Linux VST3 + * version of plugin X, and the Windows VST3 version of plugin X running + * through yabridge to be compatible. + */ +class WineUID { + public: + WineUID(); + WineUID(const Steinberg::TUID& tuid); + + ArrayUID get_native_uid() const; + + template + void serialize(S& s) { + s.container1b(uid); + } + + protected: + ArrayUID uid; +}; + +/** + * Store a serializable UID in the 'real' format as used by the Windows version + * of the VST3 plugin on Windows and the Linux version of the same plugin on + * Linux. This then has to be converted to the format reported by the plugin on + * the Wine host. + * + * NOTE: This is crucial. The `INLINE_UID` macro from the VST3 SDK uses + * different byte ordering on Windows (with COM support) versus on other + * platforms. We need to reverse this transformation manually in order for + * projects with the Windows VST3 version of plugin X, the Linux VST3 + * version of plugin X, and the Windows VST3 version of plugin X running + * through yabridge to be compatible. + */ +class NativeUID { + public: + NativeUID(); + NativeUID(const Steinberg::TUID& tuid); + + /** + * Convert to the garbled byte order used in the Wine plugin host. + */ + ArrayUID get_wine_uid() const; + + /** + * Get a reference to the proper native UID. + */ + inline const ArrayUID& native_uid() const { return uid; }; + + template + void serialize(S& s) { + s.container1b(uid); + } + + protected: + ArrayUID uid; +}; + /** * A simple wrapper around primitive values for serialization purposes. Bitsery * doesn't seem to like serializing plain primitives using `s.object()` even if diff --git a/src/common/serialization/vst3/plugin-factory.cpp b/src/common/serialization/vst3/plugin-factory.cpp index 453736d6..64307b42 100644 --- a/src/common/serialization/vst3/plugin-factory.cpp +++ b/src/common/serialization/vst3/plugin-factory.cpp @@ -25,13 +25,6 @@ YaPluginFactory::ConstructArgs::ConstructArgs() {} YaPluginFactory::ConstructArgs::ConstructArgs( Steinberg::IPtr factory) { - // FIXME: The class IDs are incorrect! See the `INLINE_UID` macro. We need - // to shuffle the byte orders around for plugins to be compatible - // with projects saved under Windows and with native Linux versions - // of the same plugin. - // FIXME: We need to do similar translations everywhere where we encounter - // `ArrayUID`, such as `IComponent::getControllerClassId()` - // `IPluginFactory::getFactoryInfo` if (Steinberg::PFactoryInfo info; factory->getFactoryInfo(&info) == Steinberg::kResultOk) { @@ -131,6 +124,13 @@ tresult PLUGIN_API YaPluginFactory::getClassInfo(Steinberg::int32 index, return Steinberg::kInvalidArgument; } + // FIXME: The class IDs are incorrect! See the `INLINE_UID` macro. We need + // to shuffle the byte orders around for plugins to be compatible + // with projects saved under Windows and with native Linux versions + // of the same plugin. We need to do this transformation for all of + // these functions + // FIXME: We need to do similar translations everywhere where we encounter + // `ArrayUID`, such as `IComponent::getControllerClassId()` if (arguments.class_infos_1[index]) { *info = *arguments.class_infos_1[index]; return Steinberg::kResultOk; diff --git a/src/common/serialization/vst3/plugin/component.h b/src/common/serialization/vst3/plugin/component.h index 46f4abdd..3dffe3bb 100644 --- a/src/common/serialization/vst3/plugin/component.h +++ b/src/common/serialization/vst3/plugin/component.h @@ -17,7 +17,6 @@ #pragma once #include -#include #include #include "../../../bitsery/ext/vst3.h"