[pulseaudio-discuss] R: New equalizer module (module-eqpro-sink), some questions

Alexander E. Patrakov patrakov at gmail.com
Fri Apr 19 23:02:42 UTC 2019

сб, 20 апр. 2019 г. в 00:15, Georg Chini <georg at chini.tk>:
> On 19.04.19 18:23, Alexander E. Patrakov wrote:
> > пт, 19 апр. 2019 г. в 14:13, Tanu Kaskinen <tanuk at iki.fi>:
> >> If the plugin gets the number of bands during the
> >> initialization, it can create the appropriate number of non-array
> >> control ports. Interleaved audio ports aren't needed either, because
> >> PulseAudio can do the deinterleaving before passing the audio to the
> >> plugin (like module-ladspa-sink already does). If one's going to write
> >> an LV2 plugin, it's best to use standard port types so that all hosts
> >> will be able to use the plugin.
> > In addition, I think that "if the plugin gets the number of bands [at
> > runtime]" is a very big "if" for an IIR-based equalizer. So big that I
> > would rather hard-code it, or treat equalizers with a different number
> > of bands as completely different plugins. The reason is that the
> > required slope of inter-band transition (i.e., effectively, the filter
> > order) is a function of the width of each band. Implement a filter
> > with a too-low order, and it won't be able to isolate (and thus
> > control thegain of) a frequency band selectively enough. Implement a
> > filter with a too-high order, and its frequency response will be too
> > steppy.
> My understanding is that Andrea's equalizer algorithm supports
> an arbitrary number of bands (certainly within some sane limits).
> Please correct me if I am wrong.

It supports arbitrary amount of bands, but not arbitrary filter order
for a band. Just to reiterate, the whole filter is a cascade of some
per-band filters of the same order. Each filter in the cascade is
implemented, according to the dissertation, as a cut-and-boost filter,
which is based on a band-pass filter, which is in turn based on a
shelving Butterworth filter of order 2M. Hopefully I haven't missed
any order-doubling here. I have not thoroughly checked whether the
implementation actually follows the dissertation - this is complicated
by the Italian language that I don't know, and cryptic variable names.

The majority of the dissertation does contain formulas for an
arbitrary even order (2M), but on page 41, it starts talking about
filters of order 8 only. And, if I understand correctly, it doesn't
match the code, which is hard-coded to implement only filters of order
4, and it is not only a matter of increasing M and M2 in the file,
because then xn[i] must be set in eq_filter() for i >= 4. Another sign
of this mismatch between the dissertation and the code is the
different length of the "c" array - 10 in the code and 21 in algorithm
6.2 on page 43 (page numbers here are presented as printed at the
bottom, not as displayed in PDF viewers' left pane).

Because of the fixed order, there are indeed limits on the useful
number of bands. E.g., given that the minimum and maximum supported
gains in the band are -12 and 12 dB (at least this is what's mentioned
in the dissertation), it means that the gain must increase by 24 dB
between the centers of the neighboring bands. With the default 10-band
filter, i.e. with one octave per band, this means that 24 dB per
octave is the maximum supported slope, which is roughly right for a
4th order filter. In other words, more than 10 bands cannot be useful
with 4th order filters and 24 dB of gain difference between the
neighboring bands. I understand that it is odd to set the gain in two
neighboring octaves to differ by that much.

For a 5-band equalizer with the same gain limits, filters of 2nd order
would be sufficient and preferable. Also, the order of the filter
could be lowered if the gain limits are set lower.

> > Besides, consumer electronic devices (TVs, HDMI receivers, Hi-Fi
> > amplifiers) just do not have equalizers with a variable number of
> > bands, for usability reasons. I don't see a reason for PulseAudio to
> > be different.
> >
> You can't add sliders on the fly on a consumer electronic
> device but you can do so in software. Why should we be guided
> by a behavior that is governed by physical limits? If the algorithm
> supports it, I see no reason why it should not be implemented.
> (As said above naturally within some sane limits, you are right
> that it would make no sense to have for example 50 bands.)

Sliders in a consumer electronics device such as a TV are just virtual
widgets on the screen, i.e. software, not physical knobs. Again, their
number is fixed because of usable and "intuitive" UI.

> Surely you could go for several different plugins, but I do not
> see the reason why the code should be duplicated a couple
> of times. The goal is to have one plugin and not a collection.
> I just don't like the idea that you have to duplicate things only
> because of the limitation of the surrounding framework.
> That's why I am looking for a way to dynamically adapt the
> number of control ports or - which seems to be supported
> by LV2 - use a control port that is an array.

And my point is exactly that there is a reason, filter order, not
related to any framework limitations, for different code for different
number of bands.

> Another example where an array would be useful as a control
> port is the virtual-surround-sink. The HRIR data used by the filter
> is an array of floats which could vary in size.

I also disagree here. Yes, it can vary in size, but should not be
treated as a control port at all. There is no way to usefully control
it for a user, that's why. It should therefore be either hard-coded
(as done in Windows) or loaded through a file.

In summary, there is no use case presented so far that actually
requires the number of user-controllable (i.e. exposed) controls to be
a non-constant, and one of the reasons is that this won't fly past UI
guidelines. Anyway, if LV2 supports this use case, and we settle on
LV2 as the preferred plugin format, then we should support this
feature, too, despite the UI-design-related objection above.

> The focus of this mail thread is no longer the equalizer, even
> though the subject may suggest that and it is often used as an
> example. The starting point of the discussion was that I did a
> consolidation of the virtual sinks we have in pulseaudio (see
> !88) and the result shows that many of the filters we have
> could be further consolidated to a single plugin sink. The
> question then was which kind of plugin format we should use?
> Naturally it would be better to use some standard API instead
> of inventing our own. And if we move to a plugin-sink, the
> plugin API should also support the features of the new
> equalizer, so that this can be integrated as well if Andrea
> is willing to contribute to a plugin.
> Tanu suggested the LV2 standard, so I took a look into it. My
> understanding is, that the CVPort is the type of control structure
> I have been looking for, though Tanu says otherwise.

I do agree that we should use some standard API if it fits, and don't
see it a big problem if there are cases like echo-cancellation that
don't fit.

I have no my own objections to LV2, but we have discussed the idea of
module-lv2-sink with David Henningsson in 2013 on LinuxCon Europe, and
he did object - if I remember correctly, it was something related to
GUI libraries used in LV2 plugins.

> There is however another limitation I see with the LV2 standard,
> which is that it does not support interleaved audio channels.
> This is not fatal, but at least inconvenient. It looks like massive
> overhead to me if you have to de-interlace the audio data, then
> run multiple instances of the filter and finally have to interleave
> the data again. I think a plugin standard for pulseaudio should
> be able to handle interleaved data.

Pro audio world (which is the native habitat of various LADSPA and LV2
plugins) is dominated by JACK, which supports non-interleaved audio
samples only.

Alexander E. Patrakov

More information about the pulseaudio-discuss mailing list