Independent ALSA and linux audio support site

Low-pass filter for subwoofer channel (HOWTO)

From the ALSA wiki

Jump to: navigation, search

I have searched a long time for a solution to filter a single channel of a 5.1 output stream with ALSA. I wanted the channel to which the subwoofer is connected to be filtered by a low-pass filter. Without such a filter the sound from my subwoofer sounds a bit sludgy.


Important:The solution I am going to present below will only work with an ALSA library with a version higher or equal to 1.0.14rc2 (released 2007-01-16), because there was a bug with the 'policy none' behaviour in previous versions.


There is a patch against the Ubuntu feisty package (see changelog for version 1.0.13-1ubuntu2) so you can use that package and do not have to upgrade to a 1.0.14 version if you are using Ubuntu feisty.


Important:There is a problem which makes the solution presented here unusable with alsa-lib version 1.0.14rc4 up to 1.0.14a. Here is a description of the problem and ALSA bug report number 0003106. You can use alsa-lib version 1.0.15rc1, that contains a fix for this bug, or newer or you can use the older alsa-lib version 1.0.14rc3 or below.


I created a configuration that takes a stereo (two channel) stream and mixes it up to a 5.1 (six channel) stream, where the channel for the subwoofer is low-pass filtered by a ladspa plugin.

Contents

ALSA configuration

Here is the content of my file /etc/asound.conf (you can use ~/.asoundrc instead):

pcm.upmix_20to51 {
    type plug
    slave.pcm lowpass_21to21
    slave.channels 3
    ttable {
        0.0     1       # left channel
        1.1     1       # right channel
        0.2     0.5     # mix left and right ...
        1.2     0.5     # ... channel for subwoofer
    }
}

pcm.lowpass_21to21 {
    type ladspa
    slave.pcm upmix_21to51
    path "/usr/lib/ladspa"
    channels 3
    plugins {
        0 {
            id 1098 # Identity (Audio) (1098/identity_audio)
            policy duplicate
            input.bindings.0 "Input";
            output.bindings.0 "Output";
        }
        1 {
            id 1672 # 4 Pole Low-Pass Filter with Resonance (FCRCIA) (1672/lp4pole_fcrcia_oa)
            policy none
            input.bindings.2 "Input";
            output.bindings.2 "Output";
            input {
                controls [ 300 2 ]
            }
        }
    }
}

pcm.upmix_21to51 {
    type plug
    slave.pcm surround51
    slave.channels 6
    ttable {
        0.0     1       # front left
        1.1     1       # front right
        0.2     1       # rear left
        1.3     1       # rear right
        0.4     0.5     # center
        1.4     0.5     # center
        2.5     1       # subwoofer
    }
}

On some systems (e. g. openSUSE x86_64) you have to change the path for the LADSPA plugins (e. g. to "/usr/lib64/ladspa").

Explanation

The PCM upmix_20to51 takes the input stream and mixes the two stereo channels together to a new third channel. The new channel is mixed by taking 0.5 of the left and 0.5 of the right channel. This third channel is the data for the subwoofer channel. These three channels are given to the next PCM.

The PCM lowpass_21to21 does the real filtering with the help of two LADSPA plugins. The identity plugin (id 1098) just copies all channels from the input to the output without changes. The second plugin, the low-pass plugin (id 1672) takes only the third channel, the subwoofer channel, and applies the low-pass filter to it. The first control value is the cutoff frequency in Hz and the second is the resonance (0.0 to 4.0). I have tried different values but these sound best with my subwoofer. The unchanged channels 0 and 1 together with the filtered channel 2 are given to the next PCM.

The PCM upmix_21to51 takes the three input channels and distributes them to channels of the slave PCM surround51. Maybe the channels of the slave PCM are connected to different speakers on other systems. I found these numbers by trial and error.

If you now start alsaplayer -d upmix_20to51 [mysong] or specify upmix_20to51 as default ALSA plugin for stereo output in your favourite audio player you should hear the upmixed, filtered sound from your speakers.

Required LADSPA packages

Yesterday I have got a mail from an ALSA user who had a problem getting this setup to work. His problem was that the LADSPA plugins were not found. Of course you have to install the LADSPA packages which contain these plugins. For the low-pass filter you have to install the BLOP plugin set (Debian package: blop; Gentoo package: blop; Ubuntu: blop) and for the identity plugin you need the Computer Music Toolkit (CMT) (Debian: cmt; Gentoo: ladspa-cmt; Ubuntu: cmt; Slackware 10.1: cmt).

Using dmix

To get dmix working with this configuration I added the following to my configuration file:

pcm.dmixer {
    type dmix
    ipc_key 1024
    slave {
        pcm "hw:0,0"
        period_time 0
        period_size 1024
        buffer_size 4096
        rate 44100
        channels 6
    }
    bindings {
        0 0
        1 1
        2 2
        3 3
        4 4
        5 5
    }
}

Then I changed the slave.pcm in upmix_21to51 to dmixer.

Troubleshooting

With certain ALSA versions, (especially, at as it seems, at least 1.0.17a and 1.0.18rc3) the plug plugin does not seem to perform automatic format and channel conversion. (You will get an error like "pcm_params.c:170: snd1_pcm_hw_param_get_min: Assertion `!snd_interval_empty(i)' failed") Thus, you will have to define more interfaces to do so manually, for example:

pcm.upmix_20to51 {
    type route # as automatic routing does not work, use type route
    slave.pcm lowpass_21to21_plug # 'route' outputs integer data, but float data is needed for ladspa.
                                  # the additional plug will output float data
    slave.channels 3
    ttable {
        0.0     1       # left channel
        1.1     1       # right channel
        0.2     0.5     # mix left and right ...
        1.2     0.5     # ... channel for subwoofer
    }
}

pcm.lowpass_21to21_plug {
    type plug
    slave.pcm "lowpass_21to21" # now, relay further to ladspa
}


pcm.lowpass_21to21 {
    type ladspa
    slave.pcm lowpass_float # ladspa will also output float data, but hw or route devices will need integer data
    path "/usr/lib/ladspa"
    channels 3
    plugins {
            # [...] nothing important here
    }
}

pcm.lowpass_float {
    type lfloat # converts from float to integer data
    slave {
        pcm "upmix_21to51" # your slave device here
        format "S16_LE"    # the format ladspa uses
    }
}

Questions?

If you have something to annotate, have improvements or it does not work for you, write on the discussion page or contact me.

--BlazE 05:15, 3 February 2007 (EST)

Retrieved from "http://alsa.opensrc.org/Low-pass_filter_for_subwoofer_channel_(HOWTO)"

Category: Howto