rate: add some sanity checking
[sox.git] / src / dcshift.c
blob07d881d09a677232070a5d09716c3aedf2906105
1 /* libSoX dcshift.c
2 * (c) 2000.04.15 Chris Ausbrooks <weed@bucket.pp.ualr.edu>
4 * based on vol.c which is
5 * (c) 20/03/2000 Fabien COELHO <fabien@coelho.net> for sox.
7 * DC shift a sound file, with basic linear amplitude formula.
8 * Beware of saturations! clipping is checked and reported.
9 * Cannot handle different number of channels.
10 * Cannot handle rate change.
13 #include "sox_i.h"
15 typedef struct {
16 double dcshift; /* DC shift. */
17 int uselimiter; /* boolean: are we using the limiter? */
18 double limiterthreshhold;
19 double limitergain; /* limiter gain. */
20 uint64_t limited; /* number of limited values to report. */
21 uint64_t totalprocessed;
22 } priv_t;
25 * Process options: dcshift (double) type (amplitude, power, dB)
27 static int sox_dcshift_getopts(sox_effect_t * effp, int argc, char **argv)
29 priv_t * dcs = (priv_t *) effp->priv;
30 dcs->dcshift = 1.0; /* default is no change */
31 dcs->uselimiter = 0; /* default is no limiter */
33 --argc, ++argv;
34 if (argc < 1)
35 return lsx_usage(effp);
37 if (argc && (!sscanf(argv[0], "%lf", &dcs->dcshift)))
38 return lsx_usage(effp);
40 if (argc>1)
42 if (!sscanf(argv[1], "%lf", &dcs->limitergain))
43 return lsx_usage(effp);
45 dcs->uselimiter = 1; /* ok, we'll use it */
46 /* The following equation is derived so that there is no
47 * discontinuity in output amplitudes */
48 /* and a SOX_SAMPLE_MAX input always maps to a SOX_SAMPLE_MAX output
49 * when the limiter is activated. */
50 /* (NOTE: There **WILL** be a discontinuity in the slope of the
51 * output amplitudes when using the limiter.) */
52 dcs->limiterthreshhold = SOX_SAMPLE_MAX * (1.0 - (fabs(dcs->dcshift) - dcs->limitergain));
55 return SOX_SUCCESS;
59 * Start processing
61 static int sox_dcshift_start(sox_effect_t * effp)
63 priv_t * dcs = (priv_t *) effp->priv;
65 if (dcs->dcshift == 0)
66 return SOX_EFF_NULL;
68 dcs->limited = 0;
69 dcs->totalprocessed = 0;
71 return SOX_SUCCESS;
75 * Process data.
77 static int sox_dcshift_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
78 size_t *isamp, size_t *osamp)
80 priv_t * dcs = (priv_t *) effp->priv;
81 double dcshift = dcs->dcshift;
82 double limitergain = dcs->limitergain;
83 double limiterthreshhold = dcs->limiterthreshhold;
84 double sample;
85 size_t len;
87 len = min(*osamp, *isamp);
89 /* report back dealt with amount. */
90 *isamp = len; *osamp = len;
92 if (dcs->uselimiter)
94 dcs->totalprocessed += len;
96 for (;len>0; len--)
98 sample = *ibuf++;
100 if (sample > limiterthreshhold && dcshift > 0)
102 sample = (sample - limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) + limiterthreshhold + dcshift;
103 dcs->limited++;
105 else if (sample < -limiterthreshhold && dcshift < 0)
107 /* Note this should really be SOX_SAMPLE_MIN but
108 * the clip() below will take care of the overflow.
110 sample = (sample + limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) - limiterthreshhold + dcshift;
111 dcs->limited++;
113 else
115 /* Note this should consider SOX_SAMPLE_MIN but
116 * the clip() below will take care of the overflow.
118 sample = dcshift * SOX_SAMPLE_MAX + sample;
121 SOX_SAMPLE_CLIP_COUNT(sample, effp->clips);
122 *obuf++ = sample;
125 else for (; len > 0; --len) { /* quite basic, with clipping */
126 double d = dcshift * (SOX_SAMPLE_MAX + 1.) + *ibuf++;
127 *obuf++ = SOX_ROUND_CLIP_COUNT(d, effp->clips);
129 return SOX_SUCCESS;
133 * Do anything required when you stop reading samples.
134 * Don't close input file!
136 static int sox_dcshift_stop(sox_effect_t * effp)
138 priv_t * dcs = (priv_t *) effp->priv;
140 if (dcs->limited)
142 lsx_warn("DCSHIFT limited %" PRIu64 " values (%d percent).",
143 dcs->limited, (int) (dcs->limited * 100.0 / dcs->totalprocessed));
145 return SOX_SUCCESS;
148 static sox_effect_handler_t sox_dcshift_effect = {
149 "dcshift",
150 "shift [ limitergain ]\n"
151 "\tThe peak limiter has a gain much less than 1.0 (ie 0.05 or 0.02) which\n"
152 "\tis only used on peaks to prevent clipping. (default is no limiter)",
153 SOX_EFF_MCHAN | SOX_EFF_GAIN,
154 sox_dcshift_getopts,
155 sox_dcshift_start,
156 sox_dcshift_flow,
157 NULL,
158 sox_dcshift_stop,
159 NULL, sizeof(priv_t)
162 const sox_effect_handler_t *lsx_dcshift_effect_fn(void)
164 return &sox_dcshift_effect;