aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-11-23 07:25:51 +0000
committerDavid Robillard <d@drobilla.net>2011-11-23 07:25:51 +0000
commit73137d533a3e853aa13064cb76d040bcab16dceb (patch)
treebb4829e547175c7a4d431a297882a7c6f70c299e
parent820519668b7c211bf66b538c5fbc7c74986f931d (diff)
downloadlv2-73137d533a3e853aa13064cb76d040bcab16dceb.tar.xz
Merge files extension into state extension.
l---------lv2/ns/ext/files/ext.pc.in1
-rw-r--r--lv2/ns/ext/files/files.h134
-rw-r--r--lv2/ns/ext/files/files.ttl115
-rw-r--r--lv2/ns/ext/files/manifest.ttl9
l---------lv2/ns/ext/files/waf1
l---------lv2/ns/ext/files/wscript1
-rw-r--r--lv2/ns/ext/state/manifest.ttl5
-rw-r--r--lv2/ns/ext/state/state.h96
-rw-r--r--lv2/ns/ext/state/state.ttl253
9 files changed, 281 insertions, 334 deletions
diff --git a/lv2/ns/ext/files/ext.pc.in b/lv2/ns/ext/files/ext.pc.in
deleted file mode 120000
index 82b50df..0000000
--- a/lv2/ns/ext/files/ext.pc.in
+++ /dev/null
@@ -1 +0,0 @@
-../../../../ext.pc.in \ No newline at end of file
diff --git a/lv2/ns/ext/files/files.h b/lv2/ns/ext/files/files.h
deleted file mode 100644
index 623587a..0000000
--- a/lv2/ns/ext/files/files.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- Copyright 2010-2011 David Robillard <d@drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-/**
- @file files.h
- C API for the LV2 Files extension <http://lv2plug.in/ns/ext/files>.
-*/
-
-#ifndef LV2_FILES_H
-#define LV2_FILES_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define LV2_FILES_URI "http://lv2plug.in/ns/ext/files"
-#define LV2_FILES_PATH_SUPPORT_URI LV2_FILES_URI "#pathSupport"
-#define LV2_FILES_NEW_FILE_SUPPORT_URI LV2_FILES_URI "#newFileSupport"
-
-typedef void* LV2_Files_Host_Data;
-
-/**
- files:pathSupport feature struct.
-
- To support this feature, the host MUST pass an LV2_Feature struct with @a
- URI @ref LV2_FILES_PATH_SUPPORT_URI and @a data pointed to an instance of
- this struct.
-*/
-typedef struct {
-
- /**
- Opaque host data.
- */
- LV2_Files_Host_Data host_data;
-
- /**
- Map an absolute path to an abstract path for use in plugin state.
- @param host_data MUST be the @a host_data member of this struct.
- @param absolute_path The absolute path of a file.
- @return An abstract path suitable for use in plugin state.
-
- The plugin MUST use this function to map any paths that will be stored
- in plugin state. The returned value is an abstract path which MAY not
- be an actual file system path; @ref absolute_path MUST be used to map it
- to an actual path in order to use the file.
-
- Hosts MAY map paths in any way (e.g. by creating symbolic links within
- the plugin's state directory or storing a list of referenced files for
- later export). Plugins MUST NOT make any assumptions about abstract
- paths except that they can be mapped to an absolute path using @ref
- absolute_path. Particularly when restoring from state, this absolute
- path MAY not be the same as the original absolute path, but the host
- MUST guarantee it refers to a file with contents equivalent to the
- original.
-
- This function may only be called within the context of
- LV2_Persist.save() or LV2_Persist.restore(). The caller is responsible
- for freeing the returned value.
- */
- char* (*abstract_path)(LV2_Files_Host_Data host_data,
- const char* absolute_path);
-
- /**
- Map an abstract path from plugin state to an absolute path.
- @param host_data MUST be the @a host_data member of this struct.
- @param abstract_path An abstract path (e.g. a path from plugin state).
- @return An absolute file system path.
-
- Since abstract paths are not necessarily actual file paths (or at least
- not necessarily absolute paths), this function MUST be used in order to
- actually open or otherwise use the file referred to by an abstract path.
-
- This function may only be called within the context of
- LV2_Persist.save() or LV2_Persist.restore(). The caller is responsible
- for freeing the returned value.
- */
- char* (*absolute_path)(LV2_Files_Host_Data host_data,
- const char* abstract_path);
-
-} LV2_Files_Path_Support;
-
-/**
- files:newFileSupport feature struct.
-
- To support this feature, the host MUST pass an LV2_Feature struct with @a
- URI @ref LV2_FILES_NEW_FILE_SUPPORT_URI and @a data pointed to an instance
- of this struct.
-*/
-typedef struct {
-
- /**
- Opaque host data.
- */
- LV2_Files_Host_Data host_data;
-
- /**
- Return an absolute path the plugin may use to create a new file.
- @param host_data MUST be the @a host_data member of this struct.
- @param relative_path The relative path of the file.
- @return The absolute path to use for the new file.
-
- The plugin can assume @a relative_path is relative to a namespace
- dedicated to that plugin instance; hosts MUST ensure this, e.g. by
- giving each plugin instance its own state directory. The returned path
- is absolute and thus suitable for creating and using a file, but NOT
- suitable for storing in plugin state (it MUST be mapped to an abstract
- path using @ref LV2_Files_Path_Support::abstract_path to do so).
-
- This function may be called from any non-realtime context. The caller
- is responsible for freeing the returned value.
- */
- char* (*new_file_path)(LV2_Files_Host_Data host_data,
- const char* relative_path);
-
-} LV2_Files_New_File_Support;
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* LV2_FILES_H */
diff --git a/lv2/ns/ext/files/files.ttl b/lv2/ns/ext/files/files.ttl
deleted file mode 100644
index fc32c9a..0000000
--- a/lv2/ns/ext/files/files.ttl
+++ /dev/null
@@ -1,115 +0,0 @@
-# LV2 Files Extension
-# Copyright 2010-2011 David Robillard <d@drobilla.net>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
-@prefix doap: <http://usefulinc.com/ns/doap#> .
-@prefix files: <http://lv2plug.in/ns/ext/files#> .
-@prefix foaf: <http://xmlns.com/foaf/0.1/> .
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
-
-<http://lv2plug.in/ns/ext/files>
- a lv2:Specification ;
- doap:name "LV2 Files" ;
- doap:shortdesc "A standard for referring to files in plugin state." ;
- doap:license <http://opensource.org/licenses/isc> ;
- doap:release [
- doap:revision "0.2" ;
- doap:created "2011-04-05"
- ] ;
- doap:maintainer [
- a foaf:Person ;
- foaf:name "David Robillard" ;
- foaf:homepage <http://drobilla.net/> ;
- rdfs:seeAlso <http://drobilla.net/drobilla.rdf>
- ] ;
- lv2:documentation """
-<p>This extension provides a mechanism for plugins to portably refer to files
-in persistent plugin state (using the <a
-href="http://lv2plug.in/ns/ext/state">LV2 State</a> extension), and create
-instance-local files in host-defined locations (e.g. for recording).</p>
-
-<p>The motivating idea behind this extension is that all details of file
-management MUST be handled by the host since different hosts may have very
-different requirements. Plugins MUST NOT make any assumption about file system
-locations beyond what is explicitly guaranteed by this extension.</p>
-
-<p>This extension defines two features: files:newFileSupport allows plugins to
-create new files within an instance-specific namespace at any time (except in
-realtime contexts); while files:pathSupport allows plugins to refer to file
-paths in plugin state in a way transparent to the host.</p>
-
-<p>To create a new file, the plugin MUST request a path from the host using
-LV2_Files_New_File_Support::new_file_path(). Thus, the host may choose an
-appropriate location for the file (e.g. a writable path on the appropriate disk
-volume or a path within a session directory) using information not available to
-the plugin.</p>
-
-<p>To store a path in persistent state, the plugin MUST map it to an
-<q>abstract path</q> using LV2_Files_Path_Support::abstract_path(). To use a
-path loaded from persistent state, the plugin MUST map the (abstract) path to
-an absolute path using LV2_Files_Path_Support::absolute_path(). Thus, the host
-can manage all paths used in a session and support exporting sessions to a
-portable self-contained format for archival or distribution.</p> """ .
-
-files:pathSupport a lv2:Feature ;
- rdfs:label "Support for storing file paths in plugin state" ;
- lv2:documentation """
-<p>This feature allows plugins to refer to pre-existing or newly created files
-in persistent plugin state in a portable way. To support this feature a host
-MUST pass a LV2_Files_Path_Support structure to the plugin's
-LV2_Descriptor::instantiate() method as an LV2_Feature with LV2_Feature::URI =
-LV2_FILES_PATH_SUPPORT_URI and LV2_Feature::data pointed to an instance of
-LV2_Files_Path_Support.</p>
-
-<p>Plugins MUST use the functions provided by this feature to handle
-<em>all</em> paths saved to, or restored from, persistent plugin state;
-otherwise broken and/or non-portable state will silently be created resulting
-in a broken user experience.</p>
-""" .
-
-files:newFileSupport a lv2:Feature ;
- rdfs:label "Support for creating new files" ;
- lv2:documentation """
-<p>This feature allows plugins to create new files local to that plugin
-instance. To support this feature a host MUST pass a
-LV2_Files_New_File_Support structure to the plugin's
-LV2_Descriptor::instantiate() method as an LV2_Feature with LV2_Feature::URI =
-LV2_FILES_NEW_FILE_SUPPORT_URI and LV2_Feature::data pointed to an instance of
-LV2_Files_New_File_Support.</p>
-""" .
-
-files:AbstractPath a rdfs:Class ;
- rdfs:label "File Path" ;
- lv2:documentation """
-<p>An abstract path to a file in persistent plugin state.</p>
-
-<p>The format of a files:AbstractPath is a C string escaped or otherwise
-restricted in a system-specific manner. This URI,
-<q>http://lv2plug.in/ns/ext/files#AbstractPath</q>, mapped to an integer,
-should be used as the <code>type</code> parameter to a
-LV2_Persist_Store_Function; and will likewise be returned by the corresponding
-call to a LV2_Persist_Retrieve_Function.</p>
-
-<p>Abstract paths reside in a namespace specific to a plugin instance.
-Typical hosts are expected to implement this by giving each plugin instance its
-own state directory.</p>
-
-<p>When storing and retrieving an abstract path, the plugin MUST NOT assume the
-same path will be restored. However, the restored path will refer to a file
-with equivalent contents to the original.</p>
-""" .
diff --git a/lv2/ns/ext/files/manifest.ttl b/lv2/ns/ext/files/manifest.ttl
deleted file mode 100644
index d0233c4..0000000
--- a/lv2/ns/ext/files/manifest.ttl
+++ /dev/null
@@ -1,9 +0,0 @@
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-
-<http://lv2plug.in/ns/ext/files>
- a lv2:Specification ;
- lv2:minorVersion 0 ;
- lv2:microVersion 2 ;
- rdfs:seeAlso <files.ttl> .
-
diff --git a/lv2/ns/ext/files/waf b/lv2/ns/ext/files/waf
deleted file mode 120000
index b955110..0000000
--- a/lv2/ns/ext/files/waf
+++ /dev/null
@@ -1 +0,0 @@
-../../../../waf \ No newline at end of file
diff --git a/lv2/ns/ext/files/wscript b/lv2/ns/ext/files/wscript
deleted file mode 120000
index ec20a77..0000000
--- a/lv2/ns/ext/files/wscript
+++ /dev/null
@@ -1 +0,0 @@
-../../../../ext.wscript \ No newline at end of file
diff --git a/lv2/ns/ext/state/manifest.ttl b/lv2/ns/ext/state/manifest.ttl
index 7894a22..4c589bd 100644
--- a/lv2/ns/ext/state/manifest.ttl
+++ b/lv2/ns/ext/state/manifest.ttl
@@ -1,9 +1,8 @@
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/state>
a lv2:Specification ;
lv2:minorVersion 0 ;
- lv2:microVersion 2 ;
+ lv2:microVersion 4 ;
rdfs:seeAlso <state.ttl> .
-
diff --git a/lv2/ns/ext/state/state.h b/lv2/ns/ext/state/state.h
index 4e1c28a..3d39012 100644
--- a/lv2/ns/ext/state/state.h
+++ b/lv2/ns/ext/state/state.h
@@ -36,8 +36,13 @@ extern "C" {
#define LV2_STATE_URI "http://lv2plug.in/ns/ext/state"
#define LV2_STATE_INTERFACE_URI LV2_STATE_URI "#Interface"
+#define LV2_STATE_PATH_URI LV2_STATE_URI "#Path"
+#define LV2_STATE_MAP_PATH_URI LV2_STATE_URI "#pathMap"
+#define LV2_STATE_MAKE_PATH_URI LV2_STATE_URI "#newPath"
typedef void* LV2_State_Handle;
+typedef void* LV2_State_Map_Path_Handle;
+typedef void* LV2_State_Make_Path_Handle;
/**
Flags describing value characteristics.
@@ -251,6 +256,97 @@ typedef struct _LV2_State_Interface {
} LV2_State_Interface;
+/**
+ Feature data for state:pathMap (LV2_STATE_MAP_PATH_URI).
+*/
+typedef struct {
+
+ /**
+ Opaque host data.
+ */
+ LV2_State_Map_Path_Handle handle;
+
+ /**
+ Map an absolute path to an abstract path for use in plugin state.
+ @param handle MUST be the @a handle member of this struct.
+ @param absolute_path The absolute path of a file.
+ @return An abstract path suitable for use in plugin state.
+
+ The plugin MUST use this function to map any paths that will be stored
+ in files in plugin state. The returned value is an abstract path which
+ MAY not be an actual file system path; @ref absolute_path MUST be used
+ to map it to an actual path in order to use the file.
+
+ Hosts MAY map paths in any way (e.g. by creating symbolic links within
+ the plugin's state directory or storing a list of referenced files
+ elsewhere). Plugins MUST NOT make any assumptions about abstract paths
+ except that they can be mapped back to an absolute path using @ref
+ absolute_path.
+
+ This function may only be called within the context of
+ LV2_State_Interface.save() or LV2_State_Interface.restore(). The caller
+ is responsible for freeing the returned value.
+ */
+ char* (*abstract_path)(LV2_State_Map_Path_Handle handle,
+ const char* absolute_path);
+
+ /**
+ Map an abstract path from plugin state to an absolute path.
+ @param handle MUST be the @a handle member of this struct.
+ @param abstract_path An abstract path (e.g. a path from plugin state).
+ @return An absolute file system path.
+
+ Since abstract paths are not necessarily actual file paths (or at least
+ not necessarily absolute paths), this function MUST be used in order to
+ actually open or otherwise use the file referred to by an abstract path.
+
+ This function may only be called within the context of
+ LV2_State_Interface.save() or LV2_State_Interface.restore(). The caller
+ is responsible for freeing the returned value.
+ */
+ char* (*absolute_path)(LV2_State_Map_Path_Handle handle,
+ const char* abstract_path);
+
+} LV2_State_Map_Path;
+
+/**
+ Feature data for state:makePath (@ref LV2_STATE_MAKE_PATH_URI).
+*/
+typedef struct {
+
+ /**
+ Opaque host data.
+ */
+ LV2_State_Make_Path_Handle handle;
+
+ /**
+ Return a path the plugin may use to create a new file.
+ @param handle MUST be the @a handle member of this struct.
+ @param path The path of the new file relative to a namespace unique
+ to this plugin instance.
+ @return The absolute path to use for the new file.
+
+ This function can be used by plugins to create files and directories,
+ either at state saving time (if this feature is passed to
+ LV2_State_Interface.save()) or any time (if this feature is passed to
+ LV2_Descriptor.instantiate()).
+
+ The host must do whatever is necessary for the plugin to be able to
+ create a file at the returned path (e.g. using fopen), including
+ creating any leading directories.
+
+ If this function is passed to LV2_Descriptor.instantiate(), it may be
+ called from any non-realtime context. If it is passed to
+ LV2_State_Interface.save(), it may only be called within the dynamic
+ scope of that function call.
+
+ The caller is responsible for freeing the returned value with free().
+ */
+ char* (*path)(LV2_State_Make_Path_Handle handle,
+ const char* path);
+
+} LV2_State_Make_Path;
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/lv2/ns/ext/state/state.ttl b/lv2/ns/ext/state/state.ttl
index 9367a53..b029aa6 100644
--- a/lv2/ns/ext/state/state.ttl
+++ b/lv2/ns/ext/state/state.ttl
@@ -22,58 +22,72 @@
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/state>
- a lv2:Specification ;
- doap:name "LV2 State" ;
- doap:shortdesc "An interface for LV2 plugins to save and restore state." ;
- doap:license <http://opensource.org/licenses/isc> ;
- doap:release [
- doap:revision "0.2" ;
- doap:created "2011-11-14"
- ] ;
- doap:developer [
- a foaf:Person ;
- 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>
- ] ;
- lv2:documentation """
+ a lv2:Specification ;
+ doap:name "LV2 State" ;
+ doap:shortdesc "An interface for LV2 plugins to save and restore state." ;
+ doap:license <http://opensource.org/licenses/isc> ;
+ doap:release [
+ doap:revision "0.4" ;
+ doap:created "2011-11-22"
+ ] ;
+ doap:developer [
+ a foaf:Person ;
+ 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>
+ ] ;
+ lv2:documentation """
<p>This extension provides a mechanism for plugins to save and restore state
across instances, allowing hosts to save, restore, clone, or take a snapshot of
a plugin instance's state at any point in time. The intention is for a plugin
instance's state to be <em>completely</em> described by port values (as with all
LV2 plugins) and a simple dictionary.</p>
-<p>The <q>state</q> described by this extension is conceptually a single
-key/value dictionary, where keys are URIDs and values are type-tagged blobs of
-any type. The plugin provides an LV2_State_Interface for working with this
-state. To save or restore, the host calls LV2_State_Interface::save() or
+<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>. The plugin provides an LV2_State_Interface for working with
+this state. 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 key/value pair. The host is free to implement saving and restoring in
-any way; the actual mechanism is completely abstract from the plugin's
-perspective.</p>
-
-<p>Because state is a simple dictionary, hosts and plugins can work with it
-easily from many languages and protocols. Keys are URIDs for performance
-reasons as well as RDF compatibility, which makes it simple to serialise state
-in many formats (e.g. any RDF syntax, JSON, XML, key/value databases such as
-BDB, etc.). In particular, state can be elegantly described in a plugin's
-Turtle description, which is useful for e.g. presets or default state.
-Specific keys may be described in Turtle on the fly or in extensions,
-allowing plugins to use common well-defined keys.</p>
-
-<p>This extension defines a conceptual model of state and a mechanism for
-saving and restoring it, but no interface for manipulating it dynamically.
-While no such mechanism is defined here, dynamic control of plugins SHOULD be
-achieved by generic manipulations of the same conceptual state dictionary used
-by this extension (e.g. <code>plugin->set(key, value)</code>). Accordingly,
-plugins SHOULD use meaningful and well-defined keys wherever possible.</p>
-
-<p>In pseudo code, a typical use case in a plugin is:</p>
+single property. The host is free to implement property storage and retrieval
+in any way.</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:instanceState is
+ provided for this purpose).</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, making state meaningful between
+ implementations and enabling dynamic state control.</li>
+</ul>
+
+<p>This extension defines a conceptual state model and a mechanism for saving
+and restoring it, but no interface for manipulating it dynamically. However,
+any such mechanism SHOULD work with the same properties used in this extension
+to avoid complicating the concept of plugin state. For example, an extension
+to the example plugin below could be to support a message like
+<code>set(eg:greeting, "Bonjour")</code>, which could be sent by the host, UIs,
+or other plugins (via the host) to dynamically control the plugin's state.
+Accordingly, plugins SHOULD use meaningful and well-defined keys wherever
+possible.</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#"
@@ -92,7 +106,6 @@ void my_save(LV2_Handle instance,
void* handle,
uint32_t flags,
const LV2_Feature *const * features)
-
{
MyPlugin* plugin = (MyPlugin*)instance;
const char* greeting = plugin->state.greeting;
@@ -109,18 +122,15 @@ void my_restore(LV2_Handle instance,
LV2_State_Retrieve_Function retrieve,
void* handle,
uint32_t flags,
- const LV2_Feature *const * features)
+ const LV2_Feature *const * features)
{
MyPlugin* plugin = (MyPlugin*)instance;
size_t size;
uint32_t type;
uint32_t flags;
- const char* greeting = retrieve(handle,
- plugin->uris.eg_greeting,
- &amp;size,
- &amp;type,
- &amp;flags);
+ const char* greeting = retrieve(
+ handle, plugin->uris.eg_greeting, &amp;size, &amp;type, &amp;flags);
if (greeting) {
free(plugin->state->greeting);
@@ -139,7 +149,8 @@ const void* my_extension_data(const char* uri)
}
</pre>
-<p>Similarly, a typical use case in a host is:</p>
+<h3>Host Code Example</h3>
+
<pre class="c-code">
int store_callback(void* handle,
uint32_t key,
@@ -171,12 +182,33 @@ Map get_plugin_state(LV2_Handle instance)
return state_map;
}
</pre>
+
+<h3>Referring to Existing Files</h3>
+
+<p>This extension deliberately avoids imposing any file formats or file system
+dependencies on implementations. However, some plugins need to refer to
+files in their state. This is done by storing the file's path as a property
+just like any other value.</p>
+
+<p>Plugins MUST use the type state:Path for all paths in their state. This
+allows hosts to know about all such files, which is necessary for making
+session export and archival possible (among other things). Hosts are free to
+map paths in any way, and plugins MUST NOT assume the restored path will be
+identical to the saved path.</p>
+
+<h3>Creating New Files or Directories</h3>
+
+<p>New implementations and basic plugins are strongly encouraged to simply
+store all state as properties using this API. However, some plugins have an
+existing file or directory formats for state. Plugins MAY create new files
+or directories by using the state:newPath feature, if it is provided by the
+host.</p>
""" .
state:Interface
- a rdfs:Class ;
- rdfs:subClassOf lv2:ExtensionData ;
- lv2:documentation """
+ a rdfs:Class ;
+ rdfs:subClassOf lv2:ExtensionData ;
+ lv2:documentation """
<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
@@ -194,23 +226,23 @@ LV2_STATE_INTERFACE_URI.</p>
""" .
state:InstanceState
- a rdfs:Class ;
- rdfs:label "Plugin Instance State" ;
- rdfs:comment """
-This class is used to express a plugin instance's state in RDF. The key/value
+ 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:InstanceState as the subject (see state:instanceState 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.
+required to support the LV2 State extension.</p>
""" .
state:instanceState
- a rdf:Property ;
- rdfs:range state:InstanceState ;
- lv2:documentation """
+ a rdf:Property ;
+ rdfs:range state:InstanceState ;
+ lv2:documentation """
<p>Predicate to relate a plugin instance to an InstanceState. 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
@@ -219,13 +251,94 @@ sense to do so, e.g.:</p>
<pre class="turtle-code">
@prefix eg: &lt;http://example.org/&gt; .
-&lt;plugininstance&gt; state:instanceState [
- eg:somekey "some value" ;
- eg:someotherkey "some other value" ;
- eg:favourite-number 2
-] .
+&lt;plugininstance&gt;
+ state:instanceState [
+ eg:somekey "some value" ;
+ eg:someotherkey "some other value" ;
+ 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 the LV2 State extension.</p>
+required to support this extension.</p>
+""" .
+
+state:mapPath
+ a lv2:Feature ;
+ rdfs:label "Support for storing paths in files" ;
+ lv2:documentation """
+<p>This feature allows plugins to store paths inside files stored in its state
+(if, for example, a plugin saves to an existing file format which contains
+paths). 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
+plugin's LV2_State_Interface methods.</p>
+
+<p>The plugin MUST use the provided functions to map <em>all</em> paths stored
+in any files it creates (using state:makePath) and stores in the state. This
+is necessary to enable host to handle file system references correctly, e.g.
+for session export or archival.</p>
+
+<p>For example, a plugin may write a path to a state file like so:</p>
+
+<pre class="c-code">
+void write_path(LV2_State_Map_Path* map_path, FILE* myfile, const char* path)
+{
+ char* abstract_path = map_path->abstract_path(map_path->handle, path);
+ fprintf(myfile, "%s", abstract_path);
+ free(abstract_path);
+}
+</pre>
+
+<p>Then, later reload the path like so:</p>
+
+<pre class="c-code">
+char* read_path(LV2_State_Map_Path* map_path, FILE* myfile)
+{
+ /* Obviously this is not production quality code! */
+ char abstract_path[1024];
+ fscanf(myfile, "%s", abstract_path);
+ return map_path->absolute_path(map_path->handle, abstract_path);
+}
+</pre>
+""" .
+
+state:makePath
+ a lv2:Feature ;
+ rdfs:label "Support for creating new files and directories" ;
+ lv2:documentation """
+
+<p>This feature allows plugins to create new files 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 plugin. The host may provide
+this feature during state saving only or at any time, by passing the feature to
+LV2_State_Interface::save() or LV2_Descriptor::instantiate(), respectively.</p>
+
+<p>For example, a plugin may create a file in a subdirectory like so:</p>
+
+<pre class="c-code">
+void save_myfile(LV2_State_Make_Path* make_path)
+{
+ char* path = make_path->path(make_path->handle, "foo/bar/myfile.txt");
+ FILE* myfile = fopen(path, 'w');
+ fprintf(myfile, "Hello");
+ fclose(myfile);
+}
+</pre>
+""" .
+
+state:Path
+ a rdfs:Class ;
+ rdfs:label "Path" ;
+ lv2:documentation """
+<p>A path to a file or directory.</p>
+
+<p>The format of a state:Path is a C string escaped or otherwise restricted in
+a system-specific manner. This URI (LV2_STATE_PATH_URI), mapped to an integer,
+MUST be used as the <code>type</code> parameter for any files passed to the
+LV2_State_Store_Function; and will likewise be returned by the corresponding
+call to the LV2_State_Retrieve_Function.</p>
+
+<p>When storing and retrieving a path, the plugin MUST NOT assume the same path
+will be restored. However, the restored path will refer to a file with
+equivalent contents to the original.</p>
""" .