libpipewire-module-filter-chain(7) | Miscellaneous Information Manual | libpipewire-module-filter-chain(7) |
libpipewire-module-filter-chain - Filter-Chain
The filter-chain allows you to create an arbitrary processing graph from LADSPA, LV2 and builtin filters.
This filter can be made into a virtual sink/source or between any 2 nodes in the graph.
The filter chain is built with 2 streams, a capture stream providing the input to the filter chain and a playback stream sending out the filtered stream to the next nodes in the graph.
Because both ends of the filter-chain are built with streams, the session manager can manage the configuration and connection with the sinks and sources automatically.
libpipewire-module-filter-chain
The general structure of the graph description is as follows:
filter.graph = { nodes = [ { type = <ladspa | lv2 | builtin | sofa> name = <name> plugin = <plugin> label = <label> config = { <configkey> = <value> ... } control = { <controlname|controlindex> = <value> ... } } ... ] links = [ { output = <portname> input = <portname> } ... ] inputs = [ <portname> ... ] outputs = [ <portname> ... ] capture.volumes = [ { control = <portname> min = <value> max = <value> scale = <scale> } ... ] playback.volumes = [ { control = <portname> min = <value> max = <value> scale = <scale> } ... ] }
Nodes describe the processing filters in the graph. Use a tool like lv2ls or listplugins to get a list of available plugins, labels and the port names.
Links can be made between ports of nodes. The portname is given as <node_name>:<port_name>.
You can tee the output of filters to multiple other filters. You need to use a mixer if you want the output of multiple filters to go into one filter input port.
links can be omited when the graph has just 1 filter.
These are the entry and exit ports into the graph definition. Their number defines the number of channels used by the filter-chain.
The <portname> can be null when a channel is to be ignored.
Each input/output in the graph can only be linked to one filter input/output. You need to use the copy builtin filter if the stream signal needs to be routed to multiple filters. You need to use the mixer builtin plugin if multiple graph outputs need to go to one output stream.
inputs and outputs can be omitted, in which case the filter-chain will use all inputs from the first filter and all outputs from the last filter node. The graph will then be duplicated as many times to match the number of input/output channels of the streams.
Normally the volume of the sink/source is handled by the stream software volume. With the capture.volumes and playback.volumes properties this can be handled by a control port in the graph instead. Use capture.volumes for the volume of the input of the filter (when for example used as a sink). Use playback,volumes for the volume of the output of the filter (when for example used as a source).
The min and max values (defaults 0.0 and 1.0) respectively can be used to scale and translate the volume min and max values.
Normally the control values are linear and it is assumed that the plugin does not perform any scaling to the values. This can be changed with the scale property. By default this is linear but it can be set to cubic when the control applies a cubic transformation.
There are some useful builtin filters available. You select them with the label of the filter node.
Use the mixer plugin if you have multiple input signals that need to be mixed together.
The mixer plugin has up to 8 input ports labeled 'In 1' to 'In 8' and each with a gain control labeled 'Gain 1' to 'Gain 8'. There is an output port labeled 'Out'. Unused input ports will be ignored and not cause overhead.
Use the copy plugin if you need to copy a stream input signal to multiple filters.
It has one input port 'In' and one output port 'Out'.
Biquads can be used to do all kinds of filtering. They are also used when creating equalizers.
All biquad filters have an input port 'In' and an output port 'Out'. They have a 'Freq', 'Q' and 'Gain' control. Their meaning depends on the particular biquad that is used. The biquads also have 'b0', 'b1', 'b2', 'a0', 'a1' and 'a2' ports that are read-only except for the bq_raw biquad, which can configure default values depending on the graph rate and change those at runtime.
We refer to https://arachnoid.com/BiQuadDesigner/index.html for an explanation of the controls.
The following labels can be used:
filter.graph = { nodes = [ { type = builtin name = ... label = bq_raw config = { coefficients = [ { rate = 44100, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }, { rate = 48000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }, { rate = 192000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. } ] } ... } } ... }
The convolver can be used to apply an impulse response to a signal. It is usually used for reverbs or virtual surround. The convolver is implemented with a fast FFT implementation.
The convolver has an input port 'In' and an output port 'Out'. It requires a config section in the node declaration in this format:
filter.graph = { nodes = [ { type = builtin name = ... label = convolver config = { blocksize = ... tailsize = ... gain = ... delay = ... filename = ... offset = ... length = ... channel = ... resample_quality = ... } ... } } ... }
The delay can be used to delay a signal in time.
The delay has an input port 'In' and an output port 'Out'. It also has a 'Delay (s)' control port. It requires a config section in the node declaration in this format:
filter.graph = { nodes = [ { type = builtin name = ... label = delay config = { "max-delay" = ... } control = { "Delay (s)" = ... } ... } } ... }
The invert plugin can be used to invert the phase of the signal.
It has an input port 'In' and an output port 'Out'.
The clamp plugin can be used to clamp samples between min and max values.
It has an input port 'In' and an output port 'Out'. It also has a 'Control' and 'Notify' port for the control values.
The final result is clamped to the 'Min' and 'Max' control values.
The linear plugin can be used to apply a linear transformation on samples or control values.
It has an input port 'In' and an output port 'Out'. It also has a 'Control' and 'Notify' port for the control values.
The control value 'Mult' and 'Add' are used to configure the linear transform. Each sample or control value will be calculated as: new = old * Mult + Add.
The recip plugin can be used to calculate the reciprocal (1/x) of samples or control values.
It has an input port 'In' and an output port 'Out'. It also has a 'Control' and 'Notify' port for the control values.
The exp plugin can be used to calculate the exponential (base^x) of samples or control values.
It has an input port 'In' and an output port 'Out'. It also has a 'Control' and 'Notify' port for the control values.
The control value 'Base' is used to calculate base ^ x for each sample.
The log plugin can be used to calculate the logarithm of samples or control values.
It has an input port 'In' and an output port 'Out'. It also has a 'Control' and 'Notify' port for the control values.
The control value 'Base', 'M1' and 'M2' are used to calculate out = M2 * log2f(fabsf(in * M1)) / log2f(Base) for each sample.
The mult plugin can be used to multiply samples together.
It has 8 input ports named 'In 1' to 'In 8' and an output port 'Out'.
All input ports samples are multiplied together into the output. Unused input ports will be ignored and not cause overhead.
The sine plugin generates a sine wave.
It has an output port 'Out' and also a control output port 'notify'.
There is an optional builtin SOFA filter available.
The spatializer can be used to place the sound in a 3D space.
The spatializer has an input port 'In' and a stereo pair of output ports called 'Out L' and 'Out R'. It requires a config section in the node declaration in this format:
The control can be changed at runtime to move the sounds around in the 3D space.
filter.graph = { nodes = [ { type = sofa name = ... label = spatializer config = { blocksize = ... tailsize = ... filename = ... } control = { "Azimuth" = ... "Elevation" = ... "Radius" = ... } ... } } ... }
Options with well-known behavior. Most options can be added to the global configuration or the individual streams:
Stream only properties:
This example uses the rnnoise LADSPA plugin to create a new virtual source.
context.modules = [ { name = libpipewire-module-filter-chain args = { node.description = "Noise Canceling source" media.name = "Noise Canceling source" filter.graph = { nodes = [ { type = ladspa name = rnnoise plugin = ladspa/librnnoise_ladspa label = noise_suppressor_stereo control = { "VAD Threshold (%)" 50.0 } } ] } capture.props = { node.name = "capture.rnnoise_source" node.passive = true } playback.props = { node.name = "rnnoise_source" media.class = Audio/Source } } } ]
This example uses the ladpsa surround encoder to encode a 5.1 signal to a stereo Dolby Surround signal.
\code{.unparsed} context.modules = [ { name = libpipewire-module-filter-chain args = { node.description = "Dolby Surround Sink" media.name = "Dolby Surround Sink" filter.graph = { nodes = [ { type = builtin name = mixer label = mixer control = { "Gain 1" = 0.5 "Gain 2" = 0.5 } } { type = ladspa name = enc plugin = surround_encoder_1401 label = surroundEncoder } ] links = [ { output = "mixer:Out" input = "enc:S" } ] inputs = [ "enc:L" "enc:R" "enc:C" null "mixer:In 1" "mixer:In 2" ] outputs = [ "enc:Lt" "enc:Rt" ] } capture.props = { node.name = "effect_input.dolby_surround" media.class = Audio/Sink audio.channels = 6 audio.position = [ FL FR FC LFE SL SR ] } playback.props = { node.name = "effect_output.dolby_surround" node.passive = true audio.channels = 2 audio.position = [ FL FR ] } } } ]
1.0.5 | PipeWire |