ALSA .asoundrc and asound.conf - configurations that have worked.

Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.
I have been thinking recently how useful it has been stumbling over others' footprint in Linux sound "snowscape". :)

There do seem to be problems in some areas... Notably data format requirements of the various plugins differ. And there seem to be some unhandled conditions that lead to "crap-outs" and rather obtuse messages rather than something useful.

So to start, I'll list my own configs that have - and still do, work.... Once I've booted the machines and extracted the data.

:)

J.
 
Raspberry Pi B rev2 512MB running MoOde Audio Player 2.7 and Charlie Laub's ACDf V2. (Also need package ladspa-sdk to "make" ACDf.)

Speakers are Woden Redeye with Aura NS3.
Filters are high shelf (baffle step) at 400hz. And Low shelf to boost HF (actually reduce everything else) at 8kHZ.

Source is 2 channel stereo ripped and compressed to MP3 and/or FLAC at 44.1kHZ. Player is MPD (MoOde Audio 2.7).

Ignore the default stuff, it's irrelevant as MPD audio_output names "plug:filter3".

Code:
pcm.!default { 
     type hw
     card 0 
} 

ctl.!default { 
     type hw
     card 0 
} 

pcm.filter3 {
     type ladspa
     slave.pcm speaker
     path "/usr/local/lib/ladspa"  # must indicate filter directory
     channels 2                    # two is default, other channel counts must be specified
     plugins
     {
          0 {        # must start with zero and not skip numbers in sequence
               label ACDf     # you could instead use the filter id number
               policy none
               input.bindings.0 "Input"     #input to filter is channel 0
               output.bindings.0 "Output"  #output from filter is channel 0
               input { controls [25 1 -3 400 0.707] } # 2nd order high shelf
          }
          1 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.1 "Output"
               input { controls [25 1 -3 400 0.707] }
          }
          2 {      
               label ACDf    
               policy none
               input.bindings.0 "Input"     
               output.bindings.0 "Output"  
               input { controls [24 1 -6 8000 0.707] } # 2nd order low shelf
          }
          3 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.1 "Output"
               input { controls [24 1 -6 8000 0.707] }
          }
     }
}

<snip>

pcm.speaker {
    type plug
    slave {
     pcm "hw:0,0"  
     channels 2
     rate "unchanged"
    }
}

pcm.plughw.slave.rate = "unchanged";
(END)
J.
 
Test setup of "Active" FAST speaker. 8" woofer with Vifa TC9 as FR driver.

Source setup same as above, 2 channel stereo from MPD through MoOde Audio Player 2.7.

Raspberry Pi3
Knockoff "HIFI DAC+" 2 channel PCM5122 HAT.
Breeze TPA3116 amplifier.
DIY MLTL containing -
Buyout 8" woofer (AT8030)
Vifa TC9 FR driver.

Idea is to downmix to mono resulting in two identical channels. One is processed for FR driver duty and the other for the woofer.

"plug:mixmono" named as output in MPD.

"pcm.xover" is needed between the "route" plugin and the "ladspa" plugin to adapt data formats between them (apparently.... anyway it didn't work without it).

Code:
<snip>

pcm.mixmono {
     type route
     slave.pcm xover
     slave.channels 2
     ttable {
     # mix left and right channels = 2 mono channels
     0.0 0.5
     1.0 0.5
     0.1 0.5
     1.1 0.5
     }
}

pcm.xover {
     type plug
     slave.pcm ladspa
}

pcm.ladspa {
     type ladspa
     slave.pcm speaker
     path "/usr/local/lib/ladspa"  # must indicate filter directory
     channels 2                    # two is default, other channel counts must $
     plugins
     {
          0 {
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.0 "Output"
               input { controls [5 1 -3 1000] } # 1st high shelf at 1000
          }
          1 {
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.0 "Output"
               input { controls [22 1 0 250 0.707] } # 2nd order high pass 250 hz
          }
          2 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.1 "Output"
               input { controls [0 1 -3] } # gain reduce on woofer
          }
          3 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.1 "Output"
               input { controls [21 1 0 190 0.707] } # 2nd order low pass 190 hz

          }
    }
}

pcm.speaker {
    type plug
    slave {
     pcm "hw:0,0"
     channels 2
     rate "unchanged"
    }
}

pcm.plughw.slave.rate = "unchanged";

J.
 
And finally.... the config that has had me headbutting the computer keyboard for 2 days....

Raspberry Pi3 running MoOde Audio Player V2.7. Through USB soundcard - CM6206LX 5.1. Dead cheap from eBay.

