From 37d75582c03caa016e5372f7df57760cee694fa1 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 28 Mar 2011 23:51:21 +0000 Subject: Update persist extension. --- ext/persist.lv2/manifest.ttl | 2 + ext/persist.lv2/persist.h | 67 +++++++++++++++++++-------------- ext/persist.lv2/persist.ttl | 90 ++++++++++++++++++++++++++++++-------------- 3 files changed, 102 insertions(+), 57 deletions(-) (limited to 'ext') diff --git a/ext/persist.lv2/manifest.ttl b/ext/persist.lv2/manifest.ttl index f1a7ecd..2b1ac9e 100644 --- a/ext/persist.lv2/manifest.ttl +++ b/ext/persist.lv2/manifest.ttl @@ -3,5 +3,7 @@ a lv2:Specification ; + lv2:minorVersion 0 ; + lv2:microVersion 1 ; rdfs:seeAlso . diff --git a/ext/persist.lv2/persist.h b/ext/persist.lv2/persist.h index b9ac8e5..5ed6c45 100644 --- a/ext/persist.lv2/persist.h +++ b/ext/persist.lv2/persist.h @@ -25,6 +25,9 @@ #ifndef LV2_PERSIST_H #define LV2_PERSIST_H +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -34,24 +37,32 @@ extern "C" { /** A host-provided function to store a value under a given key. @param callback_data Must be the callback_data passed to LV2_Persist.save(). - @param key The URI key (predicate) under which the value is to be stored. + @param key The key (predicate) to store @a value under (URI mapped integer). @param value Pointer to the value (object) to be stored. @param size The size of the data at @a value in bytes. - @param type The type of @a value, as a URI mapped to an integer. + @param type The type of @a value (URI mapped integer). + @param pod True iff @a value is POD. + @return 0 on success, otherwise a non-zero error code. The host passes a callback of this type to LV2_Persist.save(). This callback is called repeatedly by the plugin within LV2_Persist.save() to store all the key/value records that describe its current state. - Unless @a type is 0, @a value is guaranteed to be POD (i.e. a region - of memory that does not contain pointers and can safely be copied - and persisted indefinitely with a simple memcpy). If @a type is 0, - then @a value is a reference, as defined by the LV2 Atom extension - . Hosts are not required to support - references: a plugin MUST NOT expect a host to persist references unless - the host supports the feature . - Plugins SHOULD express their state entirely with POD values. + If @a pod is true, @a value is guaranteed to be architecture-independent POD + (i.e. a region of memory that does not contain pointers or references to + non-persistent resources and can safely be copied and stored with a simple + memcpy). Note that this definition of POD is more strict than exclusively + in-memory definitions since the value MUST be architecture independent; + e.g. endianness must be considered (so basic numeric types are typically NOT + POD). Hosts MAY fail to store the value, particularly if it is + non-POD. Plugins MUST gracefully handle this situation, even though state + may not be fully restored. Hosts SHOULD support any POD value, even if the + host does not know anything about its type. Plugins SHOULD express their + state entirely with POD values whenever possible, and use non-POD values + only where necessary. Plugins SHOULD use common RDF types and/or types from + the Atom extension whenever possible since + hosts are likely to already contain the necessary implementation. Note that @a size MUST be > 0, and @a value MUST point to a valid region of memory @a size bytes long (this is required to make restore unambiguous). @@ -59,19 +70,21 @@ extern "C" { The plugin MUST NOT attempt to use this function outside of the LV2_Persist.restore() context. */ -typedef void (*LV2_Persist_Store_Function)( - void* callback_data, - const char* key, - const void* value, - size_t size, - uint32_t type); +typedef int (*LV2_Persist_Store_Function)( + void* callback_data, + const uint32_t key, + const void* value, + size_t size, + uint32_t type, + bool pod); /** A host-provided function to retrieve a value under a given key. @param callback_data Must be the callback_data passed to LV2_Persist.restore(). - @param key The URI key (predicate) under which a value has been stored. + @param key The key (predicate) of the value to retrieve (URI mapped integer). @param size (Output) If non-NULL, set to the size of the restored value. @param type (Output) If non-NULL, set to the type of the restored value. + @param pod (Output) If non-NULL, set to true iff @a value is POD. @return A pointer to the restored value (object), or NULL if no value has been stored under @a key. @@ -83,13 +96,15 @@ typedef void (*LV2_Persist_Store_Function)( The plugin MUST NOT attempt to use this function, or any value returned from it, outside of the LV2_Persist.restore() context. Returned values MAY be - copied for later use if necessary. + copied for later use if necessary, assuming the plugin knows how to + correctly do so (e.g. the value is POD, or the plugin understands the type). */ typedef const void* (*LV2_Persist_Retrieve_Function)( - void* callback_data, - const char* key, - size_t* size, - uint32_t* type); + void* callback_data, + uint32_t key, + size_t* size, + uint32_t* type, + bool* pod); /** Persist Extension Data. @@ -110,7 +125,7 @@ typedef const void* (*LV2_Persist_Retrieve_Function)( Stored data is only guaranteed to be compatible between instances of plugins with the same URI (i.e. if a change to a plugin would cause a fatal error when restoring state saved by a previous version of that plugin, the plugin - URI must change just as it must when a plugin's ports change). Plugin + URI MUST change just as it must when ports change incompatibly). Plugin authors should consider this possibility, and always store sensible data with meaningful types to avoid such compatibility issues in the future. */ @@ -149,11 +164,7 @@ typedef struct _LV2_Persist { Plugins that dynamically modify state while running, however, must take care to do so in such a way that a concurrent call to save() will save a consistent representation of plugin state for a - single instant in time. The simplest way to do this is to modify a - copy of the state map and atomically swap a pointer to the entire - map once the changes are complete (for very large state maps, - a purely functional map data structure may be more appropriate - since a complete copy is not necessary). + single instant in time. */ void (*save)(LV2_Handle instance, LV2_Persist_Store_Function store, diff --git a/ext/persist.lv2/persist.ttl b/ext/persist.lv2/persist.ttl index aa6a92c..ab524a0 100644 --- a/ext/persist.lv2/persist.ttl +++ b/ext/persist.lv2/persist.ttl @@ -31,6 +31,10 @@ a lv2:Specification ; doap:name "LV2 Persist" ; + doap:release [ + doap:revision "0.1" ; + doap:created "2011-03-25" + ] ; doap:developer [ a foaf:Person ; foaf:name "Leonard Ritter" ; @@ -84,8 +88,21 @@ or conventional state keys likely to be useful to several implementations.

