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