Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
5.8KB

  1. /*
  2. * travesty, pure C VST3-compatible interface
  3. * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #pragma once
  17. #include <stdbool.h>
  18. #include <stdint.h>
  19. #include <string.h>
  20. /**
  21. * deal with C vs C++ differences
  22. */
  23. #if !defined(__cplusplus) && !defined(constexpr)
  24. # define constexpr
  25. #endif
  26. /**
  27. * various types
  28. */
  29. typedef int32_t v3_result;
  30. typedef int16_t v3_str_128[128];
  31. typedef uint8_t v3_bool;
  32. typedef uint32_t v3_param_id;
  33. /**
  34. * low-level ABI nonsense
  35. */
  36. typedef uint8_t v3_tuid[16];
  37. static inline
  38. bool v3_tuid_match(const v3_tuid a, const v3_tuid b)
  39. {
  40. return memcmp(a, b, sizeof(v3_tuid)) == 0;
  41. }
  42. #if defined(_WIN32)
  43. # define V3_COM_COMPAT 1
  44. # define V3_API __stdcall
  45. #else
  46. # define V3_COM_COMPAT 0
  47. # define V3_API
  48. #endif
  49. #if V3_COM_COMPAT
  50. enum {
  51. _V3_SIGNEDNESS = -1,
  52. V3_NO_INTERFACE = 0x80004002L,
  53. V3_OK = 0,
  54. V3_TRUE = 0,
  55. V3_FALSE = 1,
  56. V3_INVALID_ARG = 0x80070057L,
  57. V3_NOT_IMPLEMENTED = 0x80004001L,
  58. V3_INTERNAL_ERR = 0x80004005L,
  59. V3_NOT_INITIALIZED = 0x8000FFFFL,
  60. V3_NOMEM = 0x8007000EL
  61. };
  62. # define V3_ID(a, b, c, d) { \
  63. ((a) & 0x000000FF), \
  64. ((a) & 0x0000FF00) >> 8, \
  65. ((a) & 0x00FF0000) >> 16, \
  66. ((a) & 0xFF000000) >> 24, \
  67. \
  68. ((b) & 0x00FF0000) >> 16, \
  69. ((b) & 0xFF000000) >> 24, \
  70. ((b) & 0x000000FF), \
  71. ((b) & 0x0000FF00) >> 8, \
  72. \
  73. ((c) & 0xFF000000) >> 24, \
  74. ((c) & 0x00FF0000) >> 16, \
  75. ((c) & 0x0000FF00) >> 8, \
  76. ((c) & 0x000000FF), \
  77. \
  78. ((d) & 0xFF000000) >> 24, \
  79. ((d) & 0x00FF0000) >> 16, \
  80. ((d) & 0x0000FF00) >> 8, \
  81. ((d) & 0x000000FF), \
  82. }
  83. #else // V3_COM_COMPAT
  84. enum {
  85. V3_NO_INTERFACE = -1,
  86. V3_OK,
  87. V3_TRUE = V3_OK,
  88. V3_FALSE,
  89. V3_INVALID_ARG,
  90. V3_NOT_IMPLEMENTED,
  91. V3_INTERNAL_ERR,
  92. V3_NOT_INITIALIZED,
  93. V3_NOMEM
  94. };
  95. # define V3_ID(a, b, c, d) { \
  96. ((a) & 0xFF000000) >> 24, \
  97. ((a) & 0x00FF0000) >> 16, \
  98. ((a) & 0x0000FF00) >> 8, \
  99. ((a) & 0x000000FF), \
  100. \
  101. ((b) & 0xFF000000) >> 24, \
  102. ((b) & 0x00FF0000) >> 16, \
  103. ((b) & 0x0000FF00) >> 8, \
  104. ((b) & 0x000000FF), \
  105. \
  106. ((c) & 0xFF000000) >> 24, \
  107. ((c) & 0x00FF0000) >> 16, \
  108. ((c) & 0x0000FF00) >> 8, \
  109. ((c) & 0x000000FF), \
  110. \
  111. ((d) & 0xFF000000) >> 24, \
  112. ((d) & 0x00FF0000) >> 16, \
  113. ((d) & 0x0000FF00) >> 8, \
  114. ((d) & 0x000000FF), \
  115. }
  116. #endif // V3_COM_COMPAT
  117. #define V3_ID_COPY(iid) \
  118. { iid[0], iid[1], iid[ 2], iid[ 3], iid[ 4], iid[ 5], iid[ 6], iid[ 7], \
  119. iid[8], iid[9], iid[10], iid[11], iid[12], iid[13], iid[14], iid[15] }
  120. /**
  121. * funknown
  122. */
  123. struct v3_funknown {
  124. v3_result (V3_API* query_interface)(void* self, const v3_tuid iid, void** obj);
  125. uint32_t (V3_API* ref)(void* self);
  126. uint32_t (V3_API* unref)(void* self);
  127. };
  128. static constexpr const v3_tuid v3_funknown_iid =
  129. V3_ID(0x00000000, 0x00000000, 0xC0000000, 0x00000046);
  130. /**
  131. * plugin base
  132. */
  133. struct v3_plugin_base {
  134. #ifndef __cplusplus
  135. struct v3_funknown;
  136. #endif
  137. v3_result (V3_API* initialize)(void* self, struct v3_funknown** context);
  138. v3_result (V3_API* terminate)(void* self);
  139. };
  140. static constexpr const v3_tuid v3_plugin_base_iid =
  141. V3_ID(0x22888DDB, 0x156E45AE, 0x8358B348, 0x08190625);
  142. #ifdef __cplusplus
  143. /**
  144. * cast object into its proper C++ type.
  145. * this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields.
  146. *
  147. * we can use this as a little helper for keeping both C and C++ compatiblity.
  148. * specialized templated calls are defined where required
  149. * (that is, object inherits from something other than `v3_funknown`)
  150. *
  151. * example usage: `v3_cpp_obj(obj)->method(obj, args...);`
  152. */
  153. template<class T> static inline
  154. constexpr T* v3_cpp_obj(T** obj)
  155. {
  156. /**
  157. * this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
  158. * but we need everything to be `static_cast` for it to be `constexpr` compatible.
  159. */
  160. return static_cast<T*>(static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3));
  161. }
  162. /**
  163. * helper C++ functions to manually call v3_funknown methods on an object.
  164. */
  165. template<class T, class M> static inline
  166. v3_result v3_cpp_obj_query_interface(T** obj, const v3_tuid iid, M*** obj2)
  167. {
  168. return static_cast<v3_funknown*>(static_cast<void*>(*obj))->query_interface(obj, iid, (void**)obj2);
  169. }
  170. template<class T> static inline
  171. uint32_t v3_cpp_obj_ref(T** obj)
  172. {
  173. return static_cast<v3_funknown*>(static_cast<void*>(*obj))->ref(obj);
  174. }
  175. template<class T> static inline
  176. uint32_t v3_cpp_obj_unref(T** obj)
  177. {
  178. return static_cast<v3_funknown*>(static_cast<void*>(*obj))->unref(obj);
  179. }
  180. template<class T> static inline
  181. v3_result v3_cpp_obj_initialize(T** obj, v3_funknown** context)
  182. {
  183. return static_cast<v3_plugin_base*>(
  184. static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3))->initialize(obj, context);
  185. }
  186. template<class T> static inline
  187. v3_result v3_cpp_obj_terminate(T** obj)
  188. {
  189. return static_cast<v3_plugin_base*>(
  190. static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3))->terminate(obj);
  191. }
  192. #endif