def fill_port_info(plugin, port): global index index += 1 # port types types = [typ.rsplit("#",1)[-1].replace("Port","",1) for typ in get_port_data(port, rdf.type_)] # unit block uunit = lilv.lilv_nodes_get_first(port.get_value(units.unit.me)) # contains unit if "Control" in types and 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/extensions/units#"): ulabel, urender, usymbol = get_port_unit(uuri.replace("http://lv2plug.in/ns/extensions/units#","",1)) # using custom unit else: xlabel = world.find_nodes(uunit, rdfs .label.me, None).get_first() xrender = world.find_nodes(uunit, units.render.me, None).get_first() xsymbol = world.find_nodes(uunit, units.symbol.me, None).get_first() ulabel = xlabel .as_string() if xlabel .me else "" urender = xrender.as_string() if xrender.me else "" usymbol = xsymbol.as_string() if xsymbol.me else "" # no unit else: ulabel = "" urender = "" usymbol = "" return { 'index' : index, 'name' : lilv.lilv_node_as_string(port.get_name()), 'symbol': lilv.lilv_node_as_string(port.get_symbol()), 'type' : types, 'range' : { 'default': lilv.lilv_node_as_float(lilv.lilv_nodes_get_first(port.get_value(lv2core.default.me))), 'minimum': lilv.lilv_node_as_float(lilv.lilv_nodes_get_first(port.get_value(lv2core.minimum.me))), 'maximum': lilv.lilv_node_as_float(lilv.lilv_nodes_get_first(port.get_value(lv2core.maximum.me))), } if ("Control", "Input") == types else {}, 'units' : { 'label' : ulabel, 'render': urender, 'symbol': usymbol, } if "Control" in types and (ulabel or urender or usymbol) else {}, 'designation': (get_port_data(port, lv2core.designation) or [None])[0], 'properties' : [typ.rsplit("#",1)[-1] for typ in get_port_data(port, lv2core.portProperty)], 'rangeSteps' : (get_port_data(port, pprops.rangeSteps) or [None])[0], "scalePoints": [], }
def generate_psname(self): portname = self.portname psname = lilv.lilv_nodes_get_first( self.port.get_value(self.ns_lv2core.shortName.me) ) if psname is not None: psname = lilv.lilv_node_as_string(psname) or "" if not psname: psname = self.get_short_port_name(portname) if len(psname) > Port.SHORT_NAME_SIZE: self.warnings.append("port '%s' name is too big, reduce the name size or provide a shortName" % portname) elif len(psname) > Port.SHORT_NAME_SIZE: psname = psname[:Port.SHORT_NAME_SIZE] self.register_error("short name has more than %d characters", Port.SHORT_NAME_SIZE) # check for old style shortName if self.port.get_value(self.ns_lv2core.shortname.me) is not None: self.register_error("short name is using old style 'shortname' instead of 'shortName'") return psname
def main(): # Read command line arguments if len(sys.argv) != 4: print('USAGE: lv2_apply.py PLUGIN_URI INPUT_WAV OUTPUT_WAV') sys.exit(1) # Initialise Lilv world = lilv.World() world.load_all() plugin_uri = sys.argv[1] wav_in_path = sys.argv[2] wav_out_path = sys.argv[3] # Find plugin plugin_uri_node = world.new_uri(plugin_uri) plugin = world.get_all_plugins().get_by_uri(plugin_uri_node) if not plugin: print("Unknown plugin `%s'\n" % plugin_uri) sys.exit(1) lv2_InputPort = world.new_uri(lilv.LILV_URI_INPUT_PORT) lv2_OutputPort = world.new_uri(lilv.LILV_URI_OUTPUT_PORT) lv2_AudioPort = world.new_uri(lilv.LILV_URI_AUDIO_PORT) lv2_ControlPort = world.new_uri(lilv.LILV_URI_CONTROL_PORT) lv2_default = world.new_uri("http://lv2plug.in/ns/lv2core#default") n_audio_in = plugin.get_num_ports_of_class(lv2_InputPort, lv2_AudioPort) n_audio_out = plugin.get_num_ports_of_class(lv2_OutputPort, lv2_AudioPort) if n_audio_out == 0: print("Plugin has no audio outputs\n") sys.exit(1) # Open input file try: wav_in = WavFile(wav_in_path) except: print("Failed to open input `%s'\n" % wav_in_path) sys.exit(1) if wav_in.nchannels != n_audio_in: print("Input has %d channels, but plugin has %d audio inputs\n" % ( wav_in.nchannels, n_audio_in)) sys.exit(1) # Open output file wav_out = wave.open(wav_out_path, 'w') if not wav_out: print("Failed to open output `%s'\n" % wav_out_path) sys.exit(1) # Set output file to same format as input (except possibly nchannels) wav_out.setparams(wav_in.wav_in.getparams()) wav_out.setnchannels(n_audio_out) print('%s => %s => %s @ %d Hz' % (wav_in_path, plugin.get_name(), wav_out_path, wav_in.framerate)) instance = lilv.Instance(plugin, wav_in.framerate) channels = wav_in.read() wav_in.close() # Connect all ports to buffers. NB if we fail to connect any buffer, lilv # will segfault. audio_input_buffers = [] audio_output_buffers = [] control_input_buffers = [] control_output_buffers = [] for index in range(plugin.get_num_ports()): port = plugin.get_port_by_index(index) if port.is_a(lv2_InputPort): if port.is_a(lv2_AudioPort): audio_input_buffers.append(numpy.array(channels[len(audio_input_buffers)], numpy.float32)) instance.connect_port(index, audio_input_buffers[-1]) elif port.is_a(lv2_ControlPort): #if port.has_property(lv2_default): # Doesn't seem to work default = lilv.lilv_node_as_float(lilv.lilv_nodes_get_first(port.get_value(lv2_default))) control_input_buffers.append(numpy.array([default], numpy.float32)) instance.connect_port(index, control_input_buffers[-1]) else: raise ValueError("Unhandled port type") elif port.is_a(lv2_OutputPort): if port.is_a(lv2_AudioPort): audio_output_buffers.append(numpy.array([0] * wav_in.nframes, numpy.float32)) instance.connect_port(index, audio_output_buffers[-1]) elif port.is_a(lv2_ControlPort): control_output_buffers.append(numpy.array([0], numpy.float32)) instance.connect_port(index, control_output_buffers[-1]) else: raise ValueError("Unhandled port type") # Run the plugin: instance.run(wav_in.nframes) # Interleave output buffers: data = numpy.dstack(audio_output_buffers).flatten() # Return to original int range: if wav_in.signed: data = data * float(wav_in.range / 2) else: data = (data + 1) * float(wav_in.range/2) # Write output file in chunks to stop memory usage getting out of hand: CHUNK_SIZE = 8192 for chunk in numpy.array_split(data, CHUNK_SIZE): wav_out.writeframes(wave.struct.pack("%u%s" % (len(chunk), wav_in.struct_fmt_code), *chunk)) wav_out.close()
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, })
def get_first_port_node(self, subject): return lilv.lilv_nodes_get_first(self.port.get_value(subject))
def unit(self, port): port_value = port.get_value(self.ns_units.unit.me) return lilv.lilv_nodes_get_first(port_value)