我在Android处理音频缓冲区,我的设置如下:
我希望减少第2步和第4步的延迟,以及浮动和浮动到短转换的延迟。 (撇开3-DSP中的延迟,因为我稍后会处理)。
所以,我想使用NEON SIMD一次计算多个值。
我目前对2和4的内容是以下代码:
#define CONV16BIT 32768
#define CONVMYFLT (1./32768.)
static int i;
float * floatBuffer;
short * shortInBuffer;
short * shortOutBuffer;
...(malloc and init buffers method)
...(inside callback)
//2- short to float
for(i = 0; i < bufferSize; i++) {
floatBuffer[i] = (float) (shortInBuffer[i] * CONVMYFLT);
}
...(do dsp)
//4- float to short
for(i = 0; i < bufferSize; i++) {
shortOutBuffer[i] = (short) (floatBuffer[i] * CONV16BIT);
}
我认为利用NEON所需的步骤是:
(对于浮动部分的短路)
在此post(已选择的答案)中找到此信息
__m128 factor = _mm_set1_ps(1.0f / value);
for (int i = 0; i < W*H; i += 8)
{
// Load 8 16-bit ushorts.
// vi = {a,b,c,d,e,f,g,h}
__m128i vi = _mm_load_si128((const __m128i*)(source + i));
// Convert to 32-bit integers
// vi0 = {a,0,b,0,c,0,d,0}
// vi1 = {e,0,f,0,g,0,h,0}
__m128i vi0 = _mm_cvtepu16_epi32(vi);
__m128i vi1 = _mm_cvtepu16_epi32(_mm_unpackhi_epi64(vi,vi));
// Convert to float
__m128 vf0 = _mm_cvtepi32_ps(vi0);
__m128 vf1 = _mm_cvtepi32_ps(vi1);
// Multiply
vf0 = _mm_mul_ps(vf0,factor);
vf1 = _mm_mul_ps(vf1,factor);
// Store
_mm_store_ps(destination + i + 0,vf0);
_mm_store_ps(destination + i + 4,vf1);
}
然而,对于英特尔SSE4.1而言,这不是NEON的SIMD。
Android中NEON的等效实现是什么?(很难理解NEON内在函数)
更新1 从fsheikh的答案,我能够建立这个: - 我能够从系统回调中获取int16_t - 我的所有缓冲区大小都是8的倍数:
int16x8_t i16v;
int32x4_t i32vl, i32vh;
float32x4_t f32vl, f32vh;
for(i = 0; i < bufferSize; i += 8) {
//load 8 16-bit lanes on vector
i16v = vld1q_s16((const int16x8_t*) int16_t_inBuffer[i]);
// convert into 32-bit signed integer
i32vl = vmovl_s16 (i16v);
i32vh = vmovl_s16 (vzipq_s16(i16v, i16v).val[0]);
//convert to 32-bit float
f32vl = vcvtq_f32_s32(i32vl);
f32vh = vcvtq_f32_s32(i32vh);
//multiply by scalar
f32vl = vmulq_n_f32(f32vl, CONVMYFLT);
f32vh = vmulq_n_f32(f32vh, CONVMYFLT);
//store in float buffer
vst1q_f32(floatBuffer[i], f32vl);
vst1q_f32(floatBuffer[i + 4], f32vh);
}
这应该正常吗? 我怀疑我应该使用vmovl_s16返回的交错向量的低或高部分:
i32vh = vmovl_s16(vzipq_s1 6(i16v,i16v).val [0]);或
i32vh = vmovl_s16(vzipq_s16(i16v,i16v).val [1]);
答案 0 :(得分:3)
获得SSE版本后,可以使用GCC ARM NEON内在列表将SSE宏移植到NEON。 https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/ARM-NEON-Intrinsics.html
例如:
// Load unsigned short
uint16x4_t vld1_u16 (const uint16_t *)
// Convert to unsigned int
uint32x4_t vmovl_u16 (uint16x4_t)
// Convert to float
float32x4_t vcvtq_f32_s32 (int32x4_t)
// Multiply floats with a scalar
float32x4_t vmulq_n_f32 (float32x4_t, float32_t)
// Store results into a float buffer
void vst1q_f32 (float32_t *, float32x4_t)