skip to Main Content

Better Stereo to 5.1 upmix on Linux/ALSA/.asoundrc

Recently, I discovered how to generate a perfect 5.1 upmix out of a stereo signal on Microsoft Windows. I also wanted to do this on Linux which is way more complicated and involves editing a text file called .asoundrc. But it also has much more power when done right! :) I wanted to be able to achieve six cases:

  1. Handle all sources by standard. Mono, Stereo, Surround get to their according speakers. This is easy, because it’s the default in ALSA.
  2. Upmix a stereo source with two channels to six channels
  3. Use a surround source with six channels, but take the two front channels (stereo) and additionally, send them to the subwoofer.
  4. Have a volume controller that works for all three situations above.
  5. Have an extra recording device for my (mono) webcam.
  6. Get this working with OSS, too.

Update 24.08.2014:  Tobias told me about the FreeSurround plugin that makes upmixing stereo sources to surround a piece of cake. I incorporated this plugin into my .asoundrc. Thanks for that! :)

Why number 3? Because some movies (especially from the 80’s) are poorly mixed and the sub channel is way too soft (or consists of pure nothingness). I don’t have an amplifier, I can only send one channel to my sub and it eats it! Oldschool, I know. It’s nearly perfect – at the moment my subwoofer gets the whole frequency range which doesn’t always sound right – my next goal will be incorporating a low-pass filter using LADSPA into this config file to have the perfect sound. So, here it is – just place it in your home directory as .asoundrc and uncomment the devices you want to use in the pcm.duplex part:

#Define the default device via "aplay -l"
#My CM6206 is hw2:0
pcm.snd_card {
        type hw
        card 2
        device 0
}

#Define the default control
ctl.snd_card {
        type hw
        card 2
        device 0
}

#The following section generates a "Master" volume control
#My C-Media sound card doesn't have one so this is useful.
#If your soundcard isn't crap and already has a master volume control,
#choose: slave.pcm "duplex"
#and remove the pcm.softvol part
pcm.!default {
    type            plug
    slave.pcm       "softvol"
}

pcm.softvol {
    type            softvol
    slave {
	#redirects the output to duplex (instead of "hw:2,0"):
        pcm         "duplex"
    }
    control {
        name        "Master"
        card        2
    }
}

#This is the important section where choices have to be made.
#Do you want upmix, simple stereo or something other?
pcm.duplex {
    type asym
	# --This for the FreeSurround ALSA plugin you can find here:--
    # http://micosphere.free.fr/freesurround-alsa/downloads.html
    # This plugin makes all decisions for you.
    #  playback.pcm "freesurround"
    # --The following methods are traditional-- 
    # Upmix a stereo source to six speakers
    # Front Left and Front Right get duplicated to all others:
       playback.pcm "upmix"
    # When having a true 5.1 channel source, use dmixer:
    #  playback.pcm "dmixer"
    # When having a 5.1 channel source with a poor LFE channel, use this
    # It takes left and right and sends it to the sub
	# without touching the other channels:
    #  playback.pcm "51withsub"
    # stereo recording device
       capture.pcm "dsnooper"
    # mono (webcam) recording device
    #  capture.pcm "webcam"
}

#dmixer is the "central hub" that routes everything
# to the correct speaker as we defined it in "pcm.duplex"
pcm.dmixer {
    type dmix
    ipc_key 1024
    ipc_perm 0666
    slave.pcm "snd_card"
    slave {
        period_time 0
        period_size 1024
        buffer_size 4096
        channels 6
    }
    bindings {
        0 0
        1 1
        2 2
        3 3
        4 4
        5 5
    }
}

#This controls the recording device. It is only stereo and thus
#doesn't require anything fancy
pcm.dsnooper {
    type dsnoop
    ipc_key 2048
    ipc_perm 0666 
    slave.pcm "snd_card"
    slave 
    {
        period_time 0
        period_size 1024
        buffer_size 4096
        channels 2
    }
    bindings {
        0 0
        1 1
    }
}

#I have a mono webcam, that needs this to get audio
# working in Skype etc.
pcm.webcam {
    type dsnoop
    ipc_key 4096
    ipc_perm 0666 
    slave.pcm "hw:3,0" #found webcam via aplay -l
    slave 
    {
        channels 1
    }
    bindings {
        0 0
    }
}

