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