[LV2] Parameters, groups, and dynamicism

David Robillard d at drobilla.net
Mon Sep 26 10:49:52 PDT 2016


On Mon, 2016-09-26 at 11:32 +0200, Hanspeter Portner wrote:
[...]
> > param:ampGain
> > 	...
> > 	pg:group :ampControls .
> > 
> > param:filterGain
> > 	...
> > 	pg:group :filterControls .
> > 
> > This sucks.  We could use inheritance to eliminate most of the redundant
> > description, but it still sucks, because part of the idea with parameter
> > descriptions is that host (or UI library, or...) can understand commonly
> > used parameters and implement them specially.
> 
> I feel your pain, indeed. It is really cumbersome to define each parameter
> individually.
> 
> Out of curiosity. How would such an inheritance scheme look like?

You can do property inheritance with rdfs:subPropertyOf in essentially
the same way you do for classes (just say it is a rdfs:subPropertyOf
some:superProperty).

In our case, this would require hosts (or lilv, or whatever) to actually
follow that chain to find information, but that's not too hard.

> > So, we need to do something different, and I'm thinking describing the
> > groups on the plugin directly is the way.  This is particularly nice
> > because you can re-use entire group descriptions.  For example, we have
> > params:EnvelopeControls which describe the controls for a DAHDSR
> > envelope.  If a plugin could do something like:
> > 
> > :myplug
> > 	...
> > 	foo:parameterGroup [
> > 		a param:EnvelopeControls ;
> > 		lv2:symbol "amp_env" ;
> > 	] .
> > 
> > Then you can describe an entire set of established controls with just
> > that description, and re-use the same group description for many
> > controls (e.g. for plugins with many envelopes).
> 
> Sounds reasonable to me.
> 
> > We would need rules to make the plugin-unique symbol for groups
> > parameters, probably "groupsymbol_paramsymbol", so this plugin would
> > e.g. have a control amp_env_attack.
> > 
> > So, issues:
> > 
> > * This is not compatible with the current way of using patch:readable
> > and patch:writable to discover parameters.  I don't think this is
> > terribly important since this isn't well-established anyway.  Perhaps we
> > should even move to parameters being *always* groups with some "default
> > group" defined.
> 
> Mandatory groups would be a nice thing to have as it would tremendously improve
> representation in automatic/generic UIs. Plugins that define port groups are
> much nicer to interact with in automatic UIs than those without.
> 
> > * Not sure how this works with the general concepts of
> > readable/writable.  Can a single group have parameters that are
> > differently readable/writable?  The current group description can not
> > support this.
> 
> I can think of a single group having both readable and writable parameters, yes.

Such as?

This is trouble because the way "standard" groups currently define their
elements has no such context and can be applied in either an input or
output context.  Having groups with both read-only and write-only
parameters diverges things from the way audio/control ports work.
Probably doable, but it'd be nice if we didn't have to...

> > * We need symbols to support the general LV2 design constraint that all
> > controls have a unique symbol.  These are not useful at run-time,
> > though, so it might be better to enforce URIs for parameter groups (like
> > we probably should have for ports, even though it makes the ttl
> > description a bit uglier), like:
> > 
> > :ampEnvControls
> > 	a param:EnvelopeControls ;
> > 	lv2:symbol "amp_env" .
> > 
> > :myplug
> > 	...
> > 	foo:parameterGroup :ampEnvControls .
> > 
> > Which lets you get a URID for ampEnvControls.  Setting grouped
> > parameters would use the subject property of patch messages, so:
> > 
> > []
> > 	a patch:Set ;
> > 	patch:subject :ampEnvControls ;
> > 	patch:property params:attack ;
> > 	patch:value 0.15 .
> 
> I like that.
> 
> > This is a bit worrying, however, because claiming patch:subject means it
> > is impossible to tinker grouped parameters on different "subjects" than
> > the plugin instance.  We could mandate some things about what the
> > *instance* URI is to get around this and make rules that the group URI
> > must be a fragment of it and so on, though mandating URIs syntactically
> > is generally frowned upon in some circles...
> 
> I've run into the same issue with my current way of dynamic properties (see below).
> 
> What about referencing the target plugin via a separate property instead of a
> naming rule?
> 
> []
> 	a patch:Set ;
> 	patch:plugin :myplug ;
> 	patch:subject :ampEnvControls ;
> 	patch:prperty params:attack ;
> 	patch:value 0.15 .

This would work, though the lack of genericism ala everything else rubs
me the wrong way.  Maybe that's just a terminology thing though.

"Context", perhaps...

