Browse Source

VST3: use connection point to send parameter grab and changes

Signed-off-by: falkTX <falktx@falktx.com>
pull/330/head
falkTX 3 years ago
parent
commit
5df663bba6
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
4 changed files with 347 additions and 121 deletions
  1. +48
    -4
      distrho/src/DistrhoPluginVST3.cpp
  2. +258
    -114
      distrho/src/DistrhoUIVST3.cpp
  3. +20
    -0
      distrho/src/travesty/base.h
  4. +21
    -3
      distrho/src/travesty/message.h

+ 48
- 4
distrho/src/DistrhoPluginVST3.cpp View File

@@ -113,6 +113,8 @@ const char* tuid2str(const v3_tuid iid)


if (v3_tuid_match(iid, v3_audio_processor_iid)) if (v3_tuid_match(iid, v3_audio_processor_iid))
return "{v3_audio_processor}"; return "{v3_audio_processor}";
if (v3_tuid_match(iid, v3_attribute_list_iid))
return "{v3_attribute_list_iid}";
if (v3_tuid_match(iid, v3_bstream_iid)) if (v3_tuid_match(iid, v3_bstream_iid))
return "{v3_bstream}"; return "{v3_bstream}";
if (v3_tuid_match(iid, v3_component_iid)) if (v3_tuid_match(iid, v3_component_iid))
@@ -1275,10 +1277,52 @@ public:


v3_result notify(v3_message** const message) v3_result notify(v3_message** const message)
{ {
d_stdout("notify received %p -> %s", message, v3_cpp_obj(message)->get_message_id(message));
// TESTING, ensure host gets the message
requestParameterValueChange(2, 1.0f);
return V3_OK;
const char* const msgid = v3_cpp_obj(message)->get_message_id(message);
DISTRHO_SAFE_ASSERT_RETURN(msgid != nullptr, V3_INVALID_ARG);

v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message);
DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr, V3_INVALID_ARG);

if (std::strcmp(msgid, "parameter-edit") == 0)
{
DISTRHO_SAFE_ASSERT_RETURN(fComponentHandler != nullptr, false);

int64_t rindex;
int64_t started;
v3_result res;

res = v3_cpp_obj(attrs)->get_int(attrs, "rindex", &rindex);
DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);

res = v3_cpp_obj(attrs)->get_int(attrs, "started", &started);
DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);

rindex -= fParameterOffset;
DISTRHO_SAFE_ASSERT_RETURN(rindex >= 0, V3_INTERNAL_ERR);

return started != 0 ? v3_cpp_obj(fComponentHandler)->begin_edit(fComponentHandler, rindex)
: v3_cpp_obj(fComponentHandler)->end_edit(fComponentHandler, rindex);
}

if (std::strcmp(msgid, "parameter-set") == 0)
{
int64_t rindex;
double value;
v3_result res;

res = v3_cpp_obj(attrs)->get_int(attrs, "rindex", &rindex);
DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);

res = v3_cpp_obj(attrs)->get_float(attrs, "value", &value);
DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);

rindex -= fParameterOffset;
DISTRHO_SAFE_ASSERT_RETURN(rindex >= 0, V3_INTERNAL_ERR);

return requestParameterValueChange(rindex, value) ? V3_OK : V3_INTERNAL_ERR;
}

return V3_NOT_IMPLEMENTED;
} }


// ---------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------


+ 258
- 114
distrho/src/DistrhoUIVST3.cpp View File

@@ -42,6 +42,10 @@
#include "travesty/message.h" #include "travesty/message.h"
#include "travesty/view.h" #include "travesty/view.h"


#include <atomic>
#include <map>
#include <string>

/* TODO items: /* TODO items:
* - disable UI if non-embed UI build * - disable UI if non-embed UI build
* - parameter change listener * - parameter change listener
@@ -71,19 +75,9 @@ static constexpr const setStateFunc setStateCallback = nullptr;
const char* tuid2str(const v3_tuid iid); const char* tuid2str(const v3_tuid iid);


// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
// dpf_message (needed by the UI class, implementation comes later)

struct v3_message_cpp : v3_funknown {
v3_message msg;
};
// create message object (needed by the UI class, implementation comes later)


// NOTE value type must be POD
template<typename T>
struct dpf_message : v3_message_cpp {
dpf_message(ScopedPointer<dpf_message>* self, const char* id, T value);
struct PrivateData;
PrivateData* const pData;
};
static v3_message** dpf_message_create(const char* id);


// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------


@@ -238,14 +232,21 @@ private:
// ---------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------
// DPF callbacks // DPF callbacks


void editParameter(const uint32_t /*rindex*/, const bool /*started*/) const
void editParameter(const uint32_t rindex, const bool started) const
{ {
// DISTRHO_SAFE_ASSERT_RETURN(fHandler != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr,);

v3_message** const message = dpf_message_create("parameter-edit");
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);


// if (started)
// v3_cpp_obj(fHandler)->begin_edit(fHandler, rindex);
// else
// v3_cpp_obj(fHandler)->end_edit(fHandler, rindex);
v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message);
DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr,);

