FIR-LADSPA: A LADSPA plugin for FIR filtering

flavio-PC LADSPA-FIR # chmod +x ./compile_FIR_engine.sh
flavio-PC LADSPA-FIR # ./compile_FIR_engine.sh float
compiling the FIR engine in single precision...
The FIR engine was successfully compiled into the executable file FIR_engine.exe


Perfect.
And to think that I do everything with copy and paste in order not to be wrong!
I am happy to have had two saviors on your level.
Now that I have compiled my Ferrari, I greet you and thank you.
See you when I learn to drive.
Ciao.

Grazie mille!

Drive carefully.
 
Just in case people don't know... you can use ecasound+LADSPA in combination with Pulse Audio. This You can implement both IIR and FIR filters via that route.

ALSA has a Pulse device, which IIRC appears as a virtual "monitor" device in Pulse and gets all the sounds the system sends to Pulse Audio. So, in Pulse you disable the output device you wish to use. Then you tell ecasound to use the ALSA pulse device as the input, and send the output to the soundcard you deactivated under Pulse. You can still use the Pulse audio volume control, which is very convenient, and everything works just the same as if playback was coming via Pulse except you get crossover functionality via ecasound. I use this approach on one of the systems in my home.

If someone would like, I can provide a more detailed example.
 
Last edited:

francolargo

Member
Paid Member
2007-03-12 8:07 am
Twin Cities, MN
Greetings Charlie and thanks so much for this ambitious and insightful work. I am very late to this party but for happy reasons, including the trouble-free operation of ACDf. Now, in a couple days of 'down time', I am experimenting with getting LADSPA-FIR running on a AM335x SoC. In addition, I would prefer to use ALSA rather than ecasound (for multiple off-topic reasons). ALSA is not reporting any problems, but so far I'm not seeing any FFTW processes nor output derived from ALSA LADSPA-FIR plugs. This is all new to me so I have a couple very basic questions.

1. Could I see an example of text-formatted float and double precision coefficients that properly run in FFTW? I'm creating filters in Matlab, which has its own learning curve and defaults to double. Maybe my coefficient files are not correctly formatted. I first compiled FFTW for double and then secondly for float, but no idea if that was done correctly. The /dev/shm/LADSPA-FIR.log is empty and there is no engine log.
2. I believe the AM3358 has a 200MHz cycle counter, but the FFTW compilation defaults to operating with a low resolution estimate. Does your program's 'cycle latency' specification replace the function of the cycle timer?
3. Of course, the AM3358 doesn't have much horsepower so I'm also curious to learn whether ACDf and LADSPA-FIR plugs could be combined. Any thoughts? My overall goal from these experiments is to adapt crossover processing based on original file frequencies, which is easy to do with ALSA.

Very best wishes and thanks in advance for any help!

Frank
 

francolargo

Member
Paid Member
2007-03-12 8:07 am
Twin Cities, MN
Some progress, but still some issues...

* I deleted and re-installed FFTW with more complete flags and it installed successfully with Neon support. Version 3.3.10.

* I found a typo in my asound.conf plug and fixed it. When sending signal to the ALSA LADSPA_FIR plugs, I now see the source in ALSA-generated hw_params. eg:
access: MMAP_INTERLEAVED
format: S32_LE
subformat: STD
channels: 8
rate: 48000 (48000/1)
period_size: 128
buffer_size: 2048

* I now have entries in /dev/shm/LADSPA-FIR.LOG. For each attempt to initiate filtering, I get 12 copies (for 6 channels) of:
The environmental variable LADSPA_FIR_FILTER_TABLE was not found.
The environmental variable LADSPA_FIR_FILTER_ENGINE was not found.

* Meanwhile, the export of these environmental variables can be confirmed using env | grep LADSPA_FIR_FILTER_TABLE, etc. However, must these assets be in a particular directory to be seen? I don't have them in the user-specific area.

Again, many thanks in advance!
 
My guess (totally a guess at this point but I think the same as phofman above) is that the environment where you have set the variables LADSPA_FIR_FILTER_TABLE and LADSPA_FIR_FILTER_ENGINE is your user environment, but you are running these via ALSA which I belive is a root process. The environmental variables created within each environment is isolated from the other. You might try some approach that sets these variables for whatever environment ALSA is running in. I am not exactly sure how to do that, or the best way to do it. phofman might be able to suggest the best course of action.
 
