ref: 585045c0398595059dbd37aeb7c4f1110af6b38c
parent: c220e4dab9d4c50e141f6a2e23e9a6f9e6569475
author: robs <robs>
date: Fri Mar 20 16:13:36 EDT 2009
dither improvements
--- a/src/dither.c
+++ b/src/dither.c
@@ -1,4 +1,4 @@
-/* Effect: dither/noise-shape Copyright (c) 2008 robs@users.sourceforge.net
+/* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
@@ -25,18 +25,7 @@
#undef RANQD1
#define RANQD1 ranqd1(p->ranqd1)
-#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-p->prec)) + 0.5? \
- ++(clips), SOX_SAMPLE_MAX - (1 << (31-p->prec)): (d) + 0.5)
-typedef enum {Pdf_rectangular, Pdf_triangular, Pdf_gaussian} pdf_type_t;
-static lsx_enum_item const pdf_types[] = {
- LSX_ENUM_ITEM(Pdf_,rectangular)
- LSX_ENUM_ITEM(Pdf_,triangular)
- LSX_ENUM_ITEM(Pdf_,gaussian)
- {0, 0}};
-
typedef enum {
Shape_none, Shape_lipshitz, Shape_f_weighted, Shape_modified_e_weighted,
Shape_improved_e_weighted, Shape_gesemann, Shape_shibata, Shape_low_shibata, Shape_high_shibata
@@ -70,61 +59,68 @@
static double const ges48[] = {2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571};
static double const shi48[] = {
- 2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406, -5.8483986854553222656,
- 3.7067542076110839844, -1.0495119094848632812, -1.1830236911773681641, 2.1126792430877685547,
- -1.9094531536102294922, 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609,
- 0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002,-0.023473845794796943665,
+ 2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406,
+ -5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812,
+ -1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922,
+ 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609,
+ 0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002,
+ -0.023473845794796943665,
};
-
static double const shi44[] = {
- 2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875, -7.4572014808654785156,
- 6.7263274192810058594, -4.8481650352478027344, 2.0412089824676513672, 0.7006359100341796875,
- -2.9537565708160400391, 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297,
- -2.1179926395416259766, 0.879302978515625, -0.031759146600961685181,-0.42382788658142089844,
- 0.47882103919982910156, -0.35490813851356506348, 0.17496839165687561035, -0.060908168554306030273,
+ 2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875,
+ -7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344,
+ 2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391,
+ 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297,
+ -2.1179926395416259766, 0.879302978515625, -0.031759146600961685181,
+ -0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348,
+ 0.17496839165687561035, -0.060908168554306030273,
};
-
static double const shi38[] = {
- 1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219, -2.6341717243194580078,
- 2.1440362930297851562, -1.8153258562088012695, 1.0816224813461303711, -0.70302653312683105469,
- 0.15991993248462677002, 0.041549518704414367676,-0.29416576027870178223, 0.2518316805362701416,
- -0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203, 0.016833892092108726501,
+ 1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219,
+ -2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695,
+ 1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002,
+ 0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416,
+ -0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203,
+ 0.016833892092108726501,
};
-
static double const shi32[] = {
- 0.82901298999786376953, -0.98922657966613769531, 0.59825712442398071289, -1.0028809309005737305,
- 0.59938216209411621094, -0.79502451419830322266, 0.42723315954208374023, -0.54492527246475219727,
- 0.30792605876922607422, -0.36871799826622009277, 0.18792048096656799316, -0.2261127084493637085,
- 0.10573341697454452515, -0.11435490846633911133, 0.038800679147243499756,-0.040842197835445404053,
+ 0.82901298999786376953, -0.98922657966613769531, 0.59825712442398071289,
+ -1.0028809309005737305, 0.59938216209411621094, -0.79502451419830322266,
+ 0.42723315954208374023, -0.54492527246475219727, 0.30792605876922607422,
+ -0.36871799826622009277, 0.18792048096656799316, -0.2261127084493637085,
+ 0.10573341697454452515, -0.11435490846633911133, 0.038800679147243499756,
+ -0.040842197835445404053,
};
-
static double const shi22[] = {
- 0.065229974687099456787,-0.54981261491775512695, -0.40278548002243041992, -0.31783768534660339355,
- -0.28201797604560852051, -0.16985194385051727295, -0.15433363616466522217, -0.12507140636444091797,
- -0.08903945237398147583, -0.064410120248794555664,-0.047146003693342208862,-0.032805237919092178345,
- -0.028495194390416145325,-0.011695005930960178375,-0.011831838637590408325,
+ 0.065229974687099456787, -0.54981261491775512695, -0.40278548002243041992,
+ -0.31783768534660339355, -0.28201797604560852051, -0.16985194385051727295,
+ -0.15433363616466522217, -0.12507140636444091797, -0.08903945237398147583,
+ -0.064410120248794555664, -0.047146003693342208862, -0.032805237919092178345,
+ -0.028495194390416145325, -0.011695005930960178375, -0.011831838637590408325,
};
-
static double const shl48[] = {
- 2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469, -1.8117271661758422852,
- -0.20124770700931549072, 1.4759907722473144531, -1.7210904359817504883, 0.97746700048446655273,
- -0.13790138065814971924, -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559,
- -0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035, 0.068674825131893157959,
+ 2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469,
+ -1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531,
+ -1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924,
+ -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559,
+ -0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035,
+ 0.068674825131893157959,
};
-
static double const shl44[] = {
- 2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109, -2.7571926116943359375,
- 1.4978630542755126953, -0.3427594602108001709, -0.71733748912811279297, 1.0737057924270629883,
- -1.0225815773010253906, 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996,
- 0.10322438180446624756, -0.067442022264003753662,-0.00495197344571352005,
+ 2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109,
+ -2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709,
+ -0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906,
+ 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996,
+ 0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005,
};
-
static double const shh44[] = {
- 3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375, -11.824929237365722656,
- 12.767142295837402344, -11.917946815490722656, 9.1739168167114257812, -5.3712320327758789062,
- 1.1393624544143676758, 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031,
- -5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656, 2.1909697055816650391,
- -1.1672389507293701172, 0.4903914332389831543, -0.16519790887832641602, 0.023217858746647834778,
+ 3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375,
+ -11.824929237365722656, 12.767142295837402344, -11.917946815490722656,
+ 9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758,
+ 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031,
+ -5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656,
+ 2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543,
+ -0.16519790887832641602, 0.023217858746647834778,
};
static const filter_t filters[] = {
@@ -145,45 +141,48 @@
{ 0, fir, 0, 0.0, NULL, Shape_none},
};
-#define MAX_N 30
+#define MAX_N 20
typedef struct {
- pdf_type_t pdf;
filter_name_t filter_name;
- sox_bool reseed;
- double am0, am1, depth;
+ sox_bool auto_detect;
+ double dummy;
+
double previous_errors[MAX_N * 2];
double previous_outputs[MAX_N * 2];
- size_t pos, prec;
- int32_t ranqd1;
- double const * coefs;
+ size_t pos, prec, num_output;
+ int32_t history, ranqd1;
+ double const * coefs;
+ sox_bool dither_off;
int (*flow)(sox_effect_t *, const sox_sample_t *, sox_sample_t *, size_t *, size_t *);
} priv_t;
#define CONVOLVE _ _ _ _
#define NAME flow_iir_4
+#define IIR
#define N 4
-#include "dither_iir.h"
+#include "dither.h"
+#undef IIR
#define CONVOLVE _ _ _ _ _
#define NAME flow_fir_5
#define N 5
-#include "dither_fir.h"
+#include "dither.h"
#define CONVOLVE _ _ _ _ _ _ _ _ _
#define NAME flow_fir_9
#define N 9
-#include "dither_fir.h"
+#include "dither.h"
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
#define NAME flow_fir_15
#define N 15
-#include "dither_fir.h"
+#include "dither.h"
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
#define NAME flow_fir_16
#define N 16
-#include "dither_fir.h"
+#include "dither.h"
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
#define NAME flow_fir_20
#define N 20
-#include "dither_fir.h"
+#include "dither.h"
static int flow_no_shape(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
@@ -191,11 +190,38 @@
priv_t * p = (priv_t *)effp->priv;
size_t len = *isamp = *osamp = min(*isamp, *osamp);
- while (len--) {
- double d = *ibuf++ + floor(p->am0 * RANQD1) + floor(p->am1 * RANQD1);
- SOX_SAMPLE_CLIP_COUNT(d, effp->clips);
- *obuf++ = d;
+ if (p->auto_detect) while (len--) {
+ p->history = ((p->history << 1) + !!(*ibuf & (-1u >> p->prec)));
+ if (p->history) {
+ double d = *ibuf++ + (double)(RANQD1 >> p->prec) + (RANQD1 >> p->prec);
+ d /= (1 << (32 - p->prec));
+ d = (int)(d < 0? d - .5 : d + .5);
+ if (d < (-1 << (p->prec-1)))
+ ++effp->clips, *obuf = -1 << (p->prec-1);
+ else if (d > SOX_INT_MAX(p->prec))
+ ++effp->clips, *obuf = SOX_INT_MAX(p->prec);
+ else *obuf = d;
+ *obuf++ <<= 32 - p->prec;
+ if (p->dither_off)
+ lsx_debug("flow %u: on @ %u", effp->flow, (unsigned)p->num_output);
+ p->dither_off = sox_false;
+ }
+ else {
+ *obuf++ = *ibuf++;
+ if (!p->dither_off)
+ lsx_debug("flow %u: off @ %u", effp->flow, (unsigned)p->num_output);
+ p->dither_off = sox_true;
+ }
+ ++p->num_output;
}
+ else while (len--) {
+ double d = *ibuf++ + (double)(RANQD1 >> p->prec) + (RANQD1 >> p->prec);
+ d /= (1 << (32 - p->prec));
+ d = (int)(d < 0? d - .5 : d + .5);
+ *obuf = d < (-1 << (p->prec-1))? ++effp->clips, -1 << (p->prec-1) :
+ d > SOX_INT_MAX(p->prec)? ++effp->clips, SOX_INT_MAX(p->prec) : d;
+ *obuf++ <<= 32 - p->prec;
+ }
return SOX_SUCCESS;
}
@@ -204,11 +230,9 @@
priv_t * p = (priv_t *)effp->priv;
int c;
- p->pdf = Pdf_triangular;
- while ((c = getopt(argc, argv, "+Rrtsf:")) != -1) switch (c) {
- case 'R': p->reseed = sox_true; break;
- case 'r': p->pdf = Pdf_rectangular; break;
- case 't': p->pdf = Pdf_triangular ; break;
+ while ((c = getopt(argc, argv, "+asf:""rt")) != -1) switch (c) {
+ case 'a': p->auto_detect = sox_true; break;
+ case 'r': case 't': break; /* No longer in use */
case 's': p->filter_name = Shape_shibata; break;
case 'f':
p->filter_name = lsx_enum_option(c, filter_names);
@@ -218,8 +242,7 @@
default: lsx_fail("invalid option `-%c'", optopt); return lsx_usage(effp);
}
argc -= optind, argv += optind;
- p->depth = 1;
- do {NUMERIC_PARAMETER(depth, .5, 1)} while (0);
+ do {NUMERIC_PARAMETER(dummy, 0.5, 1)} while (0); /* No longer in use */
return argc? lsx_usage(effp) : SOX_SUCCESS;
}
@@ -258,14 +281,12 @@
mult = dB_to_linear(f->gain);
}
}
- p->ranqd1 = p->reseed? ranqd1(sox_globals.ranqd1) : 0;
- p->am1 = p->depth / (1 << p->prec);
- p->am0 = (p->pdf == Pdf_triangular) * p->am1;
-
+ p->ranqd1 = ranqd1(sox_globals.ranqd1);
if (effp->in_signal.mult)
- *effp->in_signal.mult *= 1 - (p->am0 + p->am1) * mult;
+ *effp->in_signal.mult -= *effp->in_signal.mult * SOX_INT_MAX(32 - p->prec)
+ * 2 / (SOX_INT_MAX(p->prec) << (32 - p->prec)) * 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);
+ lsx_debug("filter=%s auto=%i", lsx_find_enum_value(p->filter_name, filter_names)->text, p->auto_detect);
return SOX_SUCCESS;
}
@@ -279,15 +300,12 @@
sox_effect_handler_t const * lsx_dither_effect_fn(void)
{
static sox_effect_handler_t handler = {
- "dither", "[-R] [-r|-t] [-s|-f filter] [depth]"
- "\n -R Re-seed PRNG"
- "\n -r Rectangular PDF"
- "\n -t Triangular PDF (default)"
+ "dither", "[-a] [-s|-f filter]"
+ "\n -a Automatically turn on & off dithering as needed (use with caution!)"
"\n -s Shape noise (with shibata filter)"
"\n -f name Set shaping filter to one of: lipshitz, f-weighted,"
"\n modified-e-weighted, improved-e-weighted, gesemann,"
- "\n shibata, low-shibata, high-shibata."
- "\n depth Noise depth; 0.5 to 1; default 1",
+ "\n shibata, low-shibata, high-shibata.",
SOX_EFF_PREC, getopts, start, flow, 0, 0, 0, sizeof(priv_t)
};
return &handler;
--- /dev/null
+++ b/src/dither.h
@@ -1,0 +1,57 @@
+#ifdef IIR
+#define _ output += p->coefs[j] * p->previous_errors[p->pos + j] \
+ - p->coefs[N + j] * p->previous_outputs[p->pos + j], ++j;
+#else
+#define _ d -= p->coefs[j] * p->previous_errors[p->pos + j], ++j;
+#endif
+static int NAME(sox_effect_t * effp, const sox_sample_t * ibuf,
+ 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);
+
+ while (len--) {
+ if (!p->auto_detect || (p->history = ((p->history << 1) + !!(*ibuf & (-1u >> p->prec))))) {
+ double d1, r = (RANQD1 >> p->prec) + (RANQD1 >> p->prec);
+#ifdef IIR
+ double d, output = 0;
+#else
+ double d = *ibuf++;
+#endif
+ int j = 0;
+ CONVOLVE
+ assert(j == N);
+ p->pos = p->pos? p->pos - 1 : p->pos - 1 + N;
+#ifdef IIR
+ d = *ibuf++ - output;
+ p->previous_outputs[p->pos + N] = p->previous_outputs[p->pos] = output;
+#endif
+ d1 = (d + r) / (1 << (32 - p->prec));
+ d1 = (int)(d1 < 0? d1 - .5 : d1 + .5);
+ p->previous_errors[p->pos + N] = p->previous_errors[p->pos] =
+ d1 * (1 << (32 - p->prec)) - d;
+ *obuf = d1 < (-1 << (p->prec-1))? ++effp->clips, -1 << (p->prec-1) :
+ d1 > SOX_INT_MAX(p->prec)? ++effp->clips, SOX_INT_MAX(p->prec) : d1;
+ *obuf++ <<= 32 - p->prec;
+
+ if (p->dither_off)
+ lsx_debug("flow %u: on @ %u", effp->flow, (unsigned)p->num_output);
+ p->dither_off = sox_false;
+ }
+ else {
+ *obuf++ = *ibuf++;
+ if (!p->dither_off) {
+ lsx_debug("flow %u: off @ %u", effp->flow, (unsigned)p->num_output);
+ memset(p->previous_errors, 0, sizeof(p->previous_errors));
+ memset(p->previous_outputs, 0, sizeof(p->previous_outputs));
+ }
+ p->dither_off = sox_true;
+ }
+ ++p->num_output;
+ }
+ return SOX_SUCCESS;
+}
+#undef CONVOLVE
+#undef _
+#undef NAME
+#undef N
--- a/src/dither_fir.h
+++ /dev/null
@@ -1,24 +1,0 @@
-#define _ d -= p->coefs[j] * p->previous_errors[p->pos + j], ++j;
-static int NAME(sox_effect_t * effp, const sox_sample_t * ibuf,
- 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);
-
- while (len--) {
- double r = floor(p->am0 * RANQD1) + floor(p->am1 * RANQD1);
- double error, d = *ibuf++;
- int j = 0;
- CONVOLVE
- assert(j == N);
- *obuf = SOX_ROUND_PREC_CLIP_COUNT(d + r, effp->clips);
- error = ((*obuf++ + (1 << (31-p->prec))) & (-1 << (32-p->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;
- }
- return SOX_SUCCESS;
-}
-#undef CONVOLVE
-#undef _
-#undef NAME
-#undef N
--- a/src/dither_iir.h
+++ /dev/null
@@ -1,27 +1,0 @@
-#define _ output += p->coefs[j] * p->previous_errors[p->pos + j] \
- - p->coefs[N + j] * p->previous_outputs[p->pos + j], ++j;
-static int NAME(sox_effect_t * effp, const sox_sample_t * ibuf,
- 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);
-
- while (len--) {
- 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 = SOX_ROUND_PREC_CLIP_COUNT(d + r, effp->clips);
- error = ((*obuf++ + (1 << (31-p->prec))) & (-1 << (32-p->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;
- p->previous_outputs[p->pos + N] = p->previous_outputs[p->pos] = output;
- }
- return SOX_SUCCESS;
-}
-#undef CONVOLVE
-#undef _
-#undef NAME
-#undef N