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