]> code.delx.au - pulseaudio/blob - src/tests/resampler-test.c
resampler: Support speex resampler compiled with FIXED_POINT
[pulseaudio] / src / tests / resampler-test.c
1 /***
2 This file is part of PulseAudio.
3
4 PulseAudio is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published
6 by the Free Software Foundation; either version 2.1 of the License,
7 or (at your option) any later version.
8
9 PulseAudio is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with PulseAudio; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <getopt.h>
26 #include <locale.h>
27
28 #include <pulse/pulseaudio.h>
29
30 #include <pulse/rtclock.h>
31 #include <pulse/sample.h>
32 #include <pulse/volume.h>
33
34 #include <pulsecore/i18n.h>
35 #include <pulsecore/log.h>
36 #include <pulsecore/resampler.h>
37 #include <pulsecore/macro.h>
38 #include <pulsecore/endianmacros.h>
39 #include <pulsecore/memblock.h>
40 #include <pulsecore/sample-util.h>
41 #include <pulsecore/core-util.h>
42
43 static void dump_block(const char *label, const pa_sample_spec *ss, const pa_memchunk *chunk) {
44 void *d;
45 unsigned i;
46
47 if (getenv("MAKE_CHECK"))
48 return;
49 printf("%s: \t", label);
50
51 d = pa_memblock_acquire(chunk->memblock);
52
53 switch (ss->format) {
54
55 case PA_SAMPLE_U8:
56 case PA_SAMPLE_ULAW:
57 case PA_SAMPLE_ALAW: {
58 uint8_t *u = d;
59
60 for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
61 printf(" 0x%02x ", *(u++));
62
63 break;
64 }
65
66 case PA_SAMPLE_S16NE:
67 case PA_SAMPLE_S16RE: {
68 uint16_t *u = d;
69
70 for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
71 printf(" 0x%04x ", *(u++));
72
73 break;
74 }
75
76 case PA_SAMPLE_S32NE:
77 case PA_SAMPLE_S32RE: {
78 uint32_t *u = d;
79
80 for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
81 printf("0x%08x ", *(u++));
82
83 break;
84 }
85
86 case PA_SAMPLE_S24_32NE:
87 case PA_SAMPLE_S24_32RE: {
88 uint32_t *u = d;
89
90 for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
91 printf("0x%08x ", *(u++));
92
93 break;
94 }
95
96 case PA_SAMPLE_FLOAT32NE:
97 case PA_SAMPLE_FLOAT32RE: {
98 float *u = d;
99
100 for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
101 printf("%4.3g ", ss->format == PA_SAMPLE_FLOAT32NE ? *u : PA_FLOAT32_SWAP(*u));
102 u++;
103 }
104
105 break;
106 }
107
108 case PA_SAMPLE_S24LE:
109 case PA_SAMPLE_S24BE: {
110 uint8_t *u = d;
111
112 for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
113 printf(" 0x%06x ", PA_READ24NE(u));
114 u += pa_frame_size(ss);
115 }
116
117 break;
118 }
119
120 default:
121 pa_assert_not_reached();
122 }
123
124 printf("\n");
125
126 pa_memblock_release(chunk->memblock);
127 }
128
129 static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) {
130 pa_memblock *r;
131 void *d;
132 unsigned i;
133
134 pa_assert_se(r = pa_memblock_new(pool, pa_frame_size(ss) * 10));
135 d = pa_memblock_acquire(r);
136
137 switch (ss->format) {
138
139 case PA_SAMPLE_U8:
140 case PA_SAMPLE_ULAW:
141 case PA_SAMPLE_ALAW: {
142 uint8_t *u = d;
143
144 u[0] = 0x00;
145 u[1] = 0xFF;
146 u[2] = 0x7F;
147 u[3] = 0x80;
148 u[4] = 0x9f;
149 u[5] = 0x3f;
150 u[6] = 0x1;
151 u[7] = 0xF0;
152 u[8] = 0x20;
153 u[9] = 0x21;
154 break;
155 }
156
157 case PA_SAMPLE_S16NE:
158 case PA_SAMPLE_S16RE: {
159 uint16_t *u = d;
160
161 u[0] = 0x0000;
162 u[1] = 0xFFFF;
163 u[2] = 0x7FFF;
164 u[3] = 0x8000;
165 u[4] = 0x9fff;
166 u[5] = 0x3fff;
167 u[6] = 0x1;
168 u[7] = 0xF000;
169 u[8] = 0x20;
170 u[9] = 0x21;
171 break;
172 }
173
174 case PA_SAMPLE_S32NE:
175 case PA_SAMPLE_S32RE: {
176 uint32_t *u = d;
177
178 u[0] = 0x00000001;
179 u[1] = 0xFFFF0002;
180 u[2] = 0x7FFF0003;
181 u[3] = 0x80000004;
182 u[4] = 0x9fff0005;
183 u[5] = 0x3fff0006;
184 u[6] = 0x10007;
185 u[7] = 0xF0000008;
186 u[8] = 0x200009;
187 u[9] = 0x21000A;
188 break;
189 }
190
191 case PA_SAMPLE_S24_32NE:
192 case PA_SAMPLE_S24_32RE: {
193 uint32_t *u = d;
194
195 u[0] = 0x000001;
196 u[1] = 0xFF0002;
197 u[2] = 0x7F0003;
198 u[3] = 0x800004;
199 u[4] = 0x9f0005;
200 u[5] = 0x3f0006;
201 u[6] = 0x107;
202 u[7] = 0xF00008;
203 u[8] = 0x2009;
204 u[9] = 0x210A;
205 break;
206 }
207
208 case PA_SAMPLE_FLOAT32NE:
209 case PA_SAMPLE_FLOAT32RE: {
210 float *u = d;
211
212 u[0] = 0.0f;
213 u[1] = -1.0f;
214 u[2] = 1.0f;
215 u[3] = 4711.0f;
216 u[4] = 0.222f;
217 u[5] = 0.33f;
218 u[6] = -.3f;
219 u[7] = 99.0f;
220 u[8] = -0.555f;
221 u[9] = -.123f;
222
223 if (ss->format == PA_SAMPLE_FLOAT32RE)
224 for (i = 0; i < 10; i++)
225 u[i] = PA_FLOAT32_SWAP(u[i]);
226
227 break;
228 }
229
230 case PA_SAMPLE_S24NE:
231 case PA_SAMPLE_S24RE: {
232 uint8_t *u = d;
233
234 PA_WRITE24NE(u, 0x000001);
235 PA_WRITE24NE(u+3, 0xFF0002);
236 PA_WRITE24NE(u+6, 0x7F0003);
237 PA_WRITE24NE(u+9, 0x800004);
238 PA_WRITE24NE(u+12, 0x9f0005);
239 PA_WRITE24NE(u+15, 0x3f0006);
240 PA_WRITE24NE(u+18, 0x107);
241 PA_WRITE24NE(u+21, 0xF00008);
242 PA_WRITE24NE(u+24, 0x2009);
243 PA_WRITE24NE(u+27, 0x210A);
244 break;
245 }
246
247 default:
248 pa_assert_not_reached();
249 }
250
251 pa_memblock_release(r);
252
253 return r;
254 }
255
256 static void help(const char *argv0) {
257 printf(_("%s [options]\n\n"
258 "-h, --help Show this help\n"
259 "-v, --verbose Print debug messages\n"
260 " --from-rate=SAMPLERATE From sample rate in Hz (defaults to 44100)\n"
261 " --from-format=SAMPLEFORMAT From sample type (defaults to s16le)\n"
262 " --from-channels=CHANNELS From number of channels (defaults to 1)\n"
263 " --to-rate=SAMPLERATE To sample rate in Hz (defaults to 44100)\n"
264 " --to-format=SAMPLEFORMAT To sample type (defaults to s16le)\n"
265 " --to-channels=CHANNELS To number of channels (defaults to 1)\n"
266 " --resample-method=METHOD Resample method (defaults to auto)\n"
267 " --seconds=SECONDS From stream duration (defaults to 60)\n"
268 "\n"
269 "If the formats are not specified, the test performs all formats combinations,\n"
270 "back and forth.\n"
271 "\n"
272 "Sample type must be one of s16le, s16be, u8, float32le, float32be, ulaw, alaw,\n"
273 "s24le, s24be, s24-32le, s24-32be, s32le, s32be (defaults to s16ne)\n"
274 "\n"
275 "See --dump-resample-methods for possible values of resample methods.\n"),
276 argv0);
277 }
278
279 enum {
280 ARG_VERSION = 256,
281 ARG_FROM_SAMPLERATE,
282 ARG_FROM_SAMPLEFORMAT,
283 ARG_FROM_CHANNELS,
284 ARG_TO_SAMPLERATE,
285 ARG_TO_SAMPLEFORMAT,
286 ARG_TO_CHANNELS,
287 ARG_SECONDS,
288 ARG_RESAMPLE_METHOD,
289 ARG_DUMP_RESAMPLE_METHODS
290 };
291
292 static void dump_resample_methods(void) {
293 int i;
294
295 for (i = 0; i < PA_RESAMPLER_MAX; i++)
296 if (pa_resample_method_supported(i))
297 printf("%s\n", pa_resample_method_to_string(i));
298
299 }
300
301 int main(int argc, char *argv[]) {
302 pa_mempool *pool = NULL;
303 pa_sample_spec a, b;
304 int ret = 1, c;
305 bool all_formats = true;
306 pa_resample_method_t method;
307 int seconds;
308
309 static const struct option long_options[] = {
310 {"help", 0, NULL, 'h'},
311 {"verbose", 0, NULL, 'v'},
312 {"version", 0, NULL, ARG_VERSION},
313 {"from-rate", 1, NULL, ARG_FROM_SAMPLERATE},
314 {"from-format", 1, NULL, ARG_FROM_SAMPLEFORMAT},
315 {"from-channels", 1, NULL, ARG_FROM_CHANNELS},
316 {"to-rate", 1, NULL, ARG_TO_SAMPLERATE},
317 {"to-format", 1, NULL, ARG_TO_SAMPLEFORMAT},
318 {"to-channels", 1, NULL, ARG_TO_CHANNELS},
319 {"seconds", 1, NULL, ARG_SECONDS},
320 {"resample-method", 1, NULL, ARG_RESAMPLE_METHOD},
321 {"dump-resample-methods", 0, NULL, ARG_DUMP_RESAMPLE_METHODS},
322 {NULL, 0, NULL, 0}
323 };
324
325 setlocale(LC_ALL, "");
326 #ifdef ENABLE_NLS
327 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
328 #endif
329
330 pa_log_set_level(PA_LOG_WARN);
331 if (!getenv("MAKE_CHECK"))
332 pa_log_set_level(PA_LOG_INFO);
333
334 pa_assert_se(pool = pa_mempool_new(false, 0));
335
336 a.channels = b.channels = 1;
337 a.rate = b.rate = 44100;
338 a.format = b.format = PA_SAMPLE_S16LE;
339
340 method = PA_RESAMPLER_AUTO;
341 seconds = 60;
342
343 while ((c = getopt_long(argc, argv, "hv", long_options, NULL)) != -1) {
344
345 switch (c) {
346 case 'h' :
347 help(argv[0]);
348 ret = 0;
349 goto quit;
350
351 case 'v':
352 pa_log_set_level(PA_LOG_DEBUG);
353 break;
354
355 case ARG_VERSION:
356 printf(_("%s %s\n"), argv[0], PACKAGE_VERSION);
357 ret = 0;
358 goto quit;
359
360 case ARG_DUMP_RESAMPLE_METHODS:
361 dump_resample_methods();
362 ret = 0;
363 goto quit;
364
365 case ARG_FROM_CHANNELS:
366 a.channels = (uint8_t) atoi(optarg);
367 break;
368
369 case ARG_FROM_SAMPLEFORMAT:
370 a.format = pa_parse_sample_format(optarg);
371 all_formats = false;
372 break;
373
374 case ARG_FROM_SAMPLERATE:
375 a.rate = (uint32_t) atoi(optarg);
376 break;
377
378 case ARG_TO_CHANNELS:
379 b.channels = (uint8_t) atoi(optarg);
380 break;
381
382 case ARG_TO_SAMPLEFORMAT:
383 b.format = pa_parse_sample_format(optarg);
384 all_formats = false;
385 break;
386
387 case ARG_TO_SAMPLERATE:
388 b.rate = (uint32_t) atoi(optarg);
389 break;
390
391 case ARG_SECONDS:
392 seconds = atoi(optarg);
393 break;
394
395 case ARG_RESAMPLE_METHOD:
396 if (*optarg == '\0' || pa_streq(optarg, "help")) {
397 dump_resample_methods();
398 ret = 0;
399 goto quit;
400 }
401 method = pa_parse_resample_method(optarg);
402 break;
403
404 default:
405 goto quit;
406 }
407 }
408
409 ret = 0;
410 pa_assert_se(pool = pa_mempool_new(false, 0));
411
412 if (!all_formats) {
413
414 pa_resampler *resampler;
415 pa_memchunk i, j;
416 pa_usec_t ts;
417
418 pa_log_debug(_("Compilation CFLAGS: %s"), PA_CFLAGS);
419 pa_log_debug(_("=== %d seconds: %d Hz %d ch (%s) -> %d Hz %d ch (%s)"), seconds,
420 a.rate, a.channels, pa_sample_format_to_string(a.format),
421 b.rate, b.channels, pa_sample_format_to_string(b.format));
422
423 ts = pa_rtclock_now();
424 pa_assert_se(resampler = pa_resampler_new(pool, &a, NULL, &b, NULL, method, 0));
425 pa_log_info("init: %llu", (long long unsigned)(pa_rtclock_now() - ts));
426
427 i.memblock = pa_memblock_new(pool, pa_usec_to_bytes(1*PA_USEC_PER_SEC, &a));
428
429 ts = pa_rtclock_now();
430 i.length = pa_memblock_get_length(i.memblock);
431 i.index = 0;
432 while (seconds--) {
433 pa_resampler_run(resampler, &i, &j);
434 if (j.memblock)
435 pa_memblock_unref(j.memblock);
436 }
437 pa_log_info("resampling: %llu", (long long unsigned)(pa_rtclock_now() - ts));
438 pa_memblock_unref(i.memblock);
439
440 pa_resampler_free(resampler);
441
442 goto quit;
443 }
444
445 for (a.format = 0; a.format < PA_SAMPLE_MAX; a.format ++) {
446 for (b.format = 0; b.format < PA_SAMPLE_MAX; b.format ++) {
447 pa_resampler *forth, *back;
448 pa_memchunk i, j, k;
449
450 pa_log_debug("=== %s -> %s -> %s -> /2",
451 pa_sample_format_to_string(a.format),
452 pa_sample_format_to_string(b.format),
453 pa_sample_format_to_string(a.format));
454
455 pa_assert_se(forth = pa_resampler_new(pool, &a, NULL, &b, NULL, method, 0));
456 pa_assert_se(back = pa_resampler_new(pool, &b, NULL, &a, NULL, method, 0));
457
458 i.memblock = generate_block(pool, &a);
459 i.length = pa_memblock_get_length(i.memblock);
460 i.index = 0;
461 pa_resampler_run(forth, &i, &j);
462 pa_resampler_run(back, &j, &k);
463
464 dump_block("before", &a, &i);
465 dump_block("after", &b, &j);
466 dump_block("reverse", &a, &k);
467
468 pa_memblock_unref(i.memblock);
469 pa_memblock_unref(j.memblock);
470 pa_memblock_unref(k.memblock);
471
472 pa_resampler_free(forth);
473 pa_resampler_free(back);
474 }
475 }
476
477 quit:
478 if (pool)
479 pa_mempool_free(pool);
480
481 return ret;
482 }