[LV2] Need help sending a variable size atom from the UI of my plug-in

David Robillard d at drobilla.net
Mon Sep 13 12:10:11 PDT 2021

On Mon, 2021-09-06 at 10:25 -0500, Clay Citadel wrote:
> Hi,
> I'm using c++ and lvtk framework, but I'll be perfectly happy with
> using raw lv2 C functions to do this. Here is the code I have that
> works with LV2_ATOM__eventTransfer:
> In the UI code:
>       struct VectorOf5Ints {
>         uint32_t size; // sizeof(LV2_Atom_Vector_Body) + (42 *
> sizeof(float);
>         uint32_t type; // map(expand("Vector"))
>         uint32_t child_size; // sizeof(float)
>         uint32_t child_type; // map(expand("Float"))
>         uint32_t elems[5];
>       };
>       VectorOf5Ints vec{sizeof(LV2_Atom_Vector_Body) + (5 *
> sizeof(uint32_t)),
>                         map(LV2_ATOM__Vector),
>                         sizeof(uint32_t),
>                         map(LV2_ATOM__Int),
>                         {5, 9, 5, 9, 7}};
>       write(5, sizeof(vec), map(LV2_ATOM__eventTransfer), &vec);
> where write is a LV2UI_Write_Function.
> In the turtle file:
>     ... , [
>      a lv2:InputPort, atom:AtomPort ;
>      atom:bufferType atom:Vector ;
>      lv2:designation lv2:control ;
>      lv2:index 5 ;
>      lv2:symbol "out_ui" ;
>      lv2:name "UI to Business comm" ;
>      rdfs:comment "UI -> communication" ;
>      resize_port:minimumSize 15360 ;
>      ] ...
> In the plug-in connect_port function:
>    configuration_from_ui = static_cast<int *>(data);
> In the run function of my plugin:
>     for (auto i{0}; i <= 5+9; ++i) {
>          log.printf(map(LV2_LOG__Entry), "LV2LOGGER: %d\n",
>                    configuration_from_ui[i]);
>     }
> This works, but it attaches the event header because I'm using
> LV2_ATOM__eventTransfer, but I really just want to use
> LV2_ATOM__atomTransfer is there a way to do this? when I change it in
> the code I get the following message in the console:
> UI write with unsupported protocol 48
> (http://lv2plug.in/ns/ext/atom#atomTransfer)
> Questions:
> 1) Is it really unsupported or am I doing something wrong? Like for
> example, do I need to change something in the turtle file?

It's not very widely supported in practice.  A port like this would
have to treat the (vector, in this case) value like audio and update it
every time.  Although the spec allows atom ports of whatever variety,
this isn't usually what people use them for.  It's almost always event.

In other words, non-Sequence atom ports are an esoteric thing, don't
expect most typical hosts to support it.

> 2) What I'm trying to do is send a configuration state from the UI to
> the business end. Ideally I would like it to avoid sending the message
> every frame, what is it doing right now? is the host constantly copying
> a 15360 size buffer every frame? or only when I use the
> LV2UI_Write_Function it will copy the buffer into the business end of
> the plugin? what is the best way of doing this? Am I on the right
> track?

Sounds like you want to use events.  That is the standard well-
supported mechanism for not sending the whole buffer every frame.

> 3) If I must use eventTransfer how can get just the event body when I'm
> reading it on the business end, notice I'm just doing a "for loop" for
> testing and I figured out the event header is 5 ints worth of size.
> Similarly, how do I get the atom body other than doing what I currently
> do which is just added a number to the pointer and taking that.

I don't really know what you mean by "business end".  I guess since
you're talking about sending from a UI, you mean the plugin itself.

The event header is followed immediately by the body, which is an atom.
The cleanest way is to use the types in atom.h.  The original code you
posted would benefit from this as well, it avoids the potential of
screwing up and defining a struct that isn't actually binary
compatible.  It's C, so you can do whatever pointer arithmetic you
like, but there's really no reason to be doing something like
experimentally determining how big a header is.  Use the types!

So, when you have an event pointer, the body is just event->body.  See
more or less any example that uses events, they all need to do this. 
handle_event() in sampler.c is one example.  I don't know a direct
reference to an lvtk one off the top of my head but I'm sure there's
some there too.


More information about the Devel mailing list