#include <suil/suil.h>
#endif
+// Compatibility for lv2-1.0.0
+#ifndef LV2_ATOM_CONTENTS_CONST
+#define LV2_ATOM_CONTENTS_CONST(type, atom) \
+ ((const void*)((const uint8_t*)(atom) + sizeof(type)))
+#endif
+#ifndef LV2_ATOM_BODY_CONST
+#define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom)
+#endif
+
/** The number of MIDI buffers that will fit in a UI/worker comm buffer.
This needs to be roughly the number of cycles the UI will get around to
actually processing the traffic. Lower values are flakier but save memory.
using namespace ARDOUR;
using namespace PBD;
-URIMap LV2Plugin::_uri_map;
-
-LV2Plugin::URIDs LV2Plugin::urids = {
- _uri_map.uri_to_id(LV2_ATOM__Chunk),
- _uri_map.uri_to_id(LV2_ATOM__Path),
- _uri_map.uri_to_id(LV2_ATOM__Sequence),
- _uri_map.uri_to_id(LV2_ATOM__eventTransfer),
- _uri_map.uri_to_id(LV2_ATOM__URID),
- _uri_map.uri_to_id(LV2_ATOM__Blank),
- _uri_map.uri_to_id(LV2_LOG__Error),
- _uri_map.uri_to_id(LV2_LOG__Note),
- _uri_map.uri_to_id(LV2_LOG__Warning),
- _uri_map.uri_to_id(LV2_MIDI__MidiEvent),
- _uri_map.uri_to_id(LV2_TIME__Position),
- _uri_map.uri_to_id(LV2_TIME__bar),
- _uri_map.uri_to_id(LV2_TIME__barBeat),
- _uri_map.uri_to_id(LV2_TIME__beatUnit),
- _uri_map.uri_to_id(LV2_TIME__beatsPerBar),
- _uri_map.uri_to_id(LV2_TIME__beatsPerMinute),
- _uri_map.uri_to_id(LV2_TIME__frame),
- _uri_map.uri_to_id(LV2_TIME__speed),
- _uri_map.uri_to_id(LV2_PATCH__Set),
- _uri_map.uri_to_id(LV2_PATCH__property),
- _uri_map.uri_to_id(LV2_PATCH__value)
-};
-
class LV2World : boost::noncopyable {
public:
LV2World ();
LilvNode* lv2_freewheeling;
LilvNode* lv2_inPlaceBroken;
LilvNode* lv2_integer;
+ LilvNode* lv2_default;
+ LilvNode* lv2_minimum;
+ LilvNode* lv2_maximum;
LilvNode* lv2_reportsLatency;
LilvNode* lv2_sampleRate;
LilvNode* lv2_toggled;
LilvNode* midi_MidiEvent;
LilvNode* rdfs_comment;
+ LilvNode* rdfs_label;
+ LilvNode* rdfs_range;
LilvNode* rsz_minimumSize;
LilvNode* time_Position;
LilvNode* ui_GtkUI;
{
char* str = NULL;
const int ret = g_vasprintf(&str, fmt, args);
- if (type == LV2Plugin::urids.log_Error) {
+ if (type == URIMap::instance().urids.log_Error) {
error << str << endmsg;
- } else if (type == LV2Plugin::urids.log_Warning) {
+ } else if (type == URIMap::instance().urids.log_Warning) {
warning << str << endmsg;
- } else if (type == LV2Plugin::urids.log_Note) {
+ } else if (type == URIMap::instance().urids.log_Note) {
info << str << endmsg;
}
// TODO: Toggleable log:Trace message support
const LV2_Worker_Interface* work_iface;
LilvState* state;
LV2_Atom_Forge forge;
+ LV2_Atom_Forge ui_forge;
};
LV2Plugin::LV2Plugin (AudioEngine& engine,
, _features(NULL)
, _worker(NULL)
, _insert_id("0")
- , _patch_count(0)
- , _patch_value_uri(NULL)
- , _patch_value_key(NULL)
- , _patch_value_cur(NULL)
- , _patch_value_set(NULL)
+ , _patch_port_in_index((uint32_t)-1)
+ , _patch_port_out_index((uint32_t)-1)
+ , _uri_map(URIMap::instance())
{
init(c_plugin, rate);
}
, _features(NULL)
, _worker(NULL)
, _insert_id(other._insert_id)
- , _patch_count(0)
- , _patch_value_uri(NULL)
- , _patch_value_key(NULL)
- , _patch_value_cur(NULL)
- , _patch_value_set(NULL)
+ , _patch_port_in_index((uint32_t)-1)
+ , _patch_port_out_index((uint32_t)-1)
+ , _uri_map(URIMap::instance())
{
init(other._impl->plugin, other._sample_rate);
#endif
lv2_atom_forge_init(&_impl->forge, _uri_map.urid_map());
+ lv2_atom_forge_init(&_impl->ui_forge, _uri_map.urid_map());
#ifdef HAVE_LV2_1_2_0
LV2_URID atom_Int = _uri_map.uri_to_id(LV2_ATOM__Int);
}
if (lilv_nodes_contains(atom_supports, _world.patch_Message)) {
flags |= PORT_PATCHMSG;
+ if (flags & PORT_INPUT) {
+ _patch_port_in_index = i;
+ } else {
+ _patch_port_out_index = i;
+ }
}
}
LilvNodes* min_size_v = lilv_port_get_value(_impl->plugin, port, _world.rsz_minimumSize);
delete[] params;
- /* scan supported patch:writable for this plugin.
- * Note: the first Atom-port (in every direction) that supports patch:Message will be used
- */
- LilvNode* rdfs_label = lilv_new_uri(_world.world, LILV_NS_RDFS "label");
- LilvNode* rdfs_range = lilv_new_uri(_world.world, LILV_NS_RDFS "range");
- LilvNodes* properties = lilv_world_find_nodes (_world.world, lilv_plugin_get_uri(plugin), _world.patch_writable, NULL);
- LILV_FOREACH(nodes, p, properties) {
- const LilvNode* property = lilv_nodes_get(properties, p);
- LilvNode* label = lilv_nodes_get_first (lilv_world_find_nodes (_world.world, property, rdfs_label, NULL));
- LilvNode* range = lilv_nodes_get_first (lilv_world_find_nodes (_world.world, property, rdfs_range, NULL));
- if (!range || _uri_map.uri_to_id(lilv_node_as_uri(range)) != LV2Plugin::urids.atom_Path) {
- continue;
- }
-
- _patch_value_uri = (char**) realloc (_patch_value_uri, (_patch_count + 1) * sizeof(char**));
- _patch_value_key = (char**) realloc (_patch_value_key, (_patch_count + 1) * sizeof(char**));
- _patch_value_uri[_patch_count] = strdup(lilv_node_as_uri(property));
- _patch_value_key[_patch_count] = strdup(lilv_node_as_string(label ? label : property));
- ++_patch_count;
- }
- lilv_node_free(rdfs_label);
- lilv_node_free(rdfs_range);
- lilv_nodes_free(properties);
- _patch_value_cur = (char(*)[PATH_MAX]) calloc(_patch_count, sizeof(char[PATH_MAX]));
- _patch_value_set = (char(*)[PATH_MAX]) calloc(_patch_count, sizeof(char[PATH_MAX]));
-
LilvUIs* uis = lilv_plugin_get_uis(plugin);
if (lilv_uis_size(uis) > 0) {
#ifdef HAVE_SUIL
}
}
+ load_supported_properties(_property_descriptors);
allocate_atom_event_buffers();
latency_compute_run();
}
free(_make_path_feature.data);
free(_work_schedule_feature.data);
- for (uint32_t pidx = 0; pidx < _patch_count; ++pidx) {
- free(_patch_value_uri[pidx]);
- free(_patch_value_key[pidx]);
- }
- free(_patch_value_cur);
- free(_patch_value_set);
-
delete _to_ui;
delete _from_ui;
delete _worker;
uint32_t type)
{
LV2Plugin* self = (LV2Plugin*)user_data;
- if (type != 0 && type != self->_uri_map.uri_to_id(LV2_ATOM__Float)) {
+ if (type != 0 && type != URIMap::instance().urids.atom_Float) {
return; // TODO: Support non-float ports
}
return true;
}
+static void
+forge_variant(LV2_Atom_Forge* forge, const Variant& value)
+{
+ switch (value.type()) {
+ case Variant::VOID:
+ break;
+ case Variant::BOOL:
+ lv2_atom_forge_bool(forge, value.get_bool());
+ break;
+ case Variant::DOUBLE:
+ lv2_atom_forge_double(forge, value.get_double());
+ break;
+ case Variant::FLOAT:
+ lv2_atom_forge_float(forge, value.get_float());
+ break;
+ case Variant::INT:
+ lv2_atom_forge_int(forge, value.get_int());
+ break;
+ case Variant::LONG:
+ lv2_atom_forge_long(forge, value.get_long());
+ break;
+ case Variant::PATH:
+ lv2_atom_forge_path(
+ forge, value.get_path().c_str(), value.get_path().size());
+ break;
+ case Variant::STRING:
+ lv2_atom_forge_string(
+ forge, value.get_string().c_str(), value.get_string().size());
+ break;
+ case Variant::URI:
+ lv2_atom_forge_uri(
+ forge, value.get_uri().c_str(), value.get_uri().size());
+ break;
+ }
+}
+
+/** Get a variant type from a URI, return false iff no match found. */
+static bool
+uri_to_variant_type(const std::string& uri, Variant::Type& type)
+{
+ if (uri == LV2_ATOM__Bool) {
+ type = Variant::BOOL;
+ } else if (uri == LV2_ATOM__Double) {
+ type = Variant::DOUBLE;
+ } else if (uri == LV2_ATOM__Float) {
+ type = Variant::FLOAT;
+ } else if (uri == LV2_ATOM__Int) {
+ type = Variant::INT;
+ } else if (uri == LV2_ATOM__Long) {
+ type = Variant::LONG;
+ } else if (uri == LV2_ATOM__Path) {
+ type = Variant::PATH;
+ } else if (uri == LV2_ATOM__String) {
+ type = Variant::STRING;
+ } else if (uri == LV2_ATOM__URI) {
+ type = Variant::URI;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void
+LV2Plugin::set_property(uint32_t key, const Variant& value)
+{
+ if (_patch_port_in_index == (uint32_t)-1) {
+ error << "LV2: set_property called with unset patch_port_in_index" << endmsg;
+ return;
+ } else if (value.type() == Variant::VOID) {
+ error << "LV2: set_property called with void value" << endmsg;
+ return;
+ }
+
+ // Set up forge to write to temporary buffer on the stack
+ LV2_Atom_Forge* forge = &_impl->ui_forge;
+ LV2_Atom_Forge_Frame frame;
+ uint8_t buf[PATH_MAX]; // Ought to be enough for anyone...
+
+ lv2_atom_forge_set_buffer(forge, buf, sizeof(buf));
+
+ // Serialize patch:Set message to set property
+#ifdef HAVE_LV2_1_10_0
+ lv2_atom_forge_object(forge, &frame, 1, _uri_map.urids.patch_Set);
+ lv2_atom_forge_key(forge, _uri_map.urids.patch_property);
+ lv2_atom_forge_urid(forge, key);
+ lv2_atom_forge_key(forge, _uri_map.urids.patch_value);
+#else
+ lv2_atom_forge_blank(forge, &frame, 1, _uri_map.urids.patch_Set);
+ lv2_atom_forge_property_head(forge, _uri_map.urids.patch_property, 0);
+ lv2_atom_forge_urid(forge, key);
+ lv2_atom_forge_property_head(forge, _uri_map.urids.patch_value, 0);
+#endif
+
+ forge_variant(forge, value);
+
+ // Write message to UI=>Plugin ring
+ const LV2_Atom* const atom = (const LV2_Atom*)buf;
+ write_from_ui(_patch_port_in_index,
+ _uri_map.urids.atom_eventTransfer,
+ lv2_atom_total_size(atom),
+ (const uint8_t*)atom);
+}
+
+const ParameterDescriptor&
+LV2Plugin::get_property_descriptor(uint32_t id) const
+{
+ PropertyDescriptors::const_iterator p = _property_descriptors.find(id);
+ if (p != _property_descriptors.end()) {
+ return p->second;
+ }
+ return Plugin::get_property_descriptor(id);
+}
+
+static void
+set_parameter_descriptor(LV2World& world,
+ ParameterDescriptor& desc,
+ Variant::Type datatype,
+ const LilvNode* subject)
+{
+ LilvWorld* lworld = _world.world;
+ LilvNode* label = lilv_world_get(lworld, subject, _world.rdfs_label, NULL);
+ LilvNode* def = lilv_world_get(lworld, subject, _world.lv2_default, NULL);
+ LilvNode* minimum = lilv_world_get(lworld, subject, _world.lv2_minimum, NULL);
+ LilvNode* maximum = lilv_world_get(lworld, subject, _world.lv2_maximum, NULL);
+ if (label) {
+ desc.label = lilv_node_as_string(label);
+ }
+ if (def && lilv_node_is_float(def)) {
+ desc.normal = lilv_node_as_float(def);
+ }
+ if (minimum && lilv_node_is_float(minimum)) {
+ desc.lower = lilv_node_as_float(minimum);
+ }
+ if (maximum && lilv_node_is_float(maximum)) {
+ desc.upper = lilv_node_as_float(maximum);
+ }
+ desc.datatype = datatype;
+ desc.toggled |= datatype == Variant::BOOL;
+ desc.integer_step |= datatype == Variant::INT || datatype == Variant::LONG;
+}
+
+void
+LV2Plugin::load_supported_properties(PropertyDescriptors& descs)
+{
+ LilvWorld* lworld = _world.world;
+ const LilvNode* subject = lilv_plugin_get_uri(_impl->plugin);
+ LilvNodes* properties = lilv_world_find_nodes(
+ lworld, subject, _world.patch_writable, NULL);
+ LILV_FOREACH(nodes, p, properties) {
+ // Get label and range
+ const LilvNode* prop = lilv_nodes_get(properties, p);
+ LilvNode* range = lilv_world_get(lworld, prop, _world.rdfs_range, NULL);
+ if (!range) {
+ warning << string_compose(_("LV2: property <%1> has no range datatype, ignoring"),
+ lilv_node_as_uri(prop)) << endmsg;
+ continue;
+ }
+
+ // Convert range to variant type (TODO: support for multiple range types)
+ Variant::Type datatype;
+ if (!uri_to_variant_type(lilv_node_as_uri(range), datatype)) {
+ error << string_compose(_("LV2: property <%1> has unsupported datatype <%1>"),
+ lilv_node_as_uri(prop), lilv_node_as_uri(range)) << endmsg;
+ continue;
+ }
+
+ // Add description to result
+ ParameterDescriptor desc;
+ desc.key = _uri_map.uri_to_id(lilv_node_as_uri(prop));
+ desc.datatype = datatype;
+ set_parameter_descriptor(_world, desc, datatype, prop);
+ descs.insert(std::make_pair(desc.key, desc));
+
+ lilv_node_free(range);
+ }
+ lilv_nodes_free(properties);
+}
+
+void
+LV2Plugin::announce_property_values()
+{
+ if (_patch_port_in_index == (uint32_t)-1) {
+ return;
+ }
+
+ // Set up forge to write to temporary buffer on the stack
+ LV2_Atom_Forge* forge = &_impl->ui_forge;
+ LV2_Atom_Forge_Frame frame;
+ uint8_t buf[PATH_MAX]; // Ought to be enough for anyone...
+
+ lv2_atom_forge_set_buffer(forge, buf, sizeof(buf));
+
+ // Serialize patch:Get message with no subject (implicitly plugin instance)
+#ifdef HAVE_LV2_1_10_0
+ lv2_atom_forge_object(forge, &frame, 1, _uri_map.urids.patch_Get);
+#else
+ lv2_atom_forge_blank(forge, &frame, 1, _uri_map.urids.patch_Get);
+#endif
+
+ // Write message to UI=>Plugin ring
+ const LV2_Atom* const atom = (const LV2_Atom*)buf;
+ write_from_ui(_patch_port_in_index,
+ _uri_map.urids.atom_eventTransfer,
+ lv2_atom_total_size(atom),
+ (const uint8_t*)atom);
+}
+
void
LV2Plugin::enable_ui_emission()
{
LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) const
{
const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, which);
+ if (!port) {
+ error << string_compose("LV2: get descriptor of non-existent port %1", which)
+ << endmsg;
+ return 1;
+ }
LilvNodes* portunits;
LilvNode *def, *min, *max;
}
desc.enumeration = lilv_port_has_property(_impl->plugin, port, _world.lv2_enumeration);
+ desc.scale_points = get_scale_points(which);
lilv_node_free(def);
lilv_node_free(min);
}
}
+ for (PropertyDescriptors::const_iterator p = _property_descriptors.begin();
+ p != _property_descriptors.end();
+ ++p) {
+ ret.insert(ret.end(), Evoral::Parameter(PluginPropertyAutomation, 0, p->first));
+ }
return ret;
}
_atom_ev_buffers = (LV2_Evbuf**) malloc((total_atom_buffers + 1) * sizeof(LV2_Evbuf*));
for (int i = 0; i < total_atom_buffers; ++i ) {
_atom_ev_buffers[i] = lv2_evbuf_new(minimumSize, LV2_EVBUF_ATOM,
- LV2Plugin::urids.atom_Chunk, LV2Plugin::urids.atom_Sequence);
+ _uri_map.urids.atom_Chunk, _uri_map.urids.atom_Sequence);
}
_atom_ev_buffers[total_atom_buffers] = 0;
return;
framepos_t position,
framecnt_t offset)
{
+ const URIMap::URIDs& urids = URIMap::instance().urids;
+
uint8_t pos_buf[256];
lv2_atom_forge_set_buffer(forge, pos_buf, sizeof(pos_buf));
LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.time_Position);
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_frame, 0);
+#ifdef HAVE_LV2_1_10_0
+ lv2_atom_forge_object(forge, &frame, 1, urids.time_Position);
+ lv2_atom_forge_key(forge, urids.time_frame);
lv2_atom_forge_long(forge, position);
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_speed, 0);
+ lv2_atom_forge_key(forge, urids.time_speed);
lv2_atom_forge_float(forge, speed);
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_barBeat, 0);
+ lv2_atom_forge_key(forge, urids.time_barBeat);
lv2_atom_forge_float(forge, bbt.beats - 1 +
(bbt.ticks / Timecode::BBT_Time::ticks_per_beat));
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_bar, 0);
+ lv2_atom_forge_key(forge, urids.time_bar);
lv2_atom_forge_long(forge, bbt.bars - 1);
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatUnit, 0);
+ lv2_atom_forge_key(forge, urids.time_beatUnit);
lv2_atom_forge_int(forge, t.meter().note_divisor());
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerBar, 0);
+ lv2_atom_forge_key(forge, urids.time_beatsPerBar);
lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerMinute, 0);
+ lv2_atom_forge_key(forge, urids.time_beatsPerMinute);
lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
+#else
+ lv2_atom_forge_blank(forge, &frame, 1, urids.time_Position);
+ lv2_atom_forge_property_head(forge, urids.time_frame, 0);
+ lv2_atom_forge_long(forge, position);
+ lv2_atom_forge_property_head(forge, urids.time_speed, 0);
+ lv2_atom_forge_float(forge, speed);
+ lv2_atom_forge_property_head(forge, urids.time_barBeat, 0);
+ lv2_atom_forge_float(forge, bbt.beats - 1 +
+ (bbt.ticks / Timecode::BBT_Time::ticks_per_beat));
+ lv2_atom_forge_property_head(forge, urids.time_bar, 0);
+ lv2_atom_forge_long(forge, bbt.bars - 1);
+ lv2_atom_forge_property_head(forge, urids.time_beatUnit, 0);
+ lv2_atom_forge_int(forge, t.meter().note_divisor());
+ lv2_atom_forge_property_head(forge, urids.time_beatsPerBar, 0);
+ lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
+ lv2_atom_forge_property_head(forge, urids.time_beatsPerMinute, 0);
+ lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
+#endif
LV2_Evbuf_Iterator end = lv2_evbuf_end(buf);
const LV2_Atom* const atom = (const LV2_Atom*)pos_buf;
(const uint8_t*)(atom + 1));
}
-static bool
-write_patch_change(
- LV2_Atom_Forge* forge,
- LV2_Evbuf* buf,
- const char* uri,
- const char* filename
- )
-{
- LV2_Atom_Forge_Frame frame;
- uint8_t patch_buf[PATH_MAX];
- lv2_atom_forge_set_buffer(forge, patch_buf, sizeof(patch_buf));
-
-#if 0 // new LV2
- lv2_atom_forge_object(forge, &frame, 0, LV2Plugin::urids.patch_Set);
- lv2_atom_forge_key(forge, LV2Plugin::urids.patch_property);
- lv2_atom_forge_urid(forge, uri_map.uri_to_id(uri));
- lv2_atom_forge_key(forge, LV2Plugin::urids.patch_value);
- lv2_atom_forge_path(forge, filename, strlen(filename));
-#else
- lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.patch_Set);
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_property, 0);
- lv2_atom_forge_urid(forge, LV2Plugin::_uri_map.uri_to_id(uri));
- lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_value, 0);
- lv2_atom_forge_path(forge, filename, strlen(filename));
-#endif
-
- LV2_Evbuf_Iterator end = lv2_evbuf_end(buf);
- const LV2_Atom* const atom = (const LV2_Atom*)patch_buf;
- return lv2_evbuf_write(&end, 0, 0, atom->type, atom->size,
- (const uint8_t*)(atom + 1));
-}
-
-bool
-LV2Plugin::patch_set (const uint32_t p, const char * val) {
- if (p >= _patch_count) return false;
- _patch_set_lock.lock();
- strncpy(_patch_value_set[p], val, PATH_MAX);
- _patch_value_set[p][PATH_MAX - 1] = 0;
- _patch_set_lock.unlock();
- return true;
-}
-
int
LV2Plugin::connect_and_run(BufferSet& bufs,
ChanMapping in_map, ChanMapping out_map,
: m;
// Now merge MIDI and any transport events into the buffer
- const uint32_t type = LV2Plugin::urids.midi_MidiEvent;
+ const uint32_t type = _uri_map.urids.midi_MidiEvent;
const framepos_t tend = _session.transport_frame() + nframes;
++metric_i;
while (m != m_end || (metric_i != tmap.metrics_end() &&
(flags & PORT_INPUT), 0, (flags & PORT_EVENT));
}
- /* queue patch messages */
- if (flags & PORT_PATCHMSG) {
- if (_patch_set_lock.trylock()) {
- for (uint32_t pidx = 0; pidx < _patch_count; ++ pidx) {
- if (strlen(_patch_value_set[pidx]) > 0
- && 0 != strcmp(_patch_value_cur[pidx], _patch_value_set[pidx])
- )
- {
- write_patch_change(&_impl->forge, _ev_buffers[port_index],
- _patch_value_uri[pidx], _patch_value_set[pidx]);
- strncpy(_patch_value_cur[pidx], _patch_value_set[pidx], PATH_MAX);
- }
- }
- _patch_set_lock.unlock();
- }
- }
-
buf = lv2_evbuf_get_buffer(_ev_buffers[port_index]);
} else {
continue; // Control port, leave buffer alone
error << "Error reading from UI=>Plugin RingBuffer" << endmsg;
break;
}
- if (msg.protocol == urids.atom_eventTransfer) {
+ if (msg.protocol == URIMap::instance().urids.atom_eventTransfer) {
LV2_Evbuf* buf = _ev_buffers[msg.index];
LV2_Evbuf_Iterator i = lv2_evbuf_end(buf);
const LV2_Atom* const atom = (const LV2_Atom*)&body[0];
// Write messages to UI
- if ((_to_ui || _patch_count > 0) && (flags & PORT_OUTPUT) && (flags & (PORT_EVENT|PORT_SEQUENCE))) {
+ if ((_to_ui || _patch_port_out_index != (uint32_t)-1) &&
+ (flags & PORT_OUTPUT) && (flags & (PORT_EVENT|PORT_SEQUENCE))) {
LV2_Evbuf* buf = _ev_buffers[port_index];
for (LV2_Evbuf_Iterator i = lv2_evbuf_begin(buf);
lv2_evbuf_is_valid(i);
uint8_t* data;
lv2_evbuf_get(i, &frames, &subframes, &type, &size, &data);
- // intercept patch change messages
- /* TODO this should eventually be done in the UI-thread
- * using a ringbuffer and no locks.
- * The current UI ringbuffer is unsuitable. It only exists
- * if a UI enabled and misses initial patch-set or changes.
- */
- if (_patch_count > 0 && (flags & PORT_OUTPUT) && (flags & PORT_PATCHMSG)) {
- // TODO reduce if() nesting below:
+ // Intercept patch change messages to emit PropertyChanged signal
+ if ((flags & PORT_PATCHMSG)) {
LV2_Atom* atom = (LV2_Atom*)(data - sizeof(LV2_Atom));
- if (atom->type == LV2Plugin::urids.atom_Blank) {
+ if (atom->type == _uri_map.urids.atom_Blank ||
+ atom->type == _uri_map.urids.atom_Object) {
LV2_Atom_Object* obj = (LV2_Atom_Object*)atom;
- if (obj->body.otype == LV2Plugin::urids.patch_Set) {
+ if (obj->body.otype == _uri_map.urids.patch_Set) {
const LV2_Atom* property = NULL;
- lv2_atom_object_get (obj, LV2Plugin::urids.patch_property, &property, 0);
- if (property->type == LV2Plugin::urids.atom_URID) {
- for (uint32_t pidx = 0; pidx < _patch_count; ++ pidx) {
- if (((const LV2_Atom_URID*)property)->body != _uri_map.uri_to_id(_patch_value_uri[pidx])) {
- continue;
- }
- /* Get value. */
- const LV2_Atom* file_path = NULL;
- lv2_atom_object_get(obj, LV2Plugin::urids.patch_value, &file_path, 0);
- if (!file_path || file_path->type != LV2Plugin::urids.atom_Path) {
- continue;
- }
- // LV2_ATOM_BODY() casts away qualifiers, so do it explicitly:
- const char* uri = (const char*)((uint8_t const*)(file_path) + sizeof(LV2_Atom));
- _patch_set_lock.lock();
- strncpy(_patch_value_cur[pidx], uri, PATH_MAX);
- strncpy(_patch_value_set[pidx], uri, PATH_MAX);
- _patch_value_cur[pidx][PATH_MAX - 1] = 0;
- _patch_value_set[pidx][PATH_MAX - 1] = 0;
- _patch_set_lock.unlock();
- PatchChanged(pidx); // emit signal
- }
+ const LV2_Atom* value = NULL;
+ lv2_atom_object_get(obj,
+ _uri_map.urids.patch_property, &property,
+ _uri_map.urids.patch_value, &value,
+ 0);
+
+ if (!property || !value ||
+ property->type != _uri_map.urids.atom_URID ||
+ value->type != _uri_map.urids.atom_Path) {
+ std::cerr << "warning: patch:Set for unknown property" << std::endl;
+ continue;
}
+
+ const uint32_t prop_id = ((const LV2_Atom_URID*)property)->body;
+ const char* path = (const char*)LV2_ATOM_BODY_CONST(value);
+
+ // Emit PropertyChanged signal for UI
+ // TODO: This should emit the control's Changed signal
+ PropertyChanged(prop_id, Variant(Variant::PATH, path));
}
}
}
if (!_to_ui) continue;
- write_to_ui(port_index, urids.atom_eventTransfer,
+ write_to_ui(port_index, URIMap::instance().urids.atom_eventTransfer,
size + sizeof(LV2_Atom),
data - sizeof(LV2_Atom));
}
}
}
-boost::shared_ptr<Plugin::ScalePoints>
+boost::shared_ptr<ScalePoints>
LV2Plugin::get_scale_points(uint32_t port_index) const
{
const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, port_index);
LilvScalePoints* points = lilv_port_get_scale_points(_impl->plugin, port);
- boost::shared_ptr<Plugin::ScalePoints> ret;
+ boost::shared_ptr<ScalePoints> ret;
if (!points) {
return ret;
}
- ret = boost::shared_ptr<Plugin::ScalePoints>(new ScalePoints());
+ ret = boost::shared_ptr<ScalePoints>(new ScalePoints());
LILV_FOREACH(scale_points, i, points) {
const LilvScalePoint* p = lilv_scale_points_get(points, i);
lv2_OutputPort = lilv_new_uri(world, LILV_URI_OUTPUT_PORT);
lv2_inPlaceBroken = lilv_new_uri(world, LV2_CORE__inPlaceBroken);
lv2_integer = lilv_new_uri(world, LV2_CORE__integer);
+ lv2_default = lilv_new_uri(world, LV2_CORE__default);
+ lv2_minimum = lilv_new_uri(world, LV2_CORE__minimum);
+ lv2_maximum = lilv_new_uri(world, LV2_CORE__maximum);
lv2_reportsLatency = lilv_new_uri(world, LV2_CORE__reportsLatency);
lv2_sampleRate = lilv_new_uri(world, LV2_CORE__sampleRate);
lv2_toggled = lilv_new_uri(world, LV2_CORE__toggled);
lv2_freewheeling = lilv_new_uri(world, LV2_CORE__freeWheeling);
midi_MidiEvent = lilv_new_uri(world, LILV_URI_MIDI_EVENT);
rdfs_comment = lilv_new_uri(world, LILV_NS_RDFS "comment");
+ rdfs_label = lilv_new_uri(world, LILV_NS_RDFS "label");
+ rdfs_range = lilv_new_uri(world, LILV_NS_RDFS "range");
rsz_minimumSize = lilv_new_uri(world, LV2_RESIZE_PORT__minimumSize);
time_Position = lilv_new_uri(world, LV2_TIME__Position);
ui_GtkUI = lilv_new_uri(world, LV2_UI__GtkUI);
lilv_node_free(time_Position);
lilv_node_free(rsz_minimumSize);
lilv_node_free(rdfs_comment);
+ lilv_node_free(rdfs_label);
+ lilv_node_free(rdfs_range);
lilv_node_free(midi_MidiEvent);
lilv_node_free(lv2_enumeration);
lilv_node_free(lv2_freewheeling);