Raspberry Pi3
CM6206LX USB 5.1 soundcard
4 x TPA3118 "Sanwu blue" mono amplifiers. One per driver - i.e. 2 per speaker cabinet.
DIY MLTLs (2 of them) running AT8030 8" woofer and Vifa TC9 FR drivers.

Source material is MP3/FLAC 44.1kHZ stereo.

This looks rather different from what was working fine with the test mule (above). ALSA decided to sulk when I added the extra channels. :( .

This is what is working now. essentially the extra channels are created in the LADSPA plugin and their contents populated (ch 2,3) rather than setting it up beforehand in a "route" plugin. At the least it shows another way of doing things that may work for you if you get stuck.

The final "route" plugin is there to reduce gain/volume only (by a factor of 10). Without it, the volume control couldn't be used effectively as the setup became "too loud" below 20% of 100% volume.

Code:
<snip>
pcm.ladspa_xover {
     type ladspa
     slave.pcm out4way
     path "/usr/local/lib/ladspa"  # must indicate filter directory
     channels 4                    # two is default, other channel counts must $
     plugins
     {
          0 {
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.0 "Output"
               input { controls [5 1 -3 1000] } # 1st high shelf at 1000
          }
          1 {
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.0 "Output"
               input { controls [22 1 0 250 0.707] } # 2nd order high pass 250 hz
          }
          2 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.1 "Output"
               input { controls [0 1 -3] } # gain reduce on woofer
          }
          3 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.1 "Output"
               input { controls [21 1 0 190 0.707] } # 2nd order low pass 190 hz

          }
          4 {
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.2 "Output"
               input { controls [5 1 -3 1000] } # 1st high shelf at 1000
          }
          5 {
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.2 "Output"
               input { controls [22 1 0 250 0.707] } # 2nd order high pass 250 $
          }
          6 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.3 "Output"
               input { controls [0 1 -3] } # gain reduce on woofer
          }
          7 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.3 "Output"
               input { controls [21 1 0 190 0.707] } # 2nd order low pass 190 hz

          }
    }
}

pcm.out4way {
     type plug
     slave {
          pcm "vout4way"
          channels 4
     }
}     


pcm.vout4way {
     type route
     slave {
          pcm "hw:1,0"
          channels 4
     }
     ttable {
          0.0 0.1
          1.1 0.1
          2.2 0.1
          3.3 0.1
     }
}
 
I've discovered that the configuration in post 3 is wrong. Input channels to the LADSPA filters are assigned wrongly.

Thank you Christina Aguilera for emphasising the problem that I could fix it.

Code:
<snip>
pcm.ladspa_xover {
     type ladspa
     slave.pcm out4way
     path "/usr/local/lib/ladspa"  # must indicate filter directory
     channels 4                    # two is default, other channel counts must $
     plugins
     {
          0 {
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.0 "Output"
               input { controls [5 1 -3 1000] } # 1st high shelf at 1000
          }
          1 {
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.0 "Output"
               input { controls [22 1 0 250 0.707] } # 2nd order high pass 250 hz
          }
          2 {
               label ACDf
               policy none
              [B] input.bindings.0 "Input"[/B]
               output.bindings.1 "Output"
               input { controls [0 1 -3] } # gain reduce on woofer
          }
          3 {
               label ACDf
               policy none
               [B]input.bindings.0 "Input"[/B]
               output.bindings.1 "Output"
               input { controls [21 1 0 190 0.707] } # 2nd order low pass 190 hz

          }
          4 {
               label ACDf
               policy none
               [B]input.bindings.1 "Input"[/B]
               output.bindings.2 "Output"
               input { controls [5 1 -3 1000] } # 1st high shelf at 1000
          }
          5 {
               label ACDf
               policy none
               [B]input.bindings.1 "Input"[/B]
               output.bindings.2 "Output"
               input { controls [22 1 0 250 0.707] } # 2nd order high pass 250 $
          }
          6 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.3 "Output"
               input { controls [0 1 -3] } # gain reduce on woofer
          }
          7 {
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.3 "Output"
               input { controls [21 1 0 190 0.707] } # 2nd order low pass 190 hz

          }
    }
}

pcm.out4way {
     type plug
     slave {
          pcm "vout4way"
          channels 4
     }
}     


pcm.vout4way {
     type route
     slave {
          pcm "hw:1,0"
          channels 4
     }
     ttable {
          0.0 0.1
          1.1 0.1
          2.2 0.1
          3.3 0.1
     }
}
 
Last edited:
Thanks for sharing these!

