Posts: 2
Threads: 1
Joined: May 2020
Reputation:
0
Hi there,
I'm trying to use Moode to run my rpi music server, the trick is that I'm using ALSA + Charlie Laub's ACD LADSPA plugins. So I set up a alsa config at /etc/asound.conf, which makes it the 'default' output. This config runs my EQ and handles crossover. Audio then goes to an old HT receiver via HDMI.
This all works well with ecasound.
Code: ecasound ~/downloads/test.flac
ecasound ~/downloads/test.flac -o default
both work just fine.
But I can't get the output from MPD to route through the same output, it just goes to the hw0,0 output (direct to HDMI)
I've tried updating MPD.conf, but not joy with doing that either, and mpd.conf gets overwritten every reboot anyway.
any thoughts?
Posts: 14,056
Threads: 321
Joined: Mar 2018
Reputation:
571
mpd.conf is a critical file and is programmatically generated from a sql table and other dependent settings in moOde. It's just not possible to support user edits to this file.
Charlie's code is really cool and I'd like to find a way to support it in moOde. It could be as simple as creating an additional MPD output with a specific name for an ALSA virtual device. You could then use that name in your ALSA config and then switch to the MPD output.
Is your usage scenario and ALSA configuration specific or does it represent a more general scenario for using the plugins?
Posts: 439
Threads: 10
Joined: Apr 2018
Reputation:
29
Hi Tim
If I have understood, then the changes I suggested in
http://moodeaudio.org/forum/showthread.p...2#pid16272
would solve this, as they allow the "player application" (MPD in this case) output to be processed by an external application and then handed back to the Moode assigned "hardware" output.
Adrian.
Posts: 14,056
Threads: 321
Joined: Mar 2018
Reputation:
571
That would work. I'm just not sure what the implications are for always having a duplicate PCM stream being made by ALSA even though it's not going to be used in many cases.
Posts: 2
Threads: 1
Joined: May 2020
Reputation:
0
(05-10-2020, 09:50 PM)Tim Curtis Wrote: mpd.conf is a critical file and is programmatically generated from a sql table and other dependent settings in moOde. It's just not possible to support user edits to this file.
Charlie's code is really cool and I'd like to find a way to support it in moOde. It could be as simple as creating an additional MPD output with a specific name for an ALSA virtual device. You could then use that name in your ALSA config and then switch to the MPD output.
Is your usage scenario and ALSA configuration specific or does it represent a more general scenario for using the plugins?
No, I don't think it's Alsa configuration specific. Charlie uses Gstreamer, I think. What I found was that its more processor efficient to do this as an alsa confguration on its way out to the hardware. Using asound.conf makes it my default, so all audio goes through that crossover and EQ.
I have figured out why hacking the mpd.conf wasn't working. Whenever I restarted MPD it was bringing back the graphic eq alsa configuration - I had tried to edit that alsa configuration so that it connected to "default" rather than to hw:0,0
If the settings are stored in a db, can't I just edit the DB then?
I have a few other tweaks that I want to make, like getting an analog input working from a different device (usb), and making sure that all inputs/outputs are routed through 'default' rather than direct to hardware.
in case you are interested, my asound.conf is below. This worked fine on my old pi2 running squeezelite. The pi4 is so different that I figured it was worth a shot to try something new, like Moode
Thanks!
Code: #asound rc new version jrubinstein - experimental with charlies plugin
pcm.!default {
type plug
slave.pcm filtereq
}
ctl.!default {
type hw
card 0
}
pcm.filtereq {
type ladspa
slave.pcm filtercross
path "/usr/lib/ladspa"
channels 8
plugins
{
0{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -8.8 113 3.82 1 1] } #parametric digital eq cutting 8.8db at 113hz with q of 3.82
}
1{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -6.6 157 3.87 1 1] } #parametric digital eq
}
2{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 9 408 5 1 1] } #parametric digital eq
}
3{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -8.3 409 5 1 1] } #parametric digital eq
}
4{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -7 800 1.15 1 1] } #parametric digital eq
}
5{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -6.2 4440 1 1 1] } #parametric digital eq
}
6{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [0 1 -9 1 1 1 1] } #gain block cutting boost by 9db to accommadate boost in filter 2
}
7{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -8.8 113 3.82 1 1] } #parametric digital eq cutting 8.8db at 113hz with q of 3.82
}
8{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -6.6 157 3.87 1 1] } #parametric digital eq
}
9{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 9 408 5 1 1] } #parametric digital eq
}
10{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -8.3 409 5 1 1] } #parametric digital eq
}
11{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -7 800 1.15 1 1] } #parametric digital eq
}
12{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -6.2 4440 1 1 1] } #parametric digital eq
}
13{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [0 1 -9 1 1 1 1] } #gain block cutting boost by 9db to accommadate boost in filter 2
}
}
}
pcm.filtercross {
type ladspa
slave.pcm speaker
path "/usr/lib/ladspa"
channels 8
plugins
{
0 {
label ACDf #lowpass for woofer output to channel2
policy none
input.bindings.0 "Input"
output.bindings.2 "Output"
input { controls [21 1 0 330 0.5 1 1] } # [filter type polarity dbgain frequency q]
}
1 {
label ACDf #lowpass for woofer output to channel3
policy none
input.bindings.1 "Input"
output.bindings.3 "Output"
input { controls [21 1 0 330 0.5 1 1] } #2nd order lowpass at 300hz
}
2 {
label ACDf #highpass for tweeter output to channel4
policy none
input.bindings.0 "Input"
output.bindings.4 "Output"
input { controls [22 -1 -5 3000 1 1 1] } #2nd order highpass at 3000 hz
}
3 {
label ACDf #highpass for tweeter output to channel4 filter 2
policy none
input.bindings.0 "Input"
output.bindings.4 "Output"
input { controls [22 1 0 3000 1 1 1] } #2nd order highpass at 3000 hz
}
4 {
label ACDf #highpass for tweeter output to channel4
policy none
input.bindings.1 "Input"
output.bindings.5 "Output"
input { controls [22 -1 -5 3000 1 1 1] } #2nd order highpass at 3000 hz
}
5 {
label ACDf #highpass for tweeter output to channel4 filter 2
policy none
input.bindings.1 "Input"
output.bindings.5 "Output"
input { controls [22 1 0 3000 1 1 1] } #2nd order highpass at 3000 hz
}
6 {
label ACDf #lowpass1 for mid output to channel0
policy none
input.bindings.0 "Input"
output.bindings.6 "Output"
input { controls [21 1 -6 3000 0.707 1 1] } # 2nd order lowpass at 3000 hz -4db cut
}
7 {
label ACDf #lowpass2 for mid output to channel0
policy none
input.bindings.0 "Input"
output.bindings.6 "Output"
input { controls [21 1 0 3000 0.707 1 1] } # 2nd order lowpass at 3000 hz
}
8 {
label ACDf #highpass for mid output to channel0
policy none
input.bindings.0 "Input"
output.bindings.6 "Output"
input { controls [22 1 0 300 0.5 1 1] } # 2nd order highpass at 300 hz
}
9 {
label ACDf #lowpass1 for mid output to channel1
policy none
input.bindings.1 "Input"
output.bindings.7 "Output"
input { controls [21 1 -6 3000 0.707 1 1] } # 2nd order lowpass at 3000 hz -4db cut
}
10 {
label ACDf #lowpass2 for mid output to channel1
policy none
input.bindings.1 "Input"
output.bindings.7 "Output"
input { controls [21 1 0 3000 0.707 1 1] } # 2nd order lowpass at 3000 hz
}
11 {
label ACDf #highpass for mid output to channel1
policy none
input.bindings.1 "Input"
output.bindings.7 "Output"
input { controls [22 1 0 300 0.5 1 1] } # 2nd order highpass at 300 hz
}
12{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.2 "Output"
input { controls [22 1 0 50 1 1 1] } #2nd order highpass at 30 hz to act as subsonic filter
}
13{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.2 "Output"
input { controls [22 1 0 50 1 1 1] } #2nd order highpass at 30 hz
}
14{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.3 "Output"
input { controls [22 1 0 50 1 1 1] } #2nd order highpass at 30 hz to act as subsonic filter
}
15{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.3 "Output"
input { controls [22 1 0 50 1 1 1] } #2nd order highpass at 30 hz
}
16{
label ACDf #lowpass for woofer output to channel2
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [21 1 0 50 0.5 1 1] } # [filter type polarity dbgain frequency q]
}
17{
label ACDf #lowpass for woofer output to channel3
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [21 1 0 50 0.5 1 1] } #2nd order lowpass at 50hz
}
}
}
pcm.speaker {
type plug
slave {
pcm "t-table"
channels 8
rate "unchanged"
}
}
pcm.t-table {
type route
slave {
pcm "hw:0,0"
channels 8
}
ttable {
0.2 1 # audio = left woofer channel = left front (channel 2 is sub out)
1.2 1 # channel in.channel out on/off
2.1 1 #left bass this gives me the low filter for left woofer onto channel 0 = front left
3.0 1 #right bass = SBR
4.7 1 #left tweeter = SBL
5.6 1 #right tweeter = Surr Right
6.5 1 #left mid = surr left
7.4 1 #right mid = center
}
}
pcm.plughw.slave.rate = "unchanged";
Posts: 439
Threads: 10
Joined: Apr 2018
Reputation:
29
Hi Tim
The possibility to duplicate the stream was part of the suggestion, but I was referring to the mechanism to achieve this, which is for the player applications to output to a named virtual device, which then outputs to another named virtual device, which then outputs to the "hardware" device. This gives the user the opportunity to intercept the audio between the two named virtual devices.
In my case, I want to create a copy of the audio, which I would do by overriding the first named device using an ALSA configuration file and making a duplicate copy of the stream before writing the original stream to the second named device (which would then output to the "hardware" device). For ecasound, I imagine you could, for example, override the first named device to output to an alternative named device then the command would be something like "ecasound -i alternative_named_device -o second_named_device", which would connect the chain and add in the audio processing (with the final output going to the Moode assigned audio device as before).
Adrian.
Posts: 14,056
Threads: 321
Joined: Mar 2018
Reputation:
571
(05-11-2020, 11:52 AM)jrubins Wrote: (05-10-2020, 09:50 PM)Tim Curtis Wrote: mpd.conf is a critical file and is programmatically generated from a sql table and other dependent settings in moOde. It's just not possible to support user edits to this file.
Charlie's code is really cool and I'd like to find a way to support it in moOde. It could be as simple as creating an additional MPD output with a specific name for an ALSA virtual device. You could then use that name in your ALSA config and then switch to the MPD output.
Is your usage scenario and ALSA configuration specific or does it represent a more general scenario for using the plugins?
No, I don't think it's Alsa configuration specific. Charlie uses Gstreamer, I think. What I found was that its more processor efficient to do this as an alsa confguration on its way out to the hardware. Using asound.conf makes it my default, so all audio goes through that crossover and EQ.
I have figured out why hacking the mpd.conf wasn't working. Whenever I restarted MPD it was bringing back the graphic eq alsa configuration - I had tried to edit that alsa configuration so that it connected to "default" rather than to hw:0,0
If the settings are stored in a db, can't I just edit the DB then?
I have a few other tweaks that I want to make, like getting an analog input working from a different device (usb), and making sure that all inputs/outputs are routed through 'default' rather than direct to hardware.
in case you are interested, my asound.conf is below. This worked fine on my old pi2 running squeezelite. The pi4 is so different that I figured it was worth a shot to try something new, like Moode
Thanks!
Code: #asound rc new version jrubinstein - experimental with charlies plugin
pcm.!default {
type plug
slave.pcm filtereq
}
ctl.!default {
type hw
card 0
}
pcm.filtereq {
type ladspa
slave.pcm filtercross
path "/usr/lib/ladspa"
channels 8
plugins
{
0{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -8.8 113 3.82 1 1] } #parametric digital eq cutting 8.8db at 113hz with q of 3.82
}
1{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -6.6 157 3.87 1 1] } #parametric digital eq
}
2{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 9 408 5 1 1] } #parametric digital eq
}
3{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -8.3 409 5 1 1] } #parametric digital eq
}
4{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -7 800 1.15 1 1] } #parametric digital eq
}
5{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [26 1 -6.2 4440 1 1 1] } #parametric digital eq
}
6{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [0 1 -9 1 1 1 1] } #gain block cutting boost by 9db to accommadate boost in filter 2
}
7{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -8.8 113 3.82 1 1] } #parametric digital eq cutting 8.8db at 113hz with q of 3.82
}
8{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -6.6 157 3.87 1 1] } #parametric digital eq
}
9{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 9 408 5 1 1] } #parametric digital eq
}
10{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -8.3 409 5 1 1] } #parametric digital eq
}
11{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -7 800 1.15 1 1] } #parametric digital eq
}
12{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [26 1 -6.2 4440 1 1 1] } #parametric digital eq
}
13{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [0 1 -9 1 1 1 1] } #gain block cutting boost by 9db to accommadate boost in filter 2
}
}
}
pcm.filtercross {
type ladspa
slave.pcm speaker
path "/usr/lib/ladspa"
channels 8
plugins
{
0 {
label ACDf #lowpass for woofer output to channel2
policy none
input.bindings.0 "Input"
output.bindings.2 "Output"
input { controls [21 1 0 330 0.5 1 1] } # [filter type polarity dbgain frequency q]
}
1 {
label ACDf #lowpass for woofer output to channel3
policy none
input.bindings.1 "Input"
output.bindings.3 "Output"
input { controls [21 1 0 330 0.5 1 1] } #2nd order lowpass at 300hz
}
2 {
label ACDf #highpass for tweeter output to channel4
policy none
input.bindings.0 "Input"
output.bindings.4 "Output"
input { controls [22 -1 -5 3000 1 1 1] } #2nd order highpass at 3000 hz
}
3 {
label ACDf #highpass for tweeter output to channel4 filter 2
policy none
input.bindings.0 "Input"
output.bindings.4 "Output"
input { controls [22 1 0 3000 1 1 1] } #2nd order highpass at 3000 hz
}
4 {
label ACDf #highpass for tweeter output to channel4
policy none
input.bindings.1 "Input"
output.bindings.5 "Output"
input { controls [22 -1 -5 3000 1 1 1] } #2nd order highpass at 3000 hz
}
5 {
label ACDf #highpass for tweeter output to channel4 filter 2
policy none
input.bindings.1 "Input"
output.bindings.5 "Output"
input { controls [22 1 0 3000 1 1 1] } #2nd order highpass at 3000 hz
}
6 {
label ACDf #lowpass1 for mid output to channel0
policy none
input.bindings.0 "Input"
output.bindings.6 "Output"
input { controls [21 1 -6 3000 0.707 1 1] } # 2nd order lowpass at 3000 hz -4db cut
}
7 {
label ACDf #lowpass2 for mid output to channel0
policy none
input.bindings.0 "Input"
output.bindings.6 "Output"
input { controls [21 1 0 3000 0.707 1 1] } # 2nd order lowpass at 3000 hz
}
8 {
label ACDf #highpass for mid output to channel0
policy none
input.bindings.0 "Input"
output.bindings.6 "Output"
input { controls [22 1 0 300 0.5 1 1] } # 2nd order highpass at 300 hz
}
9 {
label ACDf #lowpass1 for mid output to channel1
policy none
input.bindings.1 "Input"
output.bindings.7 "Output"
input { controls [21 1 -6 3000 0.707 1 1] } # 2nd order lowpass at 3000 hz -4db cut
}
10 {
label ACDf #lowpass2 for mid output to channel1
policy none
input.bindings.1 "Input"
output.bindings.7 "Output"
input { controls [21 1 0 3000 0.707 1 1] } # 2nd order lowpass at 3000 hz
}
11 {
label ACDf #highpass for mid output to channel1
policy none
input.bindings.1 "Input"
output.bindings.7 "Output"
input { controls [22 1 0 300 0.5 1 1] } # 2nd order highpass at 300 hz
}
12{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.2 "Output"
input { controls [22 1 0 50 1 1 1] } #2nd order highpass at 30 hz to act as subsonic filter
}
13{
label ACDf
policy none
input.bindings.0 "Input"
output.bindings.2 "Output"
input { controls [22 1 0 50 1 1 1] } #2nd order highpass at 30 hz
}
14{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.3 "Output"
input { controls [22 1 0 50 1 1 1] } #2nd order highpass at 30 hz to act as subsonic filter
}
15{
label ACDf
policy none
input.bindings.1 "Input"
output.bindings.3 "Output"
input { controls [22 1 0 50 1 1 1] } #2nd order highpass at 30 hz
}
16{
label ACDf #lowpass for woofer output to channel2
policy none
input.bindings.0 "Input"
output.bindings.0 "Output"
input { controls [21 1 0 50 0.5 1 1] } # [filter type polarity dbgain frequency q]
}
17{
label ACDf #lowpass for woofer output to channel3
policy none
input.bindings.1 "Input"
output.bindings.1 "Output"
input { controls [21 1 0 50 0.5 1 1] } #2nd order lowpass at 50hz
}
}
}
pcm.speaker {
type plug
slave {
pcm "t-table"
channels 8
rate "unchanged"
}
}
pcm.t-table {
type route
slave {
pcm "hw:0,0"
channels 8
}
ttable {
0.2 1 # audio = left woofer channel = left front (channel 2 is sub out)
1.2 1 # channel in.channel out on/off
2.1 1 #left bass this gives me the low filter for left woofer onto channel 0 = front left
3.0 1 #right bass = SBR
4.7 1 #left tweeter = SBL
5.6 1 #right tweeter = Surr Right
6.5 1 #left mid = surr left
7.4 1 #right mid = center
}
}
pcm.plughw.slave.rate = "unchanged";
If you want to do some hacking then have a look at /var/www/inc/playerlib.php, function updMpdConf()
Posts: 14,056
Threads: 321
Joined: Mar 2018
Reputation:
571
(05-11-2020, 11:58 AM)adrii Wrote: Hi Tim
The possibility to duplicate the stream was part of the suggestion, but I was referring to the mechanism to achieve this, which is for the player applications to output to a named virtual device, which then outputs to another named virtual device, which then outputs to the "hardware" device. This gives the user the opportunity to intercept the audio between the two named virtual devices.
In my case, I want to create a copy of the audio, which I would do by overriding the first named device using an ALSA configuration file and making a duplicate copy of the stream before writing the original stream to the second named device (which would then output to the "hardware" device). For ecasound, I imagine you could, for example, override the first named device to output to an alternative named device then the command would be something like "ecasound -i alternative_named_device -o second_named_device", which would connect the chain and add in the audio processing (with the final output going to the Moode assigned audio device as before).
Adrian.
Hi,
I understood that part. Currently in moOde MPD outputs to hw and the renderers output to plughw. This has been a stable configuration for many years.
I could change to virtual ALSA device but I think users that want to intercept and pre-process the PCM stream can just override pcm.default in asound.
Posts: 439
Threads: 10
Joined: Apr 2018
Reputation:
29
Hi Tim
I had no success overriding "default" on Moode to capture audio output (which I believe is also the problem that @ jrubins reported), and I assumed it was not possible because MPD was writing to the "hw" plugin rather than to the default device. If this is not correct then please let me know as I would rather override "default" than override the "hw" plugin, which is the only working ALSA solution I currently have for making a copy of the audio on Moode
https://github.com/antiprism/mpd_oled/is...-567146826
Regarding my suggestion, it wouldn't change the final outputs; MPD would still end up outputting to hw and the renderers would still end up outputting to plughw.
I'll give an example of how this works in practice by modifying the alsaequal configuration. I have just enabled the graphic equaliser and edited /etc/alsa/conf.d/alsaequal.conf so that alsequal is a dummy entry point and the original alsaequal is renamed alsaequal2
Code: pcm.alsaequal {
type plug
slave.pcm "alsaequal2"
}
pcm.alsaequal2 {
type plug
slave.pcm "plug_alsaequal";
}
ctl.alsaequal2 {
type equal
controls "/usr/local/bin/alsaequal.bin";
}
pcm.plug_alsaequal {
type equal
slave.pcm "plughw:0,0";
controls "/usr/local/bin/alsaequal.bin";
}
Now, all I have to do in /etc/asound.conf is override alsaequal, and make sure that I pass the original audio back to alsaequal2. (alsaequal and alsaequal2 correspond to the two named devices that I was referring to that allow the audio to be intercepted). The equalisation process is not affected
Code: pcm.!alsaequal {
type plug
slave.pcm "duplicatecopy"
}
pcm.duplicatecopy {
type plug
slave.pcm {
type multi
slaves {
a { channels 2 pcm "alsaequal2" } # the real device
b { channels 2 pcm "hw:Loopback,0" } # the loopback driver
}
bindings {
0 { slave a channel 0 }
1 { slave a channel 1 }
2 { slave b channel 0 }
3 { slave b channel 1 }
}
}
ttable [
[ 1 0 1 0 ] # left -> a.left, b.left
[ 0 1 0 1 ] # right -> a.right, b.right
]
}
The idea is that Moode would provide two names for all audio output to pass through (both MPD and renderers), and then the first name could be overriden by the user and, after processing the audio stream, the user would typically pass the stream on to the second named device.
Adrian.
Posts: 14,056
Threads: 321
Joined: Mar 2018
Reputation:
571
My bad, You're correct regarding "default"
I'll have a look and see if it something that can be included in 6.6.0
http://moodeaudio.org/forum/showthread.p...2#pid16272
|