Well, alsa-lib is just a library, it does not start any new process. The question is what process calls the alsa routines, what is the playback app. E.g. MPD runs under a different user as a daemon.
I believe francolargo directly implements LADSA within asoundrc, but you are right that some process must open the ALSA device to play audio.
 

francolargo

Member
Paid Member
2007-03-12 8:07 am
Twin Cities, MN
Thanks so much Charlie and @phofman!
I have always run this little system from the root login. ...no issues in ~6 years...
This morning I:
* put the export commands in /root/.profile, and they reliably show up with 'env' after logout-login.
* tried adding a '$' to the two variable names as part of the definition - couldn't find a quick description of the '$' role, but my export command for LADSPA_PATH uses it so, ...didn't know...
* double-checked all the chown settings - all 'root:root'
* checked the process that pipes data to the ALSA plug (SoX) and htop lists it as a 'root' process.
And I'm still getting the same result - twelve error messages in the log file.

[email protected]:~# env
COMP_WORDBREAKS=
"'><;|&:)
TERM=xterm-256color
SHELL=/bin/bash
SSH_CLIENT=192.168.1.134 57611 22
LADSPA_FIR_FILTER_ENGINE=:/usr/filter/LADSPA-FIR/FIR_engine.exe
SSH_TTY=/dev/pts/0
USER=root
PRU_C_DIR=/usr/share/ti/cgt-pru/include;/usr/share/ti/cgt-pru/lib
LADSPA_FIR_FILTER_TABLE=:/usr/filter/LADSPA-FIR/FIR_filter_table.txt
MAIL=/var/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/root
LANG=en_US
NODE_PATH=/usr/local/lib/node_modules
SHLVL=1
HOME=/root
LOGNAME=root
SSH_CONNECTION=192.168.1.134 57611 192.168.1.53 22
LADSPA_PATH=:/usr/local/lib/ladspa:/usr/lib/ladspa
_=/usr/bin/env
Of course! That 'smiley' must be the problem! ;)
 
Greetings Charlie and thanks so much for this ambitious and insightful work. I am very late to this party but for happy reasons, including the trouble-free operation of ACDf. Now, in a couple days of 'down time', I am experimenting with getting LADSPA-FIR running on a AM335x SoC. In addition, I would prefer to use ALSA rather than ecasound (for multiple off-topic reasons). ALSA is not reporting any problems, but so far I'm not seeing any FFTW processes nor output derived from ALSA LADSPA-FIR plugs. This is all new to me so I have a couple very basic questions.

1. Could I see an example of text-formatted float and double precision coefficients that properly run in FFTW? I'm creating filters in Matlab, which has its own learning curve and defaults to double. Maybe my coefficient files are not correctly formatted. I first compiled FFTW for double and then secondly for float, but no idea if that was done correctly. The /dev/shm/LADSPA-FIR.log is empty and there is no engine log.
2. I believe the AM3358 has a 200MHz cycle counter, but the FFTW compilation defaults to operating with a low resolution estimate. Does your program's 'cycle latency' specification replace the function of the cycle timer?
3. Of course, the AM3358 doesn't have much horsepower so I'm also curious to learn whether ACDf and LADSPA-FIR plugs could be combined. Any thoughts? My overall goal from these experiments is to adapt crossover processing based on original file frequencies, which is easy to do with ALSA.

Very best wishes and thanks in advance for any help!

Frank
I will try to answer these questions here.

1. Let's get the environmental variable stuff fixed first. But if you want to check how this is done, see lines 593-640 in FIR_convolution_engine.cpp. Text format coefficients are read one line at a time and then stof is used to convert the text to a float. I don't think double is supported for coefficients. This part of the code was thrown together and could certainly be optimized/improved but since it only runs once at startup I didn't put much effort into it and I just wanted to cover the basics. I can always modify the code if that is needed - feel free to let me know if you want to import other data types.

