[LV2] [LAD] LV2: Communicate from the DSP to the UI

David Robillard d at drobilla.net
Tue Nov 5 20:41:13 PST 2013


On Wed, 2013-11-06 at 04:33 +0100, Robin Gareus wrote:
> Hi guys,
> 
> On 11/05/2013 06:48 AM, Michael Fisher wrote:
> [..]
> > 
> > ForgeFrame frame;
> > 
> > AtomObject obj (forge.write_blank (frame, 0, object_type));
> > forge.property_head (prop_type, 0);
> > forge.write_raw (buffer, sizeof (float) * bufsize);
> [..]
> 
> That works all right, but it's not proper LV2 Atom/RDF.
>  - the receiver has no idea about the length
>  - if the host-buffer overflows there's no way to re-sync
>  - it cannot be interleaved with other DSP -> UI messages
>  - `jalv.gtk -d ...` cannot parse it as RDF
>  - ...

Indeed.  Don't Do That(TM).  Using non-standard types is not so good,
but can be valid.  This, however, is not valid.  The property value has
no atom header, so the host might look for the type and/or size the
standard guarantees is there, find some float bytes instead, and boom.
Do not send corrupt atoms around!

raw() is very much a "do not use this unless you really very definitely
know exactly what you are doing" function.  Perhaps the docs should say
as much.

Anyway, jalv.gtk -d is a good indicator of sanity, it should print
something human readable.  Practical reasons aside (e.g. working in
separated hosts like Ingen), debugging is a heck of a lot nicer when you
can just look at the data flying around.  If it crashes, it's probably
because the atoms are corrupt.

> Anyway even if you make it work, I doubt that you'll have much fun:
> 
> Atom messages are written into a ringbuffer in the LV2host in the
> DSP-thread. This ringbuffer is sent to the UI by another thread
> (jalv.gtk and ardour use a g_timeout() usually at 40ms ~ 25fps), and
> finally things are drawn in the X11 thread ie. gtk-main or qt's main.
> 
> Other LV2 hosts may do do things differently and you have no control
> over it.
> 
> As much as like LV2 from a user's perspective and host integration. It
> kinds sucks for visualizations. The only realistic way do to RT
> *visualizations* (e.g. a scope) right is to bypass the host (use
> instance access & a semaphore) and use openGL with vblank-sync using a
> custom thread in the UI (drobilla is going to blacklist me now).

Why?  I have constantly said since day 1 that instance-access is
suitable for visualization use.  For plugins that do a bunch of stuff
*and* have visualization, they can simply degrade to not having the
fancy visualization part if it's not available.  It's people abusing the
facility to do control that I have a problem with, for very good
reasons.

Using instance-access for visualization is 100% OK (assuming graceful
degradation if the plugin does other things).  Using it for control is
grounds for being taken out back and shot.

> Synchronizing even one [audio] thread with the gfx-hardware is not
> trivial. Default LV2 communication involves two or mo
> That being said I do like LV2 Atoms, event-queues, mapped URIs, and more
> generally the CY-y way of LV2, though. It's very nice, robust and
> elegant for control. Sometimes a tad overkill, but heck, therefore it's
> portable, too.

While this is practically true in most cases, it's not really the right
thinking for what's going on here.  Essentially what you have between
the plugin instance and UI is a network.  The best you get is
"recentish".  So, yeah, hardish sync is inherently not happening.

While messages will work just fine for many kinds of basic
visualization, for hyper accurate scopes that want to go so far as to
sync with graphics hardware, obviously it's not the best approach.
That's why instance-access exists.  By all means, use it.  I'd actually
like to see somebody use the god damned thing for the intended purpose
for a change :P

(If such performance is not required, though, messages are better,
because working across processes and/or networks is handy.  Scopes are a
bit much, but e.g. simple meters should certainly do so)

Cheers,

-- 
dr




More information about the Devel mailing list