【发布时间】:2016-08-28 22:00:07
【问题描述】:
我正在实现一个混音器,它在没有 SIMD 指令的情况下运行良好,但很难弄清楚如何将我的声音数据提取到单独的通道中。
我的数据采用交错格式:L0R0 L1R1 L2R2 L3R3... 我以相同的格式将它们加载到 __m128i 中,因此我在寄存器中有 4 个样本。
我希望它们位于不同的通道中:L0L1L2L3 R0R1R2R3。这是我缺少的部分。
所以输入是:8 x i16(4xi32 交错) 我希望输出为 left = 4 x f32 和 right = 4 x f32,然后进行混合。
混合后,我可以交错通道,我得到 L0R0 L1R1 L2R2...:
__m128 *src0 = mixed_channel0;
__m128 *src1 = mixed_channel1;
__m128 *dest = (__m128i *)buffer;
for (u32 sample_index = 0; sample_index < sample_chunk_count; ++sample_index)
{
__m128 s0 = _mm_load_ps((f32 *)src0++);
__m128 s1 = _mm_load_ps((f32 *)src1++);
__m128i l = _mm_cvtps_epi32(s0);
__m128i r = _mm_cvtps_epi32(s1);
__m128i lr0 = _mm_unpacklo_epi32(l, r);
__m128i lr1 = _mm_unpackhi_epi32(l, r);
*dest++ = _mm_packs_epi32(lr0, lr1);
}
基本上我需要做相反的事情:
__m128i input = [L0R0, L1R1, L2R2, L3R3] packed pairs of 16bit ints
// magic happens, then
__m128 left = [L0, L1, L2, L3] packed 32bit floats
__m128 right = [R0, R1, R2, R3] packed 32bit floats
即使我屏蔽了低/高阶 i16-s,那么如何将它们转换为 f32-s?屏蔽后我会得到:
__m128i right = [xx, R0, xx, R1, xx, R2, xx, R3]
__m128i left = [L0, xx, L1, xx, L2, xx, L3, xx]
如果我可以将它们转换为 4 x i32-s,那么使用 _mm_cvtepi32_ps 将它们转换为 f32-s 会很容易,我就完成了。
谢谢。
【问题讨论】:
-
我认为转换低/高
i16s 的最佳选择是位移。high_halves = _mm_srai_epi32(packed, 16);。由于您的值是有符号的,您可能需要通过左移然后使用算术右移来对低半部分进行符号扩展。我想不出更好的 ATM 方式,但这确实有点笨重。 -
一些 SIMD 指令集(如 ARM NEON / ARMv8)有更多的双输入或双输出指令,我认为可以用一条指令解包。 (也许解压缩,IIRC)。因此,重要的是要专门针对英特尔 SSE,而不仅仅是任何 SIMD。
-
@ChuckWalbourn:你想用 SSE3 复制偶数或奇数元素是什么? OP 所需的输出不需要将任何数据移到它们开始的 32 位元素之外。起初我在设想使用
shufps组合来自两个向量的数据,但后来我更仔细地阅读,并且中间代码块是显示输入和所需输出的代码块。 -
@PeterCordes 谢谢,
_mm_srai_epi32给了我左声道值;_mm_slli_epi3216 然后_mm_srai_epi3216 给了我正确的通道值,将它们转换为f32-s 是直截了当的。如果可以的话,我会接受您的评论作为答案,或者我会在我在家进行测试时发布代码。谢谢!
标签: audio x86 sse simd intrinsics