v3_cpp_obj(attrs)->set_int(attrs, "rindex", rindex);
v3_cpp_obj(attrs)->set_int(attrs, "started", started ? 1 : 0);
v3_cpp_obj(fConnection)->notify(fConnection, message);

v3_cpp_obj_unref(message);
} }


static void editParameterCallback(void* ptr, uint32_t rindex, bool started) static void editParameterCallback(void* ptr, uint32_t rindex, bool started)
@@ -256,16 +257,18 @@ private:
void setParameterValue(const uint32_t rindex, const float realValue) void setParameterValue(const uint32_t rindex, const float realValue)
{ {
DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr,);
d_stdout("setParameterValue %p %u %f", this, rindex, realValue);


struct IndexAndValue {
uint32_t index;
float value;
};
ScopedPointer<dpf_message<IndexAndValue>>* const messageptr = new ScopedPointer<dpf_message<IndexAndValue>>;
*messageptr = new dpf_message<IndexAndValue>(messageptr, "parameter-value-set", { rindex, realValue });
v3_message** const message = dpf_message_create("parameter-set");
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);

v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message);
DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr,);

v3_cpp_obj(attrs)->set_int(attrs, "rindex", rindex);
v3_cpp_obj(attrs)->set_float(attrs, "value", realValue);
v3_cpp_obj(fConnection)->notify(fConnection, message);


v3_cpp_obj(fConnection)->notify(fConnection, (v3_message**)messageptr);
v3_cpp_obj_unref(message);
} }


static void setParameterCallback(void* ptr, uint32_t rindex, float value) static void setParameterCallback(void* ptr, uint32_t rindex, float value)
@@ -334,117 +337,258 @@ private:
*/ */


// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
// dpf_message (implementation only, declaration already done as needed by UI class)
// dpf_attribute_list

struct dpf_attribute_value {
char type;
union {
int64_t integer;
double v_float;
int16_t* string;
struct {
void* ptr;
uint32_t size;
} binary;
};
};

struct v3_attribute_list_cpp : v3_funknown {
v3_attribute_list attr;
};

struct dpf_attribute_list : v3_attribute_list_cpp {
std::map<std::string, dpf_attribute_value> attrs;

dpf_attribute_list()
{
static const uint8_t* kSupportedInterfaces[] = {
v3_funknown_iid,
v3_attribute_list_iid
};

// ------------------------------------------------------------------------------------------------------------
// v3_funknown

query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
{
d_stdout("dpf_attribute_list::query_interface => %p %s %p", self, tuid2str(iid), iface);
*iface = NULL;
DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);

for (const uint8_t* interface_iid : kSupportedInterfaces)
{
if (v3_tuid_match(interface_iid, iid))
{
*iface = self;
return V3_OK;
}
}

return V3_NO_INTERFACE;
};

// there is only a single instance of this, so we don't have to care here
ref = []V3_API(void*) -> uint32_t { return 1; };
unref = []V3_API(void*) -> uint32_t { return 0; };

// ------------------------------------------------------------------------------------------------------------
// v3_attribute_list

attr.set_int = []V3_API(void* self, const char* id, int64_t value) -> v3_result
{
dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);

dpf_attribute_value& attrval(attr->attrs[id]);
attrval.integer = value;
return V3_OK;
};

attr.get_int = []V3_API(void* self, const char* id, int64_t* value) -> v3_result
{
dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);

if (attr->attrs.find(id) == attr->attrs.end())
return V3_INVALID_ARG;

const dpf_attribute_value& attrval(attr->attrs[id]);
*value = attrval.integer;
return V3_OK;
};

attr.set_float = []V3_API(void* self, const char* id, double value) -> v3_result
{
dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);

dpf_attribute_value& attrval(attr->attrs[id]);
attrval.v_float = value;
return V3_OK;
};

attr.get_float = []V3_API(void* self, const char* id, double* value) -> v3_result
{
dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);

if (attr->attrs.find(id) == attr->attrs.end())
return V3_INVALID_ARG;

const dpf_attribute_value& attrval(attr->attrs[id]);
*value = attrval.v_float;
return V3_OK;
};

attr.set_string = []V3_API(void* self, const char* /*id*/, const int16_t* /*string*/) -> v3_result
{
dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);

return V3_NOT_IMPLEMENTED;
};

attr.get_string = []V3_API(void* self, const char* id, int16_t* /*string*/, uint32_t /*size*/) -> v3_result
{
dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);

