gboolean gst_lv2_check_required_features (const LilvPlugin * lv2plugin) { LilvNodes *required_features = lilv_plugin_get_required_features (lv2plugin); if (required_features) { LilvIter *i; gint j; gboolean missing = FALSE; for (i = lilv_nodes_begin (required_features); !lilv_nodes_is_end (required_features, i); i = lilv_nodes_next (required_features, i)) { const LilvNode *required_feature = lilv_nodes_get (required_features, i); const char *required_feature_uri = lilv_node_as_uri (required_feature); missing = TRUE; for (j = 0; lv2_features[j]; j++) { if (!strcmp (lv2_features[j]->URI, required_feature_uri)) { missing = FALSE; break; } } if (missing) { GST_FIXME ("lv2 plugin %s needs host feature: %s", lilv_node_as_uri (lilv_plugin_get_uri (lv2plugin)), required_feature_uri); break; } } lilv_nodes_free (required_features); return (!missing); } return TRUE; }
bool LV2EffectsModule::AutoRegisterPlugins(PluginManagerInterface & pm) { EffectManager& em = EffectManager::Get(); #ifdef EFFECT_CATEGORIES // Add all LV2 categories and their relationships LilvPluginClasses classes = Lilv_world_get_plugin_classes(gWorld); for (unsigned index = 0; index < Lilv_plugin_classes_size(classes);++index){ LilvPluginClass c = Lilv_plugin_classes_get_at(classes, index); em.AddCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(c))), wxString::FromUTF8(lilv_node_as_string(Lilv_plugin_class_get_label(c)))); } for (unsigned index = 0; index < Lilv_plugin_classes_size(classes);++index){ LilvPluginClass c = Lilv_plugin_classes_get_at(classes, index); LilvPluginClasses ch = Lilv_plugin_class_get_children(c); EffectCategory* pCat = em.LookupCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(c)))); for (unsigned j = 0; j < Lilv_plugin_classes_size(ch); ++j) { EffectCategory* chCat = em.LookupCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(Lilv_plugin_classes_get_at(ch, j))))); if (chCat && pCat) { em.AddCategoryParent(chCat, pCat); } } } #endif // Retrieve data about all plugins const LilvPlugins *plugs = lilv_world_get_all_plugins(gWorld); // Iterate over all plugins and register them with the EffectManager LILV_FOREACH(plugins, i, plugs) { const LilvPlugin *plug = lilv_plugins_get(plugs, i); std::set<wxString> cats; cats.insert(wxString::FromUTF8(lilv_node_as_uri(lilv_plugin_class_get_uri(lilv_plugin_get_class(plug))))); LV2Effect *effect = new LV2Effect(plug, cats); if (effect->IsValid()) { em.RegisterEffect(this, effect); } else { delete effect; } } return true; }
bool LV2World::isPluginSupported (const LilvPlugin* plugin) { // Required features support LilvNodes* nodes = lilv_plugin_get_required_features (plugin); LILV_FOREACH (nodes, iter, nodes) { const LilvNode* node (lilv_nodes_get (nodes, iter)); if (! isFeatureSupported (CharPointer_UTF8 (lilv_node_as_uri (node)))) { return false; // Feature not supported } } lilv_nodes_free (nodes); nodes = nullptr; // Check this plugin's port types are supported const uint32 numPorts = lilv_plugin_get_num_ports (plugin); for (uint32 i = 0; i < numPorts; ++i) { // const LilvPort* port (lilv_plugin_get_port_by_index (plugin, i)); // nothing here yet (or ever) } return true; }
LILV_API char* lilv_node_get_path(const LilvNode* value, char** hostname) { if (lilv_node_is_uri(value)) { return lilv_file_uri_parse(lilv_node_as_uri(value), hostname); } return NULL; }
LILV_FOREACH(plugins, i, list) { const LilvPlugin* p = lilv_plugins_get(list, i); if (show_names) { LilvNode* n = lilv_plugin_get_name(p); printf("%s\n", lilv_node_as_string(n)); lilv_node_free(n); } else { printf("%s\n", lilv_node_as_uri(lilv_plugin_get_uri(p))); } }
void print_port(const LilvPlugin* p, uint32_t index, float* mins, float* maxes, float* defaults) { const LilvPort* port = lilv_plugin_get_port_by_index(p, index); printf("\n\tPort %d:\n", index); if (!port) { printf("\t\tERROR: Illegal/nonexistent port\n"); return; } bool first = true; const LilvNodes* classes = lilv_port_get_classes(p, port); printf("\t\tType: "); LILV_FOREACH(nodes, i, classes) { const LilvNode* value = lilv_nodes_get(classes, i); if (!first) { printf("\n\t\t "); } printf("%s", lilv_node_as_uri(value)); first = false; } if (lilv_port_is_a(p, port, event_class)) { LilvNodes* supported = lilv_port_get_value( p, port, supports_event_pred); if (lilv_nodes_size(supported) > 0) { printf("\n\t\tSupported events:\n"); LILV_FOREACH(nodes, i, supported) { const LilvNode* value = lilv_nodes_get(supported, i); printf("\t\t\t%s\n", lilv_node_as_uri(value)); } } lilv_nodes_free(supported); }
LILV_API unsigned lilv_ui_is_supported(const LilvUI* ui, LilvUISupportedFunc supported_func, const LilvNode* container_type, const LilvNode** ui_type) { const LilvNodes* classes = lilv_ui_get_classes(ui); LILV_FOREACH(nodes, c, classes) { const LilvNode* type = lilv_nodes_get(classes, c); const unsigned q = supported_func(lilv_node_as_uri(container_type), lilv_node_as_uri(type)); if (q) { if (ui_type) { *ui_type = type; } return q; } } return 0; }
URISet properties(World* world, SPtr<const Client::ObjectModel> model) { URISet properties; URISet types = RDFS::types(world, model); LilvNode* rdf_type = lilv_new_uri(world->lilv_world(), LILV_NS_RDF "type"); LilvNode* rdf_Property = lilv_new_uri(world->lilv_world(), LILV_NS_RDF "Property"); LilvNode* rdfs_domain = lilv_new_uri(world->lilv_world(), LILV_NS_RDFS "domain"); LilvNodes* props = lilv_world_find_nodes( world->lilv_world(), NULL, rdf_type, rdf_Property); LILV_FOREACH(nodes, p, props) { const LilvNode* prop = lilv_nodes_get(props, p); if (lilv_node_is_uri(prop)) { LilvNodes* domains = lilv_world_find_nodes( world->lilv_world(), prop, rdfs_domain, NULL); unsigned n_matching_domains = 0; LILV_FOREACH(nodes, d, domains) { const LilvNode* domain_node = lilv_nodes_get(domains, d); if (!lilv_node_is_uri(domain_node)) { // TODO: Blank node domains (e.g. unions) continue; } const Raul::URI domain(lilv_node_as_uri(domain_node)); if (types.count(domain)) { ++n_matching_domains; } } if (lilv_nodes_size(domains) == 0 || ( n_matching_domains > 0 && n_matching_domains == lilv_nodes_size(domains))) { properties.insert(Raul::URI(lilv_node_as_uri(prop))); } lilv_nodes_free(domains); } } lilv_node_free(rdfs_domain); lilv_node_free(rdf_Property); lilv_node_free(rdf_type); return properties; }
const std::string& LV2Plugin::library_path() const { static const std::string empty_string; if (_library_path.empty()) { const LilvNode* n = lilv_plugin_get_library_uri(_lilv_plugin); if (n) { _library_path = lilv_uri_to_path(lilv_node_as_uri(n)); } else { Raul::warn << uri() << " has no library path" << std::endl; return empty_string; } } return _library_path; }
SuilInstance* instantiateUI (const LilvUI* ui, const LilvNode* containerType, const LilvNode* widgetType, const LV2_Feature* const * features) { const LilvNode* uri = lilv_ui_get_uri (ui); const LilvPlugin* plugin = owner.getPlugin(); SuilInstance* instance = suil_instance_new (suil, &owner, lilv_node_as_uri (containerType), lilv_node_as_uri (lilv_plugin_get_uri (plugin)), lilv_node_as_uri (uri), lilv_node_as_uri (widgetType), lilv_uri_to_path (lilv_node_as_uri (lilv_ui_get_bundle_uri (ui))), lilv_uri_to_path (lilv_node_as_uri (lilv_ui_get_binary_uri (ui))), features ); if (instance != nullptr) { // do something here? } return instance; }
static void gst_lv2_filter_base_init (gpointer g_class) { GstLV2FilterClass *klass = (GstLV2FilterClass *) g_class; GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); LilvPlugin *lv2plugin; LilvNode *val; /* FIXME Handle channels positionning * GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_INVALID; */ guint j, in_pad_index = 0, out_pad_index = 0; gchar *longname, *author; lv2plugin = (LilvPlugin *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), descriptor_quark); g_assert (lv2plugin); GST_INFO ("base_init %p, plugin %s", g_class, lilv_node_get_turtle_token (lilv_plugin_get_uri (lv2plugin))); klass->in_group.ports = g_array_new (FALSE, TRUE, sizeof (GstLV2FilterPort)); klass->out_group.ports = g_array_new (FALSE, TRUE, sizeof (GstLV2FilterPort)); klass->control_in_ports = g_array_new (FALSE, TRUE, sizeof (GstLV2FilterPort)); klass->control_out_ports = g_array_new (FALSE, TRUE, sizeof (GstLV2FilterPort)); /* find ports and groups */ for (j = 0; j < lilv_plugin_get_num_ports (lv2plugin); j++) { const LilvPort *port = lilv_plugin_get_port_by_index (lv2plugin, j); const gboolean is_input = lilv_port_is_a (lv2plugin, port, input_class); struct _GstLV2FilterPort desc = { j, 0, }; LilvNodes *lv2group = lilv_port_get (lv2plugin, port, group_pred); if (lv2group) { /* port is part of a group */ const gchar *group_uri = lilv_node_as_uri (lv2group); GstLV2FilterGroup *group = is_input ? &klass->in_group : &klass->out_group; if (group->uri == NULL) { group->uri = g_strdup (group_uri); group->pad = is_input ? in_pad_index++ : out_pad_index++; group->ports = g_array_new (FALSE, TRUE, sizeof (GstLV2FilterPort)); } /* FIXME Handle channels positionning position = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; sub_values = lilv_port_get_value (lv2plugin, port, has_role_pred); if (lilv_nodes_size (sub_values) > 0) { LilvNode *role = lilv_nodes_get_at (sub_values, 0); position = gst_lv2_filter_role_to_position (role); } lilv_nodes_free (sub_values); if (position != GST_AUDIO_CHANNEL_POSITION_INVALID) { desc.position = position; } */ g_array_append_val (group->ports, desc); } else { /* port is not part of a group, or it is part of a group but that group * is illegal so we just ignore it */ if (lilv_port_is_a (lv2plugin, port, audio_class)) { desc.pad = is_input ? in_pad_index++ : out_pad_index++; if (is_input) g_array_append_val (klass->in_group.ports, desc); else g_array_append_val (klass->out_group.ports, desc); } else if (lilv_port_is_a (lv2plugin, port, control_class)) { if (is_input) g_array_append_val (klass->control_in_ports, desc); else g_array_append_val (klass->control_out_ports, desc); } else { /* unknown port type */ GST_INFO ("unhandled port %d", j); continue; } } } gst_lv2_filter_type_class_add_pad_templates (klass); val = lilv_plugin_get_name (lv2plugin); if (val) { longname = g_strdup (lilv_node_as_string (val)); lilv_node_free (val); } else { longname = g_strdup ("no description available"); } val = lilv_plugin_get_author_name (lv2plugin); if (val) { author = g_strdup (lilv_node_as_string (val)); lilv_node_free (val); } else { author = g_strdup ("no author available"); } gst_element_class_set_metadata (element_class, longname, "Filter/Effect/Audio/LV2", longname, author); g_free (longname); g_free (author); klass->plugin = lv2plugin; }
Lv2Plugin *Lv2PluginCache::getPlugin(const char *uri, const char *preset, Lv2State *state) { // create a unique key for uri/preset/state std::string keyString(uri); if(preset) { keyString.append(":"); keyString.append(preset); } std::size_t hash = std::hash<std::string>()(keyString); if(state) { hash = hash ^ (state->getHash() << 1); } // count tells how many instances of this type of plugin int count = ++instanceCount[hash]; // return cached plugin instance if available int key = hash + count; Lv2Plugin *cachedPlugin = findObject(key); if(cachedPlugin) { cachedPlugin->restore(); return cachedPlugin; } // look in cache for plugin type by uri std::string uriString(uri); const LilvPlugin *lilvPlugin = pluginMap[uriString]; if(!lilvPlugin) { // find lv2 plugin in lilv LilvNode *lilvUri = lilv_new_uri(world, uri); lilvPlugin = lilv_plugins_get_by_uri(plugins, lilvUri); lilv_node_free(lilvUri); if(!lilvPlugin) { throw std::logic_error(std::string("Plugin is not installed on this system: ") + uriString); } // check that required features are supported LilvNodes* features = lilv_plugin_get_required_features(lilvPlugin); for (LilvIter* f = lilv_nodes_begin(features); !lilv_nodes_is_end(features, f); f = lilv_nodes_next(features, f)) { const char* featureUri = lilv_node_as_uri(lilv_nodes_get(features, f)); if(!supported[featureUri]) { throw std::logic_error(std::string("Plugin ") + uriString + " requires unsupported feature: " + featureUri); } } lilv_nodes_free(features); pluginMap[uriString] = lilvPlugin; } // create worker if required Lv2Worker *worker = 0; if (lilv_plugin_has_feature(lilvPlugin, lv2Constants.lv2WorkerSchedule) && lilv_plugin_has_extension_data(lilvPlugin, lv2Constants.lv2WorkerInterface)) { worker = new Lv2Worker(); ((LV2_Worker_Schedule*)lv2Features[5]->data)->handle = worker; } // instantiate LilvInstance *instance = lilv_plugin_instantiate(lilvPlugin, sampleRate, lv2Features); // connect worker with plugin instance if(worker) { worker->setInstance(instance); } // create plugin object Lv2Plugin *plugin = new Lv2Plugin(lilvPlugin, instance, lv2Constants, worker); // restore baseline default state LilvState *defaultState = lilv_state_new_from_world(world, &map, lilv_plugin_get_uri(lilvPlugin)); lilv_state_restore(defaultState, instance, setPortValue, plugin, 0, lv2Features); // find and restore preset if(preset) { LilvNodes* presets = lilv_plugin_get_related(lilvPlugin, lv2Constants.lv2Presets); LilvNode *myPreset = 0; LILV_FOREACH(nodes, i, presets) { const LilvNode* presetNode = lilv_nodes_get(presets, i); lilv_world_load_resource(world, presetNode); LilvNodes* labels = lilv_world_find_nodes(world, presetNode, lv2Constants.lv2RdfsLabel, NULL); if (labels) { const LilvNode* label = lilv_nodes_get_first(labels); const char *labelString = lilv_node_as_string(label); // TODO: free? if(!strcmp(labelString, preset)) { myPreset = lilv_node_duplicate(presetNode); } lilv_nodes_free(labels); } } lilv_nodes_free(presets); if(myPreset) { LilvState* presetState = lilv_state_new_from_world(world, &map, myPreset); lilv_state_restore(presetState, instance, setPortValue, plugin, 0, NULL); // lilv_state_free(state); // TODO } else { throw std::logic_error(std::string("Plugin ") + uriString + " has no such preset: " + preset); } } // restore state else if(state) { // TODO: what if state is requested on a plugin that doesn't support?
static double bench(const LilvPlugin* p, uint32_t sample_count, uint32_t block_size) { URITable uri_table; uri_table_init(&uri_table); LV2_URID_Map map = { &uri_table, uri_table_map }; LV2_Feature map_feature = { LV2_URID_MAP_URI, &map }; LV2_URID_Unmap unmap = { &uri_table, uri_table_unmap }; LV2_Feature unmap_feature = { LV2_URID_UNMAP_URI, &unmap }; const LV2_Feature* features[] = { &map_feature, &unmap_feature, NULL }; float* const buf = (float*)calloc(block_size * 2, sizeof(float)); float* const in = buf; float* const out = buf + block_size; if (!buf) { fprintf(stderr, "Out of memory\n"); return 0.0; } LV2_Atom_Sequence seq = { { sizeof(LV2_Atom_Sequence_Body), uri_table_map(&uri_table, LV2_ATOM__Sequence) }, { 0, 0 } }; const char* uri = lilv_node_as_string(lilv_plugin_get_uri(p)); LilvNodes* required = lilv_plugin_get_required_features(p); LILV_FOREACH(nodes, i, required) { const LilvNode* feature = lilv_nodes_get(required, i); if (!lilv_node_equals(feature, urid_map)) { fprintf(stderr, "<%s> requires feature <%s>, skipping\n", uri, lilv_node_as_uri(feature)); free(buf); uri_table_destroy(&uri_table); return 0.0; } } LilvInstance* instance = lilv_plugin_instantiate(p, 48000.0, features); if (!instance) { fprintf(stderr, "Failed to instantiate <%s>\n", lilv_node_as_uri(lilv_plugin_get_uri(p))); free(buf); uri_table_destroy(&uri_table); return 0.0; } float* controls = (float*)calloc( lilv_plugin_get_num_ports(p), sizeof(float)); lilv_plugin_get_port_ranges_float(p, NULL, NULL, controls); const uint32_t n_ports = lilv_plugin_get_num_ports(p); for (uint32_t index = 0; index < n_ports; ++index) { const LilvPort* port = lilv_plugin_get_port_by_index(p, index); if (lilv_port_is_a(p, port, lv2_ControlPort)) { lilv_instance_connect_port(instance, index, &controls[index]); } else if (lilv_port_is_a(p, port, lv2_AudioPort) || lilv_port_is_a(p, port, lv2_CVPort)) { if (lilv_port_is_a(p, port, lv2_InputPort)) { lilv_instance_connect_port(instance, index, in); } else if (lilv_port_is_a(p, port, lv2_OutputPort)) { lilv_instance_connect_port(instance, index, out); } else { fprintf(stderr, "<%s> port %d neither input nor output, skipping\n", uri, index); lilv_instance_free(instance); free(buf); free(controls); uri_table_destroy(&uri_table); return 0.0; } } else if (lilv_port_is_a(p, port, atom_AtomPort)) { lilv_instance_connect_port(instance, index, &seq); } else { fprintf(stderr, "<%s> port %d has unknown type, skipping\n", uri, index); lilv_instance_free(instance); free(buf); free(controls); uri_table_destroy(&uri_table); return 0.0; } } lilv_instance_activate(instance); struct timespec ts = bench_start(); for (uint32_t i = 0; i < (sample_count / block_size); ++i) { lilv_instance_run(instance, block_size); } const double elapsed = bench_end(&ts); lilv_instance_deactivate(instance); lilv_instance_free(instance); uri_table_destroy(&uri_table); if (full_output) { printf("%d %d ", block_size, sample_count); } printf("%lf %s\n", elapsed, uri); free(buf); free(controls); return elapsed; }