lv2: messaging wip (actually broken)

This commit is contained in:
Paolo Marrone 2025-06-10 18:18:18 +02:00
parent 3bdff1ea8f
commit f7b8b434c8
4 changed files with 232 additions and 6 deletions

View File

@ -69,7 +69,7 @@
lv2:portProperty lv2:integer ;
lv2:portProperty lv2:reportsLatency ;
{{??}}
a {{?p.type == "control"}}lv2:ControlPort{{??p.type == "midi"}}atom:AtomPort{{??}}{{?p.cv}}lv2:CVPort{{??}}lv2:AudioPort{{?}}{{?}} ,
a {{?p.type == "control"}}lv2:ControlPort{{??p.type == "midi"}}atom:AtomPort{{??p.type == "message"}}atom:AtomPort{{??}}{{?p.cv}}lv2:CVPort{{??}}lv2:AudioPort{{?}}{{?}} ,
{{?p.direction == "input"}}lv2:InputPort{{??}}lv2:OutputPort{{?}} ;
lv2:name "{{=p.name}}" ;
{{?"shortName" in p}}
@ -83,6 +83,11 @@
{{??p.type == "midi"}}
atom:bufferType atom:Sequence ;
atom:supports midi:MidiEvent ;
{{??p.type == "message"}}
atom:bufferType atom:Sequence ;
{{?}}
{{?p.maxSize}}
rsz:minimumSize {{=p.maxSize}};
{{?}}
{{?p.sidechain}}
lv2:portProperty lv2:isSideChain ;
@ -140,5 +145,13 @@
{{?}}
{{?}}
lv2:requiredFeature ui:idleInterface ;
lv2:extensionData ui:idleInterface .
lv2:extensionData ui:idleInterface ;
{{?}}
{{?it.product.messaging}}
ui:portNotification [
ui:ui {{=it.tibia.lv2.ttlURI(it.lv2.uri)}} ;
lv2:symbol "notify" ;
ui:notifyType atom:Blank
]
{{?}}
.

View File

