[pulseaudio-discuss] Biquad LR4 for module-lfe-lp
justin at justinzane.com
Sat Mar 30 08:37:13 PDT 2013
On Saturday, March 30, 2013 04:04:59 PM you wrote:
> 2013/3/30 Justin Chudgar <justin at justinzane.com>:
> > https://github.com/justinzane/pulseaudio.git
> > Alexander:
> > Now that I have a possibly working rewind implementation, Iwanted to make
> > sure that I understand your guidance on doing a correct LR4. Following is
> > what I currently think I need to do:
> > - split channels into 3 sets: lowpass, highpass, and allpass
> > - calculate the respective biquad coefficients using a Q=0.5, with one set
> > of coefficients for both stages of the lp/hp/ap cascades -- that is,
> > [a0,a1,a2,b0,b1,b2]
> > - use two separate data buffersfor each channel, for the first and second
> > stages respectively -- that is,
> > [numchannels][ [y0,y1,y2,w0,w1,w2]
> > Another question I have is whether float or double are more appropriate
> > for the actual calculations. Reducing my implementation from double to
> > float seems wise to me for speed and space reasons on 32bit platforms,
> > but I'm not sure that loss of precision in an IIR filter is acceptable.
> > If you review the actual code, I know it is not done to the style
> > standards. I am going to clean it up once I've made sure that it is
> > fundamentally correct.
> The description above does not match the logic behind LR4 filters.
> Since you are repeating the same misunderstanding over and over again,
> it would be useless to review your code now, and I am nearly out of
> ideas how to help you. So I will try the remaining two ideas: "use
> different words" and "use a picture".
> So, with different words and an example. Let's consider what you call
> a highpass channel. Let's say it is the rear-left channel. You filter
> it twice with a highpass filter and copy the filtered-twice result to
> the corresponding output channel. During this process, the high
> frequencies pass through, and the low frequencies are discarded. The
> "unwanted frequencies are discarded" part is what you did wrong.
I disagree with this analysis for this use-case. If this implementation were
in remix.c it would make sense. However, it works with fictitious, synthetic,
duplicated, averaged, generally boooooooogus (can't find quite the right
adjective) source data. This module does NOT do remixing. Though I would
prefer this to be done in remix.c, many people have said that it should be in
a module and I am simply trying to achieve what I want within the guidelines
laid out by more experienced and smarter pulseaudio community members.
The only reason I began this effort was to get lowpass filtered output to my
subwoofer when enabling lfe remixing in daemon.conf.
I added the highpass to the center channel because it also makes sense to me
to logically consider the center and lfe channels as a group of synthesized
channels. The allpassing is just done to address the group delay, as I thought
you had suggested. Everything but the lowpass filtering of the lfe channel is
extraneous to me. And, since my wife and I and a couple of our guests have
been listening to a previous commit all week, quite happily, I am sure that it
mostly works as intended.
You seem to have a design for a "crossover" that would be excellent for
inclusion in remix.c. If that is something that might be considered for actual
mainlining, I would consider trying to do it. For this module, I cannot see
the relevance to my design goals.
> They should not be discarded. They should be extracted from the rear-left
> channel (and from all other channels) with a chain of two lowpass
> filters and moved to a channel capable of reproducing them - i.e., in
> our case, to the subwoofer. Conversely, unwanted high frequencies
> should be moved from the subwoofer, say, to the center channel or to
> all other channels.
My center channel speaker can reproduce 106Hz-20kHz. If I did not filter the
low frequencies, they would be discarded by the little 3 inch drivers that are
physically unable to reproduce them. Since the center channel source exists
only due to remix.c averaging front-left and front-right in any case, nothing
is discarded overall.
The parallel is true for the subwoofer, it is fed an average of l+r, which
includes frequecies that it simply cannot reproduce. These are discarded by
the physical speaker in any case, so removing them with a filter simple allows
the subwoofer to clearly reproduce the bass without muddying things up. Those
"discarded" frequencies still exist in all the other channels.
The use-case for this module is primarily with mono/stereo sources that have
been remixed by remix.c. It is easy enough, either with pacmd or something
like Veromix (in KDE's Plasma) to move that BluRay playing in smplayer to the
master sink and skip the filter. I am not yet familiar with how "properties"
are used to guide the filter heuristics, but it may be possible to have this
filter selectively applied for mono/stereo audio/video source streams while
using the master sink directly with natively surround streams. In many ways,
that would be an ideal outcome, to me.
> As for your use of allpass filters, I will verify separately whether
> it is a valid optimization.
> Regarding the biquad itself - the order of assignments in
> filter_biquad() is definitely wrong. Look, w1 always ends up being
> equal to w0, and y1 equal to y0.
That was intentional, [unless I munged something since I tested this :)] they
are the historical data. They are simply a convenience since I did not want to
do bounds checking on the *src_sample/*dst_sample pointers to the in and out
memblock_q's because I do not understand the architecture that well.
It should be the case that w0 == *src_sample; w1 == *(src_sample -
(sample_size * channels)); w2 == *(src_sample - 2 * (sample_size * channels));
and the same for the output samples.
> And now the promised picture:
> edirection_1.png . Each ^\ filter should be understood as a cascade of two
> Butterworth lowpass filters, and _/ is a cascade of two Butterworth
> filters. As for their treatment of the subwoofer, I'd replace their
> allpass filter with a lowpass, and redirect (unwanted) high
> frequencies from the subwoofer to the center channel.
Since, by definition,
(0.5 * (src_frame[left] + src_frame[right])_,
that seems to be exactly what I am accomplishing.
> Alexander E. Patrakov
More information about the pulseaudio-discuss