diff options
author | David Robillard <d@drobilla.net> | 2011-03-29 08:56:22 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2011-03-29 08:56:22 +0000 |
commit | 9bfc43bf66caed425bde10af7cd030aa0699e351 (patch) | |
tree | f717d44cdb430f12a1bec829ad5418648e192986 | |
parent | 02d551d18390a5a59cb3977ade0811cf5822d32b (diff) |
Update for latest LV2 persist extension.
git-svn-id: svn://localhost/ardour2/branches/3.0@9225 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | libs/ardour/ardour/lv2_plugin.h | 6 | ||||
-rw-r--r-- | libs/ardour/lv2_plugin.cc | 40 | ||||
-rw-r--r-- | libs/ardour/lv2ext/lv2_persist.h | 166 | ||||
-rw-r--r-- | libs/ardour/rdff.c | 13 | ||||
-rw-r--r-- | libs/ardour/rdff.h | 12 |
5 files changed, 147 insertions, 90 deletions
diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h index 71d9bfa624..fff58464b3 100644 --- a/libs/ardour/ardour/lv2_plugin.h +++ b/libs/ardour/ardour/lv2_plugin.h @@ -150,17 +150,19 @@ class LV2Plugin : public ARDOUR::Plugin static uint32_t _midi_event_type; static int lv2_persist_store_callback (void* callback_data, + uint32_t subject, uint32_t key, const void* value, size_t size, uint32_t type, - bool pod); + uint32_t flags); static const void* lv2_persist_retrieve_callback (void* callback_data, + uint32_t subject, uint32_t key, size_t* size, uint32_t* type, - bool* pod); + uint32_t* flags); void init (LV2World& world, SLV2Plugin plugin, framecnt_t rate); void run (pframes_t nsamples); diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 992a909b99..bbcf6d8c38 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -297,15 +297,15 @@ LV2Plugin::nth_parameter(uint32_t n, bool& ok) const } struct PersistValue { - inline PersistValue(uint32_t k, const void* v, size_t s, uint32_t t, bool p) - : key(k), value(v), size(s), type(t), pod(p) + inline PersistValue(uint32_t k, const void* v, size_t s, uint32_t t, uint32_t f) + : key(k), value(v), size(s), type(t), flags(f) {} const uint32_t key; const void* value; const size_t size; const uint32_t type; - const bool pod; + const bool flags; }; struct PersistState { @@ -329,11 +329,12 @@ struct PersistState { return 0; } - int add_value(uint32_t file_key, + int add_value(uint32_t file_subject, + uint32_t file_key, const void* value, size_t size, uint32_t file_type, - bool pod) { + uint32_t flags) { const uint32_t key = file_id_to_runtime_id(file_key); const uint32_t type = file_id_to_runtime_id(file_type); if (!key || !type) { @@ -349,7 +350,7 @@ struct PersistState { memcpy(value_copy, value, size); // FIXME: leak values.insert( make_pair(key, - PersistValue(key, value_copy, size, type, pod))); + PersistValue(key, value_copy, size, type, flags))); return 0; } } @@ -361,11 +362,12 @@ struct PersistState { int LV2Plugin::lv2_persist_store_callback(void* callback_data, + uint32_t subject, uint32_t key, const void* value, size_t size, uint32_t type, - bool pod) + uint32_t flags) { DEBUG_TRACE(DEBUG::LV2, string_compose("persist store %1\n", _uri_map.id_to_uri(NULL, key))); @@ -373,19 +375,17 @@ LV2Plugin::lv2_persist_store_callback(void* callback_data, PersistState* state = (PersistState*)callback_data; state->add_uri(key, _uri_map.id_to_uri(NULL, key)); state->add_uri(type, _uri_map.id_to_uri(NULL, type)); - return state->add_value(key, value, size, type, pod); + return state->add_value(subject, key, value, size, type, flags); } const void* LV2Plugin::lv2_persist_retrieve_callback(void* callback_data, + uint32_t subject, uint32_t key, size_t* size, uint32_t* type, - bool* pod) + uint32_t* flags) { - DEBUG_TRACE(DEBUG::LV2, string_compose("persist retrieve %1\n", - _uri_map.id_to_uri(NULL, key))); - PersistState* state = (PersistState*)callback_data; PersistState::Values::const_iterator i = state->values.find(key); if (i == state->values.end()) { @@ -395,7 +395,10 @@ LV2Plugin::lv2_persist_retrieve_callback(void* callback_data, } *size = i->second.size; *type = i->second.type; - *pod = true; // FIXME + *flags = LV2_PERSIST_IS_POD | LV2_PERSIST_IS_PORTABLE; // FIXME + DEBUG_TRACE(DEBUG::LV2, string_compose( + "persist retrieve %1 = %s (size: %u, type: %u)\n", + _uri_map.id_to_uri(NULL, key), i->second.value, *size, *type)); return i->second.value; } @@ -418,7 +421,7 @@ LV2Plugin::add_state(XMLNode* root) const if (_supports_persist) { // Create state directory for this plugin instance - const std::string state_filename = _id.to_s() + ".lv2f"; + const std::string state_filename = _id.to_s() + ".rdff"; const std::string state_path = Glib::build_filename( _session.plugins_dir(), state_filename); @@ -641,20 +644,21 @@ LV2Plugin::set_state(const XMLNode& node, int version) RDFFChunk* chunk = (RDFFChunk*)malloc(sizeof(RDFFChunk)); chunk->size = 0; while (!rdff_read_chunk(file, &chunk)) { - if (!strncmp(chunk->type, "URID", 4)) { + if (rdff_chunk_is_uri(chunk)) { RDFFURIChunk* body = (RDFFURIChunk*)chunk->data; printf("READ URI %u: %s\n", body->id, body->uri); state.add_uri(body->id, body->uri); - } else if (!strncmp(chunk->type, "KVAL", 4)) { + } else if (rdff_chunk_is_triple(chunk)) { RDFFTripleChunk* body = (RDFFTripleChunk*)chunk->data; printf("READ VAL %u = %s (size: %u type: %u)\n", body->predicate, body->object, body->object_size, body->object_type); - state.add_value(body->predicate, + state.add_value(body->subject, + body->predicate, body->object, body->object_size, body->object_type, - true); + LV2_PERSIST_IS_POD | LV2_PERSIST_IS_PORTABLE); } } free(chunk); diff --git a/libs/ardour/lv2ext/lv2_persist.h b/libs/ardour/lv2ext/lv2_persist.h index 5ed6c45030..f225709b65 100644 --- a/libs/ardour/lv2ext/lv2_persist.h +++ b/libs/ardour/lv2ext/lv2_persist.h @@ -35,34 +35,59 @@ extern "C" { #define LV2_PERSIST_URI "http://lv2plug.in/ns/ext/persist" /** - A host-provided function to store a value under a given key. + Flags describing value characteristics. + + These flags are used along with the value's type URI to determine how to + (de-)serialise the value data, or whether it is even possible to do so. +*/ +typedef enum { + + /** + Plain Old Data. + + Values with this flag contain no references to non-persistent or + non-global resources (e.g. pointers, handles, local paths, etc.). It is + safe to copy POD values with a simple memcpy and store them for use at + any time in the future on a machine with a compatible architecture + (e.g. the same endianness and alignment). + + Implementations MUST NOT attempt to copy or serialise a non-POD value if + they do not understand its type (and thus know how to correctly do so). + */ + LV2_PERSIST_IS_POD = 1, + + /** + Portable (architecture independent) data. + + Values with this flag are in a format that is usable on any + architecture, i.e. if the value is saved on one machine it can safely be + restored on another machine regardless of endianness, alignment, etc. + */ + LV2_PERSIST_IS_PORTABLE = 1 << 1 + +} LV2_Persist_Flags; + +/** + A host-provided function to store a property. @param callback_data Must be the callback_data passed to LV2_Persist.save(). + @param subject The subject of this property (URI), or 0 for plugin instance. @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 (URI mapped integer). - @param pod True iff @a value is POD. + @param type The type of @a value (URI). + @param flags LV2_Persist_Flags for @a value. @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. - - 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 <http://lv2plug.in/ns/ext/atom> whenever possible since - hosts are likely to already contain the necessary implementation. + 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 statements that describe its current state. + + The host MAY fail to store a statement if the type is not understood and is + not LV2_PERSIST_IS_POD and/or LV2_PERSIST_IS_PORTABLE. Implementations are + encouraged to use POD and portable values (e.g. string literals) wherever + possible, and use common types (e.g. types from + http://lv2plug.in/ns/ext/atom) regardless, 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). @@ -71,56 +96,60 @@ extern "C" { LV2_Persist.restore() context. */ typedef int (*LV2_Persist_Store_Function)( - void* callback_data, - const uint32_t key, - const void* value, - size_t size, - uint32_t type, - bool pod); + void* callback_data, + uint32_t subject, + uint32_t key, + const void* value, + size_t size, + uint32_t type, + uint32_t flags); /** - A host-provided function to retrieve a value under a given key. + A host-provided function to retrieve a property. @param callback_data Must be the callback_data passed to LV2_Persist.restore(). - @param key The key (predicate) of the value to retrieve (URI mapped integer). + @param subject The subject of the property (URI), or 0 for plugin instance. + @param key The key (predicate) of the property to retrieve (URI). @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. + @param flags (Output) If non-NULL, set to the LV2_Persist_Flags for + the returned value. @return A pointer to the restored value (object), or NULL if no value has been stored under @a key. A callback of this type is passed by the host to LV2_Persist.restore(). This callback is called repeatedly by the plugin within LV2_Persist.restore() to - retrieve the values of any keys it requires to restore its state. + retrieve any properties it requires to restore its state. The returned value MUST remain valid until LV2_Persist.restore() returns. 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, assuming the plugin knows how to - correctly do so (e.g. the value is POD, or the plugin understands the type). + copied for later use if necessary, assuming the plugin knows how to do so + correctly (e.g. the value is POD, or the plugin understands the type). */ typedef const void* (*LV2_Persist_Retrieve_Function)( void* callback_data, + uint32_t subject, uint32_t key, size_t* size, uint32_t* type, - bool* pod); + uint32_t* flags); /** Persist Extension Data. When the plugin's extension_data is called with argument LV2_PERSIST_URI, - the plugin MUST return an LV2_Persist structure, which remains valid for - the lifetime of the plugin. + the plugin MUST return an LV2_Persist structure, which remains valid for the + lifetime of the plugin. The host can use the contained function pointers to save and restore the state of a plugin instance at any time (provided the threading restrictions for the given function are met). - The typical use case is to save the plugin's state when a project is - saved, and to restore the state when a project has been loaded. Other - uses are possible (e.g. cloning plugin instances or taking a snapshot - of plugin state). + The typical use case is to save the plugin's state when a project is saved, + and to restore the state when a project has been loaded. Other uses are + possible (e.g. cloning plugin instances or taking a snapshot of plugin + state). 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 @@ -141,30 +170,27 @@ typedef struct _LV2_Persist { this MUST be passed as its callback_data parameter. The plugin is expected to store everything necessary to completely - restore its state later (possibly much later, in a different - process, on a completely different machine, etc.) - - The @a callback_data pointer and @a store function MUST NOT be - used beyond the scope of save(). - - This function has its own special threading class: it may not be - called concurrently with any "Instantiation" function, but it - may be called concurrently with functions in any other class, - unless the definition of that class prohibits it (e.g. it may - not be called concurrently with a "Discovery" function, but it - may be called concurrently with an "Audio" function. The plugin - is responsible for any locking or lock-free techniques necessary - to make this possible. - - Note that in the simple case where state is only modified by - restore(), there are no synchronization issues since save() is - never called concurrently with restore() (though run() may read - it during a save). - - 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. + restore its state later (possibly much later, in a different process, on + a completely different machine, etc.) + + The @a callback_data pointer and @a store function MUST NOT be used + beyond the scope of save(). + + This function has its own special threading class: it may not be called + concurrently with any "Instantiation" function, but it may be called + concurrently with functions in any other class, unless the definition of + that class prohibits it (e.g. it may not be called concurrently with a + "Discovery" function, but it may be called concurrently with an "Audio" + function. The plugin is responsible for any locking or lock-free + techniques necessary to make this possible. + + Note that in the simple case where state is only modified by restore(), + there are no synchronization issues since save() is never called + concurrently with restore() (though run() may read it during a save). + + 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. */ void (*save)(LV2_Handle instance, LV2_Persist_Store_Function store, @@ -182,15 +208,15 @@ typedef struct _LV2_Persist { The plugin MAY assume a restored value was set by a previous call to LV2_Persist.save() by a plugin with the same URI. - The plugin MUST gracefully fall back to a default value when a - value can not be retrieved. This allows the host to reset the - plugin state with an empty map. + The plugin MUST gracefully fall back to a default value when a value can + not be retrieved. This allows the host to reset the plugin state with an + empty map. The @a callback_data pointer and @a store function MUST NOT be used beyond the scope of restore(). - This function is in the "Instantiation" threading class as defined - by LV2. This means it MUST NOT be called concurrently with any other + This function is in the "Instantiation" threading class as defined by + LV2. This means it MUST NOT be called concurrently with any other function on the same plugin instance. */ void (*restore)(LV2_Handle instance, diff --git a/libs/ardour/rdff.c b/libs/ardour/rdff.c index eacdc0b0af..42a77c7230 100644 --- a/libs/ardour/rdff.c +++ b/libs/ardour/rdff.c @@ -163,6 +163,19 @@ rdff_read_chunk(RDFF file, return RDFF_STATUS_OK; } +bool +rdff_chunk_is_uri(RDFFChunk* chunk) + +{ + return !strncmp(chunk->type, CHUNK_URID, CHUNK_ID_LEN); +} + +bool +rdff_chunk_is_triple(RDFFChunk* chunk) +{ + return !strncmp(chunk->type, CHUNK_TRIP, CHUNK_ID_LEN); +} + void rdff_close(RDFF file) { diff --git a/libs/ardour/rdff.h b/libs/ardour/rdff.h index 3d52553a4b..c66a938a30 100644 --- a/libs/ardour/rdff.h +++ b/libs/ardour/rdff.h @@ -122,6 +122,18 @@ rdff_read_chunk(RDFF file, RDFFChunk** buf); /** + Return true iff @a chunk is a URI chunk. +*/ +bool +rdff_chunk_is_uri(RDFFChunk* chunk); + +/** + Return true iff @a chunk is a Triple chunk. +*/ +bool +rdff_chunk_is_triple(RDFFChunk* chunk); + +/** Close @a file. After this call, @a file is invalid. */ |