# This for the FreeSurround ALSA plugin you can find here:
# http://micosphere.free.fr/freesurround-alsa/downloads.html
pcm.freesurround {
     type freesurround
     slave.pcm "snd_card" #surround51 for built-in default
}

# These are the custom routings I specified.
# Every speaker can be routed to another speaker,
# signals can be mixed etc.
pcm.upmix {
     type route
     slave.pcm dmixer
     slave.channels 6
     ttable.0.0 1 #left
     ttable.1.1 1 #right
     ttable.0.2 0.5 #half left to center
     ttable.1.2 0.5 #half right to center
     ttable.0.3 0.5 #half left to sub
     ttable.1.3 0.5 #half right to sub
     ttable.0.4 1 #left to rear left
     ttable.1.5 1 #right to rear right
}

pcm.51withsub {
     type route
     slave.pcm dmixer
     slave.channels 6
     ttable.0.0 1	#left
     ttable.1.1 1	#right
     ttable.2.2 1	#center
     # ttable.3.3 1	#sub
     ttable.4.4 1	#rear left
     ttable.5.5 1	#rear right
     # half left and half right to sub
     ttable.0.3 0.5
     ttable.1.3 0.5
}

#Old stuff: for OSS compatibility using the aoss wrapper:
pcm.dsp0 {
    type plug
    slave.pcm "!default"
}

This Post Has 6 Comments

  1. This is awesome! Thank you.

    I just made the switch from my Windows 7 to Linux Mint 16.
    There is one difference though:

    “Speaker Fill” on the Hardware does some calculation and only mixes sound on L [AND] R to Center. Like a logical AND, you can only hear what is on both speakers and this way – in our real world – in the center.

    Also, it routes sound only to the surround speakers, if it is not present on the opposite speaker. kinda like: L [AND NOT] R goes to SurroundLeft and likewise. This way, left-panned sounds will feel like behind you, which is also very natural.

    Is there a way to achive this behavior? It is pure maths and logic, but I have no idea how to get this into a plugin or .asoundrc

    Thanks for your great work! I’m looking forward to your answer, gerne auch auf deutsch 😉

    (See also my StackExchange Thread in the URL Field)

    1. Hi,

      I kinda incorporated that in a cheap way in the upmix section:

      ttable.0.0 1 #left
      ttable.1.1 1 #right
      ttable.0.2 1 #left to center
      ttable.1.3 1 #right to sub
      ttable.0.4 0.5 #left to rear left
      ttable.1.4 0.5 #right to rear left
      ttable.0.5 0.5 #left to rear right
      ttable.1.5 0.5 #right to rear right
      }

      You can at least modify that in a way that you only get front left to rear left or you can mix the two front channels into center where I chose to send the left channel to the center and the right one to the subwoofer. That would be something like this:

      ttable.0.0 1 #left
      ttable.1.1 1 #right
      ttable.0.2 0.5 #half left to center
      ttable.1.2 0.5 #half right to center
      ttable.0.3 0.5 #half left to sub
      ttable.1.3 0.5 #half right to sub
      ttable.0.4 1 #left to rear left
      ttable.1.5 1 #right to rear right
      }

      If you want to compare two channels and only send things to one channel that are not present on the other channel you can only achieve that with a LADSPA plugin. If anyone ever wrote such a plugin, I don’t know of that (yet). I’m still figuring out how to use a low-pass filter in there, so I’m not that “into” the topic of LADSPA myself. Good luck! 🙂

    1. That plugin is awesome! Thanks 🙂

      I had trouble building it on Slackware, because it uses /usr/lib64 for ALSA. Changed all references in the Makefile from /usr/lib to /usr/lib64 and now it runs.

      I made the following changes in my asoundrc:

      1. In the “pcm.duplex” section I added a new line:
      playback.pcm "freesurround"

      2. I added a new section to start up FreeSound:
      pcm.freesurround {
      type freesurround
      slave.pcm "snd_card" #surround51 for built-in default
      }

      That’s it! It works like a charme and using this way we can also retain the software volume control.

  2. Can’t get it to work – bummer. Exactly the point keeps me from using Linux for years. I just can’t get the upmix to work. Is there possibly a tutorial for beginners under Ubuntu 20.x

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top