Provided by: libpipewire-0.3-modules_1.2.7-1_amd64 bug

NAME

       libpipewire-module-filter-chain - Filter-Chain

DESCRIPTION

       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.

MODULE NAME

       libpipewire-module-filter-chain

MODULE OPTIONS

       • node.description: a human readable name for the filter chain

       • filter.graph = []: a description of the filter graph to run, see below

       • capture.props = {}: properties to be passed to the input stream

       • playback.props = {}: properties to be passed to the output stream

FILTER GRAPH DESCRIPTION

       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
       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.

       • type is one of ladspa, lv2, builtin or sofa.

       • name is the name for this node, you might need this later to refer to this node and its
         ports when setting controls or making links.

       • plugin is the type specific plugin name.

         • For LADSPA plugins it will append .so to find the shared object with that name in the
           LADSPA plugin path.

         • For LV2, this is the plugin URI obtained with lv2ls.

         • For builtin and sofa this is ignored

       • label is the type specific filter inside the plugin.

         • For LADSPA this is the label

         • For LV2 this is unused

         • For builtin and sofa this is the name of the filter to use

       • config contains a filter specific configuration section. Some plugins need this.
         (convolver, sofa, delay, ...)

       • control contains the initial values for the control ports of the filter. normally these
         are given with the port name but it is also possible to give the control index as the
         key.

   Links
       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 omitted when the graph has just 1 filter.

   Inputs and Outputs
       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.

   Volumes
       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.

BUILTIN FILTERS

       There are some useful builtin filters available. You select them with the label of the
       filter node.

   Mixer
       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.

   Copy
       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
       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:

       • bq_lowpass a lowpass filter.

       • bq_highpass a highpass filter.

       • bq_bandpass a bandpass filter.

       • bq_lowshelf a low shelf filter.

       • bq_highshelf a high shelf filter.

       • bq_peaking a peaking filter.

       • bq_notch a notch filter.

       • bq_allpass an allpass filter.

       • bq_raw a raw biquad filter. You need a config section to specify coefficients per sample
         rate. The coefficients of the sample rate closest to the graph rate are selected:

       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=.. }
                       ]
                   }
                   ...
               }
           }
           ...
       }

   Convolver
       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 = ...
                   }
                   ...
               }
           }
           ...
       }

       • blocksize specifies the size of the blocks to use in the FFT. It is a value between 64
         and 256. When not specified, this value is computed automatically from the number of
         samples in the file.

       • tailsize specifies the size of the tail blocks to use in the FFT.

       • gain the overall gain to apply to the IR file.

       • delay The extra delay (in samples) to add to the IR.

       • filename The IR to load or create. Possible values are:

         • /hilbert creates a hilbert function that can be used to phase shift the signal by
           +/-90 degrees. The length will be used as the number of coefficients.

         • /dirac creates a Dirac function that can be used as gain.

         • A filename to load as the IR. This needs to be a file format supported by sndfile.

         • [ filename, ... ] an array of filenames. The file with the closest samplerate match
           with the graph samplerate will be used.

       • offset The sample offset in the file as the start of the IR.

       • length The number of samples to use as the IR.

       • channel The channel to use from the file as the IR.

       • resample_quality The resample quality in case the IR does not match the graph
         samplerate.

   Delay
       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)" = ...
                   }
                   ...
               }
           }
           ...
       }

       • max-delay the maximum delay in seconds. The 'Delay (s)' parameter will be clamped to
         this value.

   Invert
       The invert plugin can be used to invert the phase of the signal.

       It has an input port 'In' and an output port 'Out'.

   Clamp
       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.

   Linear
       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.

   Reciprocal
       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.

   Exp
       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.

   Log
       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.

   Multiply
       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.

   Sine
       The sine plugin generates a sine wave.

       It has an output port 'Out' and also a control output port 'notify'.

SOFA FILTER

       There is an optional builtin SOFA filter available.

   Spatializer
       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" = ...
                   }
                   ...
               }
           }
           ...
       }

       • blocksize specifies the size of the blocks to use in the FFT. It is a value between 64
         and 256. When not specified, this value is computed automatically from the number of
         samples in the file.

       • tailsize specifies the size of the tail blocks to use in the FFT.

       • filename The SOFA file to load. SOFA files usually end in the .sofa extension and
         contain the HRTF for the various spatial positions.

       • Azimuth controls the azimuth, this is the direction the sound is coming from in degrees
         between 0 and 360. 0 is straight ahead. 90 is left, 180 behind, 270 right.

       • Elevation controls the elevation, this is how high/low the signal is in degrees between
         -90 and 90. 0 is straight in front, 90 is directly above and -90 directly below.

       • Radius controls how far away the signal is as a value between 0 and 100. default is 1.0.

GENERAL OPTIONS

       Options with well-known behavior. Most options can be added to the global configuration or
       the individual streams:

       • remote.nameaudio.rateaudio.channelsaudio.positionmedia.namenode.latencynode.descriptionnode.groupnode.link.groupnode.virtualnode.name : See notes below. If not specified, defaults to 'filter-chain-PID-MODULEID'.

       Stream only properties:

       • media.classnode.name : if not given per stream, the global node.name will be prefixed with 'input.'
         and 'output.' to generate a capture and playback stream node.name respectively.

EXAMPLE CONFIGURATION OF A VIRTUAL SOURCE

       This example uses the rnnoise LADSPA plugin to create a new virtual source.

       Run with pipewire -c filter-chain.conf. The configuration can also be put under
       pipewire.conf.d/ to run it inside the PipeWire server.

       # ~/.config/pipewire/filter-chain.conf.d/my-filter-chain-1.conf

       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
               }
           }
       }
       ]

EXAMPLE CONFIGURATION OF A DOLBY SURROUND ENCODER VIRTUAL SINK

       This example uses the ladpsa surround encoder to encode a 5.1 signal to a stereo Dolby
       Surround signal.

       # ~/.config/pipewire/filter-chain.conf.d/my-filter-chain-2.conf

       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 ]
               }
           }
       }
       ]