It's a bit late now but there are problems with the last set (again). Only recently discovered some problems trying to setup a new MoOde on a Pi3B+.

  • I used a source channel for multiple operations to the same, different out channel (example - lost the bass attentuation but kept the crossover).
  • I modified channel zero (to be a high passed wideband channel) and then copied it to output channel one (to be a low passed bass channel).

Thankfully all this messing about has been with wideband and bass drivers. So no broken or melted tweeters.

Using REW on an old laptop has greatly helped in identifying levels and correct configuration.

J.
 
The current asound.conf

  • The LADSPA pcm is named as output in mpd, Ignore defaults.
  • Filters now in 2 blocks.
  • ladspa_filters2 splits 2 input channels into 4 output channels and applies crossover, changing channel "1" and channel "0" last.
  • woofermatch reduces woofer gain to suit widerange driver. The entries for the widerange channels are effectively null operations. I get no output through the widerange channels without them being named, however.

Code:
pcm.!default {
     type hw
     card 1
}

ctl.!default {
     type hw
     card 1
}

# LADSPA filters; they act serially on each channel
# Altering a channel first will alter any channels
# that channel is copied.
# Filters with the same input and output channel MUST be last to operate

pcm.ladspa_filters2 {
     type ladspa
     slave.pcm woofermatch
     path "/usr/local/lib/ladspa"  # must indicate filter directory
     channels 4                    # two is default, other channel counts must $
     plugins
     {
          0 {                      # Output 2 (RHF)- 2nd order HPF on TC9
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.2 "Output"
               input { controls [22 1 0 500 0.707] } # 22 = 2nd order HPF
          }
          1 {                      # Output 3 (RLF)- 2nd order LPF on woofer
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.3 "Output"
               input { controls [21 1 0 500 0.707] } # 21 = 2nd order LPF
          }
          2 {                      # Output 1 (LLF)- 2nd order LPF on woofer
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.1 "Output"
               input { controls [21 1 0 500 0.707] } # 21 = 2nd order LPF
          }
          3 {                      # Output 0 (LHF) - 2nd order HPF on TC9
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.0 "Output"
               input { controls [22 1 0 500 0.707] } # 22 = 2nd order HPF
          }
     }
}

# gain block to normalise woofer level
pcm.woofermatch {
     type ladspa
     slave.pcm out4way
     path "/usr/local/lib/ladspa"  # must indicate filter directory
     channels 4                    # two is default, other channel counts must $
     plugins
     {
          0 {                      # Output 0 (LHF) - raise HF
               label ACDf
               policy none
               input.bindings.0 "Input"
               output.bindings.0 "Output"
               input { controls [0 1 0] } # 0 = gain/phase
          }
          1 {                      # Output 1 (LLF) - Reduce woofer gain
               label ACDf
               policy none
               input.bindings.1 "Input"
               output.bindings.1 "Output"
               input { controls [0 1 -9] } # 0 = gain/phase
          }
          2 {                      # Output 2 (RHF) - raise HF
               label ACDf
               policy none
               input.bindings.2 "Input"
               output.bindings.2 "Output"
               input { controls [0 1 0] } # 0 = gain/phase
          }
          3 {                      # Output 3 (RLF) - Reduce woofer gain
               label ACDf
               policy none
               input.bindings.3 "Input"
               output.bindings.3 "Output"
               input { controls [0 1 -9] } # 0 = gain/phase
          }
     }

}


pcm.out4way {
     type plug
     slave {
          pcm "hw:1,0"
#          pcm "vout4way"
          channels 4
     }
}

# pcm.vout4way {
#      type route
#      slave {
#           pcm "hw:1,0"
#           channels 4
#      }
#      ttable {
#           0.0 0.5
#           1.1 0.5
#           2.2 0.5
#           3.3 0.5
#      }
# }
 
Jerms,
You too have realised that the very first function when making a crossover is to establish the two (or more) extra channels.
You can then manipulate those channels independently. If you change channels 0 and 1 before creating the extra channels, those changes apply to the copies also.

Code:
pcm.!default { type plug; slave.pcm Crossover }
ctl.!default { type hw; card 0 }
#
pcm.Crossover { type ladspa; slave.pcm Eq;
                path "/usr/local/lib/ladspa";
                channels 4; plugins {
#
# Second order high and low pass filters at 150Hz 
# to establish the 4 channels
# must be done in this order to prevent 
# channels 0 and 1 having both sets of crossover applied
#
0 { label ACDf; policy none;
    input.bindings.0 "Input"; output.bindings.2 "Output";
    input { controls [ 21 1 0 150 0.71 1 1 ] } # LP 
  }
1 { label ACDf; policy none;
    input.bindings.1 "Input"; output.bindings.3 "Output";
    input { controls [ 21 1 0 150 0.71 1 1 ] } # LP 
  }
2 { label ACDf; policy none;
    input.bindings.0 "Input"; output.bindings.0 "Output";
    input { controls [ 22 1 1 150 0.71 1 1 ] }
  }
3 { label ACDf; policy none;
    input.bindings.1 "Input"; output.bindings.1 "Output";
    input { controls [ 22 1 1 150 0.71 1 1 ] }
  }
                                        }
              }

