Re: sndiod: (mostly) suppress aliasing noise

2020-12-20 Thread Alexandre Ratchov
On Sun, Dec 20, 2020 at 05:58:22PM +0200, Paul Irofti wrote:
> Hi,
> 
> Interesting diff.
> 
> I did not have time to look at it thoroughly, but here are a few
> observations:
> 

Hi,

Thanks for looking at this.

  - why do you keep the symmetric filter coefficients? (this could halve your
> while-loop computations too, right?)
> 

The filter function is indeed symetric:

h(t) = h(-t)

but they are used at points that are not symetric, we need:

...
h(-2 + x)
h(-1 + x)
h(0 + x)
h(1 + x)
h(2 + x)
...

h(-1 + x) is not the same as h(1 + x), so using the symetry to save
CPU cycles is not easy

I also tried to store only half of the static table to save few bytes;
this makes the code larger (and messy) so the benefit is not that
important for such a small filter order.

>  - the diff's mainlobe look kind of strange at the end, why is that? What
> kind of filter did you use? 
> the side-lobes seem also a bit strange as they
> do not decrease monotonically nor are the first sidelobes small and then
> increasing

To measure the response, we're supposed to apply the filter to a
peak. But on the link I sent the plot it the result of the whole
8k->48k conversion, so the peak is not really peak anymore and the
result is harder to understand.

Here's plot of the Fourier transform of the coefficients in the code:

https://vm.caoua.org/src/coef-dft.png

which should look way more familiar (x-axis is multiples of the
Nyquist frequency, y-axis is the Fourier transform amplitude in dB)

The filter is an ideal "sinc" low-pass with the cut-off frequency set
to 0.75 of the Nyquist frequency, multiplied by a Blackman window of
length 8:

  h(t) = 0.75 * sinc(0.75 * pi * t) * win(t / 8)

where win(t) is the Blackman window function with a = 0.16, defined as:

  win(t) = 0.5 * ((1 - a) + cos(2 * pi * x) + a * cos(4 * pi * x))

At 48kHz, the transition band starts at 0.75 * 24kHz = 18kHz.  Besides
preserving audible frequencies, with this choice the ideal filter's
impulse response (the pure sinc function) crosses zero at the edges of
the window, which makes the result smoother (derivative is 0) and in
turn improves the roll-off.

>   - would be nice to see some SNR comparisons if you can to better show the
> effects of your anti-aliasing effort
> 

Here's an array of measurements I did.

https://vm.caoua.org/src/sweeps.html

The signal and the aliasing amplitudes are represented for each
frequency for various conversion ratios. Anything except the
increasing white curve (the signal, 0dB) is aliasing, the color indicates
its strength.



Re: sndiod: (mostly) suppress aliasing noise

2020-12-20 Thread Paul Irofti

Hi,

Interesting diff.

I did not have time to look at it thoroughly, but here are a few 
observations:


 - why do you keep the symmetric filter coefficients? (this could halve 
your while-loop computations too, right?)


 - the diff's mainlobe look kind of strange at the end, why is that? 
What kind of filter did you use? the side-lobes seem also a bit strange 
as they do not decrease monotonically nor are the first sidelobes small 
and then increasing


  - would be nice to see some SNR comparisons if you can to better show 
the effects of your anti-aliasing effort


Thanks for this,
Paul

On 20.12.2020 01:52, Alexandre Ratchov wrote:

Hi,

The current sndiod resampling algorithm is very basic mainly to keep
CPU usage very low, which used to make sense for the zaurus. So,
resampling produces aliasing noise, easily audible in 8kHz to 48kHz
conversions but present in other cases.

The diff below reduces the aliasing noise. It's a trade-off between
audio quality, CPU consumption and code simplicity. It adds a better
resampling filter (8-th order FIR low-pass), which mostly suppresses
aliasing noise in the audible part of the spectrum.

Few plots here: https://vm.caoua.org/src

I measured the CPU usage of resampling 16-bit stereo from 44.1kHz to
48kHz.

On a ~7 years old i5-2500K:
   - current code:  0.07% CPU
   - with diff: 0.45% CPU

On a ~15 years old Thinkpad x40:
   - current:   0.25% CPU
   - with diff: 1.90% CPU

This is still acceptable even for slow machines, IMHO. Enjoy and let
me know if this introduces any regression.

Index: dsp.c
===
RCS file: /cvs/src/usr.bin/sndiod/dsp.c,v
retrieving revision 1.15
diff -u -p -r1.15 dsp.c
--- dsp.c   10 Dec 2020 17:30:49 -  1.15
+++ dsp.c   19 Dec 2020 23:38:24 -
@@ -38,6 +38,75 @@ int aparams_ctltovol[128] = {
26008,  27029,  28090,  29193,  30339,  31530,  32768
  };
  
