+static void
+forge_variant(LV2_Atom_Forge* forge, const Variant& value)
+{
+ switch (value.type()) {
+ case Variant::NOTHING:
+ break;
+ case Variant::BEATS:
+ // No atom type for this, just forge a double
+ lv2_atom_forge_double(forge, value.get_beats().to_double());
+ 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::NOTHING) {
+ 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
+load_parameter_descriptor_units(LilvWorld* lworld, ParameterDescriptor& desc, const LilvNodes* units)
+{
+ if (lilv_nodes_contains(units, _world.units_midiNote)) {
+ desc.unit = ParameterDescriptor::MIDI_NOTE;
+ } else if (lilv_nodes_contains(units, _world.units_db)) {
+ desc.unit = ParameterDescriptor::DB;
+ } else if (lilv_nodes_contains(units, _world.units_hz)) {
+ desc.unit = ParameterDescriptor::HZ;
+ }
+ if (lilv_nodes_size(units) > 0) {
+ const LilvNode* unit = lilv_nodes_get_first(units);
+ LilvNode* render = get_value(lworld, unit, _world.units_render);
+ if (render) {
+ desc.print_fmt = lilv_node_as_string(render);
+ lilv_node_free(render);
+ }
+ }
+}
+
+static void
+load_parameter_descriptor(LV2World& world,
+ ParameterDescriptor& desc,
+ Variant::Type datatype,
+ const LilvNode* subject)
+{
+ LilvWorld* lworld = _world.world;
+ LilvNode* label = get_value(lworld, subject, _world.rdfs_label);
+ LilvNode* def = get_value(lworld, subject, _world.lv2_default);
+ LilvNode* minimum = get_value(lworld, subject, _world.lv2_minimum);
+ LilvNode* maximum = get_value(lworld, subject, _world.lv2_maximum);
+ LilvNodes* units = lilv_world_find_nodes(lworld, subject, _world.units_unit, 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);
+ }
+ load_parameter_descriptor_units(lworld, desc, units);
+ desc.datatype = datatype;
+ desc.toggled |= datatype == Variant::BOOL;
+ desc.integer_step |= datatype == Variant::INT || datatype == Variant::LONG;
+ desc.update_steps();
+
+ lilv_nodes_free(units);
+ lilv_node_free(label);
+ lilv_node_free(def);
+ lilv_node_free(minimum);
+ lilv_node_free(maximum);
+}
+