def generate_bundles(self): if not self.useAbsolutePath: return [] bundles = [] bnodes = lilv.lilv_plugin_get_data_uris(self.plugin.me) it = lilv.lilv_nodes_begin(bnodes) while not lilv.lilv_nodes_is_end(bnodes, it): bnode = lilv.lilv_nodes_get(bnodes, it) it = lilv.lilv_nodes_next(bnodes, it) if bnode is None: continue if not lilv.lilv_node_is_uri(bnode): continue bpath = os.path.abspath( os.path.dirname( lilv.lilv_uri_to_path(lilv.lilv_node_as_uri(bnode)) ) ) if not bpath.endswith(os.sep): bpath += os.sep if bpath not in bundles: bundles.append(bpath) if self.bundle not in bundles: bundles.append(self.bundle) del bnodes, it return bundles
def refresh(): global W, BUNDLES, PLUGINS, PLUGNFO BUNDLES = [] PLUGINS = W.get_all_plugins() PLUGNFO = {} # Make a list of all installed bundles for p in PLUGINS: bundles = lilv.lilv_plugin_get_data_uris(p.me) # store empty dict for later PLUGNFO[p.get_uri().as_uri()] = {} it = lilv.lilv_nodes_begin(bundles) while not lilv.lilv_nodes_is_end(bundles, it): bundle = lilv.lilv_nodes_get(bundles, it) it = lilv.lilv_nodes_next(bundles, it) if bundle is None: continue if not lilv.lilv_node_is_uri(bundle): continue bundle = os.path.dirname(lilv.lilv_uri_to_path(lilv.lilv_node_as_uri(bundle))) if not bundle.endswith(os.sep): bundle += os.sep if bundle not in BUNDLES: BUNDLES.append(bundle)
def refresh(): global W, BUNDLES, PLUGINS, PLUGNFO, PLUGNFOk BUNDLES = [] PLUGINS = W.get_all_plugins() PLUGNFO = {} PLUGNFOk = [] # Make a list of all installed bundles for p in PLUGINS: bundles = lilv.lilv_plugin_get_data_uris(p.me) # store empty dict for later uri = p.get_uri().as_uri() PLUGNFO[uri] = {} PLUGNFOk.append(uri) it = lilv.lilv_nodes_begin(bundles) while not lilv.lilv_nodes_is_end(bundles, it): bundle = lilv.lilv_nodes_get(bundles, it) it = lilv.lilv_nodes_next(bundles, it) if bundle is None: continue if not lilv.lilv_node_is_uri(bundle): continue bundle = os.path.dirname( lilv.lilv_uri_to_path(lilv.lilv_node_as_uri(bundle))) if not bundle.endswith(os.sep): bundle += os.sep if bundle not in BUNDLES: BUNDLES.append(bundle)
def generate_bundles(self): if not self.useAbsolutePath: return [] bundles = [] bnodes = lilv.lilv_plugin_get_data_uris(self.plugin.me) it = lilv.lilv_nodes_begin(bnodes) while not lilv.lilv_nodes_is_end(bnodes, it): bnode = lilv.lilv_nodes_get(bnodes, it) it = lilv.lilv_nodes_next(bnodes, it) if bnode is None: continue if not lilv.lilv_node_is_uri(bnode): continue bpath = os.path.abspath( os.path.dirname( lilv.lilv_uri_to_path(lilv.lilv_node_as_uri(bnode)))) if not bpath.endswith(os.sep): bpath += os.sep if bpath not in bundles: bundles.append(bpath) if self.bundle not in bundles: bundles.append(self.bundle) del bnodes, it return bundles
def get_port_data(port, subj): nodes = port.get_value(subj.me) data = [] it = lilv.lilv_nodes_begin(nodes) while not lilv.lilv_nodes_is_end(nodes, it): dat = lilv.lilv_nodes_get(nodes, it) it = lilv.lilv_nodes_next(nodes, it) if dat is None: continue data.append(lilv.lilv_node_as_string(dat)) return data
def get_port_data(self, port, subj): nodes = port.get_value(subj.me) data = [] it = lilv.lilv_nodes_begin(nodes) while not lilv.lilv_nodes_is_end(nodes, it): dat = lilv.lilv_nodes_get(nodes, it) it = lilv.lilv_nodes_next(nodes, it) if dat is None: continue data.append(lilv.lilv_node_as_string(dat)) return data
def get_pedalboard_info(bundle): # lilv wants the last character as the separator if not bundle.endswith(os.sep): bundle += os.sep # Create our own unique lilv world # We'll load a single bundle and get all plugins from it world = lilv.World() # this is needed when loading specific bundles instead of load_all # (these functions are not exposed via World yet) lilv.lilv_world_load_specifications(world.me) lilv.lilv_world_load_plugin_classes(world.me) # convert bundle string into a lilv node bundlenode = lilv.lilv_new_file_uri(world.me, None, bundle) # load the bundle world.load_bundle(bundlenode) # free bundlenode, no longer needed lilv.lilv_node_free(bundlenode) # get all plugins in the bundle plugins = world.get_all_plugins() # make sure the bundle includes 1 and only 1 plugin (the pedalboard) if plugins.size() != 1: raise Exception('get_info_from_lv2_bundle(%s) - bundle has 0 or > 1 plugin'.format(bundle)) # no indexing in python-lilv yet, just get the first item plugin = None for p in plugins: plugin = p break if plugin is None: raise Exception('get_info_from_lv2_bundle(%s) - failed to get plugin, you are using an old lilv!'.format(bundle)) # define the needed stuff rdf = NS(lilv.LILV_NS_RDF, world) ingen = NS('http://drobilla.net/ns/ingen#', world) lv2core = NS(lilv.LILV_NS_LV2, world) modpedal = NS("http://portalmod.com/ns/modpedal#", world) # check if the plugin is a pedalboard def fill_in_type(node): return node.as_string() plugin_types = [i for i in LILV_FOREACH(plugin.get_value(rdf.type_), fill_in_type)] if "http://portalmod.com/ns/modpedal#Pedalboard" not in plugin_types: raise Exception('get_info_from_lv2_bundle(%s) - plugin has no mod:Pedalboard type'.format(bundle)) # let's get all the info now ingenarcs = [] ingenblocks = [] info = { 'name': plugin.get_value(modpedal.name).get_first().as_string(), 'author': plugin.get_author_name().as_string() or '', # Might be empty 'uri': plugin.get_uri().as_string(), 'hardware': { # we save this info later 'audio': { 'ins': 0, 'outs': 0 }, 'cv': { 'ins': 0, 'outs': 0 }, 'midi': { 'ins': 0, 'outs': 0 } }, 'size': { 'width': plugin.get_value(modpedal.width).get_first().as_int(), 'height': plugin.get_value(modpedal.height).get_first().as_int(), }, 'screenshot': os.path.basename(plugin.get_value(modpedal.screenshot).get_first().as_string()), 'thumbnail': os.path.basename(plugin.get_value(modpedal.thumbnail).get_first().as_string()), 'connections': [], # we save this info later 'plugins': [] # we save this info later } # connections arcs = plugin.get_value(ingen.arc) it = arcs.begin() while not arcs.is_end(it): arc = arcs.get(it) it = arcs.next(it) if arc.me is None: continue head = lilv.lilv_world_get(world.me, arc.me, ingen.head.me, None) tail = lilv.lilv_world_get(world.me, arc.me, ingen.tail.me, None) if head is None or tail is None: continue ingenarcs.append({ "source": lilv.lilv_node_as_string(tail).replace("file://","",1).replace(bundle,"",1), "target": lilv.lilv_node_as_string(head).replace("file://","",1).replace(bundle,"",1) }) # hardware ports handled_port_uris = [] ports = plugin.get_value(lv2core.port) it = ports.begin() while not ports.is_end(it): port = ports.get(it) it = ports.next(it) if port.me is None: continue # check if we already handled this port port_uri = port.as_uri() if port_uri in handled_port_uris: continue handled_port_uris.append(port_uri) # get types port_types = lilv.lilv_world_find_nodes(world.me, port.me, rdf.type_.me, None) if port_types is None: continue portDir = "" # input or output portType = "" # atom, audio or cv it2 = lilv.lilv_nodes_begin(port_types) while not lilv.lilv_nodes_is_end(port_types, it2): port_type = lilv.lilv_nodes_get(port_types, it2) it2 = lilv.lilv_nodes_next(port_types, it2) if port_type is None: continue port_type_uri = lilv.lilv_node_as_uri(port_type) if port_type_uri == "http://lv2plug.in/ns/lv2core#InputPort": portDir = "input" elif port_type_uri == "http://lv2plug.in/ns/lv2core#OutputPort": portDir = "output" elif port_type_uri == "http://lv2plug.in/ns/lv2core#AudioPort": portType = "audio" elif port_type_uri == "http://lv2plug.in/ns/lv2core#CVPort": portType = "cv" elif port_type_uri == "http://lv2plug.in/ns/ext/atom#AtomPort": portType = "atom" if not (portDir or portType): continue if portType == "audio": if portDir == "input": info['hardware']['audio']['ins'] += 1 else: info['hardware']['audio']['outs'] += 1 elif portType == "atom": if portDir == "input": info['hardware']['midi']['ins'] += 1 else: info['hardware']['midi']['outs'] += 1 elif portType == "cv": if portDir == "input": info['hardware']['cv']['ins'] += 1 else: info['hardware']['cv']['outs'] += 1 # plugins blocks = plugin.get_value(ingen.block) it = blocks.begin() while not blocks.is_end(it): block = blocks.get(it) it = blocks.next(it) if block.me is None: continue protouri1 = lilv.lilv_world_get(world.me, block.me, lv2core.prototype.me, None) protouri2 = lilv.lilv_world_get(world.me, block.me, ingen.prototype.me, None) if protouri1 is not None: proto = protouri1 elif protouri2 is not None: proto = protouri2 else: continue uri = lilv.lilv_node_as_uri(proto) ingenblocks.append({ "uri": uri, "x": lilv.lilv_node_as_float(lilv.lilv_world_get(world.me, block.me, ingen.canvasX.me, None)), "y": lilv.lilv_node_as_float(lilv.lilv_world_get(world.me, block.me, ingen.canvasY.me, None)) }) info['connections'] = ingenarcs info['plugins'] = ingenblocks return info
def get_plugin_info(world, plugin): # define the needed stuff ns_doap = NS(world, lilv.LILV_NS_DOAP) ns_rdf = NS(world, lilv.LILV_NS_RDF) ns_rdfs = NS(world, lilv.LILV_NS_RDFS) ns_lv2core = NS(world, lilv.LILV_NS_LV2) ns_atom = NS(world, "http://lv2plug.in/ns/ext/atom#") ns_midi = NS(world, "http://lv2plug.in/ns/ext/midi#") ns_pprops = NS(world, "http://lv2plug.in/ns/ext/port-props#") ns_pset = NS(world, "http://lv2plug.in/ns/ext/presets#") ns_units = NS(world, "http://lv2plug.in/ns/extensions/units#") ns_mod = NS(world, "http://moddevices.com/ns/mod#") ns_modgui = NS(world, "http://moddevices.com/ns/modgui#") bundleuri = plugin.get_bundle_uri().as_string() bundle = lilv.lilv_uri_to_path(bundleuri) errors = [] warnings = [] # -------------------------------------------------------------------------------------------------------- # uri uri = plugin.get_uri().as_string() or "" if not uri: errors.append("plugin uri is missing or invalid") elif uri.startswith("file:"): errors.append("plugin uri is local, and thus not suitable for redistribution") #elif not (uri.startswith("http:") or uri.startswith("https:")): #warnings.append("plugin uri is not a real url") # -------------------------------------------------------------------------------------------------------- # name name = plugin.get_name().as_string() or "" if not name: errors.append("plugin name is missing") # -------------------------------------------------------------------------------------------------------- # binary binary = lilv.lilv_uri_to_path(plugin.get_library_uri().as_string() or "") if not binary: errors.append("plugin binary is missing") # -------------------------------------------------------------------------------------------------------- # license license = plugin.get_value(ns_doap.license).get_first().as_string() or "" if not license: errors.append("plugin license is missing") elif license.startswith(bundleuri): license = license.replace(bundleuri,"",1) warnings.append("plugin license entry is a local path instead of a string") # -------------------------------------------------------------------------------------------------------- # comment comment = plugin.get_value(ns_rdfs.comment).get_first().as_string() or "" if not comment: errors.append("plugin comment is missing") # -------------------------------------------------------------------------------------------------------- # version microver = plugin.get_value(ns_lv2core.microVersion).get_first() minorver = plugin.get_value(ns_lv2core.minorVersion).get_first() if microver.me is None and minorver.me is None: errors.append("plugin is missing version information") microVersion = 0 minorVersion = 0 else: if microver.me is None: errors.append("plugin is missing microVersion") microVersion = 0 else: microVersion = microver.as_int() if minorver.me is None: errors.append("plugin is missing minorVersion") minorVersion = 0 else: minorVersion = minorver.as_int() del microver del minorver version = "%d.%d" % (microVersion, minorVersion) if minorVersion == 0 and microVersion == 0: stability = "experimental" elif minorVersion % 2 == 0: stability = "stable" if microVersion % 2 == 0 else "testing" else: stability = "unstable" # -------------------------------------------------------------------------------------------------------- # author author = { 'name' : plugin.get_author_name().as_string() or "", 'homepage': plugin.get_author_homepage().as_string() or "", 'email' : plugin.get_author_email().as_string() or "", } if not author['name']: errors.append("plugin author name is missing") if not author['homepage']: warnings.append("plugin author homepage is missing") if not author['email']: warnings.append("plugin author email is missing") elif author['email'].startswith(bundleuri): author['email'] = author['email'].replace(bundleuri,"",1) warnings.append("plugin author email entry is missing 'mailto:' prefix") elif author['email'].startswith("mailto:"): author['email'] = author['email'].replace("mailto:","",1) # -------------------------------------------------------------------------------------------------------- # brand brand = plugin.get_value(ns_mod.brand).get_first().as_string() or "" if not brand: brand = author['name'].split(" - ",1)[0].split(" ",1)[0] brand = brand.rstrip(",").rstrip(";") if len(brand) > 10: brand = brand[:10] warnings.append("plugin brand is missing") elif len(brand) > 10: brand = brand[:10] errors.append("plugin brand has more than 10 characters") # -------------------------------------------------------------------------------------------------------- # label label = plugin.get_value(ns_mod.label).get_first().as_string() or "" if not label: if len(name) <= 16: label = name else: labels = name.split(" - ",1)[0].split(" ") if labels[0].lower() in bundle.lower() and len(labels) > 1 and not labels[1].startswith(("(","[")): label = labels[1] else: label = labels[0] if len(label) > 16: label = label[:16] warnings.append("plugin label is missing") del labels elif len(label) > 16: label = label[:16] errors.append("plugin label has more than 16 characters") # -------------------------------------------------------------------------------------------------------- # bundles bnodes = lilv.lilv_plugin_get_data_uris(plugin.me) bundles = [] it = lilv.lilv_nodes_begin(bnodes) while not lilv.lilv_nodes_is_end(bnodes, it): bnode = lilv.lilv_nodes_get(bnodes, it) it = lilv.lilv_nodes_next(bnodes, it) if bnode is None: continue if not lilv.lilv_node_is_uri(bnode): continue bpath = os.path.dirname(lilv.lilv_uri_to_path(lilv.lilv_node_as_uri(bnode))) if not bpath.endswith(os.sep): bpath += os.sep if bpath not in bundles: bundles.append(bpath) if bundle not in bundles: bundles.append(bundle) del bnodes, it # -------------------------------------------------------------------------------------------------------- # get the proper modgui modguigui = None nodes = plugin.get_value(ns_modgui.gui) it = nodes.begin() while not nodes.is_end(it): mgui = nodes.get(it) it = nodes.next(it) if mgui.me is None: continue resdir = world.find_nodes(mgui.me, ns_modgui.resourcesDirectory.me, None).get_first() if resdir.me is None: continue modguigui = mgui if os.path.expanduser("~") in lilv.lilv_uri_to_path(resdir.as_string()): # found a modgui in the home dir, stop here and use it break del nodes, it # -------------------------------------------------------------------------------------------------------- # gui gui = {} if modguigui is None or modguigui.me is None: warnings.append("no modgui available") else: # resourcesDirectory *must* be present modgui_resdir = world.find_nodes(modguigui.me, ns_modgui.resourcesDirectory.me, None).get_first() if modgui_resdir.me is None: errors.append("modgui has no resourcesDirectory data") else: gui['resourcesDirectory'] = lilv.lilv_uri_to_path(modgui_resdir.as_string()) # check if modgui is defined in a separate file gui['usingSeeAlso'] = os.path.exists(os.path.join(bundle, "modgui.ttl")) # check if the modgui definition is on its own file and in the user dir gui['modificableInPlace'] = bool((bundle not in gui['resourcesDirectory'] or gui['usingSeeAlso']) and os.path.expanduser("~") in gui['resourcesDirectory']) # icon and settings templates modgui_icon = world.find_nodes(modguigui.me, ns_modgui.iconTemplate .me, None).get_first() modgui_setts = world.find_nodes(modguigui.me, ns_modgui.settingsTemplate.me, None).get_first() if modgui_icon.me is None: errors.append("modgui has no iconTemplate data") else: iconFile = lilv.lilv_uri_to_path(modgui_icon.as_string()) if os.path.exists(iconFile): with open(iconFile, 'r') as fd: gui['iconTemplate'] = fd.read() else: errors.append("modgui iconTemplate file is missing") del iconFile if modgui_setts.me is not None: settingsFile = lilv.lilv_uri_to_path(modgui_setts.as_string()) if os.path.exists(settingsFile): with open(settingsFile, 'r') as fd: gui['settingsTemplate'] = fd.read() else: errors.append("modgui settingsTemplate file is missing") del settingsFile # javascript and stylesheet files modgui_script = world.find_nodes(modguigui.me, ns_modgui.javascript.me, None).get_first() modgui_style = world.find_nodes(modguigui.me, ns_modgui.stylesheet.me, None).get_first() if modgui_script.me is not None: javascriptFile = lilv.lilv_uri_to_path(modgui_script.as_string()) if os.path.exists(javascriptFile): gui['javascript'] = javascriptFile else: errors.append("modgui javascript file is missing") del javascriptFile if modgui_style.me is None: errors.append("modgui has no stylesheet data") else: stylesheetFile = lilv.lilv_uri_to_path(modgui_style.as_string()) if os.path.exists(stylesheetFile): gui['stylesheet'] = stylesheetFile else: errors.append("modgui stylesheet file is missing") del stylesheetFile # template data for backwards compatibility # FIXME remove later once we got rid of all templateData files modgui_templ = world.find_nodes(modguigui.me, ns_modgui.templateData.me, None).get_first() if modgui_templ.me is not None: warnings.append("modgui is using old deprecated templateData") templFile = lilv.lilv_uri_to_path(modgui_templ.as_string()) if os.path.exists(templFile): with open(templFile, 'r') as fd: try: data = json.loads(fd.read()) except: data = {} keys = list(data.keys()) if 'author' in keys: gui['brand'] = data['author'] if 'label' in keys: gui['label'] = data['label'] if 'color' in keys: gui['color'] = data['color'] if 'knob' in keys: gui['knob'] = data['knob'] if 'controls' in keys: index = 0 ports = [] for ctrl in data['controls']: ports.append({ 'index' : index, 'name' : ctrl['name'], 'symbol': ctrl['symbol'], }) index += 1 gui['ports'] = ports del templFile # screenshot and thumbnail modgui_scrn = world.find_nodes(modguigui.me, ns_modgui.screenshot.me, None).get_first() modgui_thumb = world.find_nodes(modguigui.me, ns_modgui.thumbnail .me, None).get_first() if modgui_scrn.me is not None: gui['screenshot'] = lilv.lilv_uri_to_path(modgui_scrn.as_string()) if not os.path.exists(gui['screenshot']): errors.append("modgui screenshot file is missing") else: errors.append("modgui has no screnshot data") if modgui_thumb.me is not None: gui['thumbnail'] = lilv.lilv_uri_to_path(modgui_thumb.as_string()) if not os.path.exists(gui['thumbnail']): errors.append("modgui thumbnail file is missing") else: errors.append("modgui has no thumbnail data") # extra stuff, all optional modgui_brand = world.find_nodes(modguigui.me, ns_modgui.brand.me, None).get_first() modgui_label = world.find_nodes(modguigui.me, ns_modgui.label.me, None).get_first() modgui_model = world.find_nodes(modguigui.me, ns_modgui.model.me, None).get_first() modgui_panel = world.find_nodes(modguigui.me, ns_modgui.panel.me, None).get_first() modgui_color = world.find_nodes(modguigui.me, ns_modgui.color.me, None).get_first() modgui_knob = world.find_nodes(modguigui.me, ns_modgui.knob .me, None).get_first() if modgui_brand.me is not None: gui['brand'] = modgui_brand.as_string() if modgui_label.me is not None: gui['label'] = modgui_label.as_string() if modgui_model.me is not None: gui['model'] = modgui_model.as_string() if modgui_panel.me is not None: gui['panel'] = modgui_panel.as_string() if modgui_color.me is not None: gui['color'] = modgui_color.as_string() if modgui_knob.me is not None: gui['knob'] = modgui_knob.as_string() # ports errpr = False ports = [] nodes = world.find_nodes(modguigui.me, ns_modgui.port.me, None) it = lilv.lilv_nodes_begin(nodes.me) while not lilv.lilv_nodes_is_end(nodes.me, it): port = lilv.lilv_nodes_get(nodes.me, it) it = lilv.lilv_nodes_next(nodes.me, it) if port is None: break port_indx = world.find_nodes(port, ns_lv2core.index .me, None).get_first() port_symb = world.find_nodes(port, ns_lv2core.symbol.me, None).get_first() port_name = world.find_nodes(port, ns_lv2core.name .me, None).get_first() if None in (port_indx.me, port_name.me, port_symb.me): if not errpr: errors.append("modgui has some invalid port data") errpr = True continue ports.append({ 'index' : port_indx.as_int(), 'symbol': port_symb.as_string(), 'name' : port_name.as_string(), }) # sort ports if len(ports) > 0: ports2 = {} for port in ports: ports2[port['index']] = port gui['ports'] = [ports2[i] for i in ports2] del ports2 # cleanup del ports, nodes, it # -------------------------------------------------------------------------------------------------------- # ports index = 0 ports = { 'audio' : { 'input': [], 'output': [] }, 'control': { 'input': [], 'output': [] }, 'midi' : { 'input': [], 'output': [] } } portsymbols = [] portnames = [] # function for filling port info def fill_port_info(port): # base data portname = lilv.lilv_node_as_string(port.get_name()) or "" if not portname: portname = "_%i" % index errors.append("port with index %i has no name" % index) portsymbol = lilv.lilv_node_as_string(port.get_symbol()) or "" if not portsymbol: portsymbol = "_%i" % index errors.append("port with index %i has no symbol" % index) # check for duplicate names if portname in portsymbols: warnings.append("port name '%s' is not unique" % portname) else: portnames.append(portname) # check for duplicate symbols if portsymbol in portsymbols: errors.append("port symbol '%s' is not unique" % portsymbol) else: portsymbols.append(portsymbol) # short name psname = lilv.lilv_nodes_get_first(port.get_value(ns_lv2core.shortname.me)) if psname is not None: psname = lilv.lilv_node_as_string(psname) or "" if not psname: psname = get_short_port_name(portname) warnings.append("port '%s' has no short name" % portname) elif len(psname) > 16: psname = psname[:16] errors.append("port '%s' short name has more than 16 characters" % portname) # port types types = [typ.rsplit("#",1)[-1].replace("Port","",1) for typ in get_port_data(port, ns_rdf.type_)] if "Atom" in types \ and port.supports_event(ns_midi.MidiEvent.me) \ and lilv.Nodes(port.get_value(ns_atom.bufferType.me)).get_first() == ns_atom.Sequence: types.append("MIDI") # port properties properties = [typ.rsplit("#",1)[-1] for typ in get_port_data(port, ns_lv2core.portProperty)] # data ranges = {} scalepoints = [] # unit block ulabel = "" urender = "" usymbol = "" # control and cv must contain ranges, might contain scale points if "Control" in types or "CV" in types: isInteger = "integer" in properties if isInteger and "CV" in types: errors.append("port '%s' has integer property and CV type" % portname) xdefault = lilv.lilv_nodes_get_first(port.get_value(ns_lv2core.default.me)) xminimum = lilv.lilv_nodes_get_first(port.get_value(ns_lv2core.minimum.me)) xmaximum = lilv.lilv_nodes_get_first(port.get_value(ns_lv2core.maximum.me)) if xminimum is not None and xmaximum is not None: if isInteger: if is_integer(lilv.lilv_node_as_string(xminimum)): ranges['minimum'] = lilv.lilv_node_as_int(xminimum) else: ranges['minimum'] = lilv.lilv_node_as_float(xminimum) if fmod(ranges['minimum'], 1.0) == 0.0: warnings.append("port '%s' has integer property but minimum value is float" % portname) else: errors.append("port '%s' has integer property but minimum value has non-zero decimals" % portname) ranges['minimum'] = int(ranges['minimum']) if is_integer(lilv.lilv_node_as_string(xmaximum)): ranges['maximum'] = lilv.lilv_node_as_int(xmaximum) else: ranges['maximum'] = lilv.lilv_node_as_float(xmaximum) if fmod(ranges['maximum'], 1.0) == 0.0: warnings.append("port '%s' has integer property but maximum value is float" % portname) else: errors.append("port '%s' has integer property but maximum value has non-zero decimals" % portname) ranges['maximum'] = int(ranges['maximum']) else: ranges['minimum'] = lilv.lilv_node_as_float(xminimum) ranges['maximum'] = lilv.lilv_node_as_float(xmaximum) if is_integer(lilv.lilv_node_as_string(xminimum)): warnings.append("port '%s' minimum value is an integer" % portname) if is_integer(lilv.lilv_node_as_string(xmaximum)): warnings.append("port '%s' maximum value is an integer" % portname) if ranges['minimum'] >= ranges['maximum']: ranges['maximum'] = ranges['minimum'] + (1 if isInteger else 0.1) errors.append("port '%s' minimum value is equal or higher than its maximum" % portname) if xdefault is not None: if isInteger: if is_integer(lilv.lilv_node_as_string(xdefault)): ranges['default'] = lilv.lilv_node_as_int(xdefault) else: ranges['default'] = lilv.lilv_node_as_float(xdefault) if fmod(ranges['default'], 1.0) == 0.0: warnings.append("port '%s' has integer property but default value is float" % portname) else: errors.append("port '%s' has integer property but default value has non-zero decimals" % portname) ranges['default'] = int(ranges['default']) else: ranges['default'] = lilv.lilv_node_as_float(xdefault) if is_integer(lilv.lilv_node_as_string(xdefault)): warnings.append("port '%s' default value is an integer" % portname) testmin = ranges['minimum'] testmax = ranges['maximum'] if "sampleRate" in properties: testmin *= 48000 testmax *= 48000 if not (testmin <= ranges['default'] <= testmax): ranges['default'] = ranges['minimum'] errors.append("port '%s' default value is out of bounds" % portname) else: ranges['default'] = ranges['minimum'] if "Input" in types: errors.append("port '%s' is missing default value" % portname) else: if isInteger: ranges['minimum'] = 0 ranges['maximum'] = 1 ranges['default'] = 0 else: ranges['minimum'] = -1.0 if "CV" in types else 0.0 ranges['maximum'] = 1.0 ranges['default'] = 0.0 if "CV" not in types: errors.append("port '%s' is missing value ranges" % portname) nodes = port.get_scale_points() if nodes is not None: it = lilv.lilv_scale_points_begin(nodes) while not lilv.lilv_scale_points_is_end(nodes, it): sp = lilv.lilv_scale_points_get(nodes, it) it = lilv.lilv_scale_points_next(nodes, it) if sp is None: continue label = lilv.lilv_scale_point_get_label(sp) value = lilv.lilv_scale_point_get_value(sp) if label is None: errors.append("a port scalepoint is missing its label") continue label = lilv.lilv_node_as_string(label) or "" if not label: errors.append("a port scalepoint is missing its label") continue if value is None: errors.append("port scalepoint '%s' is missing its value" % label) continue if isInteger: if is_integer(lilv.lilv_node_as_string(value)): value = lilv.lilv_node_as_int(value) else: value = lilv.lilv_node_as_float(value) if fmod(value, 1.0) == 0.0: warnings.append("port '%s' has integer property but scalepoint '%s' value is float" % (portname, label)) else: errors.append("port '%s' has integer property but scalepoint '%s' value has non-zero decimals" % (portname, label)) value = int(value) else: if is_integer(lilv.lilv_node_as_string(value)): warnings.append("port '%s' scalepoint '%s' value is an integer" % (portname, label)) value = lilv.lilv_node_as_float(value) if ranges['minimum'] <= value <= ranges['maximum']: scalepoints.append({'label': label, 'value': value}) else: errors.append(("port scalepoint '%s' has an out-of-bounds value:\n" % label) + ("%d < %d < %d" if isInteger else "%f < %f < %f") % (ranges['minimum'], value, ranges['maximum'])) if "enumeration" in properties and len(scalepoints) <= 1: errors.append("port '%s' wants to use enumeration but doesn't have enough values" % portname) properties.remove("enumeration") # control ports might contain unit if "Control" in types: # unit uunit = lilv.lilv_nodes_get_first(port.get_value(ns_units.unit.me)) if uunit is not None: uuri = lilv.lilv_node_as_uri(uunit) # using pre-existing lv2 unit if uuri is not None and uuri.startswith("http://lv2plug.in/ns/"): uuri = uuri.replace("http://lv2plug.in/ns/extensions/units#","",1) alnum = uuri.isalnum() if not alnum: errors.append("port '%s' has wrong lv2 unit uri" % portname) uuri = uuri.rsplit("#",1)[-1].rsplit("/",1)[-1] ulabel, urender, usymbol = get_port_unit(uuri) if alnum and not (ulabel and urender and usymbol): errors.append("port '%s' has unknown lv2 unit (our bug?, data is '%s', '%s', '%s')" % (portname, ulabel, urender, usymbol)) # using custom unit else: xlabel = world.find_nodes(uunit, ns_rdfs .label.me, None).get_first() xrender = world.find_nodes(uunit, ns_units.render.me, None).get_first() xsymbol = world.find_nodes(uunit, ns_units.symbol.me, None).get_first() if xlabel.me is not None: ulabel = xlabel.as_string() else: errors.append("port '%s' has custom unit with no label" % portname) if xrender.me is not None: urender = xrender.as_string() else: errors.append("port '%s' has custom unit with no render" % portname) if xsymbol.me is not None: usymbol = xsymbol.as_string() else: errors.append("port '%s' has custom unit with no symbol" % portname) return (types, { 'name' : portname, 'symbol' : portsymbol, 'ranges' : ranges, 'units' : { 'label' : ulabel, 'render': urender, 'symbol': usymbol, } if "Control" in types and ulabel and urender and usymbol else {}, 'designation': (get_port_data(port, ns_lv2core.designation) or [None])[0], 'properties' : properties, 'rangeSteps' : (get_port_data(port, ns_mod.rangeSteps) or get_port_data(port, ns_pprops.rangeSteps) or [None])[0], "scalePoints": scalepoints, 'shortname' : psname, }) for p in (plugin.get_port_by_index(i) for i in range(plugin.get_num_ports())): types, info = fill_port_info(p) info['index'] = index index += 1 isInput = "Input" in types types.remove("Input" if isInput else "Output") for typ in [typl.lower() for typl in types]: if typ not in ports.keys(): ports[typ] = { 'input': [], 'output': [] } ports[typ]["input" if isInput else "output"].append(info) # -------------------------------------------------------------------------------------------------------- # presets def get_preset_data(preset): world.load_resource(preset.me) uri = preset.as_string() or "" label = world.find_nodes(preset.me, ns_rdfs.label.me, None).get_first().as_string() or "" if not uri: errors.append("preset with label '%s' has no uri" % (label or "<unknown>")) if not label: errors.append("preset with uri '%s' has no label" % (uri or "<unknown>")) return { 'uri': uri, 'label': label } presetsrel = plugin.get_related(ns_pset.Preset) presets = list(LILV_FOREACH(presetsrel, get_preset_data)) del presetsrel # -------------------------------------------------------------------------------------------------------- # done return { 'uri' : uri, 'name': name, 'binary' : binary, 'brand' : brand, 'label' : label, 'license': license, 'comment': comment, 'category' : get_category(plugin.get_value(ns_rdf.type_)), 'microVersion': microVersion, 'minorVersion': minorVersion, 'version' : version, 'stability': stability, 'author' : author, 'bundles': bundles, 'gui' : gui, 'ports' : ports, 'presets': presets, 'errors' : errors, 'warnings': warnings, }
def remove_bundle_to_lilv_world(bundlepath, returnPlugins=False): global W, BUNDLES, PLUGINS, PLUGNFO, PLUGNFOk # lilv wants the last character as the separator if not bundlepath.endswith(os.sep): bundlepath += os.sep # stop now if bundle is not loaded if bundlepath not in BUNDLES: return [] if returnPlugins else False # In case returnPlugins is used removedPlugins = [] # remove from loaded list BUNDLES.remove(bundlepath) # remove all plugins that are present on that bundle for p in PLUGINS: uri = p.get_uri().as_uri() if uri not in PLUGNFOk: continue bundles = lilv.lilv_plugin_get_data_uris(p.me) it = lilv.lilv_nodes_begin(bundles) while not lilv.lilv_nodes_is_end(bundles, it): bundle = lilv.lilv_nodes_get(bundles, it) it = lilv.lilv_nodes_next(bundles, it) if bundle is None: continue if not lilv.lilv_node_is_uri(bundle): continue bundle = os.path.dirname( lilv.lilv_uri_to_path(lilv.lilv_node_as_uri(bundle))) if not bundle.endswith(os.sep): bundle += os.sep if bundlepath != bundle: continue PLUGNFOk.remove(uri) PLUGNFO.pop(uri) if returnPlugins: removedPlugins.append(uri) # convert bundle string into a lilv node bundlenode = lilv.lilv_new_file_uri(W.me, None, bundlepath) # unload the bundle lilv.lilv_world_unload_bundle(W.me, bundlenode) # free bundlenode, no longer needed lilv.lilv_node_free(bundlenode) # refresh lilv plugins PLUGINS = W.get_all_plugins() return removedPlugins if returnPlugins else True
from mod.lilvlib import LILV_FOREACH, get_category, get_port_unit # LILV stuff W = lilv.World() W.load_all() PLUGINS = W.get_all_plugins() BUNDLES = [] # Make a list of all installed bundles for p in PLUGINS: bundles = lilv.lilv_plugin_get_data_uris(p.me) it = lilv.lilv_nodes_begin(bundles) while not lilv.lilv_nodes_is_end(bundles, it): bundle = lilv.lilv_nodes_get(bundles, it) it = lilv.lilv_nodes_next(bundles, it) if bundle is None: continue if not lilv.lilv_node_is_uri(bundle): continue bundle = os.path.dirname(lilv.lilv_uri_to_path(lilv.lilv_node_as_uri(bundle))) if not bundle.endswith(os.sep): bundle += os.sep if bundle not in BUNDLES:
def get_pedalboard_info(bundle): # lilv wants the last character as the separator bundle = os.path.abspath(bundle) if not bundle.endswith(os.sep): bundle += os.sep # Create our own unique lilv world # We'll load a single bundle and get all plugins from it world = lilv.World() # this is needed when loading specific bundles instead of load_all # (these functions are not exposed via World yet) lilv.lilv_world_load_specifications(world.me) lilv.lilv_world_load_plugin_classes(world.me) # convert bundle string into a lilv node bundlenode = lilv.lilv_new_file_uri(world.me, None, bundle) # load the bundle world.load_bundle(bundlenode) # free bundlenode, no longer needed lilv.lilv_node_free(bundlenode) # get all plugins in the bundle plugins = world.get_all_plugins() # make sure the bundle includes 1 and only 1 plugin (the pedalboard) if plugins.size() != 1: raise Exception( 'get_pedalboard_info(%s) - bundle has 0 or > 1 plugin'.format( bundle)) # no indexing in python-lilv yet, just get the first item plugin = None for p in plugins: plugin = p break if plugin is None: raise Exception( 'get_pedalboard_info(%s) - failed to get plugin, you are using an old lilv!' .format(bundle)) # define the needed stuff ns_rdf = NS(world, lilv.LILV_NS_RDF) ns_lv2core = NS(world, lilv.LILV_NS_LV2) ns_ingen = NS(world, "http://drobilla.net/ns/ingen#") ns_modpedal = NS(world, "http://moddevices.com/ns/modpedal#") # check if the plugin is a pedalboard def fill_in_type(node): return node.as_string() plugin_types = [ i for i in LILV_FOREACH(plugin.get_value(ns_rdf.type_), fill_in_type) ] if "http://moddevices.com/ns/modpedal#Pedalboard" not in plugin_types: raise Exception( 'get_pedalboard_info(%s) - plugin has no mod:Pedalboard type'. format(bundle)) # let's get all the info now ingenarcs = [] ingenblocks = [] info = { 'name': plugin.get_name().as_string(), 'uri': plugin.get_uri().as_string(), 'author': plugin.get_author_name().as_string() or "", # Might be empty 'hardware': { # we save this info later 'audio': { 'ins': 0, 'outs': 0 }, 'cv': { 'ins': 0, 'outs': 0 }, 'midi': { 'ins': 0, 'outs': 0 } }, 'size': { 'width': plugin.get_value(ns_modpedal.width).get_first().as_int(), 'height': plugin.get_value(ns_modpedal.height).get_first().as_int(), }, 'screenshot': os.path.basename( plugin.get_value(ns_modpedal.screenshot).get_first().as_string() or ""), 'thumbnail': os.path.basename( plugin.get_value(ns_modpedal.thumbnail).get_first().as_string() or ""), 'connections': [], # we save this info later 'plugins': [] # we save this info later } # connections arcs = plugin.get_value(ns_ingen.arc) it = arcs.begin() while not arcs.is_end(it): arc = arcs.get(it) it = arcs.next(it) if arc.me is None: continue head = lilv.lilv_world_get(world.me, arc.me, ns_ingen.head.me, None) tail = lilv.lilv_world_get(world.me, arc.me, ns_ingen.tail.me, None) if head is None or tail is None: continue ingenarcs.append({ "source": lilv.lilv_uri_to_path(lilv.lilv_node_as_string(tail)).replace( bundle, "", 1), "target": lilv.lilv_uri_to_path(lilv.lilv_node_as_string(head)).replace( bundle, "", 1) }) # hardware ports handled_port_uris = [] ports = plugin.get_value(ns_lv2core.port) it = ports.begin() while not ports.is_end(it): port = ports.get(it) it = ports.next(it) if port.me is None: continue # check if we already handled this port port_uri = port.as_uri() if port_uri in handled_port_uris: continue if port_uri.endswith("/control_in") or port_uri.endswith( "/control_out"): continue handled_port_uris.append(port_uri) # get types port_types = lilv.lilv_world_find_nodes(world.me, port.me, ns_rdf.type_.me, None) if port_types is None: continue portDir = "" # input or output portType = "" # atom, audio or cv it2 = lilv.lilv_nodes_begin(port_types) while not lilv.lilv_nodes_is_end(port_types, it2): port_type = lilv.lilv_nodes_get(port_types, it2) it2 = lilv.lilv_nodes_next(port_types, it2) if port_type is None: continue port_type_uri = lilv.lilv_node_as_uri(port_type) if port_type_uri == "http://lv2plug.in/ns/lv2core#InputPort": portDir = "input" elif port_type_uri == "http://lv2plug.in/ns/lv2core#OutputPort": portDir = "output" elif port_type_uri == "http://lv2plug.in/ns/lv2core#AudioPort": portType = "audio" elif port_type_uri == "http://lv2plug.in/ns/lv2core#CVPort": portType = "cv" elif port_type_uri == "http://lv2plug.in/ns/ext/atom#AtomPort": portType = "atom" if not (portDir or portType): continue if portType == "audio": if portDir == "input": info['hardware']['audio']['ins'] += 1 else: info['hardware']['audio']['outs'] += 1 elif portType == "atom": if portDir == "input": info['hardware']['midi']['ins'] += 1 else: info['hardware']['midi']['outs'] += 1 elif portType == "cv": if portDir == "input": info['hardware']['cv']['ins'] += 1 else: info['hardware']['cv']['outs'] += 1 # plugins blocks = plugin.get_value(ns_ingen.block) it = blocks.begin() while not blocks.is_end(it): block = blocks.get(it) it = blocks.next(it) if block.me is None: continue protouri1 = lilv.lilv_world_get(world.me, block.me, ns_lv2core.prototype.me, None) protouri2 = lilv.lilv_world_get(world.me, block.me, ns_ingen.prototype.me, None) if protouri1 is not None: proto = protouri1 elif protouri2 is not None: proto = protouri2 else: continue instance = lilv.lilv_uri_to_path(lilv.lilv_node_as_string( block.me)).replace(bundle, "", 1) uri = lilv.lilv_node_as_uri(proto) enabled = lilv.lilv_world_get(world.me, block.me, ns_ingen.enabled.me, None) minorver = lilv.lilv_world_get(world.me, block.me, ns_lv2core.minorVersion.me, None) microver = lilv.lilv_world_get(world.me, block.me, ns_lv2core.microVersion.me, None) ingenblocks.append({ "instance": instance, "uri": uri, "x": lilv.lilv_node_as_float( lilv.lilv_world_get(world.me, block.me, ns_ingen.canvasX.me, None)), "y": lilv.lilv_node_as_float( lilv.lilv_world_get(world.me, block.me, ns_ingen.canvasY.me, None)), "enabled": lilv.lilv_node_as_bool(enabled) if enabled is not None else False, "minorVersion": lilv.lilv_node_as_int(minorver) if minorver else 0, "microVersion": lilv.lilv_node_as_int(microver) if microver else 0, }) info['connections'] = ingenarcs info['plugins'] = ingenblocks return info
def remove_bundle_to_lilv_world(bundlepath, returnPlugins = False): global W, BUNDLES, PLUGINS, PLUGNFO, PLUGNFOk # lilv wants the last character as the separator if not bundlepath.endswith(os.sep): bundlepath += os.sep # stop now if bundle is not loaded if bundlepath not in BUNDLES: return [] if returnPlugins else False # In case returnPlugins is used removedPlugins = [] # remove from loaded list BUNDLES.remove(bundlepath) # remove all plugins that are present on that bundle for p in PLUGINS: uri = p.get_uri().as_uri() if uri not in PLUGNFOk: continue bundles = lilv.lilv_plugin_get_data_uris(p.me) it = lilv.lilv_nodes_begin(bundles) while not lilv.lilv_nodes_is_end(bundles, it): bundle = lilv.lilv_nodes_get(bundles, it) it = lilv.lilv_nodes_next(bundles, it) if bundle is None: continue if not lilv.lilv_node_is_uri(bundle): continue bundle = os.path.dirname(lilv.lilv_uri_to_path(lilv.lilv_node_as_uri(bundle))) if not bundle.endswith(os.sep): bundle += os.sep if bundlepath != bundle: continue PLUGNFOk.remove(uri) PLUGNFO.pop(uri) if returnPlugins: removedPlugins.append(uri) # convert bundle string into a lilv node bundlenode = lilv.lilv_new_file_uri(W.me, None, bundlepath) # unload the bundle lilv.lilv_world_unload_bundle(W.me, bundlenode) # free bundlenode, no longer needed lilv.lilv_node_free(bundlenode) # refresh lilv plugins PLUGINS = W.get_all_plugins() return removedPlugins if returnPlugins else True