+int resamp_filt[RESAMP_LENGTH / RESAMP_STEP + 1] = {

+ 0,   0,   3,   9,  22,  42,  73, 116,
+   174, 248, 341, 454, 589, 749, 934,1148,
+  1392,1666,1974,2316,2693,3107,3560,4051,
+  4582,5154,5766,6420,7116,7853,8632,9451,
+ 10311,   11210,   12148,   13123,   14133,   15178,   16253,   17359,
+ 18491,   19647,   20824,   22018,   23226,   24443,   25665,   26888,
+ 28106,   29315,   30509,   31681,   32826,   33938,   35009,   36033,
+ 37001,   37908,   38744,   39502,   40174,   40750,   41223,   41582,
+ 41819,   41925,   41890,   41704,   41358,   40842,   40147,   39261,
+ 38176,   36881,   35366,   33623,   31641,   29411,   26923,   24169,
+ 21140,   17827,   14222,   10317,6105,1580,   -3267,   -8440,
+-13944,  -19785,  -25967,  -32492,  -39364,  -46584,  -54153,  -62072,
+-70339,  -78953,  -87911,  -97209, -106843, -116806, -127092, -137692,
+   -148596, -159795, -171276, -183025, -195029, -207271, -219735, -232401,
+   -245249, -258259, -271407, -284670, -298021, -311434, -324880, -338329,
+   -351750, -365111, -378378, -391515, -404485, -417252, -429775, -442015,
+   -453930, -465477, -476613, -487294, -497472, -507102, -516137, -524527,
+   -532225, -539181, -545344, -550664, -555090, -558571, -561055, -562490,
+   -562826, -562010, -559990, -556717, -552139, -546205, -538866, -530074,
+   -519779, -507936, -494496, -479416, -462652, -444160, -423901, -401835,
+   -377923, -352132, -324425, -294772, -263143, -229509, -193847, -156134,
+   -116348,  -74474,  -30494,   15601,   63822,  114174,  11,  221283,
+278037,  336916,  397911,  461009,  526194,  593446,  662741,  734054,
+807354,  882608,  959779, 1038826, 1119706, 1202370, 1286768, 1372846,
+   1460546, 1549808, 1640566, 1732753, 1826299, 1921130, 2017169, 2114336,
+   2212550, 2311723, 2411770, 2512598, 2614116, 2716228, 2818836, 2921841,
+   3025142, 3128636, 3232218, 3335782, 3439219, 3542423, 3645282, 3747687,
+   3849526, 3950687, 4051059, 4150530, 4248987, 4346320, 4442415, 4537163,
+   4630453, 4722177, 4812225, 4900493, 4986873, 5071263, 5153561, 5233668,
+   5311485, 5386917, 5459872, 5530259, 5597992, 5662986, 5725160, 5784436,
+   5840739, 5893999, 5944148, 5991122, 6034862, 6075313, 6112422, 6146142,
+   6176430, 6203247, 6226559, 6246335, 6262551, 6275185, 6284220, 6289647,
+   6291456, 6289647, 6284220, 6275185, 6262551, 6246335, 6226559, 6203247,
+   6176430, 6146142, 6112422, 6075313, 6034862, 5991122, 5944148, 5893999,
+   5840739, 5784436, 5725160, 5662986, 5597992, 5530259, 5459872, 5386917,
+   5311485, 5233668, 5153561, 5071263, 4986873, 4900493, 4812225, 4722177,
+   4630453, 4537163, 4442415, 4346320, 4248987, 4150530, 4051059, 3950687,
+   

sndiod: (mostly) suppress aliasing noise

2020-12-19 Thread Alexandre Ratchov
Hi,

The current sndiod resampling algorithm is very basic mainly to keep
CPU usage very low, which used to make sense for the zaurus. So,
resampling produces aliasing noise, easily audible in 8kHz to 48kHz
conversions but present in other cases.

The diff below reduces the aliasing noise. It's a trade-off between
audio quality, CPU consumption and code simplicity. It adds a better
resampling filter (8-th order FIR low-pass), which mostly suppresses
aliasing noise in the audible part of the spectrum.

Few plots here: https://vm.caoua.org/src

I measured the CPU usage of resampling 16-bit stereo from 44.1kHz to
48kHz.

On a ~7 years old i5-2500K:
  - current code:   0.07% CPU
  - with diff:  0.45% CPU

On a ~15 years old Thinkpad x40:
  - current:0.25% CPU
  - with diff:  1.90% CPU

This is still acceptable even for slow machines, IMHO. Enjoy and let
me know if this introduces any regression.

Index: dsp.c
===
RCS file: /cvs/src/usr.bin/sndiod/dsp.c,v
retrieving revision 1.15
diff -u -p -r1.15 dsp.c
--- dsp.c   10 Dec 2020 17:30:49 -  1.15
+++ dsp.c   19 Dec 2020 23:38:24 -
@@ -38,6 +38,75 @@ int aparams_ctltovol[128] = {
26008,  27029,  28090,  29193,  30339,  31530,  32768
 };
 
+int resamp_filt[RESAMP_LENGTH / RESAMP_STEP + 1] = {
+ 0,   0,   3,   9,  22,  42,  73, 116,
+   174, 248, 341, 454, 589, 749, 934,1148,
+  1392,1666,1974,2316,2693,3107,3560,4051,
+  4582,5154,5766,6420,7116,7853,8632,9451,
+ 10311,   11210,   12148,   13123,   14133,   15178,   16253,   17359,
+ 18491,   19647,   20824,   22018,   23226,   24443,   25665,   26888,
+ 28106,   29315,   30509,   31681,   32826,   33938,   35009,   36033,
+ 37001,   37908,   38744,   39502,   40174,   40750,   41223,   41582,
+ 41819,   41925,   41890,   41704,   41358,   40842,   40147,   39261,
+ 38176,   36881,   35366,   33623,   31641,   29411,   26923,   24169,
+ 21140,   17827,   14222,   10317,6105,1580,   -3267,   -8440,
+-13944,  -19785,  -25967,  -32492,  -39364,  -46584,  -54153,  -62072,
+-70339,  -78953,  -87911,  -97209, -106843, -116806, -127092, -137692,
+   -148596, -159795, -171276, -183025, -195029, -207271, -219735, -232401,
+   -245249, -258259, -271407, -284670, -298021, -311434, -324880, -338329,
+   -351750, -365111, -378378, -391515, -404485, -417252, -429775, -442015,
+   -453930, -465477, -476613, -487294, -497472, -507102, -516137, -524527,
+   -532225, -539181, -545344, -550664, -555090, -558571, -561055, -562490,
+   -562826, -562010, -559990, -556717, -552139, -546205, -538866, -530074,
+   -519779, -507936, -494496, -479416, -462652, -444160, -423901, -401835,
+   -377923, -352132, -324425, -294772, -263143, -229509, -193847, -156134,
+   -116348,  -74474,  -30494,   15601,   63822,  114174,  11,  221283,
+278037,  336916,  397911,  461009,  526194,  593446,  662741,  734054,
+807354,  882608,  959779, 1038826, 1119706, 1202370, 1286768, 1372846,
+   1460546, 1549808, 1640566, 1732753, 1826299, 1921130, 2017169, 2114336,
+   2212550, 2311723, 2411770, 2512598, 2614116, 2716228, 2818836, 2921841,
+   3025142, 3128636, 3232218, 3335782, 3439219, 3542423, 3645282, 3747687,
+   3849526, 3950687, 4051059, 4150530, 4248987, 4346320, 4442415, 4537163,
+   4630453, 4722177, 4812225, 4900493, 4986873, 5071263, 5153561, 5233668,
+   5311485, 5386917, 5459872, 5530259, 5597992, 5662986, 5725160, 5784436,
+   5840739, 5893999, 5944148, 5991122, 6034862, 6075313, 6112422, 6146142,
+   6176430, 6203247, 6226559, 6246335, 6262551, 6275185, 6284220, 6289647,
+   6291456, 6289647, 6284220, 6275185, 6262551, 6246335, 6226559, 6203247,
+   6176430, 6146142, 6112422, 6075313, 6034862, 5991122, 5944148, 5893999,
+   5840739, 5784436, 5725160, 5662986, 5597992, 5530259, 5459872, 5386917,
+   5311485, 5233668, 5153561, 5071263, 4986873, 4900493, 4812225, 4722177,
+   4630453, 4537163, 4442415, 4346320, 4248987, 4150530, 4051059, 3950687,
+   3849526, 3747687, 3645282, 3542423, 3439219, 3335782, 3232218, 3128636,
+   3025142, 2921841, 2818836, 2716228, 2614116, 2512598, 2411770, 2311723,
+   2212550, 2114336, 2017169, 1921130, 1826299, 1732753, 1640566, 1549808,
+   1460546, 1372846, 1286768, 1202370, 1119706, 1038826,  959779,  882608,
+807354,  734054,  662741,  593446,  526194,  461009,  397911,  336916,
+278037,  221283,  11,  114174,   63822,   15601,  -30494,  -74474,
+   -116348, -156134, -193847, -229509, -263143, -294772, -324425, -352132,
+   -377923, -401835, -423901, -444160, -462652, -479416, -494496, -507936,
+   -519779,