aboutsummaryrefslogtreecommitdiffstats
path: root/lv2/lv2plug.in/ns/ext/state/state.ttl
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-03-04 04:10:19 +0000
committerDavid Robillard <d@drobilla.net>2012-03-04 04:10:19 +0000
commitc768da6fb7c299d66ef1af0f9423ceba525c1b3c (patch)
tree2a91ddf30971b8e3d3f16e9fc2887d2bd96f029e /lv2/lv2plug.in/ns/ext/state/state.ttl
parent039f76cacd875fe8a68f131a3cfbef959a8cd40c (diff)
downloadlv2-c768da6fb7c299d66ef1af0f9423ceba525c1b3c.tar.xz
Update documentation to reflect reality.
Diffstat (limited to 'lv2/lv2plug.in/ns/ext/state/state.ttl')
-rw-r--r--lv2/lv2plug.in/ns/ext/state/state.ttl201
1 files changed, 107 insertions, 94 deletions
diff --git a/lv2/lv2plug.in/ns/ext/state/state.ttl b/lv2/lv2plug.in/ns/ext/state/state.ttl
index 4b86eb6..5b4610f 100644
--- a/lv2/lv2plug.in/ns/ext/state/state.ttl
+++ b/lv2/lv2plug.in/ns/ext/state/state.ttl
@@ -35,8 +35,8 @@
doap:shortdesc "An interface for LV2 plugins to save and restore state." ;
doap:license <http://opensource.org/licenses/isc> ;
doap:release [
- doap:revision "0.5" ;
- doap:created "2012-01-29" ;
+ doap:revision "0.6" ;
+ doap:created "2012-03-03" ;
dcs:blame <http://drobilla.net/drobilla#me>
] ;
doap:developer [
@@ -44,71 +44,86 @@
foaf:name "Leonard Ritter" ;
foaf:homepage <http://paniq.org>
] ;
- doap:maintainer [
- a foaf:Person ;
- foaf:name "David Robillard" ;
- foaf:homepage <http://drobilla.net/> ;
- rdfs:seeAlso <http://drobilla.net/drobilla.rdf>
- ] ;
+ doap:maintainer <http://drobilla.net/drobilla#me> ;
lv2:documentation """
-<p>This extension provides a simple mechanism for plugins to save and restore
-state across instances, allowing hosts to save and restore a plugin instance's
-state at any time. The goal is for an instance's state to be
+
+<p>This extension defines a simple mechanism which allows hosts to save and
+restore a plugin instance's state. The goal is for an instance's state to be
<em>completely</em> described by port values (as with all LV2 plugins) and a
-dictionary.</p>
+simple dictionary.</p>
-<p>The <q>state</q> described by this extension is conceptually a simple
-key:value dictionary, where keys are URIDs (URIs mapped to integers) and values
-are type-tagged blobs of any type. A single key:value pair is called a
-<q>property</q>. To implement state, the plugin provides a state:Interface to
-the host. To save or restore, the host calls LV2_State_Interface::save() or
-LV2_State_Interface::restore(), passing a callback to be used for handling a
-single property. The host is free to implement property storage and retrieval
-in any way.</p>
+<p>The <q>state</q> defined here is conceptually a key:value dictionary, with
+URI keys and values of any type. For performance reasons the key and value
+type are actually a <q>URID</q>, a URI mapped to an integer. A single
+key:value pair is called a <q>property</q>.</p>
<p>This state model is simple yet has many benefits:</p>
<ul>
- <li>URID keys provide both fast performance and RDF compatibility.</li>
- <li>Fully extensible, no limitations on keys or value types.</li>
- <li>Easy to serialise in many formats (e.g. any RDF syntax, plain
- text, JSON, XML, key:value databases, SQL, s-expressions, etc.).</li>
- <li>Elegantly described in Turtle, which is useful for describing presets
- or default state in LV2 data files (the predicate state:state is provided
- for this purpose).</li>
+ <li>Both fast and extensible thanks to URID keys.</li>
+ <li>No limitations on possible value types.</li>
+ <li>Easy to serialise in almost any format.</li>
+ <li>Easy to store in a typical <q>map</q> or <q>dictionary</q> data
+ structure.</li>
+ <li>Elegantly described in Turtle, so state can be described in LV2 data
+ files (including presets).</li>
<li>Does not impose any file formats, data structures, or file system
requirements.</li>
<li>Suitable for portable persistent state as well as fast in-memory
snapshots.</li>
- <li>Easily stored in a typical <q>map</q> or <q>dictionary</q> data
- structure.</li>
- <li>Keys may be defined by extensions and used by several plugins,
- making state meaningful enabling dynamic state control.</li>
+ <li>Keys <em>may</em> be well-defined and used meaningfully across several
+ implementations.</li>
+ <li>State <em>may</em> be dynamic, but plugins are not required to have a
+ dynamic dictionary data structure available.</li>
</ul>
-<p>Implementations or further extensions which work with plugin state
-(including dynamic plugin control) SHOULD work entirely within this model.
-That is, <strong>do not complicate the state model</strong>. <em>All</em>
-information required to express an instance's state at any given time can, and
-should, be expressed within this model.</p>
+<p>To implement state, the plugin provides a state:Interface to the host. To
+save or restore, the host calls LV2_State_Interface::save() or
+LV2_State_Interface::restore(), passing a callback to be used for handling a
+single property. The host is free to implement property storage and retrieval
+in any way.</p>
+
+<p>Since value types are defined by URI, any type is possible. However, a set
+of standard types is defined by the <a href="http://lv2plug.in/ns/ext/atom">LV2
+Atom</a> extension. Use of these types is recommended. Hosts MUST implement
+at least <a href="http://lv2plug.in/ns/ext/atom#String">atom:String</a>, which
+is simply a C string.</p>
+
+<h3>Referring to Files</h3>
+
+<p>Plugins may need to refer to existing files (e.g. loaded samples) in their
+state. This is done by storing the file's path as a property just like any
+other value. However, there are some rules which MUST be followed when storing
+paths, see <a href="#mapPath">state:mapPath</a> for details. Plugins MUST use
+the type <a href="http://lv2plug.in/ns/ext/atom#Path">atom:Path</a> for all
+paths in their state.</p>
+
+<p>Plugins are strongly encouraged to avoid creating files, instead storing all
+state as properties. However, occasionally the ability to create files is
+necessary. To make this possible, the host can provide the feature <a
+href="#makePath">state:makePath</a> which allocates paths for plugin-created
+files. Plugins MUST NOT create files in any other locations.</p>
<h3>Plugin Code Example</h3>
<pre class="c-code">
-#define NS_EG "http://example.org/"
-#define NS_ATOM "http://lv2plug.in/ns/ext/atom#"
+
+/* Namespace for this plugin's keys. This SHOULD be something that could be
+ published as a document, even if that document does not exist right now.
+*/
+#define NS_MY "http://example.org/myplugin/schema#"
LV2_Handle my_instantiate(...)
{
MyPlugin* plugin = ...;
- plugin->uris.atom_String = map_uri(NS_ATOM "String");
- plugin->uris.eg_greeting = map_uri(NS_EG "greeting");
- plugin->state.greeting = strdup("Hello");
+ plugin->uris.atom_String = map_uri(LV2_ATOM__String);
+ plugin->uris.my_greeting = map_uri(NS_MY "greeting");
+ plugin->state.greeting = strdup("Hello"); // Default value
return plugin;
}
void my_save(LV2_Handle instance,
LV2_State_Store_Function store,
- void* handle,
+ LV2_State_Handle handle,
uint32_t flags,
const LV2_Feature *const * features)
{
@@ -116,16 +131,16 @@ void my_save(LV2_Handle instance,
const char* greeting = plugin->state.greeting;
store(handle,
- plugin->uris.eg_greeting,
+ plugin->uris.my_greeting,
greeting,
- strlen(greeting) + 1,
+ strlen(greeting) + 1, // Careful! Need space for terminator
plugin->uris.atom_String,
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
}
void my_restore(LV2_Handle instance,
LV2_State_Retrieve_Function retrieve,
- void* handle,
+ LV2_State_Handle handle,
uint32_t flags,
const LV2_Feature *const * features)
{
@@ -135,7 +150,7 @@ void my_restore(LV2_Handle instance,
uint32_t type;
uint32_t flags;
const char* greeting = retrieve(
- handle, plugin->uris.eg_greeting, &amp;size, &amp;type, &amp;flags);
+ handle, plugin->uris.my_greeting, &amp;size, &amp;type, &amp;flags);
if (greeting) {
free(plugin->state->greeting);
@@ -157,20 +172,19 @@ const void* my_extension_data(const char* uri)
<h3>Host Code Example</h3>
<pre class="c-code">
-int store_callback(void* handle,
- uint32_t key,
- const void* value,
- size_t size,
- uint32_t type,
- uint32_t flags)
+int store_callback(LV2_State_Handle handle,
+ uint32_t key,
+ const void* value,
+ size_t size,
+ uint32_t type,
+ uint32_t flags)
{
if ((flags &amp; LV2_STATE_IS_POD)) {
/* We only care about POD since we're keeping state in memory only.
- If this was for disk or network storage/transmission,
- LV2_STATE_IS_PORTABLE would have to be checked as well.
+ For disk or network use, LV2_STATE_IS_PORTABLE must also be checked.
*/
Map* state_map = (Map*)handle;
- state_map->insert(key, Value(copy(value), size, type, pod));
+ state_map->insert(key, Value(copy(value), size, type));
return 0;
} else {
return 1; /* Non-POD events are unsupported. */
@@ -179,7 +193,7 @@ int store_callback(void* handle,
Map get_plugin_state(LV2_Handle instance)
{
- LV2_State* state = instance.extension_data("http://lv2plug.in/ns/ext/state");
+ LV2_State* state = instance.extension_data(LV2_STATE__Interface);
Map state_map;
/** Request a fast/native/POD save, since we're just copying in memory */
state.save(instance, store_callback, &amp;state_map,
@@ -188,22 +202,30 @@ Map get_plugin_state(LV2_Handle instance)
}
</pre>
-<h3>Referring to Existing Files</h3>
+<h3>Extensions to this Specification</h3>
-<p>Plugins may need to refer to files (e.g. loaded samples) in their state.
-This is done by storing the file's path as a property just like any other
-value. However, there are some rules which MUST be followed when storing
-paths, see <a href="#mapPath">state:mapPath</a> for details. Plugins MUST
-use the type <a href="http://lv2plug.in/ns/ext/atom#Path">atom:Path</a>
-for all paths in their state.</p>
+<p>It is likely that other interfaces for working with plugin state will be
+developed as needed. This is encouraged, however everything SHOULD work within
+the state <em>model</em> defined here. That is, <strong>do not complicate the
+state model</strong>. Implementations can assume the following:</p>
-<h3>Creating New Files or Directories</h3>
+<ul>
+<li>The current port values and state dictionary completely describe a plugin
+instance, at least well enough that saving and restoring will yield an
+<q>identical</q> instance from the user's perspective.</li>
+<li>Hosts are not expected to save and/or restore any other attributes of a
+plugin instance.</li>
+</ul>
-<p>Implementations are strongly encouraged to avoid the use of files and simply
-store all state as properties whenever possible. However, occasionally the
-ability to create files is necessary. The feature <a
-href="#newPath">state:newPath</a> makes this possible, if it is provided by the
-host.</p>
+<p>The recommended way to add new functionality that may affect state is to
+simply define it in terms of properties. For example, instead of defining a
+new set of commands, define properties whose values can be set appropriately.
+This provides persistence <q>for free</q>, since rather than having to define a
+set of commands <em>and</em> a set of properties for storing their effects,
+only the properties need to be defined.</p>
+
+<p>This <q>property principle</q> is summed up in the phrase: <q>Don't
+stop; set playing to false</q>.</p>
""" .
state:Interface
@@ -213,8 +235,8 @@ state:Interface
<p>A structure (LV2_State_Interface) which contains functions to be called by
the host to save and restore state. In order to support this extension, the
plugin must return a valid LV2_State_Interface from
-LV2_Descriptor::extension_data() when it is called with
-LV2_STATE_INTERFACE_URI.</p>
+LV2_Descriptor::extension_data() when it is called with URI
+LV2_STATE__Interface.</p>
<p>The plugin data file should describe this like so:</p>
<pre class="turtle-code">
@@ -230,26 +252,20 @@ state:State
a rdfs:Class ;
rdfs:label "Plugin Instance State" ;
lv2:documentation """
-<p>This class is used to express a plugin instance's state in RDF. The
-key/value properties of the instance form the predicate/object (respectively)
-of triples with a state:State as the subject (see <a
-href="#state">state:state</a> for an example). This may be used wherever it is
-useful to express a plugin instance's state in RDF (e.g. for serialisation,
-storing in a model, or transmitting over a network). Note that this class is
-provided because it may be useful for hosts, plugins, or extensions that work
-with instance state, but its use is not required to support the LV2 State
-extension.</p>
+<p>A state dictionary. This type should be used wherever instance state is
+described in RDF, or any other context that uses type URIs. The properties of
+a resource with this type correspond directly to the properties of the state
+dictionary (except the property that states it has this type).</p>
""" .
state:state
a rdf:Property ;
+ rdfs:label "State" ;
rdfs:range state:State ;
lv2:documentation """
-<p>Predicate to relate a plugin instance to its State. This may be used
-wherever the state of a particular plugin instance needs to be represented.
-Note that the domain of this property is unspecified, since LV2 does not define
-any RDF class for plugin instance. This predicate may be used wherever it makes
-sense to do so, e.g.:</p>
+<p>The state of this plugin instance, or similar resource. This property may
+be used anywhere a state needs to be described, for example:</p>
+
<pre class="turtle-code">
@prefix eg: &lt;http://example.org/&gt; .
@@ -260,23 +276,20 @@ sense to do so, e.g.:</p>
eg:favourite-number 2
] .
</pre>
-<p>Note that this property is provided because it may be useful for hosts,
-plugins, or extensions that work with instance state, but its use is not
-required to support this extension.</p>
""" .
state:mapPath
a lv2:Feature ;
- rdfs:label "Support for storing paths in files" ;
+ rdfs:label "Support for storing paths in state" ;
lv2:documentation """
<p>This feature maps absolute paths to/from <q>abstract paths</q> which are
stored in state. To support this feature a host must pass an LV2_Feature with
-URI LV2_STATE_MAP_PATH_URI and data pointed to an LV2_State_Map_Path to the
+URI LV2_STATE__mapPath and data pointed to an LV2_State_Map_Path to the
plugin's LV2_State_Interface methods.</p>
-<p>The plugin MUST map <em>all</em> paths stored in its state (including in any
-files in its state). This is necessary to enable host to handle file system
-references correctly, e.g. for distribution or archival.</p>
+<p>The plugin MUST map <em>all</em> paths stored in its state (including those
+inside any files in its state). This is necessary to enable host to handle
+file system references correctly, e.g. for distribution or archival.</p>
<p>For example, a plugin may write a path to a state file like so:</p>
@@ -308,7 +321,7 @@ state:makePath
lv2:documentation """
<p>This feature allows plugins to create new files and/or directories. To
support this feature the host passes an LV2_Feature with URI
-LV2_STATE_MAKE_PATH_URI and data pointed to an LV2_State_Make_Path to the
+LV2_STATE__makePath and data pointed to an LV2_State_Make_Path to the
plugin. The host may make this feature available only during save by passing
it to LV2_State_Interface::save(), or available any time by passing it to
LV2_Descriptor::instantiate(). If passed to LV2_State_Interface::save(), the