ref: 2317e8455b554c97e9dc42aafde31fa0df69ae1b
parent: f7e36c194096f7048f931ad69afb681720eb9291
author: robs <robs>
date: Tue Jan 13 16:14:34 EST 2009
dither: slight accuracy improvement; add headroom values
--- a/src/dither.c
+++ b/src/dither.c
@@ -24,6 +24,10 @@
#include <assert.h>
#define PREC effp->out_signal.precision
+#define SOX_ROUND_PREC_CLIP_COUNT(d, clips) \
+ ((d) < 0? (d) <= SOX_SAMPLE_MIN - 0.5? ++(clips), SOX_SAMPLE_MIN: (d) - 0.5 \
+ : (d) >= SOX_SAMPLE_MAX - (1 << (31-PREC)) + 0.5? \
+ ++(clips), SOX_SAMPLE_MAX - (1 << (31-PREC)): (d) + 0.5)
typedef enum {Pdf_rectangular, Pdf_triangular, Pdf_gaussian} pdf_type_t;
static lsx_enum_item const pdf_types[] = {
@@ -50,8 +54,9 @@
typedef struct {
sox_rate_t rate;
- enum {fir, iir} type ;
+ enum {fir, iir} type;
size_t len;
+ double gain;
double const * coefs;
filter_name_t name;
} filter_t;
@@ -68,7 +73,7 @@
3.7067542076110839844, -1.0495119094848632812, -1.1830236911773681641, 2.1126792430877685547,
-1.9094531536102294922, 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609,
0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002,-0.023473845794796943665,
-}; /* 48k, N=16, amp=18 */
+};
static double const shi44[] = {
2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875, -7.4572014808654785156,
@@ -76,7 +81,7 @@
-2.9537565708160400391, 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297,
-2.1179926395416259766, 0.879302978515625, -0.031759146600961685181,-0.42382788658142089844,
0.47882103919982910156, -0.35490813851356506348, 0.17496839165687561035, -0.060908168554306030273,
-}; /* 44.1k, N=20, amp=27 */
+};
static double const shi38[] = {
1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219, -2.6341717243194580078,
@@ -83,7 +88,7 @@
2.1440362930297851562, -1.8153258562088012695, 1.0816224813461303711, -0.70302653312683105469,
0.15991993248462677002, 0.041549518704414367676,-0.29416576027870178223, 0.2518316805362701416,
-0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203, 0.016833892092108726501,
-}; /* 37.8k, N=16 */
+};
static double const shi32[] = {
0.82901298999786376953, -0.98922657966613769531, 0.59825712442398071289, -1.0028809309005737305,
@@ -90,7 +95,7 @@
0.59938216209411621094, -0.79502451419830322266, 0.42723315954208374023, -0.54492527246475219727,
0.30792605876922607422, -0.36871799826622009277, 0.18792048096656799316, -0.2261127084493637085,
0.10573341697454452515, -0.11435490846633911133, 0.038800679147243499756,-0.040842197835445404053,
-}; /* 32k, N=16 */
+};
static double const shi22[] = {
0.065229974687099456787,-0.54981261491775512695, -0.40278548002243041992, -0.31783768534660339355,
@@ -97,7 +102,7 @@
-0.28201797604560852051, -0.16985194385051727295, -0.15433363616466522217, -0.12507140636444091797,
-0.08903945237398147583, -0.064410120248794555664,-0.047146003693342208862,-0.032805237919092178345,
-0.028495194390416145325,-0.011695005930960178375,-0.011831838637590408325,
-}; /* 22.05k, N=15 */
+};
static double const shl48[] = {
2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469, -1.8117271661758422852,
@@ -104,7 +109,7 @@
-0.20124770700931549072, 1.4759907722473144531, -1.7210904359817504883, 0.97746700048446655273,
-0.13790138065814971924, -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559,
-0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035, 0.068674825131893157959,
-}; /* 48k, N=16, amp=10 */
+};
static double const shl44[] = {
2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109, -2.7571926116943359375,
@@ -111,7 +116,7 @@
1.4978630542755126953, -0.3427594602108001709, -0.71733748912811279297, 1.0737057924270629883,
-1.0225815773010253906, 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996,
0.10322438180446624756, -0.067442022264003753662,-0.00495197344571352005,
-}; /* 44.1k, N=15, amp=9 */
+};
static double const shh44[] = {
3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375, -11.824929237365722656,
@@ -119,24 +124,24 @@
1.1393624544143676758, 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031,
-5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656, 2.1909697055816650391,
-1.1672389507293701172, 0.4903914332389831543, -0.16519790887832641602, 0.023217858746647834778,
-}; /* 44.1k, N=20 */
+};
static const filter_t filters[] = {
- {44100, fir, 5, lip44, Shape_lipshitz},
- {46000, fir, 9, fwe44, Shape_f_weighted},
- {46000, fir, 9, mew44, Shape_modified_e_weighted},
- {46000, fir, 9, iew44, Shape_improved_e_weighted},
- {48000, iir, 4, ges48, Shape_gesemann},
- {44100, iir, 4, ges44, Shape_gesemann},
- {48000, fir, 16, shi48, Shape_shibata},
- {44100, fir, 20, shi44, Shape_shibata},
- {37800, fir, 16, shi38, Shape_shibata},
- {32000, fir, 16, shi32, Shape_shibata},
- {22050, fir, 15, shi22, Shape_shibata},
- {48000, fir, 16, shl48, Shape_low_shibata},
- {44100, fir, 15, shl44, Shape_low_shibata},
- {44100, fir, 20, shh44, Shape_high_shibata},
- { 0, fir, 0, NULL, Shape_none},
+ {44100, fir, 5, 19.6, lip44, Shape_lipshitz},
+ {46000, fir, 9, 26.6, fwe44, Shape_f_weighted},
+ {46000, fir, 9, 14.6, mew44, Shape_modified_e_weighted},
+ {46000, fir, 9, 30.6, iew44, Shape_improved_e_weighted},
+ {48000, iir, 4, 21.0, ges48, Shape_gesemann},
+ {44100, iir, 4, 21.2, ges44, Shape_gesemann},
+ {48000, fir, 16, 28.8, shi48, Shape_shibata},
+ {44100, fir, 20, 32.5, shi44, Shape_shibata},
+ {37800, fir, 16, 22.7, shi38, Shape_shibata},
+ {32000, fir, 16, 15.7, shi32, Shape_shibata},
+ {22050, fir, 15, 9.0, shi22, Shape_shibata},
+ {48000, fir, 16, 23.5, shl48, Shape_low_shibata},
+ {44100, fir, 15, 23.0, shl44, Shape_low_shibata},
+ {44100, fir, 20, 37.5, shh44, Shape_high_shibata},
+ { 0, fir, 0, 0.0, NULL, Shape_none},
};
#define MAX_N 30
@@ -181,13 +186,12 @@
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
-
size_t len = *isamp = *osamp = min(*isamp, *osamp);
- int dummy = 0;
while (len--) {
- double d = *ibuf++ + p->am0 * RANQD1 + p->am1 * RANQD1;
- *obuf++ = SOX_ROUND_CLIP_COUNT(d, dummy);
+ double d = *ibuf++ + floor(p->am0 * RANQD1) + floor(p->am1 * RANQD1);
+ SOX_SAMPLE_CLIP_COUNT(d, effp->clips);
+ *obuf++ = d;
}
return SOX_SUCCESS;
}
@@ -218,8 +222,9 @@
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
+ double mult = 1;
- if (PREC >= 24)
+ if (PREC > 24)
return SOX_EFF_NULL; /* Dithering not needed at this resolution */
if (!p->filter_name)
@@ -245,9 +250,14 @@
default: assert(sox_false);
}
p->coefs = f->coefs;
+ mult = dB_to_linear(f->gain);
}
p->am1 = p->depth / (1 << PREC);
p->am0 = (p->pdf == Pdf_triangular) * p->am1;
+
+ if (effp->flow == 0 && effp->in_signal.mult)
+ *effp->in_signal.mult *= 1 - (p->am0 + p->am1) * mult;
+
lsx_debug("pdf=%s filter=%s depth=%g", lsx_find_enum_value(p->pdf, pdf_types)->text, lsx_find_enum_value(p->filter_name, filter_names)->text, p->depth);
return SOX_SUCCESS;
}
--- a/src/dither_fir.h
+++ b/src/dither_fir.h
@@ -6,14 +6,12 @@
size_t len = *isamp = *osamp = min(*isamp, *osamp);
while (len--) {
- double r = p->am0 * RANQD1 + p->am1 * RANQD1;
+ double r = floor(p->am0 * RANQD1) + floor(p->am1 * RANQD1);
double error, d = *ibuf++;
int j = 0;
CONVOLVE
assert(j == N);
- *obuf = d + r < 0? d + r <= SOX_SAMPLE_MIN - .5? SOX_SAMPLE_MIN: d + r - .5
- : d + r >= SOX_SAMPLE_MAX - (1 << (31-PREC)) + 0.5?
- SOX_SAMPLE_MAX - (1 << (31-PREC)): d + r + .5;
+ *obuf = SOX_ROUND_PREC_CLIP_COUNT(d + r, effp->clips);
error = ((*obuf++ + (1 << (31-PREC))) & (-1 << (32-PREC))) - d;
p->pos = p->pos? p->pos - 1 : p->pos - 1 + N;
p->previous_errors[p->pos + N] = p->previous_errors[p->pos] = error;
--- a/src/dither_iir.h
+++ b/src/dither_iir.h
@@ -7,15 +7,13 @@
size_t len = *isamp = *osamp = min(*isamp, *osamp);
while (len--) {
- double r = p->am0 * RANQD1 + p->am1 * RANQD1;
+ double r = floor(p->am0 * RANQD1) + floor(p->am1 * RANQD1);
double error, d, output = 0;
int j = 0;
CONVOLVE
assert(j == N);
d = *ibuf++ - output;
- *obuf = d + r < 0? d + r <= SOX_SAMPLE_MIN - .5? SOX_SAMPLE_MIN: d + r - .5
- : d + r >= SOX_SAMPLE_MAX - (1 << (31-PREC)) + 0.5?
- SOX_SAMPLE_MAX - (1 << (31-PREC)): d + r + .5;
+ *obuf = SOX_ROUND_PREC_CLIP_COUNT(d + r, effp->clips);
error = ((*obuf++ + (1 << (31-PREC))) & (-1 << (32-PREC))) - d;
p->pos = p->pos? p->pos - 1 : p->pos - 1 + N;
p->previous_errors[p->pos + N] = p->previous_errors[p->pos] = error;
--- a/src/sox.h
+++ b/src/sox.h
@@ -197,6 +197,7 @@
unsigned channels; /* number of sound channels */
unsigned precision; /* in bits */
size_t length; /* samples * chans in file */
+ double * mult; /* Effects headroom multiplier; may be null */
} sox_signalinfo_t;
typedef enum {