• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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