if (attr->attrs.find(id) == attr->attrs.end())
return V3_INVALID_ARG;

return V3_NOT_IMPLEMENTED;
};

attr.set_binary = []V3_API(void* self, const char* /*id*/, const void* /*data*/, uint32_t /*size*/) -> v3_result
{
dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);

return V3_NOT_IMPLEMENTED;
};

attr.get_binary = []V3_API(void* self, const char* id, const void** /*data*/, uint32_t* /*size*/) -> v3_result
{
dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);

if (attr->attrs.find(id) == attr->attrs.end())
return V3_INVALID_ARG;

return V3_NOT_IMPLEMENTED;
};
}
};

// --------------------------------------------------------------------------------------------------------------------
// dpf_message


template<typename T>
struct dpf_message<T>::PrivateData {
struct v3_message_cpp : v3_funknown {
v3_message msg;
};

struct dpf_message : v3_message_cpp {
std::atomic<int> refcounter; std::atomic<int> refcounter;
ScopedPointer<dpf_message>* self; ScopedPointer<dpf_message>* self;
ScopedPointer<dpf_attribute_list> attrlist;
String id; String id;
const T value;


PrivateData(ScopedPointer<dpf_message>* const s, const char* const id2, T value2)
: refcounter(1),
self(s),
id(id2),
value(value2) {}
};
dpf_message(ScopedPointer<dpf_message>* const s, const char* const id2)
: self(s),
id(id2)
{
static const uint8_t* kSupportedInterfaces[] = {
v3_funknown_iid,
v3_message_iid
};


static V3_API v3_result dpf_message__query_interface(void* self, const v3_tuid iid, void** iface)
{
d_stdout("dpf_message::query_interface => %p %s %p", self, tuid2str(iid), iface);
*iface = NULL;
DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
// ------------------------------------------------------------------------------------------------------------
// v3_funknown


static const uint8_t* kSupportedInterfaces[] = {
v3_funknown_iid,
v3_message_iid
};
query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
{
d_stdout("dpf_plugin_view::query_interface => %p %s %p", self, tuid2str(iid), iface);
*iface = NULL;
DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);


for (const uint8_t* interface_iid : kSupportedInterfaces)
{
if (v3_tuid_match(interface_iid, iid))
for (const uint8_t* interface_iid : kSupportedInterfaces)
{
if (v3_tuid_match(interface_iid, iid))
{
*iface = self;
return V3_OK;
}
}

return V3_NO_INTERFACE;
};

ref = []V3_API(void* const self) -> uint32_t
{ {
*iface = self;
return V3_OK;
}
}
d_stdout("dpf_message::ref => %p", self);
dpf_message** const messageptr = static_cast<dpf_message**>(self);
DISTRHO_SAFE_ASSERT_RETURN(messageptr != nullptr, 0);
dpf_message* const message = *messageptr;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);


return V3_NO_INTERFACE;
}
return ++message->refcounter;
};


template<typename T>
static V3_API uint32_t dpf_message__ref(void* const self)
{
d_stdout("dpf_message::ref => %p", self);
dpf_message<T>* const message = *(dpf_message<T>**)self;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);
unref = []V3_API(void* const self) -> uint32_t
{
d_stdout("dpf_message::unref => %p", self);
dpf_message** const messageptr = static_cast<dpf_message**>(self);
DISTRHO_SAFE_ASSERT_RETURN(messageptr != nullptr, 0);
dpf_message* const message = *messageptr;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);


return ++message->pData->refcounter;
}
if (const int refcounter = --message->refcounter)
return refcounter;


template<typename T>
static V3_API uint32_t dpf_message__unref(void* const self)
{
d_stdout("dpf_message::unref => %p", self);
dpf_message<T>* const message = *(dpf_message<T>**)self;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);

if (const int refcounter = --message->pData->refcounter)
return refcounter;

dpf_message<T>* const messageptr = message->pData->self->release();
delete message->pData;
delete messageptr;
delete (dpf_message<T>**)self;
return 0;
}
*message->self = nullptr;
delete messageptr;
return 0;
};


template<typename T>
static V3_API const char* dpf_message__get_message_id(void* const self)
{
d_stdout("dpf_message::get_message_id => %p", self);
dpf_message<T>* const message = *(dpf_message<T>**)self;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);
msg.get_message_id = []V3_API(void* const self) -> const char*
{
d_stdout("dpf_message::get_message_id => %p", self);
dpf_message* const message = *(dpf_message**)self;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);


return message->pData->id;
}
return message->id;
};


template<typename T>
static V3_API void dpf_message__set_message_id(void* const self, const char* const id)
{
d_stdout("dpf_message::set_message_id => %p %s", self, id);
dpf_message<T>* const message = *(dpf_message<T>**)self;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);
msg.set_message_id = []V3_API(void* const self, const char* const id) -> void
{
d_stdout("dpf_message::set_message_id => %p %s", self, id);
dpf_message* const message = *(dpf_message**)self;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);


