diff --git a/meson.build b/meson.build
index 20f455a6..01bb3857 100644
--- a/meson.build
+++ b/meson.build
@@ -77,6 +77,7 @@ vst3_plugin_sources = [
'src/common/communication/common.cpp',
'src/common/logging/common.cpp',
'src/common/logging/vst3.cpp',
+ 'src/common/serialization/vst3/base.cpp',
'src/common/serialization/vst3/component.cpp',
'src/common/serialization/vst3/plugin-factory.cpp',
'src/common/configuration.cpp',
@@ -110,6 +111,7 @@ host_sources = [
if with_vst3
host_sources += [
'src/common/logging/vst3.cpp',
+ 'src/common/serialization/vst3/base.cpp',
'src/common/serialization/vst3/component.cpp',
'src/common/serialization/vst3/plugin-factory.cpp',
'src/wine-host/bridges/vst3.cpp',
diff --git a/src/common/serialization/vst3/base.cpp b/src/common/serialization/vst3/base.cpp
new file mode 100644
index 00000000..afbdceff
--- /dev/null
+++ b/src/common/serialization/vst3/base.cpp
@@ -0,0 +1,91 @@
+// yabridge: a Wine VST bridge
+// Copyright (C) 2020 Robbert van der Helm
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "base.h"
+
+UniversalTResult::UniversalTResult(tresult native_result)
+ : universal_result(to_universal_result(native_result)) {
+ //
+}
+
+tresult UniversalTResult::native() const {
+ static_assert(Steinberg::kResultOk == Steinberg::kResultTrue);
+ switch (universal_result) {
+ case Value::kNoInterface:
+ return Steinberg::kNoInterface;
+ break;
+ case Value::kResultOk:
+ return Steinberg::kResultOk;
+ break;
+ case Value::kResultFalse:
+ return Steinberg::kResultFalse;
+ break;
+ case Value::kInvalidArgument:
+ return Steinberg::kInvalidArgument;
+ break;
+ case Value::kNotImplemented:
+ return Steinberg::kNotImplemented;
+ break;
+ case Value::kInternalError:
+ return Steinberg::kInternalError;
+ break;
+ case Value::kNotInitialized:
+ return Steinberg::kNotInitialized;
+ break;
+ case Value::kOutOfMemory:
+ return Steinberg::kOutOfMemory;
+ break;
+ default:
+ // Shouldn't be happening
+ return Steinberg::kInvalidArgument;
+ break;
+ }
+}
+
+UniversalTResult::Value UniversalTResult::to_universal_result(
+ tresult native_result) {
+ static_assert(Steinberg::kResultOk == Steinberg::kResultTrue);
+ switch (native_result) {
+ case Steinberg::kNoInterface:
+ return Value::kNoInterface;
+ break;
+ case Steinberg::kResultOk:
+ return Value::kResultOk;
+ break;
+ case Steinberg::kResultFalse:
+ return Value::kResultFalse;
+ break;
+ case Steinberg::kInvalidArgument:
+ return Value::kInvalidArgument;
+ break;
+ case Steinberg::kNotImplemented:
+ return Value::kNotImplemented;
+ break;
+ case Steinberg::kInternalError:
+ return Value::kInternalError;
+ break;
+ case Steinberg::kNotInitialized:
+ return Value::kNotInitialized;
+ break;
+ case Steinberg::kOutOfMemory:
+ return Value::kOutOfMemory;
+ break;
+ default:
+ // Shouldn't be happening
+ return Value::kInvalidArgument;
+ break;
+ }
+}
diff --git a/src/common/serialization/vst3/base.h b/src/common/serialization/vst3/base.h
index c9d8a591..2dd19f30 100644
--- a/src/common/serialization/vst3/base.h
+++ b/src/common/serialization/vst3/base.h
@@ -43,3 +43,46 @@ struct Ack {
template
void serialize(S&) {}
};
+
+/**
+ * A wrapper around `Steinberg::tresult` that we can safely share between the
+ * native plugin and the Wine process. Depending on the platform and on whether
+ * or not the VST3 SDK is compiled to be COM compatible, the result codes may
+ * have three different values for the same meaning.
+ */
+class UniversalTResult {
+ public:
+ UniversalTResult(tresult native_result);
+
+ /**
+ * Get the native equivalent for the wrapped `tresult` value.
+ */
+ tresult native() const;
+
+ template
+ void serialize(S& s) {
+ s.value4b(universal_result);
+ }
+
+ private:
+ /**
+ * These are the non-COM compatible values copied from
+ * ` The actual values h ere don't matter
+ * but hopefully the compiler can be a bit smarter about it this way.
+ */
+ enum class Value {
+ kNoInterface = -1,
+ kResultOk,
+ kResultTrue = kResultOk,
+ kResultFalse,
+ kInvalidArgument,
+ kNotImplemented,
+ kInternalError,
+ kNotInitialized,
+ kOutOfMemory
+ };
+
+ static Value to_universal_result(tresult native_result);
+
+ Value universal_result;
+};