//////////////////////////////////////////////////////////////////////////////// /// /// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE /// optimized functions have been gathered into this single source /// code file, regardless to their class or original source code file, in order /// to ease porting the library to other compiler and processor platforms. /// /// The SSE-optimizations are programmed using SSE compiler intrinsics that /// are supported both by Microsoft Visual C++ and GCC compilers, so this file /// should compile with both toolsets. /// /// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ /// 6.0 processor pack" update to support SSE instruction set. The update is /// available for download at Microsoft Developers Network, see here: /// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx /// /// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and /// perform a search with keywords "processor pack". /// /// Author : Copyright (c) Olli Parviainen /// Author e-mail : oparviai 'at' iki.fi /// SoundTouch WWW: http://www.surina.net/soundtouch /// //////////////////////////////////////////////////////////////////////////////// // // License : // // SoundTouch audio processing library // Copyright (c) Olli Parviainen // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ////////////////////////////////////////////////////////////////////////////////
#include"cpu_detect.h" #include"STTypes.h"
usingnamespace soundtouch;
#ifdef SOUNDTOUCH_ALLOW_SSE
// SSE routines available only with float sample type
////////////////////////////////////////////////////////////////////////////// // // implementation of SSE optimized functions of class 'TDStretchSSE' // //////////////////////////////////////////////////////////////////////////////
// Calculates cross correlation of two buffers double TDStretchSSE::calcCrossCorr(constfloat *pV1, constfloat *pV2, double &anorm)
{ int i; constfloat *pVec1; const __m128 *pVec2;
__m128 vSum, vNorm;
// Note. It means a major slow-down if the routine needs to tolerate // unaligned __m128 memory accesses. It's way faster if we can skip // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. // This can mean up to ~ 10-fold difference (incl. part of which is // due to skipping every second round for stereo sound though). // // Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided // for choosing if this little cheating is allowed.
#ifdef ST_SIMD_AVOID_UNALIGNED // Little cheating allowed, return valid correlation only for // aligned locations, meaning every second round for stereo sound.
#define _MM_LOAD _mm_load_ps
if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations
#else // No cheating allowed, use unaligned load & take the resulting // performance hit. #define _MM_LOAD _mm_loadu_ps #endif
// ensure overlapLength is divisible by 8
assert((overlapLength % 8) == 0);
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
pVec1 = (constfloat*)pV1;
pVec2 = (const __m128*)pV2;
vSum = vNorm = _mm_setzero_ps();
// Unroll the loop by factor of 4 * 4 operations. Use same routine for // stereo & mono, for mono it just means twice the amount of unrolling. for (i = 0; i < channels * overlapLength / 16; i ++)
{
__m128 vTemp; // vSum += pV1[0..3] * pV2[0..3]
vTemp = _MM_LOAD(pVec1);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
double TDStretchSSE::calcCrossCorrAccumulate(constfloat *pV1, constfloat *pV2, double &norm)
{ // call usual calcCrossCorr function because SSE does not show big benefit of // accumulating "norm" value, and also the "norm" rolling algorithm would get // complicated due to SSE-specific alignment-vs-nonexact correlation rules. return calcCrossCorr(pV1, pV2, norm);
}
////////////////////////////////////////////////////////////////////////////// // // implementation of SSE optimized functions of class 'FIRFilter' // //////////////////////////////////////////////////////////////////////////////
// Scale the filter coefficients so that it won't be necessary to scale the filtering result // also rearrange coefficients suitably for SSE // Ensure that filter coeffs array is aligned to 16-byte boundary delete[] filterCoeffsUnalign;
filterCoeffsUnalign = newfloat[2 * newLength + 4];
filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);
fDivider = (float)resultDivider;
// rearrange the filter coefficients for mmx routines for (i = 0; i < newLength; i ++)
{
filterCoeffsAlign[2 * i + 0] =
filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;
}
}
// SSE-optimized version of the filter routine for stereo sound
uint FIRFilterSSE::evaluateFilterStereo(float *dest, constfloat *source, uint numSamples) const
{ int count = (int)((numSamples - length) & (uint)-2); int j;
// filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' #pragma omp parallel for for (j = 0; j < count; j += 2)
{ constfloat *pSrc; float *pDest; const __m128 *pFil;
__m128 sum1, sum2;
uint i;
pSrc = (constfloat*)source + j * 2; // source audio data
pDest = dest + j * 2; // destination audio data
pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients // are aligned to 16-byte boundary
sum1 = sum2 = _mm_setzero_ps();
for (i = 0; i < length / 8; i ++)
{ // Unroll loop for efficiency & calculate filter for 2*2 stereo samples // at each pass
// sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.
// Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need // to sum the two hi- and lo-floats of these registers together.
// post-shuffle & add the filtered values and store to dest.
_mm_storeu_ps(pDest, _mm_add_ps(
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
));
}
// Ideas for further improvement: // 1. If it could be guaranteed that 'source' were always aligned to 16-byte // boundary, a faster aligned '_mm_load_ps' instruction could be used. // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte // boundary, a faster '_mm_store_ps' instruction could be used.
return (uint)count;
/* original routine in C-language. please notice the C-version has differently organized coefficients though. double suml1, suml2; double sumr1, sumr2; uint i, j;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.