From 17c6df0bc3043c57d2c02c58284ec4794f656b3c Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 30 Mar 2012 23:27:26 +0000 Subject: Fix screwy invalid ExtensionData definitions as classes (now matches how Feature is used). Add status return codes to state methods for error handling. --- lv2/lv2plug.in/ns/ext/state/manifest.ttl | 2 +- lv2/lv2plug.in/ns/ext/state/state.h | 34 +++---- lv2/lv2plug.in/ns/ext/state/state.ttl | 151 ++++++++++++++++++------------- lv2/lv2plug.in/ns/ext/worker/worker.h | 4 +- lv2/lv2plug.in/ns/ext/worker/worker.ttl | 9 +- 5 files changed, 111 insertions(+), 89 deletions(-) (limited to 'lv2/lv2plug.in/ns') diff --git a/lv2/lv2plug.in/ns/ext/state/manifest.ttl b/lv2/lv2plug.in/ns/ext/state/manifest.ttl index 84d1af0..94de219 100644 --- a/lv2/lv2plug.in/ns/ext/state/manifest.ttl +++ b/lv2/lv2plug.in/ns/ext/state/manifest.ttl @@ -4,5 +4,5 @@ a lv2:Specification ; lv2:minorVersion 0 ; - lv2:microVersion 6 ; + lv2:microVersion 8 ; rdfs:seeAlso . diff --git a/lv2/lv2plug.in/ns/ext/state/state.h b/lv2/lv2plug.in/ns/ext/state/state.h index 2f5af22..44e19cb 100644 --- a/lv2/lv2plug.in/ns/ext/state/state.h +++ b/lv2/lv2plug.in/ns/ext/state/state.h @@ -31,8 +31,8 @@ #define LV2_STATE_URI "http://lv2plug.in/ns/ext/state" #define LV2_STATE_PREFIX LV2_STATE_URI "#" -#define LV2_STATE__Interface LV2_STATE_PREFIX "Interface" #define LV2_STATE__State LV2_STATE_PREFIX "State" +#define LV2_STATE__interface LV2_STATE_PREFIX "interface" #define LV2_STATE__makePath LV2_STATE_PREFIX "makePath" #define LV2_STATE__mapPath LV2_STATE_PREFIX "mapPath" #define LV2_STATE__state LV2_STATE_PREFIX "state" @@ -95,10 +95,12 @@ typedef enum { /** A status code for state functions. */ typedef enum { - LV2_STATE_SUCCESS = 0, /**< Completed successfully. */ - LV2_STATE_ERR_UNKNOWN = 1, /**< Unknown error. */ - LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */ - LV2_STATE_ERR_BAD_FLAGS = 3 /**< Failed due to unsupported flags. */ + LV2_STATE_SUCCESS = 0, /**< Completed successfully. */ + LV2_STATE_ERR_UNKNOWN = 1, /**< Unknown error. */ + LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */ + LV2_STATE_ERR_BAD_FLAGS = 3, /**< Failed due to unsupported flags. */ + LV2_STATE_ERR_NO_FEATURE = 4, /**< Failed due to missing features. */ + LV2_STATE_ERR_NO_PROPERTY = 5 /**< Failed due to missing property. */ } LV2_State_Status; /** @@ -171,7 +173,7 @@ typedef const void* (*LV2_State_Retrieve_Function)( LV2 Plugin State Interface. When the plugin's extension_data is called with argument - LV2_STATE__Interface, the plugin MUST return an LV2_State_Interface + LV2_STATE__interface, the plugin MUST return an LV2_State_Interface structure, which remains valid for the lifetime of the plugin. The host can use the contained function pointers to save and restore the @@ -223,11 +225,11 @@ typedef struct _LV2_State_Interface { 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. */ - void (*save)(LV2_Handle instance, - LV2_State_Store_Function store, - LV2_State_Handle handle, - uint32_t flags, - const LV2_Feature *const * features); + LV2_State_Status (*save)(LV2_Handle instance, + LV2_State_Store_Function store, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature *const * features); /** Restore plugin state using a host-provided @p retrieve callback. @@ -254,11 +256,11 @@ typedef struct _LV2_State_Interface { LV2. This means it MUST NOT be called concurrently with any other function on the same plugin instance. */ - void (*restore)(LV2_Handle instance, - LV2_State_Retrieve_Function retrieve, - LV2_State_Handle handle, - uint32_t flags, - const LV2_Feature *const * features); + LV2_State_Status (*restore)(LV2_Handle instance, + LV2_State_Retrieve_Function retrieve, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature *const * features); } LV2_State_Interface; diff --git a/lv2/lv2plug.in/ns/ext/state/state.ttl b/lv2/lv2plug.in/ns/ext/state/state.ttl index 6bc884b..2d12d08 100644 --- a/lv2/lv2plug.in/ns/ext/state/state.ttl +++ b/lv2/lv2plug.in/ns/ext/state/state.ttl @@ -30,8 +30,8 @@ doap:shortdesc "An interface for LV2 plugins to save and restore state." ; doap:license ; doap:release [ - doap:revision "0.6" ; - doap:created "2012-03-03" ; + doap:revision "0.8" ; + doap:created "2012-03-30" ; dcs:blame ] ; doap:developer , @@ -68,7 +68,7 @@ key:value pair is called a property.

