
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:
- Handle all sources by standard. Mono, Stereo, Surround get to their according speakers. This is easy, because it’s the default in ALSA.
- Upmix a stereo source with two channels to six channels
- Use a surround source with six channels, but take the two front channels (stereo) and additionally, send them to the subwoofer.
- Have a volume controller that works for all three situations above.
- Have an extra recording device for my (mono) webcam.
- 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 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)
Hi,
I kinda incorporated that in a cheap way in the upmix section:
ttable.0.0 1 #leftttable.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 #leftttable.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! 🙂
If you want real surround you can do this with freesurround ALSA plugin
http://micosphere.free.fr/?lang=en
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.
Do i have to disable pulse audio as i can still see my default chip is pulseaudio.
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