]> code.delx.au - pulseaudio/blob - src/pulsecore/svolume_arm.c
remap: Change remapping function argument type from void to int16_t / float as approp...
[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 <pulsecore/random.h>
28 #include <pulsecore/macro.h>
29 #include <pulsecore/endianmacros.h>
30
31 #include "cpu-arm.h"
32
33 #include "sample-util.h"
34
35 #if defined (__arm__) && defined (HAVE_ARMV6)
36
37 #define MOD_INC() \
38 " subs r0, r6, %2 \n\t" \
39 " itt cs \n\t" \
40 " addcs r0, %1 \n\t" \
41 " movcs r6, r0 \n\t"
42
43 static pa_do_volume_func_t _volume_ref;
44
45 static void pa_volume_s16ne_arm(int16_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
46 /* Channels must be at least 4, and always a multiple of the original number.
47 * This is also the max amount we overread the volume array, which should
48 * have enough padding. */
49 const int32_t *ve = volumes + (channels == 3 ? 6 : PA_MAX (4U, channels));
50 unsigned rem = PA_ALIGN((size_t) samples) - (size_t) samples;
51
52 /* Make sure we're word-aligned, else performance _really_ sucks */
53 if (rem) {
54 _volume_ref(samples, volumes, channels, rem < length ? rem : length);
55
56 if (rem < length) {
57 length -= rem;
58 samples += rem / sizeof(*samples);
59 } else
60 return; /* we're done */
61 }
62
63 __asm__ __volatile__ (
64 " mov r6, %4 \n\t" /* r6 = volumes + rem */
65 " mov %3, %3, LSR #1 \n\t" /* length /= sizeof (int16_t) */
66
67 " cmp %3, #4 \n\t" /* check for 4+ samples */
68 " blt 2f \n\t"
69
70 /* See final case for how the multiplication works */
71
72 "1: \n\t"
73 " ldrd r2, [r6], #8 \n\t" /* 4 samples at a time */
74 " ldrd r4, [r6], #8 \n\t"
75 " ldrd r0, [%0] \n\t"
76
77 #ifdef WORDS_BIGENDIAN
78 " smulwt r2, r2, r0 \n\t"
79 " smulwb r3, r3, r0 \n\t"
80 " smulwt r4, r4, r1 \n\t"
81 " smulwb r5, r5, r1 \n\t"
82 #else
83 " smulwb r2, r2, r0 \n\t"
84 " smulwt r3, r3, r0 \n\t"
85 " smulwb r4, r4, r1 \n\t"
86 " smulwt r5, r5, r1 \n\t"
87 #endif
88
89 " ssat r2, #16, r2 \n\t"
90 " ssat r3, #16, r3 \n\t"
91 " ssat r4, #16, r4 \n\t"
92 " ssat r5, #16, r5 \n\t"
93
94 #ifdef WORDS_BIGENDIAN
95 " pkhbt r0, r3, r2, LSL #16 \n\t"
96 " pkhbt r1, r5, r4, LSL #16 \n\t"
97 #else
98 " pkhbt r0, r2, r3, LSL #16 \n\t"
99 " pkhbt r1, r4, r5, LSL #16 \n\t"
100 #endif
101 " strd r0, [%0], #8 \n\t"
102
103 MOD_INC()
104
105 " subs %3, %3, #4 \n\t"
106 " cmp %3, #4 \n\t"
107 " bge 1b \n\t"
108
109 "2: \n\t"
110 " cmp %3, #2 \n\t"
111 " blt 3f \n\t"
112
113 " ldrd r2, [r6], #8 \n\t" /* 2 samples at a time */
114 " ldr r0, [%0] \n\t"
115
116 #ifdef WORDS_BIGENDIAN
117 " smulwt r2, r2, r0 \n\t"
118 " smulwb r3, r3, r0 \n\t"
119 #else
120 " smulwb r2, r2, r0 \n\t"
121 " smulwt r3, r3, r0 \n\t"
122 #endif
123
124 " ssat r2, #16, r2 \n\t"
125 " ssat r3, #16, r3 \n\t"
126
127 #ifdef WORDS_BIGENDIAN
128 " pkhbt r0, r3, r2, LSL #16 \n\t"
129 #else
130 " pkhbt r0, r2, r3, LSL #16 \n\t"
131 #endif
132 " str r0, [%0], #4 \n\t"
133
134 MOD_INC()
135
136 " subs %3, %3, #2 \n\t"
137
138 "3: \n\t" /* check for odd # of samples */
139 " cmp %3, #1 \n\t"
140 " bne 4f \n\t"
141
142 " ldr r0, [r6], #4 \n\t" /* r0 = volume */
143 " ldrh r2, [%0] \n\t" /* r2 = sample */
144
145 " smulwb r0, r0, r2 \n\t" /* r0 = (r0 * r2) >> 16 */
146 " ssat r0, #16, r0 \n\t" /* r0 = PA_CLAMP(r0, 0x7FFF) */
147
148 " strh r0, [%0], #2 \n\t" /* sample = r0 */
149
150 "4: \n\t"
151
152 : "+r" (samples), "+r" (volumes), "+r" (ve), "+r" (length)
153 : "r" (volumes + ((rem / sizeof(*samples)) % channels))
154 : "r6", "r5", "r4", "r3", "r2", "r1", "r0", "cc"
155 );
156 }
157
158 #endif /* defined (__arm__) && defined (HAVE_ARMV6) */
159
160 void pa_volume_func_init_arm(pa_cpu_arm_flag_t flags) {
161 #if defined (__arm__) && defined (HAVE_ARMV6)
162 pa_log_info("Initialising ARM optimized volume functions.");
163
164 if (!_volume_ref)
165 _volume_ref = pa_get_volume_func(PA_SAMPLE_S16NE);
166
167 pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm);
168 #endif /* defined (__arm__) && defined (HAVE_ARMV6) */
169 }