@ -86,3 +86,10 @@ static uint32_t index_to_param[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONT
{{?it.product.state && it.product.state.dspCustom}}
#define DATA_STATE_DSP_CUSTOM
{{?}}
{{?it.product.messaging}}
#define DATA_MESSAGING 1
#define DATA_MESSAGING_MAX {{=it.product.messaging.maxSize}}
#define DATA_MESSAGING_PORT_IN {{=it.tibia.lv2.ports.indexOf(it.tibia.lv2.ports.find(p => p.id == 'message_in'))}}
#define DATA_MESSAGING_PORT_OUT {{=it.tibia.lv2.ports.indexOf(it.tibia.lv2.ports.find(p => p.id == 'message_out'))}}
{{?}}

View File

@ -49,7 +49,9 @@
#ifdef DATA_STATE_DSP_CUSTOM
# include <lv2/state/state.h>
#endif
#ifdef DATA_MESSAGING
#include <lv2/atom/forge.h>
#endif
#include <string.h>
#if defined(__i386__) || defined(__x86_64__)
@ -91,6 +93,25 @@ static float adjust_param(size_t index, float value) {
}
#endif
#ifdef DATA_MESSAGING
typedef struct {
LV2_URID prop_customMessage;
LV2_URID atom_String;
LV2_URID atom_eventTransfer;
LV2_URID ui_On;
LV2_URID length;
} communication_URIs;
static inline void map_comm_uris(LV2_URID_Map* map, communication_URIs* uris) {
uris->prop_customMessage = map->map(map->handle, "http://example.org#message");
uris->atom_String = map->map(map->handle, LV2_ATOM__String);
uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer);
uris->ui_On = map->map(map->handle, DATA_LV2_URI "#UIOn");
uris->length = map->map(map->handle, LV2_ATOM__Int);
}
#endif
typedef struct {
plugin p;
float sample_rate;
@ -132,6 +153,15 @@ typedef struct {
LV2_State_Store_Function state_store;
LV2_State_Handle state_handle;
#endif
#ifdef DATA_MESSAGING
LV2_Atom_Forge forge;
LV2_Atom_Forge_Frame frame;
communication_URIs c_uris;
const LV2_Atom_Sequence* control;
LV2_Atom_Sequence* notify;
#endif
} plugin_instance;
static const char * get_bundle_path_cb(void *handle) {
@ -168,6 +198,36 @@ static void state_set_parameter_cb(void *handle, size_t index, float value) {
# endif
#endif
#ifdef DATA_MESSAGING
static char send_to_ui (void *handle, const void *data, size_t bytes) {
plugin_instance * i = (plugin_instance *) handle;
if (!data || bytes <= 0 || bytes > DATA_MESSAGING_MAX) {
return 1;
}
const uint32_t space = i->notify->atom.size;
lv2_atom_forge_set_buffer(&i->forge, (uint8_t*)i->notify, space);
lv2_atom_forge_sequence_head(&i->forge, &i->frame, 0);
LV2_Atom_Forge_Frame frame;
lv2_atom_forge_frame_time(&i->forge, 0);
lv2_atom_forge_object(&i->forge, &frame, 0, i->c_uris.prop_customMessage);
lv2_atom_forge_key(&i->forge, i->c_uris.length);
lv2_atom_forge_int(&i->forge, (int32_t)bytes);
lv2_atom_forge_key(&i->forge, i->c_uris.prop_customMessage);
lv2_atom_forge_write(&i->forge, data, bytes);
lv2_atom_forge_pop(&i->forge, &frame);
return 0;
}
#endif
static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) {
(void)descriptor;
(void)bundle_path;
@ -209,7 +269,10 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ get_bundle_path_cb,
/* .get_datadir = */ get_bundle_path_cb
/* .get_datadir = */ get_bundle_path_cb,
#ifdef DATA_MESSAGING
/* .send_to_ui = */ send_to_ui
#endif
};
plugin_init(&instance->p, &cbs);
@ -246,6 +309,10 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
for (uint32_t i = 0; i < DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N; i++)
instance->c[i] = NULL;
#endif
#ifdef DATA_MESSAGING
lv2_atom_forge_init(&instance->forge, instance->map);
map_comm_uris(instance->map, &instance->c_uris);
#endif
return instance;
@ -263,6 +330,18 @@ err_instance:
static void connect_port(LV2_Handle instance, uint32_t port, void * data_location) {
plugin_instance * i = (plugin_instance *)instance;
printf("connect_port %u \n", port);
#ifdef DATA_MESSAGING
// Well, these should stay last...
if (port == DATA_MESSAGING_PORT_IN) {
i->control = (const LV2_Atom_Sequence*)data_location;
return;
}
if (port == DATA_MESSAGING_PORT_OUT) {
i->notify = (LV2_Atom_Sequence*)data_location;
return;
}
#endif
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
if (port < DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N) {
i->x[port] = data_location;
@ -319,6 +398,34 @@ static void activate(LV2_Handle instance) {
static void run(LV2_Handle instance, uint32_t sample_count) {
plugin_instance * i = (plugin_instance *)instance;
printf("run A \n"); fflush(stdout);
if (0 && i->control) {
const LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(i->control)->body);
while (!lv2_atom_sequence_is_end(&i->control->body, i->control->atom.size, ev)) {
if (lv2_atom_forge_is_object_type(&i->forge, ev->body.type)) {
const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
printf("audio - received object, otype: %d\n", obj->body.otype);
const LV2_Atom* msg_atom = NULL;
lv2_atom_object_get(obj, i->c_uris.prop_customMessage, &msg_atom, 0);
printf("audio - custom msg %d \n", i->c_uris.prop_customMessage);
printf("audio - %p \n", msg_atom);
printf("audio - %d %d \n", msg_atom->type, i->c_uris.atom_String);
if (msg_atom && msg_atom->type == i->c_uris.atom_String) {
const char* msg_str = (const char*)(msg_atom + 1);
printf("audio - received string from UI: %s\n", msg_str);
}
}
ev = lv2_atom_sequence_next(ev);
}
}
#if defined(__aarch64__)
uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
@ -521,6 +628,11 @@ typedef struct {
char has_touch;
LV2UI_Touch touch;
# endif
# ifdef DATA_MESSAGING
LV2_URID_Map* map;
LV2_Atom_Forge forge;
communication_URIs c_uris;
# endif
} ui_instance;
static const char * ui_get_bundle_path_cb(void *handle) {
@ -557,6 +669,38 @@ static void ui_set_parameter_end_cb(void *handle, size_t index, float value) {
}
# endif
# ifdef DATA_MESSAGING
static char send_to_dsp (void *handle, const void *data, size_t bytes) {
ui_instance* instance = (ui_instance*) handle;
printf("send_to_dsp A \n"); fflush(stdout);
if (!data || bytes <= 0 || bytes > DATA_MESSAGING_MAX) {
return 1;
}
uint8_t obj_buf[256];
lv2_atom_forge_set_buffer(&instance->forge, obj_buf, sizeof(obj_buf));
LV2_Atom_Forge_Frame frame;
// Start forging an object
LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&instance->forge, &frame, 0, instance->c_uris.ui_On);
assert(msg);
// Add a string property to the object
lv2_atom_forge_key(&instance->forge, instance->c_uris.prop_customMessage);
lv2_atom_forge_string(&instance->forge, data, bytes);
// Finish the object
lv2_atom_forge_pop(&instance->forge, &frame);
// Send the forged atom to the host
instance->write(instance->controller, 8, lv2_atom_total_size(msg), instance->c_uris.atom_eventTransfer, msg);
return 0;
}
# endif
static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const char * plugin_uri, const char * bundle_path, LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget * widget, const LV2_Feature * const * features) {
(void)descriptor;
(void)plugin_uri;
@ -596,6 +740,9 @@ static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const ch
/* .set_parameter_begin = */ ui_set_parameter_begin_cb,
/* .set_parameter = */ ui_set_parameter_cb,
/* .set_parameter_end = */ ui_set_parameter_end_cb,
# endif
# ifdef DATA_MESSAGING
/* .send_to_dsp = */ send_to_dsp
# endif
};
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
@ -610,6 +757,15 @@ static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const ch
goto err_create;
*widget = instance->ui->widget;
for (int i = 0; features[i]; ++i) {
if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
instance->map = (LV2_URID_Map*)features[i]->data;
}
}
lv2_atom_forge_init(&instance->forge, instance->map);
map_comm_uris(instance->map, &instance->c_uris);
return instance;
err_create:
@ -631,7 +787,6 @@ static void ui_cleanup(LV2UI_Handle handle) {
# if DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
static void ui_port_event(LV2UI_Handle handle, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void * buffer) {
(void)buffer_size;
(void)format;
ui_instance *instance = (ui_instance *)handle;
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
@ -646,6 +801,35 @@ static void ui_port_event(LV2UI_Handle handle, uint32_t port_index, uint32_t buf
# endif
plugin_ui_set_parameter(instance->ui, param_out_index[port_index - CONTROL_OUTPUT_INDEX_OFFSET], *((float *)buffer));
# endif
const LV2_Atom* atom = (const LV2_Atom*)buffer;
/* Check type of data received
* - format == 0: Control port event (float)
* - format > 0: Message (atom)
*/
if (format == instance->c_uris.atom_eventTransfer && lv2_atom_forge_is_object_type(&instance->forge, atom->type)) {
const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom;
if (obj->body.otype == instance->c_uris.prop_customMessage) {
printf("received something from audio INCREDIBLE \n");
const LV2_Atom* len_a = NULL;
const LV2_Atom* data_a = NULL;
const int n_props = lv2_atom_object_get(obj, instance->c_uris.length, &len_a, instance->c_uris.prop_customMessage, &data_a, NULL);
const int32_t len = ((const LV2_Atom_Int*) len_a)->body;
printf("and n_props is %d \n", n_props);
printf("and len is %d \n", len);
printf("and data_a is %p \n", (void*)data_a);
//printf("and data_a type: %u, size: %u \n", data_a->type, data_a->size);
const uint8_t* data = (uint8_t*) data_a;
printf("data... \n");
for (int x = 0; x < len; x++) {
printf("%u ", data[x]);
}
printf("\n");
}
}
}
# endif

View File

@ -37,7 +37,8 @@ module.exports = function (data, api, outputCommon, outputData) {
{ id: "state", uri: "http://lv2plug.in/ns/extensions/state#" },
{ id: "ui", uri: "http://lv2plug.in/ns/extensions/ui#" },
{ id: "units", uri: "http://lv2plug.in/ns/extensions/units#" },
{ id: "urid", uri: "http://lv2plug.in/ns/ext/urid#" }
{ id: "urid", uri: "http://lv2plug.in/ns/ext/urid#" },
{ id: "rsz", uri: "http://lv2plug.in/ns/ext/resize-port#" }
],
units: {
"bar": "@units:bar",
@ -123,6 +124,27 @@ module.exports = function (data, api, outputCommon, outputData) {
}
ports.sort((a, b) => a.direction != b.direction ? (a.direction == "input" ? -1 : 1) : 0);
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, ports);
if (data.product.messaging) {
const ps = [
{
type: "message",
direction: "input",
control: true,
id: "message_in",
name: "message_in"
},
{
type: "message",
direction: "output",
control: true,
id: "message_out",
name: "message_out",
maxSize: data.product.messaging.maxSize
}
];
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, ps);
}
}
api.generateFileFromTemplateFile(`data${sep}manifest.ttl.in`, `data${sep}manifest.ttl.in`, data);