parameter via messages system. Input control ones work. Output ones not yet
This commit is contained in:
parent
ecded4fd65
commit
2d66e616cd
@ -62,7 +62,7 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS := -O3 -Wall -Wpedantic -Wextra
|
||||
CFLAGS := -O0 -g -Wall -Wpedantic -Wextra
|
||||
CFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) $(shell pkg-config --cflags lv2) -fPIC $(CFLAGS_EXTRA) $(CFLAGS)
|
||||
|
||||
LDFLAGS :=
|
||||
|
@ -36,6 +36,11 @@
|
||||
{{?(it.product.state && it.product.state.dspCustom)}}
|
||||
lv2:extensionData state:interface ;
|
||||
{{?}}
|
||||
|
||||
{{~it.tibia.lv2.parameters:p:i}}
|
||||
patch:writable plugin:{{=p.id}};
|
||||
{{~}}
|
||||
|
||||
lv2:port [
|
||||
{{~it.tibia.lv2.ports :p:i}}
|
||||
{{?p.isBypass}}
|
||||
@ -68,6 +73,22 @@
|
||||
lv2:portProperty lv2:connectionOptional ;
|
||||
lv2:portProperty lv2:integer ;
|
||||
lv2:portProperty lv2:reportsLatency ;
|
||||
{{??p.isInputParameterMessage}}
|
||||
a lv2:InputPort ,
|
||||
atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports patch:Message ;
|
||||
lv2:designation lv2:control ;
|
||||
lv2:symbol "InputParameterMessage" ;
|
||||
lv2:name "InputParameterMessage" ;
|
||||
{{??p.isOutputParameterMessage}}
|
||||
a lv2:OutputPort ,
|
||||
atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports patch:Message ;
|
||||
lv2:designation lv2:control ;
|
||||
lv2:symbol "OutputParameterMessage" ;
|
||||
lv2:name "OutputParameterMessage" ;
|
||||
{{??}}
|
||||
a {{?p.type == "control"}}lv2:ControlPort{{??p.type == "midi"}}atom:AtomPort{{??}}{{?p.cv}}lv2:CVPort{{??}}lv2:AudioPort{{?}}{{?}} ,
|
||||
{{?p.direction == "input"}}lv2:InputPort{{??}}lv2:OutputPort{{?}} ;
|
||||
@ -129,6 +150,20 @@
|
||||
{{?}}
|
||||
{{~}}
|
||||
|
||||
{{~it.tibia.lv2.parameters:p:i}}
|
||||
|
||||
plugin:{{=p.id}}
|
||||
a lv2:Parameter ;
|
||||
rdfs:label "{{=p.name}}" ;
|
||||
rdfs:range {{?p.toggled}}atom:Bool{{??p.integer}}atom:Int{{??}}atom:Float{{?}} ;
|
||||
{{?p.unit && p.unit in it.tibia.lv2.units}}
|
||||
units:unit {{=it.tibia.lv2.ttlURI(it.tibia.lv2.units[p.unit])}} ;
|
||||
{{?}}
|
||||
lv2:minimum {{=p.minimum.toExponential()}} ;
|
||||
lv2:maximum {{=p.maximum.toExponential()}} ;
|
||||
lv2:default {{=p.defaultValue.toExponential()}} .
|
||||
{{~}}
|
||||
|
||||
{{?it.product.ui}}
|
||||
plugin:ui
|
||||
a ui:@UI_TYPE@ ;
|
||||
|
@ -37,12 +37,56 @@ static uint32_t midi_in_index[DATA_PRODUCT_MIDI_INPUTS_N] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
|
||||
|
||||
# define DATA_PARAM_BYPASS 1
|
||||
# define DATA_PARAM_TOGGLED (1<<1)
|
||||
# define DATA_PARAM_INTEGER (1<<2)
|
||||
|
||||
{{?it.lv2.use_parameters}}
|
||||
#define DATA_PRODUCT_USE_PARAMETERS 1
|
||||
|
||||
{{?it.tibia.lv2.ports.find(p => p.isInputParameterMessage)}}
|
||||
#define DATA_PRODUCT_IPM {{=it.tibia.lv2.ports.indexOf(it.tibia.lv2.ports.find(p => p.isInputParameterMessage))}}
|
||||
{{?}}
|
||||
{{?it.tibia.lv2.ports.find(p => p.isOutputParameterMessage)}}
|
||||
#define DATA_PRODUCT_OPM {{=it.tibia.lv2.ports.indexOf(it.tibia.lv2.ports.find(p => p.isOutputParameterMessage))}}
|
||||
{{?}}
|
||||
|
||||
|
||||
#if DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
|
||||
|
||||
static struct {
|
||||
uint32_t index;
|
||||
float min;
|
||||
float max;
|
||||
float def;
|
||||
uint32_t flags;
|
||||
const char *id;
|
||||
} param_data[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N] = {
|
||||
{{~it.tibia.lv2.parameters :p}}
|
||||
{
|
||||
/* .index = */ {{=p.paramIndex}},
|
||||
/* .min = */ {{=p.minimum.toExponential()}}f,
|
||||
/* .max = */ {{=p.maximum.toExponential()}}f,
|
||||
/* .def = */ {{=p.defaultValue.toExponential()}}f,
|
||||
/* .flags = */ {{?p.isBypass}}DATA_PARAM_BYPASS{{??p.isLatency}}DATA_PARAM_INTEGER{{??}}0{{?p.toggled}} | DATA_PARAM_TOGGLED{{?}}{{?p.integer}} | DATA_PARAM_INTEGER{{?}}{{?}},
|
||||
/* .id = */ DATA_LV2_URI"#{{=p.id}}"
|
||||
},
|
||||
{{~}}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
|
||||
static uint32_t param_out_index[DATA_PRODUCT_CONTROL_OUTPUTS_N] = {
|
||||
{{~it.tibia.lv2.parameters.filter(x => x.direction == "output") :p}}{{=p.paramIndex}}, {{~}}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
{{??}}
|
||||
|
||||
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
|
||||
|
||||
static struct {
|
||||
uint32_t index;
|
||||
float min;
|
||||
@ -69,6 +113,8 @@ static uint32_t param_out_index[DATA_PRODUCT_CONTROL_OUTPUTS_N] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
{{?}}
|
||||
|
||||
{{?it.product.ui}}
|
||||
#define DATA_UI
|
||||
#define DATA_LV2_UI_URI "{{=it.tibia.CGetUTF8StringLiteral(it.tibia.lv2.expandURI(it.lv2.uri + '#ui'))}}"
|
||||
|
@ -49,6 +49,10 @@
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
# include <lv2/state/state.h>
|
||||
#endif
|
||||
#if DATA_PRODUCT_USE_PARAMETERS
|
||||
# include "lv2/lv2plug.in/ns/ext/patch/patch.h"
|
||||
# include <lv2/lv2plug.in/ns/ext/atom/forge.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -131,6 +135,25 @@ typedef struct {
|
||||
LV2_State_Store_Function state_store;
|
||||
LV2_State_Handle state_handle;
|
||||
#endif
|
||||
#if DATA_PRODUCT_USE_PARAMETERS
|
||||
LV2_URID uri_atom_Blank;
|
||||
LV2_URID uri_atom_Object;
|
||||
LV2_URID uri_atom_URID;
|
||||
LV2_URID uri_atom_Float;
|
||||
LV2_URID uri_atom_Bool;
|
||||
LV2_URID uri_patch_Set;
|
||||
LV2_URID uri_patch_Get;
|
||||
LV2_URID uri_patch_property;
|
||||
LV2_URID uri_patch_value;
|
||||
LV2_URID uri_parameters[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N]; // TODO: Fix 0 params case
|
||||
# if DATA_PRODUCT_IPM
|
||||
const LV2_Atom_Sequence *controlIn;
|
||||
# endif
|
||||
# if DATA_PRODUCT_OPM
|
||||
const LV2_Atom_Sequence *controlOut;
|
||||
LV2_Atom_Forge forge;
|
||||
# endif
|
||||
#endif
|
||||
} plugin_instance;
|
||||
|
||||
static const char * get_bundle_path_cb(void *handle) {
|
||||
@ -203,6 +226,20 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
|
||||
instance->uri_state_data = instance->map->map(instance->map->handle, DATA_LV2_URI "#state_data");
|
||||
}
|
||||
#endif
|
||||
#if DATA_PRODUCT_USE_PARAMETERS
|
||||
instance->uri_atom_Blank = instance->map->map (instance->map->handle, LV2_ATOM__Blank);
|
||||
instance->uri_atom_Object = instance->map->map (instance->map->handle, LV2_ATOM__Object);
|
||||
instance->uri_atom_URID = instance->map->map (instance->map->handle, LV2_ATOM__URID);
|
||||
instance->uri_atom_Float = instance->map->map (instance->map->handle, LV2_ATOM__Float);
|
||||
instance->uri_atom_Bool = instance->map->map (instance->map->handle, LV2_ATOM__Bool);
|
||||
instance->uri_patch_Set = instance->map->map (instance->map->handle, LV2_PATCH__Set);
|
||||
instance->uri_patch_Get = instance->map->map (instance->map->handle, LV2_PATCH__Get);
|
||||
instance->uri_patch_property = instance->map->map (instance->map->handle, LV2_PATCH__property);
|
||||
instance->uri_patch_value = instance->map->map (instance->map->handle, LV2_PATCH__value);
|
||||
for (int i = 0; i < DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N; i++) {
|
||||
instance->uri_parameters[i] = instance->map->map (instance->map->handle, param_data[i].id);
|
||||
}
|
||||
#endif
|
||||
|
||||
plugin_callbacks cbs = {
|
||||
/* .handle = */ (void *)instance,
|
||||
@ -260,6 +297,7 @@ err_instance:
|
||||
}
|
||||
|
||||
static void connect_port(LV2_Handle instance, uint32_t port, void * data_location) {
|
||||
const uint32_t port0 = port;
|
||||
plugin_instance * i = (plugin_instance *)instance;
|
||||
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
|
||||
if (port < DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N) {
|
||||
@ -289,8 +327,24 @@ static void connect_port(LV2_Handle instance, uint32_t port, void * data_locatio
|
||||
}
|
||||
port -= DATA_PRODUCT_MIDI_OUTPUTS_N;
|
||||
#endif
|
||||
#if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0
|
||||
|
||||
#if DATA_PRODUCT_USE_PARAMETERS
|
||||
# if DATA_PRODUCT_IPM
|
||||
if (port0 == DATA_PRODUCT_IPM) {
|
||||
i->controlIn = (const LV2_Atom_Sequence*) data_location;
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
# if DATA_PRODUCT_OPM
|
||||
if (port0 == DATA_PRODUCT_OPM) {
|
||||
i->controlOut = (const LV2_Atom_Sequence*) data_location;
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
#else
|
||||
# if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0
|
||||
i->c[port] = data_location;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -314,6 +368,60 @@ static void activate(LV2_Handle instance) {
|
||||
plugin_reset(&i->p);
|
||||
}
|
||||
|
||||
static inline int getParamIndexByURI(plugin_instance *instance, LV2_URID uri) {
|
||||
for (int i = 0; i < DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N; i++)
|
||||
if (instance->uri_parameters[i] == uri)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline bool parse_property (plugin_instance *self, const LV2_Atom_Object *obj) {
|
||||
const LV2_Atom* property = NULL;
|
||||
lv2_atom_object_get (obj, self->uri_patch_property, &property, 0);
|
||||
|
||||
/* Get property URI.
|
||||
*
|
||||
* Note: Real world code would only call
|
||||
* if (!property || property->type != self->uris.atom_URID) { return; }
|
||||
* However this is example and test code, so..
|
||||
*/
|
||||
if (!property) {
|
||||
lv2_log_error (&self->logger, "PropEx.lv2: Malformed set message has no body.\n");
|
||||
return false;
|
||||
}
|
||||
if (property->type != self->uri_atom_URID) {
|
||||
lv2_log_error (&self->logger, "PropEx.lv2: Malformed set message has non-URID property.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get value */
|
||||
const LV2_Atom* val = NULL;
|
||||
lv2_atom_object_get (obj, self->uri_patch_value, &val, 0);
|
||||
if (!val) {
|
||||
lv2_log_error (&self->logger, "PropEx.lv2: Malformed set message has no value.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* NOTE: This code errs towards the verbose side
|
||||
* - the type is usually implicit and does not need to be checked.
|
||||
* - consolidate code e.g.
|
||||
*
|
||||
* const LV2_URID urid = (LV2_Atom_URID*)property)->body
|
||||
* PropExURIs* urid = self->uris;
|
||||
*
|
||||
* - no need to lv2_log warnings or errors
|
||||
*/
|
||||
|
||||
int index = getParamIndexByURI(self, ((LV2_Atom_URID*)property)->body);
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
float f = *((float*)(val + 1));
|
||||
lv2_log_note (&self->logger, "PropEx.lv2: Received %d = %f\n", index, f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void run(LV2_Handle instance, uint32_t sample_count) {
|
||||
plugin_instance * i = (plugin_instance *)instance;
|
||||
|
||||
@ -391,6 +499,52 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DATA_PRODUCT_USE_PARAMETERS
|
||||
|
||||
// Initially, self->out_port contains a Chunk with size set to capacity
|
||||
// Set up forge to write directly to output port
|
||||
const uint32_t out_capacity = i->controlOut->atom.size;
|
||||
lv2_atom_forge_set_buffer(&i->forge, (uint8_t*)i->controlOut, out_capacity);
|
||||
|
||||
if (!i->controlIn) {
|
||||
lv2_log_error (&i->logger, "controlIn is not.\n");
|
||||
}
|
||||
else if (i->map) {
|
||||
LV2_ATOM_SEQUENCE_FOREACH (i->controlIn, ev) {
|
||||
if (ev->body.type != i->uri_atom_Object) {
|
||||
continue;
|
||||
}
|
||||
const LV2_Atom_Object *obj = (LV2_Atom_Object*)&ev->body;
|
||||
const LV2_Atom_URID *property = NULL;
|
||||
if (obj->body.otype == i->uri_patch_Set) {
|
||||
parse_property (i, obj);
|
||||
}
|
||||
else if (obj->body.otype == i->uri_patch_Get) {
|
||||
|
||||
lv2_atom_object_get(obj, i->uri_patch_property, (const LV2_Atom**)&property, 0);
|
||||
|
||||
if (!property) {
|
||||
lv2_log_error (&i->logger, "PropEx.lv2: Malformed set message has no body.\n");
|
||||
continue;
|
||||
}
|
||||
if (property->atom.type != i->uri_atom_URID) {
|
||||
lv2_log_error(&i->logger, "Get property is not a URID\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
const LV2_URID key = property->body;
|
||||
lv2_log_note(&i->logger, "AAAAAAAAAAAAAAAAA key: %d, getParamIndexByURI: %d \n", key, getParamIndexByURI(i, key));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
|
||||
const float ** x = i->x;
|
||||
#else
|
||||
|
@ -37,7 +37,8 @@ module.exports = function (data, api, outputCommon, outputData) {
|
||||
{ id: "state", uri: "http://lv2plug.in/ns/extensions/state#" },
|
||||
{ id: "ui", uri: "http://lv2plug.in/ns/extensions/ui#" },
|
||||
{ id: "units", uri: "http://lv2plug.in/ns/extensions/units#" },
|
||||
{ id: "urid", uri: "http://lv2plug.in/ns/ext/urid#" }
|
||||
{ id: "urid", uri: "http://lv2plug.in/ns/ext/urid#" },
|
||||
{ id: "patch", uri: "http://lv2plug.in/ns/ext/patch#"}
|
||||
],
|
||||
units: {
|
||||
"bar": "@units:bar",
|
||||
@ -115,16 +116,38 @@ module.exports = function (data, api, outputCommon, outputData) {
|
||||
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, audioPorts);
|
||||
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, midiPorts);
|
||||
|
||||
var ports = [];
|
||||
for (var i = 0; i < data.product.parameters.length; i++) {
|
||||
var p = data.product.parameters[i];
|
||||
var e = Object.create(p);
|
||||
e.type = "control";
|
||||
e.paramIndex = i;
|
||||
ports.push(e);
|
||||
if (data.lv2.use_parameters) {
|
||||
let parameters = [];
|
||||
for (var i = 0; i < data.product.parameters.length; i++) {
|
||||
let e = Object.create(data.product.parameters[i]);
|
||||
e.paramIndex = i;
|
||||
parameters.push(e);
|
||||
}
|
||||
data.tibia.lv2.parameters = parameters;
|
||||
|
||||
if (data.product.parameters.find(p => p.direction == "input")) {
|
||||
data.tibia.lv2.ports.push({
|
||||
isInputParameterMessage: true
|
||||
});
|
||||
}
|
||||
if (data.product.parameters.find(p => p.direction == "output")) {
|
||||
data.tibia.lv2.ports.push({
|
||||
isOutputParameterMessage: true
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
var ports = [];
|
||||
for (var i = 0; i < data.product.parameters.length; i++) {
|
||||
var p = data.product.parameters[i];
|
||||
var e = Object.create(p);
|
||||
e.type = "control";
|
||||
e.paramIndex = i;
|
||||
ports.push(e);
|
||||
}
|
||||
ports.sort((a, b) => a.direction != b.direction ? (a.direction == "input" ? -1 : 1) : 0);
|
||||
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, ports);
|
||||
}
|
||||
ports.sort((a, b) => a.direction != b.direction ? (a.direction == "input" ? -1 : 1) : 0);
|
||||
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, ports);
|
||||
}
|
||||
|
||||
api.generateFileFromTemplateFile(`data${sep}manifest.ttl.in`, `data${sep}manifest.ttl.in`, data);
|
||||
|
@ -6,6 +6,8 @@
|
||||
"uri": "@example:tibia_test",
|
||||
"project": "@example:project",
|
||||
"types": [ "@lv2:AmplifierPlugin" ],
|
||||
"version": "1.0"
|
||||
"version": "1.0",
|
||||
|
||||
"use_parameters": true
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user