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