]> code.delx.au - pulseaudio/blob - src/pulsecore/svolume_arm.c
Fix up according to Coding Style
[pulseaudio] / src / pulsecore / svolume_arm.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2009 Wim Taymans <wim.taymans@collabora.co.uk>
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <pulse/timeval.h>
28 #include <pulsecore/random.h>
29 #include <pulsecore/macro.h>
30 #include <pulsecore/g711.h>
31 #include <pulsecore/core-util.h>
32
33 #include "cpu-arm.h"
34
35 #include "sample-util.h"
36 #include "endianmacros.h"
37
38 #if defined (__arm__) && defined (HAVE_ARMV6)
39
40 #define MOD_INC() \
41 " subs r0, r6, %2 \n\t" \
42 " itt cs \n\t" \
43 " addcs r0, %1 \n\t" \
44 " movcs r6, r0 \n\t"
45
46 static void pa_volume_s16ne_arm(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
47 int32_t *ve;
48
49 /* Channels must be at least 4, and always a multiple of the original number.
50 * This is also the max amount we overread the volume array, which should
51 * have enough padding. */
52 channels = channels == 3 ? 6 : PA_MAX (4U, channels);
53 ve = volumes + channels;
54
55 __asm__ __volatile__ (
56 " mov r6, %1 \n\t"
57 " mov %3, %3, LSR #1 \n\t" /* length /= sizeof (int16_t) */
58 " tst %3, #1 \n\t" /* check for odd samples */
59 " beq 2f \n\t"
60
61 "1: \n\t"
62 " ldr r0, [r6], #4 \n\t" /* odd samples volumes */
63 " ldrh r2, [%0] \n\t"
64
65 " smulwb r0, r0, r2 \n\t"
66 " ssat r0, #16, r0 \n\t"
67
68 " strh r0, [%0], #2 \n\t"
69
70 MOD_INC()
71
72 "2: \n\t"
73 " mov %3, %3, LSR #1 \n\t"
74 " tst %3, #1 \n\t" /* check for odd samples */
75 " beq 4f \n\t"
76
77 "3: \n\t"
78 " ldrd r2, [r6], #8 \n\t" /* 2 samples at a time */
79 " ldr r0, [%0] \n\t"
80
81 " smulwt r2, r2, r0 \n\t"
82 " smulwb r3, r3, r0 \n\t"
83
84 " ssat r2, #16, r2 \n\t"
85 " ssat r3, #16, r3 \n\t"
86
87 " pkhbt r0, r3, r2, LSL #16 \n\t"
88 " str r0, [%0], #4 \n\t"
89
90 MOD_INC()
91
92 "4: \n\t"
93 " movs %3, %3, LSR #1 \n\t"
94 " beq 6f \n\t"
95
96 "5: \n\t"
97 " ldrd r2, [r6], #8 \n\t" /* 4 samples at a time */
98 " ldrd r4, [r6], #8 \n\t"
99 " ldrd r0, [%0] \n\t"
100
101 " smulwt r2, r2, r0 \n\t"
102 " smulwb r3, r3, r0 \n\t"
103 " smulwt r4, r4, r1 \n\t"
104 " smulwb r5, r5, r1 \n\t"
105
106 " ssat r2, #16, r2 \n\t"
107 " ssat r3, #16, r3 \n\t"
108 " ssat r4, #16, r4 \n\t"
109 " ssat r5, #16, r5 \n\t"
110
111 " pkhbt r0, r3, r2, LSL #16 \n\t"
112 " pkhbt r1, r5, r4, LSL #16 \n\t"
113 " strd r0, [%0], #8 \n\t"
114
115 MOD_INC()
116
117 " subs %3, %3, #1 \n\t"
118 " bne 5b \n\t"
119 "6: \n\t"
120
121 : "+r" (samples), "+r" (volumes), "+r" (ve), "+r" (length)
122 :
123 : "r6", "r5", "r4", "r3", "r2", "r1", "r0", "cc"
124 );
125 }
126
127 #undef RUN_TEST
128
129 #ifdef RUN_TEST
130 #define CHANNELS 2
131 #define SAMPLES 1022
132 #define TIMES 1000
133 #define PADDING 16
134
135 static void run_test(void) {
136 int16_t samples[SAMPLES];
137 int16_t samples_ref[SAMPLES];
138 int16_t samples_orig[SAMPLES];
139 int32_t volumes[CHANNELS + PADDING];
140 int i, j, padding;
141 pa_do_volume_func_t func;
142 pa_usec_t start, stop;
143
144 func = pa_get_volume_func(PA_SAMPLE_S16NE);
145
146 printf("checking ARM %zd\n", sizeof(samples));
147
148 pa_random(samples, sizeof(samples));
149 memcpy(samples_ref, samples, sizeof(samples));
150 memcpy(samples_orig, samples, sizeof(samples));
151
152 for (i = 0; i < CHANNELS; i++)
153 volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
154 for (padding = 0; padding < PADDING; padding++, i++)
155 volumes[i] = volumes[padding];
156
157 func(samples_ref, volumes, CHANNELS, sizeof(samples));
158 pa_volume_s16ne_arm(samples, volumes, CHANNELS, sizeof(samples));
159 for (i = 0; i < SAMPLES; i++) {
160 if (samples[i] != samples_ref[i]) {
161 printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i],
162 samples_orig[i], volumes[i % CHANNELS]);
163 }
164 }
165
166 start = pa_rtclock_now();
167 for (j = 0; j < TIMES; j++) {
168 memcpy(samples, samples_orig, sizeof(samples));
169 pa_volume_s16ne_arm(samples, volumes, CHANNELS, sizeof(samples));
170 }
171 stop = pa_rtclock_now();
172 pa_log_info("ARM: %llu usec.", (long long unsigned int) (stop - start));
173
174 start = pa_rtclock_now();
175 for (j = 0; j < TIMES; j++) {
176 memcpy(samples_ref, samples_orig, sizeof(samples));
177 func(samples_ref, volumes, CHANNELS, sizeof(samples));
178 }
179 stop = pa_rtclock_now();
180 pa_log_info("ref: %llu usec.", (long long unsigned int) (stop - start));
181 }
182 #endif
183
184 #endif /* defined (__arm__) && defined (HAVE_ARMV6) */
185
186
187 void pa_volume_func_init_arm(pa_cpu_arm_flag_t flags) {
188 #if defined (__arm__) && defined (HAVE_ARMV6)
189 pa_log_info("Initialising ARM optimized functions.");
190
191 #ifdef RUN_TEST
192 run_test();
193 #endif
194
195 pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm);
196 #endif /* defined (__arm__) && defined (HAVE_ARMV6) */
197 }