DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

base.h (5924B)


      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 
     17 #pragma once
     18 
     19 #include <stdbool.h>
     20 #include <stdint.h>
     21 #include <string.h>
     22 
     23 /**
     24  * deal with C vs C++ differences
     25  */
     26 
     27 #if !defined(__cplusplus) && !defined(constexpr)
     28 # define constexpr
     29 #endif
     30 
     31 /**
     32  * various types
     33  */
     34 
     35 typedef int32_t v3_result;
     36 
     37 typedef int16_t v3_str_128[128];
     38 typedef uint8_t v3_bool;
     39 
     40 typedef uint32_t v3_param_id;
     41 
     42 /**
     43  * low-level ABI nonsense
     44  */
     45 
     46 typedef uint8_t v3_tuid[16];
     47 
     48 static inline
     49 bool v3_tuid_match(const v3_tuid a, const v3_tuid b)
     50 {
     51 	return memcmp(a, b, sizeof(v3_tuid)) == 0;
     52 }
     53 
     54 #if defined(_WIN32)
     55 # define V3_COM_COMPAT 1
     56 # define V3_API __stdcall
     57 #else
     58 # define V3_COM_COMPAT 0
     59 # define V3_API
     60 #endif
     61 
     62 #if V3_COM_COMPAT
     63 enum {
     64 	V3_NO_INTERFACE    = 0x80004002L,
     65 	V3_OK              = 0,
     66 	V3_TRUE            = 0,
     67 	V3_FALSE           = 1,
     68 	V3_INVALID_ARG     = 0x80070057L,
     69 	V3_NOT_IMPLEMENTED = 0x80004001L,
     70 	V3_INTERNAL_ERR    = 0x80004005L,
     71 	V3_NOT_INITIALIZED = 0x8000FFFFL,
     72 	V3_NOMEM           = 0x8007000EL
     73 };
     74 
     75 # define V3_ID(a, b, c, d) {   \
     76 	((a) & 0x000000FF),        \
     77 	((a) & 0x0000FF00) >>  8,  \
     78 	((a) & 0x00FF0000) >> 16,  \
     79 	((a) & 0xFF000000) >> 24,  \
     80 	                           \
     81 	((b) & 0x00FF0000) >> 16,  \
     82 	((b) & 0xFF000000) >> 24,  \
     83 	((b) & 0x000000FF),        \
     84 	((b) & 0x0000FF00) >>  8,  \
     85 	                           \
     86 	((c) & 0xFF000000) >> 24,  \
     87 	((c) & 0x00FF0000) >> 16,  \
     88 	((c) & 0x0000FF00) >>  8,  \
     89 	((c) & 0x000000FF),        \
     90 	                           \
     91 	((d) & 0xFF000000) >> 24,  \
     92 	((d) & 0x00FF0000) >> 16,  \
     93 	((d) & 0x0000FF00) >>  8,  \
     94 	((d) & 0x000000FF),        \
     95 }
     96 
     97 #else // V3_COM_COMPAT
     98 enum {
     99 	V3_NO_INTERFACE = -1,
    100 	V3_OK,
    101 	V3_TRUE = V3_OK,
    102 	V3_FALSE,
    103 	V3_INVALID_ARG,
    104 	V3_NOT_IMPLEMENTED,
    105 	V3_INTERNAL_ERR,
    106 	V3_NOT_INITIALIZED,
    107 	V3_NOMEM
    108 };
    109 
    110 # define V3_ID(a, b, c, d) {   \
    111 	((a) & 0xFF000000) >> 24,  \
    112 	((a) & 0x00FF0000) >> 16,  \
    113 	((a) & 0x0000FF00) >>  8,  \
    114 	((a) & 0x000000FF),        \
    115 	                           \
    116 	((b) & 0xFF000000) >> 24,  \
    117 	((b) & 0x00FF0000) >> 16,  \
    118 	((b) & 0x0000FF00) >>  8,  \
    119 	((b) & 0x000000FF),        \
    120 	                           \
    121 	((c) & 0xFF000000) >> 24,  \
    122 	((c) & 0x00FF0000) >> 16,  \
    123 	((c) & 0x0000FF00) >>  8,  \
    124 	((c) & 0x000000FF),        \
    125 	                           \
    126 	((d) & 0xFF000000) >> 24,  \
    127 	((d) & 0x00FF0000) >> 16,  \
    128 	((d) & 0x0000FF00) >>  8,  \
    129 	((d) & 0x000000FF),        \
    130 }
    131 #endif // V3_COM_COMPAT
    132 
    133 #define V3_ID_COPY(iid) \
    134 	{ iid[0], iid[1], iid[ 2], iid[ 3], iid[ 4], iid[ 5], iid[ 6], iid[ 7], \
    135 	  iid[8], iid[9], iid[10], iid[11], iid[12], iid[13], iid[14], iid[15]  }
    136 
    137 /**
    138  * funknown
    139  */
    140 
    141 struct v3_funknown {
    142 	v3_result (V3_API* query_interface)(void* self, const v3_tuid iid, void** obj);
    143 	uint32_t (V3_API* ref)(void* self);
    144 	uint32_t (V3_API* unref)(void* self);
    145 };
    146 
    147 static constexpr const v3_tuid v3_funknown_iid =
    148 	V3_ID(0x00000000, 0x00000000, 0xC0000000, 0x00000046);
    149 
    150 /**
    151  * plugin base
    152  */
    153 
    154 struct v3_plugin_base {
    155 #ifndef __cplusplus
    156 	struct v3_funknown;
    157 #endif
    158 	v3_result (V3_API* initialize)(void* self, struct v3_funknown** context);
    159 	v3_result (V3_API* terminate)(void* self);
    160 };
    161 
    162 static constexpr const v3_tuid v3_plugin_base_iid =
    163 	V3_ID(0x22888DDB, 0x156E45AE, 0x8358B348, 0x08190625);
    164 
    165 #ifdef __cplusplus
    166 
    167 /**
    168  * cast object into its proper C++ type.
    169  * this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields.
    170  *
    171  * we can use this as a little helper for keeping both C and C++ compatiblity.
    172  * specialized templated calls are defined where required
    173  * (that is, object inherits from something other than `v3_funknown`)
    174  *
    175  * example usage: `v3_cpp_obj(obj)->method(obj, args...);`
    176  */
    177 
    178 template<class T> static inline
    179 constexpr T* v3_cpp_obj(T** obj)
    180 {
    181 	/**
    182 	 * this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
    183 	 * but we need everything to be `static_cast` for it to be `constexpr` compatible.
    184 	 */
    185 	return static_cast<T*>(static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3));
    186 }
    187 
    188 /**
    189  * helper C++ functions to manually call v3_funknown methods on an object.
    190  */
    191 
    192 template<class T, class M> static inline
    193 v3_result v3_cpp_obj_query_interface(T** obj, const v3_tuid iid, M*** obj2)
    194 {
    195 	return static_cast<v3_funknown*>(static_cast<void*>(*obj))->query_interface(obj, iid, (void**)obj2);
    196 }
    197 
    198 template<class T> static inline
    199 uint32_t v3_cpp_obj_ref(T** obj)
    200 {
    201 	return static_cast<v3_funknown*>(static_cast<void*>(*obj))->ref(obj);
    202 }
    203 
    204 template<class T> static inline
    205 uint32_t v3_cpp_obj_unref(T** obj)
    206 {
    207 	return static_cast<v3_funknown*>(static_cast<void*>(*obj))->unref(obj);
    208 }
    209 
    210 template<class T> static inline
    211 v3_result v3_cpp_obj_initialize(T** obj, v3_funknown** context)
    212 {
    213 	return static_cast<v3_plugin_base*>(
    214 		static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3))->initialize(obj, context);
    215 }
    216 
    217 template<class T> static inline
    218 v3_result v3_cpp_obj_terminate(T** obj)
    219 {
    220 	return static_cast<v3_plugin_base*>(
    221 		static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3))->terminate(obj);
    222 }
    223 
    224 #endif