In pseudo code, a typical use case in a plugin is:

+#define NS_EG   "http://example.org/"
+#define NS_ATOM "http://lv2plug.in/ns/ext/atom#"
+
 static const char* const KEY_GREETING = "http://example.org/greeting";
 
+LV2_Handle my_instantiate(...)
+{
+    MyPlugin*            plugin = ...;
+    LV2_URI_Map_Feature* map    = ...;
+    plugin->uri_greeting_key = map->uri_to_id(..., NULL, NS_EG "greeting-key");
+    plugin->uri_atom_String  = map->uri_to_id(..., NULL, NS_ATOM "String");
+    plugin->state->greeting  = strdup("Hello");
+    return plugin;
+}
+
 void my_save(LV2_Handle                 instance,
              LV2_Persist_Store_Function store,
              void*                      callback_data)
@@ -93,9 +110,12 @@ void my_save(LV2_Handle                 instance,
     MyPlugin*   plugin   = (MyPlugin*)instance;
     const char* greeting = plugin->state->greeting;
     
-    store(callback_data, KEY_GREETING,
-        greeting, strlen(greeting) + 1,
-        lv2_uri_map("http://lv2plug.in/ns/ext/atom#String"));
+    store(callback_data,
+          plugin->uri_greeting_key,
+          greeting,
+          strlen(greeting) + 1,
+          plugin->uri_atom_String,
+          true);
 }
 
 void my_restore(LV2_Handle                    instance,
@@ -106,26 +126,38 @@ void my_restore(LV2_Handle                    instance,
 
     size_t      size;
     uint32_t    type;
-    const char* greeting = retrieve(callback_data, KEY_GREETING, &size, &type);
-
-    if (greeting)
-        plugin->state->greeting = greeting;
-    else
-        plugin->state->greeting = "Hello";
- 
+    bool        pod;
+    const char* greeting = retrieve(callback_data,
+                                    plugin->uri_greeting_key,
+                                    &size,
+                                    &type,
+                                    &pod);
+
+    if (greeting) {
+        free(plugin->state->greeting);
+        plugin->state->greeting = strdup(greeting);
+    } else {
+        plugin->state->greeting = strdup("Hello");
+    }
 }
 

Similarly, a typical use case in a host is:

-void store_callback(void*       callback_data,
-                    const char* key,
-                    const void* value,
-                    size_t      size,
-                    uint32_t    type)
+int store_callback(void*       callback_data,
+                   uint32_t    key,
+                   const void* value,
+                   size_t      size,
+                   uint32_t    type,
+                   bool        pod)
 {
-    Map* state_map = (Map*)callback_data;
-    state_map->insert(key, Value(value, size, type));
+    if (pod) {
+        Map* state_map = (Map*)callback_data;
+        state_map->insert(key, Value(value, size, type, pod));
+        return 0;
+    } else {
+        return 1; /* Non-POD events are unsupported. */
+    }
 }
 
 Map get_plugin_state(LV2_Handle instance)
@@ -142,14 +174,14 @@ persist: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
+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 persist:InstanceState as the subject (see persist: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 Persist extension.
+with a persist:InstanceState as the subject (see persist: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 Persist extension.
 """ .
 
 
@@ -157,18 +189,18 @@ persist:instanceState
     a rdf:Property ;
     rdfs:range persist:InstanceState ;
     lv2:documentation """
-Predicate to relate a plugin instance to an InstanceState.  This may be used
+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 any RDF class for plugin instance.  This predicate may be used
-wherever it makes sense to do so, e.g.:
+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.:
 
 @prefix eg: <http://example.org/> .
 
 <plugininstance> persist:instanceState [
     eg:somekey "some value" ;
     eg:someotherkey "some other value" ;
-    eg:favouritenumber 2 .
+    eg:favourite-number 2 .
 ]
 
Note that this property is provided because it may be useful for hosts, -- cgit v1.2.1