dynamic dictionary data structure available. -

To implement state, the plugin provides a state:Interface to the host. To +

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 @@ -85,15 +85,15 @@ is simply a C string.

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 state:mapPath for details. Plugins MUST use -the type atom:Path for all -paths in their state.

+paths, see state:mapPath for details. Plugins MUST use the type atom:Path for all paths in their +state.

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 state:makePath which allocates paths for plugin-created -files. Plugins MUST NOT create files in any other locations.

+necessary. To make this possible, the host can provide the feature +state:makePath which allocates paths for plugin-created files. Plugins MUST +NOT create files in any other locations.

Plugin Code Example

@@ -104,20 +104,24 @@ files. Plugins MUST NOT create files in any other locations.

*/ #define NS_MY "http://example.org/myplugin/schema#" -LV2_Handle my_instantiate(...) +#define DEFAULT_GREETING "Hello" + +LV2_Handle +my_instantiate(...) { MyPlugin* plugin = ...; 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 + plugin->state.greeting = strdup(DEFAULT_GREETING); return plugin; } -void my_save(LV2_Handle instance, - LV2_State_Store_Function store, - LV2_State_Handle handle, - uint32_t flags, - const LV2_Feature *const * features) +LV2_State_Status +my_save(LV2_Handle instance, + LV2_State_Store_Function store, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature *const * features) { MyPlugin* plugin = (MyPlugin*)instance; const char* greeting = plugin->state.greeting; @@ -128,13 +132,16 @@ void my_save(LV2_Handle instance, strlen(greeting) + 1, // Careful! Need space for terminator plugin->uris.atom_String, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + return LV2_STATUS_SUCCESS; } -void my_restore(LV2_Handle instance, - LV2_State_Retrieve_Function retrieve, - LV2_State_Handle handle, - uint32_t flags, - const LV2_Feature *const * features) +LV2_State_Status +my_restore(LV2_Handle instance, + LV2_State_Retrieve_Function retrieve, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature *const * features) { MyPlugin* plugin = (MyPlugin*)instance; @@ -148,14 +155,17 @@ void my_restore(LV2_Handle instance, free(plugin->state->greeting); plugin->state->greeting = strdup(greeting); } else { - plugin->state->greeting = strdup("Hello"); + plugin->state->greeting = strdup(DEFAULT_GREETING); } + + return LV2_STATUS_SUCCESS; } -const void* my_extension_data(const char* uri) +const void* +my_extension_data(const char* uri) { static const LV2_State_Interface state_iface = { my_save, my_restore }; - if (!strcmp(uri, LV2_STATE_INTERFACE_URI)) { + if (!strcmp(uri, LV2_STATE__interface)) { return &state_iface; } } @@ -164,12 +174,13 @@ const void* my_extension_data(const char* uri)

Host Code Example

-int store_callback(LV2_State_Handle handle,
-                   uint32_t         key,
-                   const void*      value,
-                   size_t           size,
-                   uint32_t         type,
-                   uint32_t         flags)
+LV2_State_Status
+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.
@@ -183,9 +194,10 @@ int store_callback(LV2_State_Handle handle,
     }
 }
 
-Map get_plugin_state(LV2_Handle instance)
+Map
+get_plugin_state(LV2_Handle instance)
 {
-    LV2_State* state = instance.extension_data(LV2_STATE__Interface);
+    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,
@@ -209,26 +221,36 @@ instance, at least well enough that saving and restoring will yield an
 plugin instance.
 
 
-

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 for free, since rather than having to define a -set of commands and a set of properties for storing their effects, -only the properties need to be defined.

- -

This property principle is summed up in the phrase: Don't -stop; set playing to false.

+

The Property Principle

+ +

The main benefit of this meaningful state model is that it can double as a +plugin control/query mechanism. For plugins that require more advanced control +than simple control ports, instead of defining a set of commands, define +properties whose values can be set appropriately. This provides both a way to +control and save that state for free, since there is no need to define +commands and a set of properties for storing their effects. In +particular, this is a good way for UIs to achieve more advanced control of +plugins.

+ +

This property principle is summed up in the phrase: +Don't stop; set playing to false.

+ +

This extension does not define a dynamic mechanism for state access and +manipulation. The LV2 Patch +extension defines a generic set of messages which can be used to access or +manipulate properties, and the LV2 +Atom extension defines a port type and data container capable of +transmitting those messages.

""" . -state:Interface - a rdfs:Class ; - rdfs:subClassOf lv2:ExtensionData ; +state:interface + a lv2:ExtensionData ; lv2:documentation """

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 URI -LV2_STATE__Interface.

+LV2_STATE__interface.

The plugin data file should describe this like so:

@@ -236,7 +258,7 @@ LV2_STATE__Interface.

<plugin> a lv2:Plugin ; - lv2:extensionData state:Interface . + lv2:extensionData state:interface .
""" . @@ -245,9 +267,9 @@ state:State rdfs:label "Plugin Instance State" ; lv2:documentation """

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).