And for those wishing to use two sound cards:

Code:
pcm.Plug_Why { type plug; slave { pcm Route_2x2; channels 4 } }

pcm.Route_2x2  { type multi
                 slaves.a.pcm "hw:0,0" #Cirrus to Monacor
                 slaves.a.channels 2 
                 slaves.b.pcm "plughw:1,0" #Sabaj to Eikona
                 slaves.b.channels 2 
                 bindings.0.slave b
                 bindings.0.channel 0
                 bindings.1.slave b
                 bindings.1.channel 1
                 bindings.2.slave a
                 bindings.2.channel 0
                 bindings.3.slave a
                 bindings.3.channel 1
               }
Plug_Why is required because a "type multi" cannot be a slave to a "type ladspa".
It seems that the coding for "type multi" must be formatted as above; attempts to put two lines on a single line cause ALSA to fail.

Andy
 
I always considered ALSA configuration as a sort of magic :) Probably partly because there are not so many good resources about that.


For one of the projects I need to send PCM signal from player (e.g. VLC) to sound card and to named pipe (ALSA file plugin). Before sending to the file plugin I need to downsample signal to make it uniform and independent from the sample rate of the input signal. Is it possible to make this kind of manipulation using just pure .asoundrc configuration?


Thanks in advance!
 
Before sending to the file plugin I need to downsample signal to make it uniform and independent from the sample rate of the input signal.

In this case sox with its efficient rate conversion comes handy. I would use the piping configuration of the file plugin and pass the stream sample rate and bit width to sox reading from stdin raw data (or wav format without any params, wav header cariies all). Sox will be started every time the device is opened, you may want to run sox from a script generating proper file names.
 
Hi phofman, thank you for the input. We discussed this in another thread. I'm just wondering if it would be possible to have a solution simply configuring .asoundrc file. For that there is the need in some ALSA plugin which could make downsampling. I'm not sure if such plugin exists though.


Using your approach with sox, do you expect any noticeable delay between sound and signal from sox+file plugin ?
 
Alsa offers rate conversion (the plug plugin, just specify fixed rate) but the algorithms available (libsamplerate, speex) are not efficient. High quality conversion takes one full core of a modern CPU. Unlike sox with its very efficient algorithm.

Look at sox parameters, it is very simple to ask it to convert any input to fixed-rate output.

In .asoundrc it would be a single command - look at file plugin parameters. BUT it would keep rewriting the same file over and over, at every open-device call. I am not sure that is what you want.

What is the purpose of the setup? I do not understand the question about the delay - why do you need low latency for storing to a file?
 
I'd like to send the signal to the sound card for playback and the same signal to VU Meter. Therefore the gap between two signals should be minimal. Otherwise VU Meter will be out-of-sync with sound.


Rewriting files too often is not so good for flash based systems like Raspberry Pi.
 
For VU meter a real file may not be needed at all, I guess, no need to write any data.

Do you really need resampling for a VU meter? Cannot you just drop samples at higher rates, without proper filtering?

A regular linux pipe introduces noticeable latency, IMO not suitable for your case. How about alsa loop sound device, and reading from it with some python alsa library? You could configure the "linear" resampling algorithm which is very efficient and for your purpose good enough. And fixing alsa loop device at a single rate in asoundrc, letting alsa-lib resample with the simple algorithm.
 
I just need fixed rate for VU meter. It doesn't care that much about sound quality.
Therefore any rate would be fine as soon as it can be used for VU meter purposes.
Could you elaborate the approach with loop device?

I hope we don't hijack this thread with unrelated stuff. If this is the case we can
continue in Peppy Meter thread.

Thanks!
 
For one of the projects I need to send PCM signal from player (e.g. VLC) to sound card and to named pipe (ALSA file plugin). Before sending to the file plugin I need to downsample signal to make it uniform and independent from the sample rate of the input signal. Is it possible to make this kind of manipulation using just pure .asoundrc configuration?

Yes it is possible, I have done it to drive Peppy Meter, but have not kept the asoundrc file because it was just an experiment.
Sadly, the only way to find out is to read and experiment; as you say there is little good documentation.

Which is why this thread should deal ONLY with ALSA as requested by Jerms in his original post.

Andy
 
Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.