Mercurial > mplayer.hg
annotate libaf/af_scaletempo.c @ 29938:eb6c70e2cbea
Very preliminary code to allow selecting the OpenGL backend at runtime.
Works in the currently supported cases for only Win32 and only X11,
the mixed case is not working yet though.
But applied anyway since the code is slightly less messy than the current one.
author | reimar |
---|---|
date | Tue, 08 Dec 2009 06:42:46 +0000 |
parents | 8c706ce21c6f |
children | a93891202051 |
rev | line source |
---|---|
24896 | 1 /* |
2 * scaletempo audio filter | |
26740
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
3 * |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
4 * scale tempo while maintaining pitch |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
5 * (WSOLA technique with cross correlation) |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
6 * inspired by SoundTouch library by Olli Parviainen |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
7 * |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
8 * basic algorithm |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
9 * - produce 'stride' output samples per loop |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
10 * - consume stride*scale input samples per loop |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
11 * |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
12 * to produce smoother transitions between strides, blend next overlap |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
13 * samples from last stride with correlated samples of current input |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
14 * |
24896 | 15 * Copyright (c) 2007 Robert Juliano |
16 * | |
17 * This file is part of MPlayer. | |
18 * | |
19 * MPlayer is free software; you can redistribute it and/or modify | |
20 * it under the terms of the GNU General Public License as published by | |
21 * the Free Software Foundation; either version 2 of the License, or | |
22 * (at your option) any later version. | |
23 * | |
24 * MPlayer is distributed in the hope that it will be useful, | |
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 * GNU General Public License for more details. | |
28 * | |
26740
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
29 * You should have received a copy of the GNU General Public License along |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
30 * with MPlayer; if not, write to the Free Software Foundation, Inc., |
b3a38b361fef
Use standard license headers with standard formatting.
diego
parents:
25188
diff
changeset
|
31 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
24896 | 32 */ |
33 | |
34 #include <stdlib.h> | |
35 #include <string.h> | |
36 #include <limits.h> | |
37 | |
38 #include "af.h" | |
39 #include "libavutil/common.h" | |
40 #include "subopt-helper.h" | |
41 #include "help_mp.h" | |
42 | |
43 // Data for specific instances of this filter | |
44 typedef struct af_scaletempo_s | |
45 { | |
46 // stride | |
47 float scale; | |
48 float speed; | |
49 float frames_stride_scaled; | |
50 float frames_stride_error; | |
51 int bytes_per_frame; | |
52 int bytes_stride; | |
53 float bytes_stride_scaled; | |
54 int bytes_queue; | |
55 int bytes_queued; | |
56 int bytes_to_slide; | |
57 int8_t* buf_queue; | |
58 // overlap | |
59 int samples_overlap; | |
60 int samples_standing; | |
61 int bytes_overlap; | |
62 int bytes_standing; | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
63 void* buf_overlap; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
64 void* table_blend; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
65 void (*output_overlap)(struct af_scaletempo_s* s, void* out_buf, int bytes_off); |
24896 | 66 // best overlap |
67 int frames_search; | |
68 int num_channels; | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
69 void* buf_pre_corr; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
70 void* table_window; |
24896 | 71 int (*best_overlap_offset)(struct af_scaletempo_s* s); |
72 // command line | |
73 float scale_nominal; | |
74 float ms_stride; | |
75 float percent_overlap; | |
76 float ms_search; | |
77 short speed_tempo; | |
78 short speed_pitch; | |
79 } af_scaletempo_t; | |
80 | |
24899 | 81 static int fill_queue(struct af_instance_s* af, af_data_t* data, int offset) |
82 { | |
24896 | 83 af_scaletempo_t* s = af->setup; |
84 int bytes_in = data->len - offset; | |
85 int offset_unchanged = offset; | |
86 | |
87 if (s->bytes_to_slide > 0) { | |
88 if (s->bytes_to_slide < s->bytes_queued) { | |
89 int bytes_move = s->bytes_queued - s->bytes_to_slide; | |
90 memmove(s->buf_queue, | |
91 s->buf_queue + s->bytes_to_slide, | |
92 bytes_move); | |
93 s->bytes_to_slide = 0; | |
94 s->bytes_queued = bytes_move; | |
95 } else { | |
96 int bytes_skip; | |
97 s->bytes_to_slide -= s->bytes_queued; | |
98 bytes_skip = FFMIN(s->bytes_to_slide, bytes_in); | |
99 s->bytes_queued = 0; | |
100 s->bytes_to_slide -= bytes_skip; | |
101 offset += bytes_skip; | |
102 bytes_in -= bytes_skip; | |
103 } | |
104 } | |
105 | |
106 if (bytes_in > 0) { | |
107 int bytes_copy = FFMIN(s->bytes_queue - s->bytes_queued, bytes_in); | |
108 memcpy(s->buf_queue + s->bytes_queued, | |
109 (int8_t*)data->audio + offset, | |
110 bytes_copy); | |
111 s->bytes_queued += bytes_copy; | |
112 offset += bytes_copy; | |
113 } | |
114 | |
115 return offset - offset_unchanged; | |
116 } | |
117 | |
25076
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
118 #define UNROLL_PADDING (4*4) |
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
119 |
24899 | 120 static int best_overlap_offset_float(af_scaletempo_t* s) |
121 { | |
24896 | 122 float *pw, *po, *ppc, *search_start; |
123 float best_corr = INT_MIN; | |
124 int best_off = 0; | |
125 int i, off; | |
126 | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
127 pw = s->table_window; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
128 po = s->buf_overlap; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
129 po += s->num_channels; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
130 ppc = s->buf_pre_corr; |
24896 | 131 for (i=s->num_channels; i<s->samples_overlap; i++) { |
132 *ppc++ = *pw++ * *po++; | |
133 } | |
134 | |
135 search_start = (float*)s->buf_queue + s->num_channels; | |
136 for (off=0; off<s->frames_search; off++) { | |
137 float corr = 0; | |
138 float* ps = search_start; | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
139 ppc = s->buf_pre_corr; |
24896 | 140 for (i=s->num_channels; i<s->samples_overlap; i++) { |
141 corr += *ppc++ * *ps++; | |
142 } | |
143 if (corr > best_corr) { | |
144 best_corr = corr; | |
145 best_off = off; | |
146 } | |
147 search_start += s->num_channels; | |
148 } | |
149 | |
24897 | 150 return best_off * 4 * s->num_channels; |
24896 | 151 } |
152 | |
24899 | 153 static int best_overlap_offset_s16(af_scaletempo_t* s) |
154 { | |
24896 | 155 int32_t *pw, *ppc; |
156 int16_t *po, *search_start; | |
25075
c18499a044ce
Change to a 64 bit accumulation variable instead of shifting.
reimar
parents:
25074
diff
changeset
|
157 int64_t best_corr = INT64_MIN; |
24896 | 158 int best_off = 0; |
25073
21227667b70a
Use "long" instead of "int" for innermost loop variable.
reimar
parents:
25072
diff
changeset
|
159 int off; |
21227667b70a
Use "long" instead of "int" for innermost loop variable.
reimar
parents:
25072
diff
changeset
|
160 long i; |
24896 | 161 |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
162 pw = s->table_window; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
163 po = s->buf_overlap; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
164 po += s->num_channels; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
165 ppc = s->buf_pre_corr; |
24896 | 166 for (i=s->num_channels; i<s->samples_overlap; i++) { |
167 *ppc++ = ( *pw++ * *po++ ) >> 15; | |
168 } | |
169 | |
170 search_start = (int16_t*)s->buf_queue + s->num_channels; | |
171 for (off=0; off<s->frames_search; off++) { | |
25075
c18499a044ce
Change to a 64 bit accumulation variable instead of shifting.
reimar
parents:
25074
diff
changeset
|
172 int64_t corr = 0; |
24896 | 173 int16_t* ps = search_start; |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
174 ppc = s->buf_pre_corr; |
25075
c18499a044ce
Change to a 64 bit accumulation variable instead of shifting.
reimar
parents:
25074
diff
changeset
|
175 ppc += s->samples_overlap - s->num_channels; |
c18499a044ce
Change to a 64 bit accumulation variable instead of shifting.
reimar
parents:
25074
diff
changeset
|
176 ps += s->samples_overlap - s->num_channels; |
25072 | 177 i = -(s->samples_overlap - s->num_channels); |
178 do { | |
25076
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
179 corr += ppc[i+0] * ps[i+0]; |
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
180 corr += ppc[i+1] * ps[i+1]; |
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
181 corr += ppc[i+2] * ps[i+2]; |
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
182 corr += ppc[i+3] * ps[i+3]; |
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
183 i += 4; |
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
184 } while (i < 0); |
24896 | 185 if (corr > best_corr) { |
186 best_corr = corr; | |
187 best_off = off; | |
188 } | |
189 search_start += s->num_channels; | |
190 } | |
191 | |
24897 | 192 return best_off * 2 * s->num_channels; |
24896 | 193 } |
194 | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
195 static void output_overlap_float(af_scaletempo_t* s, void* buf_out, |
24899 | 196 int bytes_off) |
197 { | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
198 float* pout = buf_out; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
199 float* pb = s->table_blend; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
200 float* po = s->buf_overlap; |
24896 | 201 float* pin = (float*)(s->buf_queue + bytes_off); |
202 int i; | |
203 for (i=0; i<s->samples_overlap; i++) { | |
204 *pout++ = *po - *pb++ * ( *po - *pin++ ); po++; | |
205 } | |
206 } | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
207 static void output_overlap_s16(af_scaletempo_t* s, void* buf_out, |
24899 | 208 int bytes_off) |
209 { | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
210 int16_t* pout = buf_out; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
211 int32_t* pb = s->table_blend; |
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
212 int16_t* po = s->buf_overlap; |
24896 | 213 int16_t* pin = (int16_t*)(s->buf_queue + bytes_off); |
214 int i; | |
215 for (i=0; i<s->samples_overlap; i++) { | |
216 *pout++ = *po - ( ( *pb++ * ( *po - *pin++ ) ) >> 16 ); po++; | |
217 } | |
218 } | |
219 | |
220 // Filter data through filter | |
221 static af_data_t* play(struct af_instance_s* af, af_data_t* data) | |
222 { | |
223 af_scaletempo_t* s = af->setup; | |
224 int offset_in; | |
225 int max_bytes_out; | |
226 int8_t* pout; | |
227 | |
228 if (s->scale == 1.0) { | |
229 return data; | |
230 } | |
231 | |
232 // RESIZE_LOCAL_BUFFER - can't use macro | |
233 max_bytes_out = ((int)(data->len / s->bytes_stride_scaled) + 1) * s->bytes_stride; | |
234 if (max_bytes_out > af->data->len) { | |
29049 | 235 mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, " |
24896 | 236 "old len = %i, new len = %i\n",af->info->name,af->data->len,max_bytes_out); |
237 af->data->audio = realloc(af->data->audio, max_bytes_out); | |
238 if (!af->data->audio) { | |
29049 | 239 mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory\n"); |
24896 | 240 return NULL; |
241 } | |
242 af->data->len = max_bytes_out; | |
243 } | |
244 | |
245 offset_in = fill_queue(af, data, 0); | |
246 pout = af->data->audio; | |
247 while (s->bytes_queued >= s->bytes_queue) { | |
248 int ti; | |
249 float tf; | |
250 int bytes_off = 0; | |
251 | |
252 // output stride | |
253 if (s->output_overlap) { | |
254 if (s->best_overlap_offset) | |
255 bytes_off = s->best_overlap_offset(s); | |
256 s->output_overlap(s, pout, bytes_off); | |
257 } | |
258 memcpy(pout + s->bytes_overlap, | |
259 s->buf_queue + bytes_off + s->bytes_overlap, | |
260 s->bytes_standing); | |
261 pout += s->bytes_stride; | |
262 | |
263 // input stride | |
264 memcpy(s->buf_overlap, | |
265 s->buf_queue + bytes_off + s->bytes_stride, | |
266 s->bytes_overlap); | |
267 tf = s->frames_stride_scaled + s->frames_stride_error; | |
268 ti = (int)tf; | |
269 s->frames_stride_error = tf - ti; | |
270 s->bytes_to_slide = ti * s->bytes_per_frame; | |
271 | |
272 offset_in += fill_queue(af, data, offset_in); | |
273 } | |
274 | |
24900 | 275 // This filter can have a negative delay when scale > 1: |
276 // output corresponding to some length of input can be decided and written | |
277 // after receiving only a part of that input. | |
278 af->delay = s->bytes_queued - s->bytes_to_slide; | |
279 | |
24896 | 280 data->audio = af->data->audio; |
24899 | 281 data->len = pout - (int8_t *)af->data->audio; |
24896 | 282 return data; |
283 } | |
284 | |
285 // Initialization and runtime control | |
286 static int control(struct af_instance_s* af, int cmd, void* arg) | |
287 { | |
288 af_scaletempo_t* s = af->setup; | |
289 switch(cmd){ | |
290 case AF_CONTROL_REINIT:{ | |
291 af_data_t* data = (af_data_t*)arg; | |
292 float srate = data->rate / 1000; | |
293 int nch = data->nch; | |
294 int bps; | |
295 int use_int = 0; | |
296 int frames_stride, frames_overlap; | |
297 int i, j; | |
298 | |
29049 | 299 mp_msg(MSGT_AFILTER, MSGL_V, |
24896 | 300 "[scaletempo] %.3f speed * %.3f scale_nominal = %.3f\n", |
301 s->speed, s->scale_nominal, s->scale); | |
302 | |
303 if (s->scale == 1.0) { | |
304 if (s->speed_tempo && s->speed_pitch) | |
305 return AF_DETACH; | |
306 memcpy(af->data, data, sizeof(af_data_t)); | |
307 return af_test_output(af, data); | |
308 } | |
309 | |
310 af->data->rate = data->rate; | |
311 af->data->nch = data->nch; | |
312 if ( data->format == AF_FORMAT_S16_LE | |
313 || data->format == AF_FORMAT_S16_BE ) { | |
314 use_int = 1; | |
315 af->data->format = AF_FORMAT_S16_NE; | |
316 af->data->bps = bps = 2; | |
317 } else { | |
318 af->data->format = AF_FORMAT_FLOAT_NE; | |
319 af->data->bps = bps = 4; | |
320 } | |
321 | |
322 frames_stride = srate * s->ms_stride; | |
323 s->bytes_stride = frames_stride * bps * nch; | |
324 s->bytes_stride_scaled = s->scale * s->bytes_stride; | |
325 s->frames_stride_scaled = s->scale * frames_stride; | |
326 s->frames_stride_error = 0; | |
327 af->mul = (double)s->bytes_stride / s->bytes_stride_scaled; | |
328 | |
329 frames_overlap = frames_stride * s->percent_overlap; | |
330 if (frames_overlap <= 0) { | |
331 s->bytes_standing = s->bytes_stride; | |
332 s->samples_standing = s->bytes_standing / bps; | |
333 s->output_overlap = NULL; | |
334 } else { | |
335 s->samples_overlap = frames_overlap * nch; | |
336 s->bytes_overlap = frames_overlap * nch * bps; | |
337 s->bytes_standing = s->bytes_stride - s->bytes_overlap; | |
338 s->samples_standing = s->bytes_standing / bps; | |
339 s->buf_overlap = realloc(s->buf_overlap, s->bytes_overlap); | |
340 s->table_blend = realloc(s->table_blend, s->bytes_overlap * 4); | |
341 if(!s->buf_overlap || !s->table_blend) { | |
29049 | 342 mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n"); |
24896 | 343 return AF_ERROR; |
344 } | |
25188 | 345 memset(s->buf_overlap, 0, s->bytes_overlap); |
24896 | 346 if (use_int) { |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
347 int32_t* pb = s->table_blend; |
24896 | 348 int64_t blend = 0; |
349 for (i=0; i<frames_overlap; i++) { | |
350 int32_t v = blend / frames_overlap; | |
351 for (j=0; j<nch; j++) { | |
352 *pb++ = v; | |
353 } | |
354 blend += 65536; // 2^16 | |
355 } | |
24899 | 356 s->output_overlap = output_overlap_s16; |
24896 | 357 } else { |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
358 float* pb = s->table_blend; |
24896 | 359 for (i=0; i<frames_overlap; i++) { |
360 float v = i / (float)frames_overlap; | |
361 for (j=0; j<nch; j++) { | |
362 *pb++ = v; | |
363 } | |
364 } | |
24899 | 365 s->output_overlap = output_overlap_float; |
24896 | 366 } |
367 } | |
368 | |
369 s->frames_search = (frames_overlap > 1) ? srate * s->ms_search : 0; | |
370 if (s->frames_search <= 0) { | |
371 s->best_overlap_offset = NULL; | |
372 } else { | |
373 if (use_int) { | |
374 int64_t t = frames_overlap; | |
375 int32_t n = 8589934588LL / (t * t); // 4 * (2^31 - 1) / t^2 | |
376 int32_t* pw; | |
25076
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
377 s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap * 2 + UNROLL_PADDING); |
24896 | 378 s->table_window = realloc(s->table_window, s->bytes_overlap * 2 - nch * bps * 2); |
25070
60b34bf9a41e
100l, someone mixed up && and ||, so if allocation of only one buffers failed
reimar
parents:
25069
diff
changeset
|
379 if(!s->buf_pre_corr || !s->table_window) { |
29049 | 380 mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n"); |
24896 | 381 return AF_ERROR; |
382 } | |
25076
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
383 memset((char *)s->buf_pre_corr + s->bytes_overlap * 2, 0, UNROLL_PADDING); |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
384 pw = s->table_window; |
24896 | 385 for (i=1; i<frames_overlap; i++) { |
386 int32_t v = ( i * (t - i) * n ) >> 15; | |
387 for (j=0; j<nch; j++) { | |
388 *pw++ = v; | |
389 } | |
390 } | |
24899 | 391 s->best_overlap_offset = best_overlap_offset_s16; |
24896 | 392 } else { |
393 float* pw; | |
394 s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap); | |
395 s->table_window = realloc(s->table_window, s->bytes_overlap - nch * bps); | |
396 if(!s->buf_pre_corr || !s->table_window) { | |
29049 | 397 mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n"); |
24896 | 398 return AF_ERROR; |
399 } | |
25069
d2f7027f0556
Avoid some casts by changing int8_t* to void* in af_scaletempo
reimar
parents:
24900
diff
changeset
|
400 pw = s->table_window; |
24896 | 401 for (i=1; i<frames_overlap; i++) { |
402 float v = i * (frames_overlap - i); | |
403 for (j=0; j<nch; j++) { | |
404 *pw++ = v; | |
405 } | |
406 } | |
24899 | 407 s->best_overlap_offset = best_overlap_offset_float; |
24896 | 408 } |
409 } | |
410 | |
411 s->bytes_per_frame = bps * nch; | |
412 s->num_channels = nch; | |
413 | |
414 s->bytes_queue | |
415 = (s->frames_search + frames_stride + frames_overlap) * bps * nch; | |
25076
dfd3c5702d32
Add padding and unroll loop 4x for at least another 10% speedup
reimar
parents:
25075
diff
changeset
|
416 s->buf_queue = realloc(s->buf_queue, s->bytes_queue + UNROLL_PADDING); |
24896 | 417 if(!s->buf_queue) { |
29049 | 418 mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n"); |
24896 | 419 return AF_ERROR; |
420 } | |
421 | |
29049 | 422 mp_msg (MSGT_AFILTER, MSGL_DBG2, "[scaletempo] " |
24896 | 423 "%.2f stride_in, %i stride_out, %i standing, " |
424 "%i overlap, %i search, %i queue, %s mode\n", | |
425 s->frames_stride_scaled, | |
426 (int)(s->bytes_stride / nch / bps), | |
427 (int)(s->bytes_standing / nch / bps), | |
428 (int)(s->bytes_overlap / nch / bps), | |
429 s->frames_search, | |
430 (int)(s->bytes_queue / nch / bps), | |
431 (use_int?"s16":"float")); | |
432 | |
433 return af_test_output(af, (af_data_t*)arg); | |
434 } | |
435 case AF_CONTROL_PLAYBACK_SPEED | AF_CONTROL_SET:{ | |
436 if (s->speed_tempo) { | |
437 if (s->speed_pitch) { | |
438 break; | |
439 } | |
440 s->speed = *(float*)arg; | |
441 s->scale = s->speed * s->scale_nominal; | |
442 } else { | |
443 if (s->speed_pitch) { | |
444 s->speed = 1 / *(float*)arg; | |
445 s->scale = s->speed * s->scale_nominal; | |
446 break; | |
447 } | |
448 } | |
449 return AF_OK; | |
450 } | |
451 case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_SET:{ | |
452 s->scale = *(float*)arg; | |
453 s->scale = s->speed * s->scale_nominal; | |
454 return AF_OK; | |
455 } | |
456 case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_GET: | |
457 *(float*)arg = s->scale; | |
458 return AF_OK; | |
459 case AF_CONTROL_COMMAND_LINE:{ | |
24898 | 460 strarg_t speed = {}; |
24896 | 461 opt_t subopts[] = { |
462 {"scale", OPT_ARG_FLOAT, &s->scale_nominal, NULL}, | |
463 {"stride", OPT_ARG_FLOAT, &s->ms_stride, NULL}, | |
464 {"overlap", OPT_ARG_FLOAT, &s->percent_overlap, NULL}, | |
465 {"search", OPT_ARG_FLOAT, &s->ms_search, NULL}, | |
466 {"speed", OPT_ARG_STR, &speed, NULL}, | |
467 {NULL}, | |
468 }; | |
469 if (subopt_parse(arg, subopts) != 0) { | |
470 return AF_ERROR; | |
471 } | |
472 if (s->scale_nominal <= 0) { | |
29049 | 473 mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] " |
24896 | 474 MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange |
475 ": scale > 0\n"); | |
476 return AF_ERROR; | |
477 } | |
478 if (s->ms_stride <= 0) { | |
29049 | 479 mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] " |
24896 | 480 MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange |
481 ": stride > 0\n"); | |
482 return AF_ERROR; | |
483 } | |
484 if (s->percent_overlap < 0 || s->percent_overlap > 1) { | |
29049 | 485 mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] " |
24896 | 486 MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange |
487 ": 0 <= overlap <= 1\n"); | |
488 return AF_ERROR; | |
489 } | |
490 if (s->ms_search < 0) { | |
29049 | 491 mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] " |
24896 | 492 MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange |
493 ": search >= 0\n"); | |
494 return AF_ERROR; | |
495 } | |
496 if (speed.len > 0) { | |
497 if (strcmp(speed.str, "pitch") == 0) { | |
498 s->speed_tempo = 0; | |
499 s->speed_pitch = 1; | |
500 } else if (strcmp(speed.str, "tempo") == 0) { | |
501 s->speed_tempo = 1; | |
502 s->speed_pitch = 0; | |
503 } else if (strcmp(speed.str, "none") == 0) { | |
504 s->speed_tempo = 0; | |
505 s->speed_pitch = 0; | |
506 } else if (strcmp(speed.str, "both") == 0) { | |
507 s->speed_tempo = 1; | |
508 s->speed_pitch = 1; | |
509 } else { | |
29049 | 510 mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] " |
24896 | 511 MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange |
512 ": speed=[pitch|tempo|none|both]\n"); | |
513 return AF_ERROR; | |
514 } | |
515 } | |
516 s->scale = s->speed * s->scale_nominal; | |
29049 | 517 mp_msg(MSGT_AFILTER, MSGL_DBG2, "[scaletempo] %6.3f scale, %6.2f stride, %6.2f overlap, %6.2f search, speed = %s\n", s->scale_nominal, s->ms_stride, s->percent_overlap, s->ms_search, (s->speed_tempo?(s->speed_pitch?"tempo and speed":"tempo"):(s->speed_pitch?"pitch":"none"))); |
24896 | 518 return AF_OK; |
519 } | |
520 } | |
521 return AF_UNKNOWN; | |
522 } | |
523 | |
524 // Deallocate memory | |
525 static void uninit(struct af_instance_s* af) | |
526 { | |
527 af_scaletempo_t* s = af->setup; | |
528 free(af->data->audio); | |
529 free(af->data); | |
530 free(s->buf_queue); | |
531 free(s->buf_overlap); | |
532 free(s->buf_pre_corr); | |
533 free(s->table_blend); | |
534 free(s->table_window); | |
535 free(af->setup); | |
536 } | |
537 | |
538 // Allocate memory and set function pointers | |
539 static int af_open(af_instance_t* af){ | |
540 af_scaletempo_t* s; | |
541 | |
542 af->control = control; | |
543 af->uninit = uninit; | |
544 af->play = play; | |
545 af->mul = 1; | |
546 af->data = calloc(1,sizeof(af_data_t)); | |
547 af->setup = calloc(1,sizeof(af_scaletempo_t)); | |
548 if(af->data == NULL || af->setup == NULL) | |
549 return AF_ERROR; | |
550 | |
551 s = af->setup; | |
552 s->scale = s->speed = s->scale_nominal = 1.0; | |
553 s->speed_tempo = 1; | |
554 s->speed_pitch = 0; | |
555 s->ms_stride = 60; | |
556 s->percent_overlap = .20; | |
557 s->ms_search = 14; | |
558 | |
559 return AF_OK; | |
560 } | |
561 | |
562 // Description of this filter | |
563 af_info_t af_info_scaletempo = { | |
564 "Scale audio tempo while maintaining pitch", | |
565 "scaletempo", | |
566 "Robert Juliano", | |
567 "", | |
568 AF_FLAGS_REENTRANT, | |
569 af_open | |
570 }; |