+described. 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).

""" . state:state @@ -255,13 +277,13 @@ state:state rdfs:label "State" ; rdfs:range state:State ; lv2:documentation """ -

The state of this plugin instance, or similar resource. This property may -be used anywhere a state needs to be described, for example:

+

The state of this instance. This property may be used anywhere a state +needs to be described, for example:

 @prefix eg: <http://example.org/> .
 
-<plugininstance>
+<plugin-instance>
     state:state [
         eg:somekey "some value" ;
         eg:someotherkey "some other value" ;
@@ -313,24 +335,23 @@ state:makePath
 	lv2:documentation """
 

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__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_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 feature MUST NOT be used beyond the scope of that call.

-

The plugin is guaranteed a hierarchial namespace unique to that plugin +

The plugin is guaranteed a hierarchical namespace unique to that plugin instance, and may expect the returned path to have the requested path as a suffix. There is one such namespace, even if the feature is passed to -both LV2_Descriptor::instantiate() and -LV2_State_Interface::save(). Beyond this, the plugin MUST NOT make any -assumptions about the returned paths.

+both LV2_Descriptor::instantiate() and LV2_State_Interface::save(). +Beyond this, the plugin MUST NOT make any assumptions about the returned +paths.

-

Like any other paths, the plugin MUST map these paths using state:mapPath before storing them in state. The plugin -MUST NOT assume these paths will be available across a save/restore otherwise, -i.e. only mapped paths saved to state are persistent, any other created paths -are temporary.

+

Like any other paths, the plugin MUST map these paths using state:mapPath +before storing them in state. The plugin MUST NOT assume these paths will be +available across a save/restore otherwise, i.e. only mapped paths saved to +state are persistent, any other created paths are temporary.

For example, a plugin may create a file in a subdirectory like so:

@@ -339,7 +360,7 @@ char* 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"); + fprintf(myfile, "I am some data"); fclose(myfile); return path; } diff --git a/lv2/lv2plug.in/ns/ext/worker/worker.h b/lv2/lv2plug.in/ns/ext/worker/worker.h index b0d87ec..74ac45b 100644 --- a/lv2/lv2plug.in/ns/ext/worker/worker.h +++ b/lv2/lv2plug.in/ns/ext/worker/worker.h @@ -29,7 +29,7 @@ #define LV2_WORKER_URI "http://lv2plug.in/ns/ext/worker" #define LV2_WORKER_PREFIX LV2_WORKER_URI "#" -#define LV2_WORKER__Interface LV2_WORKER_PREFIX "Interface" +#define LV2_WORKER__interface LV2_WORKER_PREFIX "interface" #define LV2_WORKER__schedule LV2_WORKER_PREFIX "schedule" /** @@ -60,7 +60,7 @@ typedef LV2_Worker_Status (*LV2_Worker_Respond_Function)( This is the interface provided by the plugin to implement a worker method. The plugin's extension_data() method should return an LV2_Worker_Interface - when called with LV2_WORKER__Interface as its argument. + when called with LV2_WORKER__interface as its argument. */ typedef struct _LV2_Worker_Interface { /** diff --git a/lv2/lv2plug.in/ns/ext/worker/worker.ttl b/lv2/lv2plug.in/ns/ext/worker/worker.ttl index 517aabb..09f7249 100644 --- a/lv2/lv2plug.in/ns/ext/worker/worker.ttl +++ b/lv2/lv2plug.in/ns/ext/worker/worker.ttl @@ -49,14 +49,13 @@ offline rendering, or in real-time with non-real-time work taking place in a separate thread.

""" . -work:Interface - a rdfs:Class ; - rdfs:subClassOf lv2:ExtensionData ; +work:interface + a lv2:ExtensionData ; lv2:documentation """

The interface provided by the plugin to implement a worker. To implement this extension, the plugin must return a valid LV2_Worker_Interface from LV2_Descriptor::extension_data() when it is called with URI -LV2_WORKER__Interface.

+LV2_WORKER__interface.

The plugin data file should describe this like so:

@@ -64,7 +63,7 @@ LV2_WORKER__Interface.

<plugin> a lv2:Plugin ; - lv2:extensionData work:Interface . + lv2:extensionData work:interface .
""" . -- cgit v1.2.1