1 /* libSoX Basic time stretcher.
2  * (c) march/april 2000 Fabien COELHO <fabien@coelho.net> for sox.
3  *
4  * cross fade samples so as to go slower or faster.
5  *
6  * The filter is based on 6 parameters:
7  * - stretch factor f
8  * - window size w
9  * - input step i
10  *   output step o=f*i
11  * - steady state of window s, ss = s*w
12  *
13  * I decided of the default values of these parameters based
14  * on some small non extensive tests. maybe better defaults
15  * can be suggested.
16  */
17 #include "sox_i.h"
18 
19 #include <stdlib.h>
20 #include <string.h>
21 #include <assert.h>
22 
23 #define DEFAULT_SLOW_SHIFT_RATIO        0.8
24 #define DEFAULT_FAST_SHIFT_RATIO        1.0
25 
26 #define DEFAULT_STRETCH_WINDOW          20.0  /* ms */
27 
28 typedef enum { input_state, output_state } stretch_status_t;
29 
30 typedef struct {
31   /* options
32    * FIXME: maybe shift could be allowed > 1.0 with factor < 1.0 ???
33    */
34   double factor;   /* strech factor. 1.0 means copy. */
35   double window;   /* window in ms */
36   double shift;    /* shift ratio wrt window. <1.0 */
37   double fading;   /* fading ratio wrt window. <0.5 */
38 
39   /* internal stuff */
40   stretch_status_t state; /* automaton status */
41 
42   size_t segment;         /* buffer size */
43   size_t index;        /* next available element */
44   sox_sample_t *ibuf;      /* input buffer */
45   size_t ishift;       /* input shift */
46 
47   size_t oindex;       /* next evailable element */
48   double * obuf;   /* output buffer */
49   size_t oshift;       /* output shift */
50 
51   size_t overlap;        /* fading size */
52   double * fade_coefs;   /* fading, 1.0 -> 0.0 */
53 
54 } priv_t;
55 
56 /*
57  * Process options
58  */
getopts(sox_effect_t * effp,int argc,char ** argv)59 static int getopts(sox_effect_t * effp, int argc, char **argv)
60 {
61   priv_t * p = (priv_t *) effp->priv;
62   --argc, ++argv;
63 
64   /* default options */
65   p->factor = 1.0; /* default is no change */
66   p->window = DEFAULT_STRETCH_WINDOW;
67 
68   if (argc > 0 && !sscanf(argv[0], "%lf", &p->factor)) {
69     lsx_fail("error while parsing factor");
70     return lsx_usage(effp);
71   }
72 
73   if (argc > 1 && !sscanf(argv[1], "%lf", &p->window)) {
74     lsx_fail("error while parsing window size");
75     return lsx_usage(effp);
76   }
77 
78   if (argc > 2) {
79     switch (argv[2][0]) {
80     case 'l':
81     case 'L':
82       break;
83     default:
84       lsx_fail("error while parsing fade type");
85       return lsx_usage(effp);
86     }
87   }
88 
89   /* default shift depends whether we go slower or faster */
90   p->shift = (p->factor <= 1.0) ?
91     DEFAULT_FAST_SHIFT_RATIO: DEFAULT_SLOW_SHIFT_RATIO;
92 
93   if (argc > 3 && !sscanf(argv[3], "%lf", &p->shift)) {
94     lsx_fail("error while parsing shift ratio");
95     return lsx_usage(effp);
96   }
97 
98   if (p->shift > 1.0 || p->shift <= 0.0) {
99     lsx_fail("error with shift ratio value");
100     return lsx_usage(effp);
101   }
102 
103   /* default fading stuff...
104      it makes sense for factor >= 0.5 */
105   if (p->factor < 1.0)
106     p->fading = 1.0 - (p->factor * p->shift);
107   else
108     p->fading = 1.0 - p->shift;
109   if (p->fading > 0.5)
110     p->fading = 0.5;
111 
112   if (argc > 4 && !sscanf(argv[4], "%lf", &p->fading)) {
113     lsx_fail("error while parsing fading ratio");
114     return lsx_usage(effp);
115   }
116 
117   if (p->fading > 0.5 || p->fading < 0.0) {
118     lsx_fail("error with fading ratio value");
119     return lsx_usage(effp);
120   }
121 
122   return SOX_SUCCESS;
123 }
124 
125 /*
126  * Start processing
127  */
start(sox_effect_t * effp)128 static int start(sox_effect_t * effp)
129 {
130   priv_t * p = (priv_t *)effp->priv;
131   size_t i;
132 
133   if (p->factor == 1)
134     return SOX_EFF_NULL;
135 
136   p->state = input_state;
137 
138   p->segment = (int)(effp->out_signal.rate * 0.001 * p->window);
139   /* start in the middle of an input to avoid initial fading... */
140   p->index = p->segment / 2;
141   p->ibuf = lsx_malloc(p->segment * sizeof(sox_sample_t));
142 
143   /* the shift ratio deal with the longest of ishift/oshift
144      hence ishift<=segment and oshift<=segment. */
145   if (p->factor < 1.0) {
146     p->ishift = p->shift * p->segment;
147     p->oshift = p->factor * p->ishift;
148   } else {
149     p->oshift = p->shift * p->segment;
150     p->ishift = p->oshift / p->factor;
151   }
152   assert(p->ishift <= p->segment);
153   assert(p->oshift <= p->segment);
154 
155   p->oindex = p->index; /* start as synchronized */
156   p->obuf = lsx_malloc(p->segment * sizeof(double));
157   p->overlap = (int)(p->fading * p->segment);
158   p->fade_coefs = lsx_malloc(p->overlap * sizeof(double));
159 
160   /* initialize buffers */
161   for (i = 0; i<p->segment; i++)
162     p->ibuf[i] = 0;
163 
164   for (i = 0; i<p->segment; i++)
165     p->obuf[i] = 0.0;
166 
167   if (p->overlap>1) {
168     double slope = 1.0 / (p->overlap - 1);
169     p->fade_coefs[0] = 1.0;
170     for (i = 1; i < p->overlap - 1; i++)
171       p->fade_coefs[i] = slope * (p->overlap - i - 1);
172     p->fade_coefs[p->overlap - 1] = 0.0;
173   } else if (p->overlap == 1)
174     p->fade_coefs[0] = 1.0;
175 
176   lsx_debug("start: (factor=%g segment=%g shift=%g overlap=%g)\nstate=%d\n"
177       "segment=%" PRIuPTR "\nindex=%" PRIuPTR "\n"
178       "ishift=%" PRIuPTR "\noindex=%" PRIuPTR "\n"
179       "oshift=%" PRIuPTR "\noverlap=%" PRIuPTR,
180       p->factor, p->window, p->shift, p->fading, p->state,
181       p->segment, p->index, p->ishift, p->oindex, p->oshift, p->overlap);
182 
183   effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */
184   return SOX_SUCCESS;
185 }
186 
187 /* accumulates input ibuf to output obuf with fading fade_coefs */
combine(priv_t * p)188 static void combine(priv_t * p)
189 {
190   size_t i;
191 
192   /* fade in */
193   for (i = 0; i < p->overlap; i++)
194     p->obuf[i] += p->fade_coefs[p->overlap - 1 - i] * p->ibuf[i];
195 
196   /* steady state */
197   for (; i < p->segment - p->overlap; i++)
198     p->obuf[i] += p->ibuf[i];
199 
200   /* fade out */
201   for (; i<p->segment; i++)
202     p->obuf[i] += p->fade_coefs[i - p->segment + p->overlap] * p->ibuf[i];
203 }
204 
205 /*
206  * Processes flow.
207  */
flow(sox_effect_t * effp,const sox_sample_t * ibuf,sox_sample_t * obuf,size_t * isamp,size_t * osamp)208 static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
209                     size_t *isamp, size_t *osamp)
210 {
211   priv_t * p = (priv_t *) effp->priv;
212   size_t iindex = 0, oindex = 0;
213   size_t i;
214 
215   while (iindex<*isamp && oindex<*osamp) {
216     if (p->state == input_state) {
217       size_t tocopy = min(*isamp-iindex,
218                              p->segment-p->index);
219 
220       memcpy(p->ibuf + p->index, ibuf + iindex, tocopy * sizeof(sox_sample_t));
221 
222       iindex += tocopy;
223       p->index += tocopy;
224 
225       if (p->index == p->segment) {
226         /* compute */
227         combine(p);
228 
229         /* shift input */
230         for (i = 0; i + p->ishift < p->segment; i++)
231           p->ibuf[i] = p->ibuf[i+p->ishift];
232 
233         p->index -= p->ishift;
234 
235         /* switch to output state */
236         p->state = output_state;
237       }
238     }
239 
240     if (p->state == output_state) {
241       while (p->oindex < p->oshift && oindex < *osamp) {
242         float f;
243         f = p->obuf[p->oindex++];
244         SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
245         obuf[oindex++] = f;
246       }
247 
248       if (p->oindex >= p->oshift && oindex<*osamp) {
249         p->oindex -= p->oshift;
250 
251         /* shift internal output buffer */
252         for (i = 0; i + p->oshift < p->segment; i++)
253           p->obuf[i] = p->obuf[i + p->oshift];
254 
255         /* pad with 0 */
256         for (; i < p->segment; i++)
257           p->obuf[i] = 0.0;
258 
259         p->state = input_state;
260       }
261     }
262   }
263 
264   *isamp = iindex;
265   *osamp = oindex;
266 
267   return SOX_SUCCESS;
268 }
269 
270 
271 /*
272  * Drain buffer at the end
273  * maybe not correct ? end might be artificially faded?
274  */
drain(sox_effect_t * effp,sox_sample_t * obuf,size_t * osamp)275 static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
276 {
277   priv_t * p = (priv_t *) effp->priv;
278   size_t i;
279   size_t oindex = 0;
280 
281   if (p->state == input_state) {
282     for (i=p->index; i<p->segment; i++)
283       p->ibuf[i] = 0;
284 
285     combine(p);
286 
287     p->state = output_state;
288   }
289 
290   while (oindex<*osamp && p->oindex<p->index) {
291     float f = p->obuf[p->oindex++];
292     SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
293     obuf[oindex++] = f;
294   }
295 
296   *osamp = oindex;
297 
298   if (p->oindex == p->index)
299     return SOX_EOF;
300   else
301     return SOX_SUCCESS;
302 }
303 
304 
stop(sox_effect_t * effp)305 static int stop(sox_effect_t * effp)
306 {
307   priv_t * p = (priv_t *) effp->priv;
308 
309   free(p->ibuf);
310   free(p->obuf);
311   free(p->fade_coefs);
312   return SOX_SUCCESS;
313 }
314 
lsx_stretch_effect_fn(void)315 const sox_effect_handler_t *lsx_stretch_effect_fn(void)
316 {
317   static const sox_effect_handler_t handler = {
318     "stretch",
319     "factor [window fade shift fading]\n"
320     "       (expansion, frame in ms, lin/..., unit<1.0, unit<0.5)\n"
321     "       (defaults: 1.0 20 lin ...)",
322     SOX_EFF_LENGTH,
323     getopts, start, flow, drain, stop, NULL, sizeof(priv_t)
324   };
325   return &handler;
326 }
327