mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-06 05:35:47 +01:00
Update for latest LV2 persist extension.
git-svn-id: svn://localhost/ardour2/branches/3.0@9225 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
02d551d183
commit
9bfc43bf66
5 changed files with 142 additions and 85 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
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.
|
||||
|
||||
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 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.)
|
||||
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().
|
||||
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.
|
||||
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).
|
||||
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.
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -121,6 +121,18 @@ RDFFStatus
|
|||
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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue