[LV2] Writing to control input ports w/o UI (DSP -> host; via atom output port) - RFC

Rui Nuno Capela rncbc at rncbc.org
Sat Apr 18 02:47:00 PDT 2020


Hi,

Many thanks for the quick reply and comments.

It's really appreciated and exactly to the point I was expecting for...


On 4/17/20 8:43 PM, David Robillard wrote:
> 
>> [...] _urid_map(LV2_ATOM__portEvent));
> 
> Types (classes) are capitalized, PortEvent in this case.
> 

No sweat, class `PortEvent` it is!
```
#define LV2_ATOM__PortEvent LV2_ATOM_PREFIX "PortEvent" ///<
http://lv2plug.in/ns/ext/atom#PortEvent>
```

>> [...] lv2_atom_forge_key(forge, forge->Tuple);
> 
> Similarly, atom:Tuple is not a property (key), it is a type.  You
> will need to invent a property for this.
> 

Easy as this, maybe a new property `portTuple`?

```
#define LV2_ATOM__portTuple LV2_ATOM_PREFIX "portTuple" ///<
http://lv2plug.in/ns/ext/atom#portTuple>
```

>> [...]
> 
> Most importantly however, thanks for prototyping this, but PLEASE DO 
> NOT RELEASE IMPLEMENTATIONS THAT USE URIS IN LV2 NAMESPACES THAT DO
> NOT EXIST IN LV2 MASTER!  Use URIs in some other namespace at first
> for things like this, people can't invent whatever URIs in the LV2 
> namespaces they want, that has caused real problems in the past.
> 

Don't worry. Although already implemented and working as proposed, in
qtractor and the vee-ones upstream, it's all still experimental code and
not yet "officially" released (simply as that, the new proposed URIs are
currently declared as above with `#ifndef`/`#define`s).

Besides, the new couple of URIs are here still proposed to the
`LV2:Atom` namespace, for which I believe is the right one, as this is
NOT a brand new  extension or vocabulary on its own: it's just about one
and simple possibility that's been missed here since a long time ago :)


Anyway, here below follows the now corrected code snippets...

---
Host: ** read_port_event **
```
#include "lv2/lv2plug.in/ns/ext/atom/util.h"

//  LV2_Atom *atom;
//
//  `atom` is a `LV2_ATOM__Object`, read from the plugin's atom output
//  port buffer, while on the real-time processing thread and then
//  transferred to the main host (non-DSP) thread, possibly via a
//  ring-buffer, wrapped in a `LV2_ATOM__eventTransfer` container.
//
    const LV2_Atom_Object *obj = (const LV2_Atom_Object *) atom;

    if (obj->body.otype == _urid_map(LV2_ATOM__PortEvent)) {
        const LV2_Atom_Tuple *tup = nullptr;
        lv2_atom_object_get(obj,
            _urid_map(LV2_ATOM__portTuple), (const LV2_Atom *) &tup, 0);
        uint32_t port_index = 0;
        if (tup) {
            uint32_t port_index = 0;
            LV2_ATOM_TUPLE_FOREACH(tup, iter) {
                if (iter->type == _urid_map(LV2_ATOM__Int))
                    port_index = *(uint32_t *) (iter + 1);
                else
                if (iter->type == _urid_map(LV2_ATOM__Float)) {
                    const uint32_t buffer_size = iter->size;
                    const void *buffer = iter + 1;
                    _control_port_write(port_index, buffer_size, 0, buffer);
                }
            }
        }
    }
//  ...
```

---
Plugin: ** write_port_event(s) **
```
#include "lv2/lv2plug.in/ns/ext/atom/forge.h"

//  LV2_Atom_Forge *forge;
//
//  `forge` should be bound to the plugin's atom output port buffer;
//  nb. remember to declare an minimum adequate port buffer size (via
//  `LV2_RESIZE_PORT__minimumSize` property) if you intend to notify in
//  bulk ie. more than one tuple or pairs (`port_index`, `port_value`)
//  in contiguous sequence.
//
//  uint32_t port_index;
//  float port_value;
//
//  `port_index` (int) is the control input port index that is desired
//  to get updated on the host-side with `port_value` (float), forming
//  one or more tuples wrapped in a LV2_ATOM__PortEvent object and sent
//  out to host.
//
    lv2_atom_forge_frame_time(forge, 0);

    LV2_Atom_Forge_Frame obj_frame;
    lv2_atom_forge_object(forge, &obj_frame, 0,
_urid_map(LV2_ATOM__portEvent));
    lv2_atom_forge_key(forge, _urid_map(LV2_ATOM__portTuple));

    LV2_Atom_Forge_Frame tup_frame;
    lv2_atom_forge_tuple(forge, &tup_frame);

    // for each (port_index, port_value) tuple ...
    lv2_atom_forge_int(forge, port_index);
    lv2_atom_forge_float(forge, port_value);
    // ...

    lv2_atom_forge_pop(forge, &tup_frame);
    lv2_atom_forge_pop(forge, &obj_frame);

//  ...
```

Hope it all looks a tad better now ;)

Cheers && Thanks again
-- 
rncbc aka. Rui Nuno Capela




More information about the Devel mailing list