ebd6fddd7ddcfdb79cde13b98e460fdf56aff93e
[platform/upstream/pulseaudio.git] / 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              "32le, 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     pa_bool_t 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     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
327
328     pa_log_set_level(PA_LOG_WARN);
329     if (!getenv("MAKE_CHECK"))
330         pa_log_set_level(PA_LOG_INFO);
331
332     pa_assert_se(pool = pa_mempool_new(FALSE, 0));
333
334     a.channels = b.channels = 1;
335     a.rate = b.rate = 44100;
336     a.format = b.format = PA_SAMPLE_S16LE;
337
338     method = PA_RESAMPLER_AUTO;
339     seconds = 60;
340
341     while ((c = getopt_long(argc, argv, "hv", long_options, NULL)) != -1) {
342
343         switch (c) {
344             case 'h' :
345                 help(argv[0]);
346                 ret = 0;
347                 goto quit;
348
349             case 'v':
350                 pa_log_set_level(PA_LOG_DEBUG);
351                 break;
352
353             case ARG_VERSION:
354                 printf(_("%s %s\n"), argv[0], PACKAGE_VERSION);
355                 ret = 0;
356                 goto quit;
357
358             case ARG_DUMP_RESAMPLE_METHODS:
359                 dump_resample_methods();
360                 ret = 0;
361                 goto quit;
362
363             case ARG_FROM_CHANNELS:
364                 a.channels = (uint8_t) atoi(optarg);
365                 break;
366
367             case ARG_FROM_SAMPLEFORMAT:
368                 a.format = pa_parse_sample_format(optarg);
369                 all_formats = FALSE;
370                 break;
371
372             case ARG_FROM_SAMPLERATE:
373                 a.rate = (uint32_t) atoi(optarg);
374                 break;
375
376             case ARG_TO_CHANNELS:
377                 b.channels = (uint8_t) atoi(optarg);
378                 break;
379
380             case ARG_TO_SAMPLEFORMAT:
381                 b.format = pa_parse_sample_format(optarg);
382                 all_formats = FALSE;
383                 break;
384
385             case ARG_TO_SAMPLERATE:
386                 b.rate = (uint32_t) atoi(optarg);
387                 break;
388
389             case ARG_SECONDS:
390                 seconds = atoi(optarg);
391                 break;
392
393             case ARG_RESAMPLE_METHOD:
394                 if (*optarg == '\0' || pa_streq(optarg, "help")) {
395                     dump_resample_methods();
396                     ret = 0;
397                     goto quit;
398                 }
399                 method = pa_parse_resample_method(optarg);
400                 break;
401
402             default:
403                 goto quit;
404         }
405     }
406
407     ret = 0;
408     pa_assert_se(pool = pa_mempool_new(FALSE, 0));
409
410     if (!all_formats) {
411
412         pa_resampler *resampler;
413         pa_memchunk i, j;
414         pa_usec_t ts;
415
416         pa_log_debug(_("Compilation CFLAGS: %s"), PA_CFLAGS);
417         pa_log_debug(_("=== %d seconds: %d Hz %d ch (%s) -> %d Hz %d ch (%s)"), seconds,
418                    a.rate, a.channels, pa_sample_format_to_string(a.format),
419                    b.rate, b.channels, pa_sample_format_to_string(b.format));
420
421         ts = pa_rtclock_now();
422         pa_assert_se(resampler = pa_resampler_new(pool, &a, NULL, &b, NULL, method, 0));
423         pa_log_info("init: %llu", (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));
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         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, 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             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_free(pool);
477
478     return ret;
479 }