dc655321
Major Contributor
- Joined
- Mar 4, 2018
- Messages
- 1,599
- Likes
- 2,255
I would very much appreciate some input from the wise members of this site on
various aspects of implementing and integrating a convolution engine into the
Linux audio stack. I'm thinking of members like @Cosmik , @mansr , @pos, @yue or
others that may have some experience digging around in the depths of audio
software.
Apologies in advance for the lengthy post.
Some Context:
--------------
I am building a convolution engine to support DSP operations as part of a
project to create a speaker system.
Why build my own engine?
Because Iam a sucker for punishment enjoy the challenge and re-learning
aspects. My education is in physics, control systems, and DSP, but I have not
really exercised those neurons since grad school (longer ago than I'm comfortable
admitting). Most of my work in the intervening years has been software
development for particle accelerators (device drivers, data acquisition, etc).
The Good:
-------------
At this point, I have constructed a basic convolution library, and integrated
it into ALSA via the extplug API. I can push audio files through my software
with aplay, cmus, Audacity and it comes out the other side (into sound
card or file) with the expected results. Yay for small victories.
The Bad:
-------------
However, sharp edges abound. If I direct the audio player to ffwd or rrew, the
system typically does not respond well (crash, burn, freeze, etc). More on that
later. Also, if I try to get REW to use my ALSA plugin, I can see it open and
close the plugin roughly once a second. REW appears hung in this state, and
more importantly, I cannot use REW like this and progress on making a set a
speakers stalls. Boo for crushing defeats.
My Suspicions:
-------------
The ALSA extplug API is very narrow, perhaps too narrow to be used
directly by audio clients. I will admit to choosing it based solely on it
being reasonably low hanging fruit. My plugin is only ~350 lines of code, most
of which is parsing configuration options to be passed to the lower level
convolution library (see example config below). My hunch is that what I'm trying
to do is far better suited to the ioplug API in ALSA (essentially a virtual
sound card). With the ioplug API, audio clients can get sufficiently duped
into thinking they're dealing with a real sound card, or at least a full
featured ALSA PCM driver. I am guessing that REW is doing something like:
Here, I guess the probing fails because the extplug API is returning bad
info. This could be due to the narrow API or (just as likely) errors in my
simplistic implementation. Perhaps @JohnPM could venture a guess?
A New Hope?
-------------
I'm not worried about throwing out my crappy little plugin for something
better, subject to the caveat that the "something better" is actually better.
So, here are some options for integration of the convolution library into the
Linux audio stack:
1) ALSA ioplug - much broader API, much more complexity. The model here is that
audio client software (REW, Audacity, etc) open and communicate with this
plugin, and in turn, the plugin opens and communicates with a real soundcard on
the client's behalf, feeding it the DSP-molested data.
2) Pulseaudio (PA) filter - Going a layer above ALSA in the audio stack may
have some benefits, but I have only minimally explored this option. I
understand how PA works and is incorporated in ALSA (via an ioplug!), but I
have no experience trying to integrate directly with PA itself. Ultimately,
integration with PA would be great, but at least at this point, that's only a
"nice-to-have".
3) ALSA PCM plugin plumbing - it may be possible to wire a set of PCM plugins
together (including mine), to better emulate the interface that sophisticated
audio clients require. The attraction here is that it would not require writing
any new code, only configuration file editing.
4) Write an ALSA driver - no libc, no userspace FFT libs,
userspace-to-kernelspace plumbing. Blech, no thanks.
Thoughts on these options or anything else covered here?
Related experiences to share? Please do!
Sample of configuration for ALSA extplug "myplug", loading a 300-3000Hz bandpass FIR filter of 1024 taps:
various aspects of implementing and integrating a convolution engine into the
Linux audio stack. I'm thinking of members like @Cosmik , @mansr , @pos, @yue or
others that may have some experience digging around in the depths of audio
software.
Apologies in advance for the lengthy post.
Some Context:
--------------
I am building a convolution engine to support DSP operations as part of a
project to create a speaker system.
Why build my own engine?
Because I
aspects. My education is in physics, control systems, and DSP, but I have not
really exercised those neurons since grad school (longer ago than I'm comfortable
admitting). Most of my work in the intervening years has been software
development for particle accelerators (device drivers, data acquisition, etc).
The Good:
-------------
At this point, I have constructed a basic convolution library, and integrated
it into ALSA via the extplug API. I can push audio files through my software
with aplay, cmus, Audacity and it comes out the other side (into sound
card or file) with the expected results. Yay for small victories.
The Bad:
-------------
However, sharp edges abound. If I direct the audio player to ffwd or rrew, the
system typically does not respond well (crash, burn, freeze, etc). More on that
later. Also, if I try to get REW to use my ALSA plugin, I can see it open and
close the plugin roughly once a second. REW appears hung in this state, and
more importantly, I cannot use REW like this and progress on making a set a
speakers stalls. Boo for crushing defeats.
My Suspicions:
-------------
The ALSA extplug API is very narrow, perhaps too narrow to be used
directly by audio clients. I will admit to choosing it based solely on it
being reasonably low hanging fruit. My plugin is only ~350 lines of code, most
of which is parsing configuration options to be passed to the lower level
convolution library (see example config below). My hunch is that what I'm trying
to do is far better suited to the ioplug API in ALSA (essentially a virtual
sound card). With the ioplug API, audio clients can get sufficiently duped
into thinking they're dealing with a real sound card, or at least a full
featured ALSA PCM driver. I am guessing that REW is doing something like:
- open "default" sound sink (myplugin)
- probe sink for its capabilities
- probe fails, close sink
- try opening sink again...
Here, I guess the probing fails because the extplug API is returning bad
info. This could be due to the narrow API or (just as likely) errors in my
simplistic implementation. Perhaps @JohnPM could venture a guess?
A New Hope?
-------------
I'm not worried about throwing out my crappy little plugin for something
better, subject to the caveat that the "something better" is actually better.
So, here are some options for integration of the convolution library into the
Linux audio stack:
1) ALSA ioplug - much broader API, much more complexity. The model here is that
audio client software (REW, Audacity, etc) open and communicate with this
plugin, and in turn, the plugin opens and communicates with a real soundcard on
the client's behalf, feeding it the DSP-molested data.
2) Pulseaudio (PA) filter - Going a layer above ALSA in the audio stack may
have some benefits, but I have only minimally explored this option. I
understand how PA works and is incorporated in ALSA (via an ioplug!), but I
have no experience trying to integrate directly with PA itself. Ultimately,
integration with PA would be great, but at least at this point, that's only a
"nice-to-have".
3) ALSA PCM plugin plumbing - it may be possible to wire a set of PCM plugins
together (including mine), to better emulate the interface that sophisticated
audio clients require. The attraction here is that it would not require writing
any new code, only configuration file editing.
4) Write an ALSA driver - no libc, no userspace FFT libs,
userspace-to-kernelspace plumbing. Blech, no thanks.
Thoughts on these options or anything else covered here?
Related experiences to share? Please do!
Sample of configuration for ALSA extplug "myplug", loading a 300-3000Hz bandpass FIR filter of 1024 taps:
Code:
pcm.!default myplug
pcm_type.myplug {
lib "/path/to/lib/libasound_module_pcm_myplug.so"
}
pcm.myplug {
type myplug
logpath "/tmp"
#slave.pcm "save"
slave.pcm "plughw:0,0"
coeffs {
myfilter "/path/to/filter/fir_bp_300_3000_1024.txt"
}
channels {
left {
input 0
output 0
mute no # or "yes"
bypass no
gain -6 # in dB
delay 55 # in microsec
filter myfilter
}
right {
input 1
output 1
mute no
bypass no
gain -6
delay 55
filter myfilter
}
}
}
pcm.save {
type file
slave.pcm "null"
file "/tmp/output.wav"
format "wav"
}