diff options
author | David Robillard <d@drobilla.net> | 2012-03-04 04:10:19 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2012-03-04 04:10:19 +0000 |
commit | c768da6fb7c299d66ef1af0f9423ceba525c1b3c (patch) | |
tree | 2a91ddf30971b8e3d3f16e9fc2887d2bd96f029e /lv2/lv2plug.in/ns/ext/state/state.ttl | |
parent | 039f76cacd875fe8a68f131a3cfbef959a8cd40c (diff) | |
download | lv2-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.ttl | 201 |
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, &size, &type, &flags); + handle, plugin->uris.my_greeting, &size, &type, &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 & 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, &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: <http://example.org/> . @@ -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 |