1 /* libSoX effect: divide   Copyright (c) 2009 robs@users.sourceforge.net
2  *
3  * This library is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation; either version 2.1 of the License, or (at
6  * your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17 
18 /* This is W.I.P. hence marked SOX_EFF_ALPHA for now.
19  * Needs better handling of when the divisor approaches or is zero; some
20  * sort of interpolation of the output values perhaps.
21  */
22 
23 #include "sox_i.h"
24 #include <string.h>
25 
26 typedef struct {
27   sox_sample_t * last;
28 } priv_t;
29 
start(sox_effect_t * effp)30 static int start(sox_effect_t * effp)
31 {
32   priv_t * p = (priv_t *)effp->priv;
33   p->last = lsx_calloc(effp->in_signal.channels, sizeof(*p->last));
34   return SOX_SUCCESS;
35 }
36 
flow(sox_effect_t * effp,const sox_sample_t * ibuf,sox_sample_t * obuf,size_t * isamp,size_t * osamp)37 static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
38     sox_sample_t * obuf, size_t * isamp, size_t * osamp)
39 {
40   priv_t * p = (priv_t *)effp->priv;
41   size_t i, len =  min(*isamp, *osamp) / effp->in_signal.channels;
42   *osamp = *isamp = len * effp->in_signal.channels;
43 
44   while (len--) {
45     double divisor = *obuf++ = *ibuf++;
46     if (divisor) {
47       double out, mult = 1. / SOX_SAMPLE_TO_FLOAT_64BIT(divisor,);
48       for (i = 1; i < effp->in_signal.channels; ++i) {
49         out = *ibuf++ * mult;
50         p->last[i] = *obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips);
51       }
52     }
53     else for (i = 1; i < effp->in_signal.channels; ++i, ++ibuf)
54       *obuf++ = p->last[i];
55   }
56   return SOX_SUCCESS;
57 }
58 
stop(sox_effect_t * effp)59 static int stop(sox_effect_t * effp)
60 {
61   priv_t * p = (priv_t *)effp->priv;
62   free(p->last);
63   return SOX_SUCCESS;
64 }
65 
lsx_divide_effect_fn(void)66 sox_effect_handler_t const * lsx_divide_effect_fn(void)
67 {
68   static sox_effect_handler_t handler = {
69     "divide", NULL, SOX_EFF_MCHAN | SOX_EFF_GAIN | SOX_EFF_ALPHA,
70     NULL, start, flow, NULL, stop, NULL, sizeof(priv_t)
71   };
72   return &handler;
73 }
74