OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/audio_processing/aecm/aecm_core.h" | |
12 | |
13 #include <arm_neon.h> | |
14 #include <assert.h> | |
15 | |
16 #include "webrtc/common_audio/signal_processing/include/real_fft.h" | |
17 | |
18 // TODO(kma): Re-write the corresponding assembly file, the offset | |
19 // generating script and makefile, to replace these C functions. | |
20 | |
21 // Square root of Hanning window in Q14. | |
22 const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = { | |
23 0, | |
24 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, | |
25 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, | |
26 6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040, | |
27 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, | |
28 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, | |
29 13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079, | |
30 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, | |
31 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384 | |
32 }; | |
33 | |
34 static inline void AddLanes(uint32_t* ptr, uint32x4_t v) { | |
35 #if defined(WEBRTC_ARCH_ARM64) | |
36 *(ptr) = vaddvq_u32(v); | |
37 #else | |
38 uint32x2_t tmp_v; | |
39 tmp_v = vadd_u32(vget_low_u32(v), vget_high_u32(v)); | |
40 tmp_v = vpadd_u32(tmp_v, tmp_v); | |
41 *(ptr) = vget_lane_u32(tmp_v, 0); | |
42 #endif | |
43 } | |
44 | |
45 void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm, | |
46 const uint16_t* far_spectrum, | |
47 int32_t* echo_est, | |
48 uint32_t* far_energy, | |
49 uint32_t* echo_energy_adapt, | |
50 uint32_t* echo_energy_stored) { | |
51 int16_t* start_stored_p = aecm->channelStored; | |
52 int16_t* start_adapt_p = aecm->channelAdapt16; | |
53 int32_t* echo_est_p = echo_est; | |
54 const int16_t* end_stored_p = aecm->channelStored + PART_LEN; | |
55 const uint16_t* far_spectrum_p = far_spectrum; | |
56 int16x8_t store_v, adapt_v; | |
57 uint16x8_t spectrum_v; | |
58 uint32x4_t echo_est_v_low, echo_est_v_high; | |
59 uint32x4_t far_energy_v, echo_stored_v, echo_adapt_v; | |
60 | |
61 far_energy_v = vdupq_n_u32(0); | |
62 echo_adapt_v = vdupq_n_u32(0); | |
63 echo_stored_v = vdupq_n_u32(0); | |
64 | |
65 // Get energy for the delayed far end signal and estimated | |
66 // echo using both stored and adapted channels. | |
67 // The C code: | |
68 // for (i = 0; i < PART_LEN1; i++) { | |
69 // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], | |
70 // far_spectrum[i]); | |
71 // (*far_energy) += (uint32_t)(far_spectrum[i]); | |
72 // *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i]; | |
73 // (*echo_energy_stored) += (uint32_t)echo_est[i]; | |
74 // } | |
75 while (start_stored_p < end_stored_p) { | |
76 spectrum_v = vld1q_u16(far_spectrum_p); | |
77 adapt_v = vld1q_s16(start_adapt_p); | |
78 store_v = vld1q_s16(start_stored_p); | |
79 | |
80 far_energy_v = vaddw_u16(far_energy_v, vget_low_u16(spectrum_v)); | |
81 far_energy_v = vaddw_u16(far_energy_v, vget_high_u16(spectrum_v)); | |
82 | |
83 echo_est_v_low = vmull_u16(vreinterpret_u16_s16(vget_low_s16(store_v)), | |
84 vget_low_u16(spectrum_v)); | |
85 echo_est_v_high = vmull_u16(vreinterpret_u16_s16(vget_high_s16(store_v)), | |
86 vget_high_u16(spectrum_v)); | |
87 vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low)); | |
88 vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high)); | |
89 | |
90 echo_stored_v = vaddq_u32(echo_est_v_low, echo_stored_v); | |
91 echo_stored_v = vaddq_u32(echo_est_v_high, echo_stored_v); | |
92 | |
93 echo_adapt_v = vmlal_u16(echo_adapt_v, | |
94 vreinterpret_u16_s16(vget_low_s16(adapt_v)), | |
95 vget_low_u16(spectrum_v)); | |
96 echo_adapt_v = vmlal_u16(echo_adapt_v, | |
97 vreinterpret_u16_s16(vget_high_s16(adapt_v)), | |
98 vget_high_u16(spectrum_v)); | |
99 | |
100 start_stored_p += 8; | |
101 start_adapt_p += 8; | |
102 far_spectrum_p += 8; | |
103 echo_est_p += 8; | |
104 } | |
105 | |
106 AddLanes(far_energy, far_energy_v); | |
107 AddLanes(echo_energy_stored, echo_stored_v); | |
108 AddLanes(echo_energy_adapt, echo_adapt_v); | |
109 | |
110 echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN], | |
111 far_spectrum[PART_LEN]); | |
112 *echo_energy_stored += (uint32_t)echo_est[PART_LEN]; | |
113 *far_energy += (uint32_t)far_spectrum[PART_LEN]; | |
114 *echo_energy_adapt += aecm->channelAdapt16[PART_LEN] * far_spectrum[PART_LEN]; | |
115 } | |
116 | |
117 void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm, | |
118 const uint16_t* far_spectrum, | |
119 int32_t* echo_est) { | |
120 assert((uintptr_t)echo_est % 32 == 0); | |
121 assert((uintptr_t)(aecm->channelStored) % 16 == 0); | |
122 assert((uintptr_t)(aecm->channelAdapt16) % 16 == 0); | |
123 | |
124 // This is C code of following optimized code. | |
125 // During startup we store the channel every block. | |
126 // memcpy(aecm->channelStored, | |
127 // aecm->channelAdapt16, | |
128 // sizeof(int16_t) * PART_LEN1); | |
129 // Recalculate echo estimate | |
130 // for (i = 0; i < PART_LEN; i += 4) { | |
131 // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], | |
132 // far_spectrum[i]); | |
133 // echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], | |
134 // far_spectrum[i + 1]); | |
135 // echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], | |
136 // far_spectrum[i + 2]); | |
137 // echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], | |
138 // far_spectrum[i + 3]); | |
139 // } | |
140 // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], | |
141 // far_spectrum[i]); | |
142 const uint16_t* far_spectrum_p = far_spectrum; | |
143 int16_t* start_adapt_p = aecm->channelAdapt16; | |
144 int16_t* start_stored_p = aecm->channelStored; | |
145 const int16_t* end_stored_p = aecm->channelStored + PART_LEN; | |
146 int32_t* echo_est_p = echo_est; | |
147 | |
148 uint16x8_t far_spectrum_v; | |
149 int16x8_t adapt_v; | |
150 uint32x4_t echo_est_v_low, echo_est_v_high; | |
151 | |
152 while (start_stored_p < end_stored_p) { | |
153 far_spectrum_v = vld1q_u16(far_spectrum_p); | |
154 adapt_v = vld1q_s16(start_adapt_p); | |
155 | |
156 vst1q_s16(start_stored_p, adapt_v); | |
157 | |
158 echo_est_v_low = vmull_u16(vget_low_u16(far_spectrum_v), | |
159 vget_low_u16(vreinterpretq_u16_s16(adapt_v))); | |
160 echo_est_v_high = vmull_u16(vget_high_u16(far_spectrum_v), | |
161 vget_high_u16(vreinterpretq_u16_s16(adapt_v))); | |
162 | |
163 vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low)); | |
164 vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high)); | |
165 | |
166 far_spectrum_p += 8; | |
167 start_adapt_p += 8; | |
168 start_stored_p += 8; | |
169 echo_est_p += 8; | |
170 } | |
171 aecm->channelStored[PART_LEN] = aecm->channelAdapt16[PART_LEN]; | |
172 echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN], | |
173 far_spectrum[PART_LEN]); | |
174 } | |
175 | |
176 void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm) { | |
177 assert((uintptr_t)(aecm->channelStored) % 16 == 0); | |
178 assert((uintptr_t)(aecm->channelAdapt16) % 16 == 0); | |
179 assert((uintptr_t)(aecm->channelAdapt32) % 32 == 0); | |
180 | |
181 // The C code of following optimized code. | |
182 // for (i = 0; i < PART_LEN1; i++) { | |
183 // aecm->channelAdapt16[i] = aecm->channelStored[i]; | |
184 // aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32( | |
185 // (int32_t)aecm->channelStored[i], 16); | |
186 // } | |
187 | |
188 int16_t* start_stored_p = aecm->channelStored; | |
189 int16_t* start_adapt16_p = aecm->channelAdapt16; | |
190 int32_t* start_adapt32_p = aecm->channelAdapt32; | |
191 const int16_t* end_stored_p = start_stored_p + PART_LEN; | |
192 | |
193 int16x8_t stored_v; | |
194 int32x4_t adapt32_v_low, adapt32_v_high; | |
195 | |
196 while (start_stored_p < end_stored_p) { | |
197 stored_v = vld1q_s16(start_stored_p); | |
198 vst1q_s16(start_adapt16_p, stored_v); | |
199 | |
200 adapt32_v_low = vshll_n_s16(vget_low_s16(stored_v), 16); | |
201 adapt32_v_high = vshll_n_s16(vget_high_s16(stored_v), 16); | |
202 | |
203 vst1q_s32(start_adapt32_p, adapt32_v_low); | |
204 vst1q_s32(start_adapt32_p + 4, adapt32_v_high); | |
205 | |
206 start_stored_p += 8; | |
207 start_adapt16_p += 8; | |
208 start_adapt32_p += 8; | |
209 } | |
210 aecm->channelAdapt16[PART_LEN] = aecm->channelStored[PART_LEN]; | |
211 aecm->channelAdapt32[PART_LEN] = (int32_t)aecm->channelStored[PART_LEN] << 16; | |
212 } | |
OLD | NEW |