message->pData->id = id;
}
message->id = id;
};


template<typename T>
static V3_API v3_attribute_list* dpf_message__get_attributes(void* const self)
{
d_stdout("dpf_message::get_attributes => %p", self);
dpf_message<T>* const message = *(dpf_message<T>**)self;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);
msg.get_attributes = []V3_API(void* const self) -> v3_attribute_list**
{
d_stdout("dpf_message::get_attributes => %p", self);
dpf_message* const message = *(dpf_message**)self;
DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);


// TODO
return nullptr;
}
if (message->attrlist == nullptr)
message->attrlist = new dpf_attribute_list();


template<typename T>
dpf_message<T>::dpf_message(ScopedPointer<dpf_message>* const self, const char* const id, const T value)
: pData(new PrivateData(self, id, value))
return (v3_attribute_list**)&message->attrlist;
};
}
};

static v3_message** dpf_message_create(const char* const id)
{ {
query_interface = dpf_message__query_interface;
ref = dpf_message__ref<T>;
unref = dpf_message__unref<T>;
msg.get_message_id = dpf_message__get_message_id<T>;
msg.set_message_id = dpf_message__set_message_id<T>;
msg.get_attributes = dpf_message__get_attributes<T>;
ScopedPointer<dpf_message>* const messageptr = new ScopedPointer<dpf_message>;
*messageptr = new dpf_message(messageptr, id);
return static_cast<v3_message**>(static_cast<void*>(messageptr));
} }


template struct dpf_message<float>;

// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
// dpf_plugin_view_content_scale // dpf_plugin_view_content_scale




+ 20
- 0
distrho/src/travesty/base.h View File

@@ -25,6 +25,15 @@
*/ */


#ifdef __cplusplus #ifdef __cplusplus
/**
* cast object into its proper C++ type.
* this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields.
* we can use this as a little helper for keeping both C and C++ compatiblity.
* specialized templated calls are defined where required
* (that is, object inherits from something other than `v3_funknown`)
*
* example usage: `v3_cpp_obj(obj)->method(obj, args...);`
*/
template<class T> static inline template<class T> static inline
constexpr T* v3_cpp_obj(T** obj) constexpr T* v3_cpp_obj(T** obj)
{ {
@@ -168,3 +177,14 @@ struct v3_plugin_base {


static constexpr const v3_tuid v3_plugin_base_iid = static constexpr const v3_tuid v3_plugin_base_iid =
V3_ID(0x22888DDB, 0x156E45AE, 0x8358B348, 0x08190625); V3_ID(0x22888DDB, 0x156E45AE, 0x8358B348, 0x08190625);

#ifdef __cplusplus
/**
* helper C++ function to manually call unref on an object.
*/
template<class T> static inline
uint32_t v3_cpp_obj_unref(T** obj)
{
return static_cast<v3_funknown*>(static_cast<void*>(*obj))->unref(obj);
}
#endif

+ 21
- 3
distrho/src/travesty/message.h View File

@@ -21,17 +21,35 @@
#include "align_push.h" #include "align_push.h"


/** /**
* message
* attribute list
*/ */


struct v3_attribute_list;
struct v3_attribute_list {
struct v3_funknown;

V3_API v3_result (*set_int)(void* self, const char* id, int64_t value);
V3_API v3_result (*get_int)(void* self, const char* id, int64_t* value);
V3_API v3_result (*set_float)(void* self, const char* id, double value);
V3_API v3_result (*get_float)(void* self, const char* id, double* value);
V3_API v3_result (*set_string)(void* self, const char* id, const int16_t* string);
V3_API v3_result (*get_string)(void* self, const char* id, int16_t* string, uint32_t size);
V3_API v3_result (*set_binary)(void* self, const char* id, const void* data, uint32_t size);
V3_API v3_result (*get_binary)(void* self, const char* id, const void** data, uint32_t* size);
};

static constexpr const v3_tuid v3_attribute_list_iid =
V3_ID(0x1E5F0AEB, 0xCC7F4533, 0xA2544011, 0x38AD5EE4);

/**
* message
*/


struct v3_message { struct v3_message {
struct v3_funknown; struct v3_funknown;


V3_API const char* (*get_message_id)(void* self); V3_API const char* (*get_message_id)(void* self);
V3_API void (*set_message_id)(void* self, const char* id); V3_API void (*set_message_id)(void* self, const char* id);
V3_API v3_attribute_list* (*get_attributes)(void* self);
V3_API v3_attribute_list** (*get_attributes)(void* self);
}; };


static constexpr const v3_tuid v3_message_iid = static constexpr const v3_tuid v3_message_iid =


Loading…
Cancel
Save