[pulseaudio-discuss] [PATCH 10/10] tests: Add remap-special-test
Peter Meerwald
pmeerw at pmeerw.net
Fri Mar 29 08:56:51 PDT 2013
From: Peter Meerwald <p.meerwald at bct-electronic.com>
beware, lots of code duplication between test and runtime code
for illustration purpose only :)
compiled with Ubuntu/Linaro gcc 4.6.3:
arm-linux-gnueabi-gcc -O2 -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon
runtime on beagle-xm measured remap-special-test:
Testing s16 2-channel-to-mono remap performance with 3 sample alignment
func: 1128848 usec (avg: 11288.5, min = 11200, max = 11871, stddev = 92.7675).
orig: 2821201 usec (avg: 28212, min = 28106, max = 28595, stddev = 91.0587).
Testing s16 4-channel-to-mono remap performance with 3 sample alignment
func: 1536317 usec (avg: 15363.2, min = 15289, max = 15900, stddev = 82.5403).
orig: 5551764 usec (avg: 55517.6, min = 55359, max = 56702, stddev = 196.81).
Testing s16 mono-to-2-channel remap performance with 3 sample alignment
func: 415250 usec (avg: 4152.5, min = 4119, max = 4456, stddev = 52.7611).
orig: 1537903 usec (avg: 15379, min = 15289, max = 15869, stddev = 93.078).
Testing s16 mono-to-4-channel remap performance with 3 sample alignment
func: 710513 usec (avg: 7105.13, min = 7019, max = 7630, stddev = 86.6658).
orig: 3062413 usec (avg: 30624.1, min = 30518, max = 31128, stddev = 109.456).
Testing float 2-channel-to-mono remap performance with 3 sample alignment
func: 4049533 usec (avg: 40495.3, min = 40374, max = 41046, stddev = 128.187).
orig: 12115179 usec (avg: 121152, min = 120910, max = 122071, stddev = 178.598).
Testing float 4-channel-to-mono remap performance with 3 sample alignment
func: 7940282 usec (avg: 79402.8, min = 79254, max = 80627, stddev = 175.874).
orig: 24183727 usec (avg: 241837, min = 241577, max = 242737, stddev = 208.3).
Testing float mono-to-2-channel remap performance with 3 sample alignment
func: 677094 usec (avg: 6770.94, min = 6073, max = 7843, stddev = 624.805).
orig: 8505589 usec (avg: 85055.9, min = 84838, max = 85511, stddev = 138.815).
Testing float mono-to-4-channel remap performance with 3 sample alignment
func: 1240600 usec (avg: 12406, min = 11078, max = 15839, stddev = 1195.99).
orig: 11538670 usec (avg: 115387, min = 115203, max = 115753, stddev = 152.72).
on Core i7, 64bit:
Testing s16 2-channel-to-mono remap performance with 3 sample alignment
func: 108723 usec (avg: 1087.23, min = 939, max = 3023, stddev = 449.7).
orig: 185219 usec (avg: 1852.19, min = 1796, max = 2210, stddev = 76.6693).
Testing s16 4-channel-to-mono remap performance with 3 sample alignment
func: 130692 usec (avg: 1306.92, min = 1272, max = 1448, stddev = 42.0549).
orig: 365576 usec (avg: 3655.76, min = 3580, max = 4376, stddev = 123.333).
Testing s16 mono-to-2-channel remap performance with 3 sample alignment
func: 60965 usec (avg: 609.65, min = 581, max = 775, stddev = 34.7144).
orig: 183806 usec (avg: 1838.06, min = 1802, max = 2231, stddev = 71.464).
Testing s16 mono-to-4-channel remap performance with 3 sample alignment
func: 118915 usec (avg: 1189.15, min = 1149, max = 1395, stddev = 48.0912).
orig: 365320 usec (avg: 3653.2, min = 3598, max = 4203, stddev = 89.2894).
Testing float 2-channel-to-mono remap performance with 3 sample alignment
func: 71056 usec (avg: 710.56, min = 582, max = 1775, stddev = 322.095).
orig: 186387 usec (avg: 1863.87, min = 1805, max = 2374, stddev = 79.5336).
Testing float 4-channel-to-mono remap performance with 3 sample alignment
func: 117826 usec (avg: 1178.26, min = 1157, max = 1277, stddev = 29.9315).
orig: 358471 usec (avg: 3584.71, min = 3539, max = 4025, stddev = 87.0788).
Testing float mono-to-2-channel remap performance with 3 sample alignment
func: 61018 usec (avg: 610.18, min = 580, max = 735, stddev = 28.4445).
orig: 190701 usec (avg: 1907.01, min = 1870, max = 2101, stddev = 52.3818).
Testing float mono-to-4-channel remap performance with 3 sample alignment
func: 117890 usec (avg: 1178.9, min = 1157, max = 1297, stddev = 32.613).
orig: 380944 usec (avg: 3809.44, min = 3743, max = 4232, stddev = 88.4906).
Signed-off-by: Peter Meerwald <p.meerwald at bct-electronic.com>
---
src/.gitignore | 1 +
src/Makefile.am | 8 +-
src/tests/remap-special-test.c | 651 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 659 insertions(+), 1 deletion(-)
create mode 100644 src/tests/remap-special-test.c
diff --git a/src/.gitignore b/src/.gitignore
index cd9c51a..33d8212 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -74,3 +74,4 @@ usergroup-test
utf8-test
volume-test
mult-s16-test
+remap-special-test
diff --git a/src/Makefile.am b/src/Makefile.am
index 915c177..eab4a15 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -247,7 +247,8 @@ TESTS_default = \
cpu-test \
lock-autospawn-test \
mult-s16-test \
- mix-special-test
+ mix-special-test \
+ remap-special-test
TESTS_norun = \
ipacl-test \
@@ -518,6 +519,11 @@ mix_special_test_LDADD = $(AM_LDADD) libpulsecore- at PA_MAJORMINOR@.la libpulse.la
mix_special_test_CFLAGS = $(AM_CFLAGS) $(LIBCHECK_CFLAGS)
mix_special_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBCHECK_LIBS)
+remap_special_test_SOURCES = tests/remap-special-test.c
+remap_special_test_LDADD = $(AM_LDADD) libpulsecore- at PA_MAJORMINOR@.la libpulse.la libpulsecommon- at PA_MAJORMINOR@.la
+remap_special_test_CFLAGS = $(AM_CFLAGS) $(LIBCHECK_CFLAGS)
+remap_special_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBCHECK_LIBS)
+
rtstutter_SOURCES = tests/rtstutter.c
rtstutter_LDADD = $(AM_LDADD) libpulsecore- at PA_MAJORMINOR@.la libpulse.la libpulsecommon- at PA_MAJORMINOR@.la
rtstutter_CFLAGS = $(AM_CFLAGS)
diff --git a/src/tests/remap-special-test.c b/src/tests/remap-special-test.c
new file mode 100644
index 0000000..4d7a0cf
--- /dev/null
+++ b/src/tests/remap-special-test.c
@@ -0,0 +1,651 @@
+/***
+ This file is part of PulseAudio.
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <check.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <pulse/rtclock.h>
+#include <pulse/volume.h>
+#include <pulsecore/random.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/remap.h>
+
+#define PA_CPU_TEST_RUN_START(l, t1, t2) \
+{ \
+ int _j, _k; \
+ int _times = (t1), _times2 = (t2); \
+ pa_usec_t _start, _stop; \
+ pa_usec_t _min = INT_MAX, _max = 0; \
+ double _s1 = 0, _s2 = 0; \
+ const char *_label = (l); \
+ \
+ for (_k = 0; _k < _times2; _k++) { \
+ _start = pa_rtclock_now(); \
+ for (_j = 0; _j < _times; _j++)
+
+#define PA_CPU_TEST_RUN_STOP \
+ _stop = pa_rtclock_now(); \
+ \
+ if (_min > (_stop - _start)) _min = _stop - _start; \
+ if (_max < (_stop - _start)) _max = _stop - _start; \
+ _s1 += _stop - _start; \
+ _s2 += (_stop - _start) * (_stop - _start); \
+ } \
+ pa_log_debug("%s: %llu usec (avg: %g, min = %llu, max = %llu, stddev = %g).", _label, \
+ (long long unsigned int)_s1, \
+ ((double)_s1 / _times2), \
+ (long long unsigned int)_min, \
+ (long long unsigned int)_max, \
+ sqrt(_times2 * _s2 - _s1 * _s1) / _times2); \
+}
+
+static void remap_mono_to_stereo_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
+ unsigned i;
+
+ switch (*m->format) {
+ case PA_SAMPLE_FLOAT32NE:
+ {
+ float *d, *s;
+
+ d = (float *) dst;
+ s = (float *) src;
+
+ for (i = n >> 2; i; i--) {
+ d[0] = d[1] = s[0];
+ d[2] = d[3] = s[1];
+ d[4] = d[5] = s[2];
+ d[6] = d[7] = s[3];
+ s += 4;
+ d += 8;
+ }
+ for (i = n & 3; i; i--) {
+ d[0] = d[1] = s[0];
+ s++;
+ d += 2;
+ }
+ break;
+ }
+ case PA_SAMPLE_S16NE:
+ {
+ int16_t *d, *s;
+
+ d = (int16_t *) dst;
+ s = (int16_t *) src;
+
+ for (i = n >> 2; i; i--) {
+ d[0] = d[1] = s[0];
+ d[2] = d[3] = s[1];
+ d[4] = d[5] = s[2];
+ d[6] = d[7] = s[3];
+ s += 4;
+ d += 8;
+ }
+ for (i = n & 3; i; i--) {
+ d[0] = d[1] = s[0];
+ s++;
+ d += 2;
+ }
+ break;
+ }
+ default:
+ pa_assert_not_reached();
+ }
+}
+
+static void remap_mono_to_ch4_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
+ unsigned i;
+
+ switch (*m->format) {
+ case PA_SAMPLE_FLOAT32NE:
+ {
+ float *d, *s;
+
+ d = (float *) dst;
+ s = (float *) src;
+
+ for (i = n >> 2; i; i--) {
+ d[0] = d[1] = d[2] = d[3] = s[0];
+ d[4] = d[5] = d[6] = d[7] = s[1];
+ d[8] = d[9] = d[10] = d[11] = s[2];
+ d[12] = d[13] = d[14] = d[15] = s[3];
+ s += 4;
+ d += 16;
+ }
+ for (i = n & 3; i; i--) {
+ d[0] = d[1] = d[2] = d[3] = s[0];
+ s++;
+ d += 4;
+ }
+ break;
+ }
+ case PA_SAMPLE_S16NE:
+ {
+ int16_t *d, *s;
+
+ d = (int16_t *) dst;
+ s = (int16_t *) src;
+
+ for (i = n >> 2; i; i--) {
+ d[0] = d[1] = d[2] = d[3] = s[0];
+ d[4] = d[5] = d[6] = d[7] = s[1];
+ d[8] = d[9] = d[10] = d[11] = s[2];
+ d[12] = d[13] = d[14] = d[15] = s[3];
+ s += 4;
+ d += 16;
+ }
+ for (i = n & 3; i; i--) {
+ d[0] = d[1] = d[2] = d[3] = s[0];
+ s++;
+ d += 4;
+ }
+ break;
+ }
+ default:
+ pa_assert_not_reached();
+ }
+}
+
+static void remap_stereo_to_mono_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
+ unsigned i;
+
+ switch (*m->format) {
+ case PA_SAMPLE_FLOAT32NE:
+ {
+ float *d = (float *) dst, *s = (float *) src;
+
+ for (i = n >> 2; i > 0; i--) {
+ d[0] = (s[0] + s[1])*0.5f;
+ d[1] = (s[2] + s[3])*0.5f;
+ d[2] = (s[4] + s[5])*0.5f;
+ d[3] = (s[6] + s[7])*0.5f;
+ s += 8;
+ d += 4;
+ }
+ for (i = n & 3; i; i--) {
+ d[0] = (s[0] + s[1])*0.5f;
+ s += 2;
+ d += 1;
+ }
+ break;
+ }
+ case PA_SAMPLE_S16NE:
+ {
+ int16_t *d = (int16_t *) dst, *s = (int16_t *) src;
+
+ for (i = n >> 2; i > 0; i--) {
+ d[0] += (s[0] + s[1])/2;
+ d[1] += (s[2] + s[3])/2;
+ d[2] += (s[4] + s[5])/2;
+ d[3] += (s[6] + s[7])/2;
+ s += 8;
+ d += 4;
+ }
+ for (i = n & 3; i; i--) {
+ d[0] += (s[0] + s[1])/2;
+ s += 2;
+ d += 1;
+ }
+ break;
+ }
+ default:
+ pa_assert_not_reached();
+ }
+}
+
+static void remap_ch4_to_mono_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
+ unsigned i;
+
+ switch (*m->format) {
+ case PA_SAMPLE_FLOAT32NE:
+ {
+ float *d = (float *) dst, *s = (float *) src;
+
+ for (i = n >> 2; i > 0; i--) {
+ d[0] = (s[0] + s[1] + s[2] + s[3])*0.25f;
+ d[1] = (s[4] + s[5] + s[6] + s[7])*0.25f;
+ d[2] = (s[8] + s[9] + s[10] + s[11])*0.25f;
+ d[3] = (s[12] + s[13] + s[14] + s[15])*0.25f;
+ s += 16;
+ d += 4;
+ }
+ for (i = n & 3; i; i--) {
+ d[0] = (s[0] + s[1] + s[2] + s[3])*0.25f;
+ s += 4;
+ d += 1;
+ }
+ break;
+ }
+ case PA_SAMPLE_S16NE:
+ {
+ int16_t *d = (int16_t *) dst, *s = (int16_t *) src;
+ for (i = n >> 2; i > 0; i--) {
+ d[0] = (s[0] + s[1] + s[2] + s[3])/4;
+ d[1] = (s[4] + s[5] + s[6] + s[7])/4;
+ d[2] = (s[8] + s[9] + s[10] + s[11])/4;
+ d[3] = (s[12] + s[13] + s[14] + s[15])/4;
+ s += 16;
+ d += 4;
+ }
+ for (i = n & 3; i; i--) {
+ d[0] = (s[0] + s[1] + s[2] + s[3])/4;
+ s += 4;
+ d += 1;
+ }
+ break;
+ }
+ default:
+ pa_assert_not_reached();
+ }
+}
+
+static void remap_channels_matrix_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
+ unsigned oc, ic, i;
+ unsigned n_ic, n_oc;
+
+ n_ic = m->i_ss->channels;
+ n_oc = m->o_ss->channels;
+
+ switch (*m->format) {
+ case PA_SAMPLE_FLOAT32NE:
+ {
+ float *d, *s;
+
+ memset(dst, 0, n * sizeof(float) * n_oc);
+
+ for (oc = 0; oc < n_oc; oc++) {
+
+ for (ic = 0; ic < n_ic; ic++) {
+ float vol;
+
+ vol = m->map_table_f[oc][ic];
+
+ if (vol <= 0.0)
+ continue;
+
+ d = (float *)dst + oc;
+ s = (float *)src + ic;
+
+ if (vol >= 1.0) {
+ for (i = n; i > 0; i--, s += n_ic, d += n_oc)
+ *d += *s;
+ } else {
+ for (i = n; i > 0; i--, s += n_ic, d += n_oc)
+ *d += *s * vol;
+ }
+ }
+ }
+
+ break;
+ }
+ case PA_SAMPLE_S16NE:
+ {
+ int16_t *d, *s;
+
+ memset(dst, 0, n * sizeof(int16_t) * n_oc);
+
+ for (oc = 0; oc < n_oc; oc++) {
+
+ for (ic = 0; ic < n_ic; ic++) {
+ int32_t vol;
+
+ vol = m->map_table_i[oc][ic];
+
+ if (vol <= 0)
+ continue;
+
+ d = (int16_t *)dst + oc;
+ s = (int16_t *)src + ic;
+
+ if (vol >= 0x10000) {
+ for (i = n; i > 0; i--, s += n_ic, d += n_oc)
+ *d += *s;
+ } else {
+ for (i = n; i > 0; i--, s += n_ic, d += n_oc)
+ *d += (int16_t) (((int32_t)*s * vol) >> 16);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ pa_assert_not_reached();
+ }
+}
+
+#define SAMPLES 1028
+#define TIMES 1000
+#define TIMES2 100
+
+static void run_remap_test_mono_channels_float(
+ pa_remap_t *remap,
+ pa_do_remap_func_t func, pa_do_remap_func_t orig_func,
+ int channels,
+ int align, pa_bool_t correct, pa_bool_t perf) {
+
+ PA_DECLARE_ALIGNED(8, float, out_ref[SAMPLES*8]) = { 0 };
+ PA_DECLARE_ALIGNED(8, float, out[SAMPLES*8]) = { 0 };
+ PA_DECLARE_ALIGNED(8, float, in[SAMPLES]) = { 0 };
+ float *ch, *ch_ref;
+ float *mono;
+ int i, nsamples;
+
+ assert(channels == 2 || channels == 4 || channels == 8);
+
+ /* Force sample alignment as requested */
+ ch = out + (8 - align);
+ ch_ref = out_ref + (8 - align);
+ mono = in + (8 - align);
+ nsamples = SAMPLES - (8 - align);
+
+ for (i = 0; i < nsamples; i++)
+ mono[i] = 2.1f * (rand()/(float) RAND_MAX - 0.5f);
+
+ if (correct) {
+ orig_func(remap, ch_ref, mono, nsamples);
+ func(remap, ch, mono, nsamples);
+
+ for (i = 0; i < nsamples * channels; i++) {
+ if (fabsf(ch[i] - ch_ref[i]) > 0.0001) {
+ pa_log_debug("Correctness test failed: align=%d", align);
+ pa_log_debug("%d: %.24f != %.24f (%.24f)\n", i, ch[i], ch_ref[i], mono[i]);
+ fail();
+ }
+ }
+ }
+
+ if (perf) {
+ pa_log_debug("Testing float mono-to-%d-channel remap performance with %d sample alignment", channels, align);
+
+ PA_CPU_TEST_RUN_START("func", TIMES, TIMES2) {
+ func(remap, ch, mono, nsamples);
+ } PA_CPU_TEST_RUN_STOP
+
+ PA_CPU_TEST_RUN_START("orig", TIMES, TIMES2) {
+ orig_func(remap, ch_ref, mono, nsamples);
+ } PA_CPU_TEST_RUN_STOP
+ }
+}
+
+static void run_remap_test_mono_channels_s16(
+ pa_remap_t *remap,
+ pa_do_remap_func_t func, pa_do_remap_func_t orig_func,
+ int channels,
+ int align, pa_bool_t correct, pa_bool_t perf) {
+
+ PA_DECLARE_ALIGNED(8, int16_t, out_ref[SAMPLES*8]) = { 0 };
+ PA_DECLARE_ALIGNED(8, int16_t, out[SAMPLES*8]) = { 0 };
+ PA_DECLARE_ALIGNED(8, int16_t, in[SAMPLES]) = { 0 };
+ int16_t *ch, *ch_ref;
+ int16_t *mono;
+ int i, nsamples;
+
+ assert(channels == 2 || channels == 4 || channels == 8);
+
+ /* Force sample alignment as requested */
+ ch = out + (8 - align);
+ ch_ref = out_ref + (8 - align);
+ mono = in + (8 - align);
+ nsamples = SAMPLES - (8 - align);
+
+ pa_random(mono, nsamples * sizeof(int16_t));
+
+ if (correct) {
+ orig_func(remap, ch_ref, mono, nsamples);
+ func(remap, ch, mono, nsamples);
+
+ for (i = 0; i < nsamples * channels; i++) {
+ if (abs(ch[i] - ch_ref[i]) > 1) {
+ pa_log_debug("Correctness test failed: align=%d", align);
+ pa_log_debug("%d: %d != %d (%d)\n", i, ch[i], ch_ref[i], mono[i]);
+ fail();
+ }
+ }
+ }
+
+ if (perf) {
+ pa_log_debug("Testing s16 mono-to-%d-channel remap performance with %d sample alignment", channels, align);
+
+ PA_CPU_TEST_RUN_START("func", TIMES, TIMES2) {
+ func(remap, ch, mono, nsamples);
+ } PA_CPU_TEST_RUN_STOP
+
+ PA_CPU_TEST_RUN_START("orig", TIMES, TIMES2) {
+ orig_func(remap, ch_ref, mono, nsamples);
+ } PA_CPU_TEST_RUN_STOP
+ }
+}
+
+static void remap_test_mono_channels(pa_sample_format_t format, int channels) {
+ pa_sample_format_t sf;
+ pa_remap_t remap;
+ pa_sample_spec iss, oss;
+ pa_do_remap_func_t orig_func, func;
+ int i;
+
+ iss.format = oss.format = sf = format;
+ iss.channels = 1;
+ oss.channels = channels;
+ remap.format = &sf;
+ remap.i_ss = &iss;
+ remap.o_ss = &oss;
+ for (i = 0; i < channels; i++) {
+ remap.map_table_f[i][0] = 1.0f;
+ remap.map_table_i[i][0] = PA_VOLUME_NORM;
+ }
+
+ orig_func = remap_channels_matrix_c;
+ if (channels == 2) func = remap_mono_to_stereo_c;
+ else if (channels == 4) func = remap_mono_to_ch4_c;
+ else pa_assert_not_reached();
+
+ if (format == PA_SAMPLE_FLOAT32NE) {
+ run_remap_test_mono_channels_float(&remap, func, orig_func, channels, 0, TRUE, FALSE);
+ run_remap_test_mono_channels_float(&remap, func, orig_func, channels, 1, TRUE, FALSE);
+ run_remap_test_mono_channels_float(&remap, func, orig_func, channels, 2, TRUE, FALSE);
+ run_remap_test_mono_channels_float(&remap, func, orig_func, channels, 3, TRUE, TRUE);
+ } else if (format == PA_SAMPLE_S16NE) {
+ run_remap_test_mono_channels_s16(&remap, func, orig_func, channels, 0, TRUE, FALSE);
+ run_remap_test_mono_channels_s16(&remap, func, orig_func, channels, 1, TRUE, FALSE);
+ run_remap_test_mono_channels_s16(&remap, func, orig_func, channels, 2, TRUE, FALSE);
+ run_remap_test_mono_channels_s16(&remap, func, orig_func, channels, 3, TRUE, TRUE);
+ } else pa_assert_not_reached();
+}
+
+static void run_remap_test_channels_mono_float(
+ pa_remap_t *remap,
+ pa_do_remap_func_t func, pa_do_remap_func_t orig_func,
+ int channels, int align, pa_bool_t correct, pa_bool_t perf) {
+
+ PA_DECLARE_ALIGNED(8, float, in[SAMPLES*8]) = { 0 };
+ PA_DECLARE_ALIGNED(8, float, out[SAMPLES]) = { 0 };
+ PA_DECLARE_ALIGNED(8, float, out_ref[SAMPLES]) = { 0 };
+ float *ch;
+ float *mono, *mono_ref;
+ int i, nsamples;
+
+ assert(channels == 2 || channels == 4 || channels == 8);
+
+ /* Force sample alignment as requested */
+ ch = in + (8 - align);
+ mono_ref = out_ref + (8 - align);
+ mono = out + (8 - align);
+ nsamples = SAMPLES - (8 - align);
+
+ for (i = 0; i < nsamples * channels; i++)
+ ch[i] = 2.1f * (rand()/(float) RAND_MAX - 0.5f);
+
+ if (correct) {
+ orig_func(remap, mono_ref, ch, nsamples);
+ func(remap, mono, ch, nsamples);
+
+ for (i = 0; i < nsamples; i++) {
+ if (fabsf(mono[i] - mono_ref[i]) > 0.0001) {
+ pa_log_debug("Correctness test failed: align=%d", align);
+ pa_log_debug("%d: %.24f != %.24f\n", i, mono[i], mono_ref[i]);
+ fail();
+ }
+ }
+ }
+
+ if (perf) {
+ pa_log_debug("Testing float %d-channel-to-mono remap performance with %d sample alignment", channels, align);
+
+ PA_CPU_TEST_RUN_START("func", TIMES, TIMES2) {
+ func(remap, mono, ch, nsamples);
+ } PA_CPU_TEST_RUN_STOP
+
+ PA_CPU_TEST_RUN_START("orig", TIMES, TIMES2) {
+ orig_func(remap, mono_ref, ch, nsamples);
+ } PA_CPU_TEST_RUN_STOP
+ }
+}
+
+static void run_remap_test_channels_mono_s16(
+ pa_remap_t *remap,
+ pa_do_remap_func_t func, pa_do_remap_func_t orig_func,
+ int channels, int align, pa_bool_t correct, pa_bool_t perf) {
+
+ PA_DECLARE_ALIGNED(8, int16_t, in[SAMPLES*8]) = { 0 };
+ PA_DECLARE_ALIGNED(8, int16_t, out[SAMPLES]) = { 0 };
+ PA_DECLARE_ALIGNED(8, int16_t, out_ref[SAMPLES]) = { 0 };
+ int16_t *ch;
+ int16_t *mono, *mono_ref;
+ int i, nsamples;
+
+ assert(channels == 2 || channels == 4 || channels == 8);
+
+ /* Force sample alignment as requested */
+ ch = in + (8 - align);
+ mono_ref = out_ref + (8 - align);
+ mono = out + (8 - align);
+ nsamples = SAMPLES - (8 - align);
+
+ pa_random(ch, nsamples * channels * sizeof(int16_t));
+
+ if (correct) {
+ orig_func(remap, mono_ref, ch, nsamples);
+ func(remap, mono, ch, nsamples);
+
+ for (i = 0; i < nsamples; i++) {
+ if (abs(mono[i] - mono_ref[i]) > 3) {
+ pa_log_debug("Correctness test failed: align=%d", align);
+ pa_log_debug("%d: %hd != %hd", i, mono[i], mono_ref[i]);
+ fail();
+ }
+ }
+ }
+
+ if (perf) {
+ pa_log_debug("Testing s16 %d-channel-to-mono remap performance with %d sample alignment", channels, align);
+
+ PA_CPU_TEST_RUN_START("func", TIMES, TIMES2) {
+ func(remap, mono, ch, nsamples);
+ } PA_CPU_TEST_RUN_STOP
+
+ PA_CPU_TEST_RUN_START("orig", TIMES, TIMES2) {
+ orig_func(remap, mono_ref, ch, nsamples);
+ } PA_CPU_TEST_RUN_STOP
+ }
+}
+
+static void remap_test_channels_mono(pa_sample_format_t format, int channels) {
+ pa_sample_format_t sf;
+ pa_remap_t remap;
+ pa_sample_spec iss, oss;
+ pa_do_remap_func_t orig_func, func;
+ int i;
+
+ iss.format = oss.format = sf = format;
+ iss.channels = channels;
+ oss.channels = 1;
+ remap.format = &sf;
+ remap.i_ss = &iss;
+ remap.o_ss = &oss;
+ for (i = 0; i < channels; i++) {
+ remap.map_table_f[0][i] = 1.0f / channels;
+ remap.map_table_i[0][i] = PA_VOLUME_NORM / channels;
+ }
+
+ orig_func = remap_channels_matrix_c;
+ if (channels == 2) func = remap_stereo_to_mono_c;
+ else if (channels == 4) func = remap_ch4_to_mono_c;
+ else pa_assert_not_reached();
+
+ if (format == PA_SAMPLE_FLOAT32NE) {
+ run_remap_test_channels_mono_float(&remap, func, orig_func, channels, 0, TRUE, FALSE);
+ run_remap_test_channels_mono_float(&remap, func, orig_func, channels, 1, TRUE, FALSE);
+ run_remap_test_channels_mono_float(&remap, func, orig_func, channels, 2, TRUE, FALSE);
+ run_remap_test_channels_mono_float(&remap, func, orig_func, channels, 3, TRUE, TRUE);
+ } else if (format == PA_SAMPLE_S16NE) {
+ run_remap_test_channels_mono_s16(&remap, func, orig_func, channels, 0, TRUE, FALSE);
+ run_remap_test_channels_mono_s16(&remap, func, orig_func, channels, 1, TRUE, FALSE);
+ run_remap_test_channels_mono_s16(&remap, func, orig_func, channels, 2, TRUE, FALSE);
+ run_remap_test_channels_mono_s16(&remap, func, orig_func, channels, 3, TRUE, TRUE);
+ } else pa_assert_not_reached();
+}
+
+START_TEST (remap_special_s16_test) {
+ remap_test_channels_mono(PA_SAMPLE_S16NE, 2);
+ remap_test_channels_mono(PA_SAMPLE_S16NE, 4);
+
+ remap_test_mono_channels(PA_SAMPLE_S16NE, 2);
+ remap_test_mono_channels(PA_SAMPLE_S16NE, 4);
+}
+END_TEST
+
+START_TEST (remap_special_float_test) {
+ remap_test_channels_mono(PA_SAMPLE_FLOAT32NE, 2);
+ remap_test_channels_mono(PA_SAMPLE_FLOAT32NE, 4);
+
+ remap_test_mono_channels(PA_SAMPLE_FLOAT32NE, 2);
+ remap_test_mono_channels(PA_SAMPLE_FLOAT32NE, 4);
+}
+END_TEST
+
+int main(int argc, char *argv[]) {
+ int failed = 0;
+ Suite *s;
+ TCase *tc;
+ SRunner *sr;
+
+ if (!getenv("MAKE_CHECK"))
+ pa_log_set_level(PA_LOG_DEBUG);
+
+ s = suite_create("Remap-special");
+ tc = tcase_create("Remap-special s16");
+ tcase_add_test(tc, remap_special_s16_test);
+ tcase_set_timeout(tc, 120);
+ suite_add_tcase(s, tc);
+ tc = tcase_create("Remap-special float");
+ tcase_add_test(tc, remap_special_float_test);
+ tcase_set_timeout(tc, 120);
+ suite_add_tcase(s, tc);
+
+ sr = srunner_create(s);
+ srunner_run_all(sr, CK_NORMAL);
+ failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
--
1.7.9.5
More information about the pulseaudio-discuss
mailing list