2. In my code, the cycle timer reports how long it takes the FIR engine to process one batch of samples and make it ready in the pipe that returns it to the LADSPA plug-in. Once you know this number you can coordinate several processes in terms of latency because you can choose it ahead of time. But you do not want to set the latency to be below the amount of time that the data is processed or there will be drop outs. I am not sure what this has to do with the "cycle counter" of your hardware.

3. Yes, you can certainly mix the IIR (ACDf) and FIR plug-ins. Keep in mind if these are operating in parallel you should consider the effect of the latency of the FIR plugin, which will cause a delay of tens to hundreds of milliseconds (depending on FIR operating parameters and available CPU horsepower) to occur for that stream compared to data running through the IIR plugin. If you operate the IIR and FIR plug-ins in series, e.g. the FIR plugin operates on the input (before splitting into channels for the crossover, which is all done via IIR) then the delay will be the same for all channels (e.g. not a problem). An application that uses a series configuration would be group delay compensation, for example.
 
Hi francolargo:

I was looking over the environmental variable dump you posted above, specifically for the two env vars that are needed to run LADSPA-FIR:
LADSPA_FIR_FILTER_ENGINE=:/usr/filter/LADSPA-FIR/FIR_engine.exe LADSPA_FIR_FILTER_TABLE=:/usr/filter/LADSPA-FIR/FIR_filter_table.txt

I suspect you might be seeing errors like The file :/usr/filter/LADSPA-FIR/FIR_engine.exe was not found.

It looks like you are using a colon or semicolon after the equals sign. These are not path variables but rather a file path. When you use the colon/semicolon that results in an invalid or not found command.

Take out the colons and check that you are using the full filepath to FIR_engine.exe and FIR_filter_table.txt, and you will be one step closer to success! ;)

P.S. you can check that the env var points to the file correctly by issuing the command:
stat $LADSPA_FIR_FILTER_ENGINE
you should see some file info (on success) or an error message on fail.

Let me know how it works out.
 

francolargo

Member
Paid Member
2007-03-12 8:07 am
Twin Cities, MN
Thanks Charlie, Yeah, I was playing around with the export command because ultimately I would want the system to work untouched after booting, without ever logging in. So I put export commands both in .profile and rc.local. That colon is gone now.

I did try ecasound, which runs. The LADSPA-FIR.log remains clear. Now we have a FIR_engine.log, which reports 6 lines of "An error ocurred when trying to import system Wisdom." Apparently FFTW is not running because there is nothing else in /dev/shm. I think I will try editing all the filter coefficients down to (IIRC) 23 decimal places.
 
Ah that seems to be on me (the Wisdom error). I initially generated and used FFTW Wisom - it is supposed to maximize speed. But after some user feedback and some testing I found that it didn't really make a difference and I took out those lines in the code. Except it seems I never uploaded the updated file, so those lines are actually still in your version. You can edit them out and then run the make steps (recompile) again.

Please remove lines 662-674 in FIR_convolution_engine.cpp, shown below:
C++:
//Import FFTW system wisdom:
      #if FFT_DATATYPE == 2     
        //get FFTW System Wisdom from /etc/fftw/wisdom
        ret_val = fftw_import_system_wisdom(); //import double precision wisdom
      #else
        //get FFTW System Wisdom from /etc/fftw/wisdomf
        ret_val = fftwf_import_system_wisdom(); //import single precision wisdom
      #endif
      if ( ret_val != 1 ) {
                //ret_val is 1 on successful wisdom import
        error_file << "An error ocurred when trying to import system Wisdom." << endl;
        cleanup_and_exit( engine_stats_file, working_directory );
      }

I'm not sure why I never updated the online file with these changes. Sorry about that!

The Wisdom not found error causes an immediate termination during setup, so nothing would happen afterwards.
 
@francolargo

Do you think you will have time to try it again but with those lines (above) removed?

Someone contacted me about this a long time ago. I didn't spot it because I had created Wisdom at one point during development, and so these lines did not create an error for me. After I told them what to do I waited for them to get back to me. Some time went by and they didn't response and unfortunately I just forgot about the issue. I don't normally use this code (still plan to but not yet) so I did not run into the issue myself.

Give it a try and it should work, at least with ecasound. Then we can figure out how to get it working from within asoundrc if you run into problems implementing it that way.