> > (Sidenote: reason #8347289 URID probably should have been a general
> > symbol interning interface instead)
> > 
> > * Dynamicism would be achieved by emitting a description much like the
> > one above about new parameters showing up.  To make this realistic,
> > probably something like lilv_controls_message_is_relevant(atom_msg),
> > which if returns true, the hosts should ringbuffer it to somewhere and
> > later call lilv_controls_update(controls, atom_msg) which will update
> > the (hypothetical) LilvControls which emits callbacks to notify the host
> > of new stuff and so on.  This is pretty nice because you can do things
> > like describe an entire new set of envelope controls in a terse message
> > without enumerating all the specifics.
> 
> Yes, I'd like to have an 'official' way for dynamicism.
> 
> I'm doing my own experiments with that already.
> 
> It's roughly the same thing as you're proposing, instead of custom parameter
> groups, I use patch:writable and patch:readable as the only available parameter
> groups.
> 
> Followingly the jalv dump of registering a single dynamic parameter
> <urn:moony:bender#bendrange> to the UI.
> 
> ## UI => Plugin (32 bytes) ##
> []
> 	a patch:Get ;
> 	patch:sequenceNumber "0"^^xsd:int .
> 
> ## Plugin => UI (104 bytes) ##
> []
> 	a patch:Patch ;
> 	patch:remove [
> 		patch:writable patch:wildcard ;
> 		patch:readable patch:wildcard
> 	] ;
> 	patch:add [
> 		
> 	] .
> 
> 
> ## Plugin => UI (104 bytes) ##
> []
> 	a patch:Patch ;
> 	patch:remove [
> 		patch:writable <urn:moony:bender#bendrange>
> 	] ;
> 	patch:add [
> 		patch:writable <urn:moony:bender#bendrange>
> 	] .
> 
> 
> ## Plugin => UI (448 bytes) ##
> []
> 	a patch:Patch ;
> 	patch:subject <urn:moony:bender#bendrange> ;
> 	patch:remove [
> 		<http://www.w3.org/2000/01/rdf-schema#label> patch:wildcard ;
> 		<http://www.w3.org/2000/01/rdf-schema#range> patch:wildcard ;
> 		<http://www.w3.org/2000/01/rdf-schema#comment> patch:wildcard ;
> 		<http://lv2plug.in/ns/lv2core#minimum> patch:wildcard ;
> 		<http://lv2plug.in/ns/lv2core#maximum> patch:wildcard ;
> 		<http://lv2plug.in/ns/extensions/units#unit> patch:wildcard ;
> 		<http://lv2plug.in/ns/lv2core#scalePoint> patch:wildcard
> 	] ;
> 	patch:add [
> 		<http://www.w3.org/2000/01/rdf-schema#label> "Pitch Bend Range" ;
> 		<http://www.w3.org/2000/01/rdf-schema#range> <http://lv2plug.in/ns/ext/atom#Int> ;
> 		<http://www.w3.org/2000/01/rdf-schema#comment> "set pitch bend range of
> receiving instrument" ;
> 		<http://lv2plug.in/ns/lv2core#minimum> "0"^^xsd:int ;
> 		<http://lv2plug.in/ns/lv2core#maximum> "9600"^^xsd:int ;
> 		<http://lv2plug.in/ns/extensions/units#unit>
> <http://lv2plug.in/ns/extensions/units#cent>
> 	] .
> 
> 
> ## UI => Plugin (56 bytes) ##
> []
> 	a patch:Get ;
> 	patch:property <urn:moony:bender#bendrange> ;
> 	patch:sequenceNumber "0"^^xsd:int .
> 
> 
> ## Plugin => UI (56 bytes) ##
> []
> 	a patch:Set ;
> 	patch:property <urn:moony:bender#bendrange> ;
> 	patch:value "200"^^xsd:int .

Cool.  Note you can use patch:Set for more terse messages that avoid all
the wildcards if the set of keys is the same anyway (not important, just
nicer, thought I'd mention it).

> > * Should we provide an index mechanism?  URIDs let you do it, but
> > frankly the requirement to map a ton of URIDs is already pretty
> > burdensome, and having to do it for all your parameters seems like it
> > could be the straw that breaks plugin developer's backs...
> 
> A lot of URIDs can be burdensome, indeed. Still, I'd prefer URIDs over indexes.
>
> Some 'official' utility functions to (un)map URIDS to/from enums would be nice,
> though.

True.  I think maybe eliminating the burden of URIs for things defined
in the standard spec would be good (more on that in a separate thread),
but having to "register" your parameters in some way seems pretty
reasonable.

-- 
dr




More information about the Devel mailing list