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