Вставить массив[4] в массив[8] (C ++, SSE) [closed]

У меня есть этот код, чтобы получить уровни вывода звука в дБ в массив (peak_dB[8]) для использования в пикометре в реальном времени:

#include <emmintrin.h>

float channelsPeak[8] = { 0 };
float peak_dB[8] = { 0 };

__m128 log2_sse(__m128 x) {
  // https://www.kvraudio.com/forum/viewtopic.php?p=7524831#p7524831
  // 12-13ulp
  const __m128 c0 = _mm_set1_ps(1.011593342e+01f);
  const __m128 c1 = _mm_set1_ps(1.929443550e+01f);
  const __m128 d0 = _mm_set1_ps(2.095932245e+00f);
  const __m128 d1 = _mm_set1_ps(1.266638851e+01f);
  const __m128 d2 = _mm_set1_ps(6.316540241e+00f);
  const __m128 one = _mm_set1_ps(1.0f);
  const __m128 multi = _mm_set1_ps(1.41421356237f);
  const __m128i mantissa_mask = _mm_set1_epi32((1 << 23) - 1);
  __m128i x_i = _mm_castps_si128(x);
  __m128i spl_exp = _mm_castps_si128(_mm_mul_ps(x, multi));
  spl_exp = _mm_sub_epi32(spl_exp, _mm_castps_si128(one));
  spl_exp = _mm_andnot_si128(mantissa_mask, spl_exp);
  __m128 spl_mantissa = _mm_castsi128_ps(_mm_sub_epi32(x_i, spl_exp));
  spl_exp = _mm_srai_epi32(spl_exp, 23);
  __m128 log2_exponent = _mm_cvtepi32_ps(spl_exp);
  __m128 num = spl_mantissa;
  num = _mm_add_ps(num, c1);
  num = _mm_mul_ps(num, spl_mantissa);
  num = _mm_add_ps(num, c0);
  num = _mm_mul_ps(num, _mm_sub_ps(spl_mantissa, one));
  __m128 denom = d2;
  denom = _mm_mul_ps(denom, spl_mantissa);
  denom = _mm_add_ps(denom, d1);
  denom = _mm_mul_ps(denom, spl_mantissa);
  denom = _mm_add_ps(denom, d0);
  __m128 res = _mm_div_ps(num, denom);
  res = _mm_add_ps(log2_exponent, res);
  return res;
}
__m128 lin2db(__m128 x) {
  const __m128 convert_10 = _mm_set1_ps(6.02059991328f);
  return _mm_mul_ps(log2_sse(x), convert_10);
}

float getPeaks_dB(int cCount) { // cCount = enabled channels (1...8)
    __m128 s1 = _mm_setzero_ps();
    
    s1 = _mm_set_ps(channelsPeak[3], channelsPeak[2], channelsPeak[1], channelsPeak[0]); //channels 1-4
    s1 = lin2db(s1);
    _mm_store_ps(peak_dB, s1);

    if(cCount > 4){
        float t2[4] = { 0 };
        __m128 s2 = _mm_setzero_ps();
        s2 = _mm_set_ps(channelsPeak[7], channelsPeak[6], channelsPeak[5], channelsPeak[4]); // channels 5-8
        s2 = lin2db(s2);
    
        _mm_store_ps(t2, s2);
        for (int i = 4; i < 8; i++){peak_dB[i] = t2[i-4];}
    }
    return 0;
}

где плавающие каналы пик[0..7] массив — хранилище для линейных уровней (0.0f..1.0f) восьми каналов, считываемых с устройства рендеринга звука (один вызов GetChannelsPeakValues ​​()), пик_дБ представляет собой массив из восьми элементов для хранения этого значения в формате дБ (для использования в некоторых последующих вычислениях и текстовом представлении) и lin2db — это приближение 20log10 (x) (быстрее (из-за меньшей точности), чем std :: log10), реализованное с использованием встроенных функций SSE.

В: Есть ли другие (лучшие) способы вставить данные из s2 в последние четыре элемента peak_dB (исключая AVX)? Я использую VS2013 и Обозреватель компилятора, компилятор, похоже, улучшает for-loop, используемый в коде сейчас, но, поскольку первая часть в пиковом_dB, хранимом с _mm_store_ps (peak_dB, s1), выглядит намного проще, просто интересно, есть ли способ сделать это без for-loop.

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *