From b66a74daf60b3541038be42e049f98b17b71b921 Mon Sep 17 00:00:00 2001 From: ownedbywuigi Date: Sat, 25 Apr 2026 09:40:24 +0100 Subject: [PATCH] Issue #451 part 1 - use OpenMP for SoundTouch --- media/libsoundtouch/src/FIRFilter.cpp | 23 +++++++++++++++------- media/libsoundtouch/src/TDStretch.cpp | 24 ++++++++++++++++------- media/libsoundtouch/src/mmx_optimized.cpp | 4 +++- media/libsoundtouch/src/moz.build | 5 +++++ media/libsoundtouch/src/sse_optimized.cpp | 10 +++++++--- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/media/libsoundtouch/src/FIRFilter.cpp b/media/libsoundtouch/src/FIRFilter.cpp index 201395bd51..604ec951c6 100644 --- a/media/libsoundtouch/src/FIRFilter.cpp +++ b/media/libsoundtouch/src/FIRFilter.cpp @@ -86,8 +86,11 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui assert((length != 0) && (length == ilength) && (src != NULL) && (dest != NULL) && (filterCoeffs != NULL)); end = 2 * (numSamples - ilength); + const SAMPLETYPE *coeffsStereo = filterCoeffsStereo; - #pragma omp parallel for +#if defined(_OPENMP) + #pragma omp parallel for default(none) shared(src, dest, end, ilength, coeffsStereo) private(j) schedule(static) +#endif for (j = 0; j < end; j += 2) { const SAMPLETYPE *ptr; @@ -98,8 +101,8 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui for (int i = 0; i < ilength; i ++) { - suml += ptr[2 * i] * filterCoeffsStereo[2 * i]; - sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1]; + suml += ptr[2 * i] * coeffsStereo[2 * i]; + sumr += ptr[2 * i + 1] * coeffsStereo[2 * i + 1]; } #ifdef SOUNDTOUCH_INTEGER_SAMPLES @@ -133,7 +136,10 @@ uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint assert(ilength != 0); end = numSamples - ilength; - #pragma omp parallel for + const SAMPLETYPE *coeffs = filterCoeffs; +#if defined(_OPENMP) + #pragma omp parallel for default(none) shared(src, dest, end, ilength, coeffs) private(j) schedule(static) +#endif for (j = 0; j < end; j ++) { const SAMPLETYPE *pSrc = src + j; @@ -143,7 +149,7 @@ uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint sum = 0; for (i = 0; i < ilength; i ++) { - sum += pSrc[i] * filterCoeffs[i]; + sum += pSrc[i] * coeffs[i]; } #ifdef SOUNDTOUCH_INTEGER_SAMPLES sum >>= resultDivFactor; @@ -176,8 +182,11 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin int ilength = length & -8; end = numChannels * (numSamples - ilength); + const SAMPLETYPE *coeffs = filterCoeffs; - #pragma omp parallel for +#if defined(_OPENMP) + #pragma omp parallel for default(none) shared(src, dest, end, ilength, numChannels, coeffs) private(j) schedule(static) +#endif for (j = 0; j < end; j += numChannels) { const SAMPLETYPE *ptr; @@ -194,7 +203,7 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin for (i = 0; i < ilength; i ++) { - SAMPLETYPE coef=filterCoeffs[i]; + SAMPLETYPE coef=coeffs[i]; for (c = 0; c < numChannels; c ++) { sums[c] += ptr[0] * coef; diff --git a/media/libsoundtouch/src/TDStretch.cpp b/media/libsoundtouch/src/TDStretch.cpp index 709e979d1d..16efdcf959 100644 --- a/media/libsoundtouch/src/TDStretch.cpp +++ b/media/libsoundtouch/src/TDStretch.cpp @@ -306,25 +306,31 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) // over the permitted range. bestCorr = calcCrossCorr(refPos, pMidBuffer, norm); bestCorr = (bestCorr + 0.1) * 0.75; + const int seekLen = seekLength; + const int nChannels = channels; + const SAMPLETYPE *midBuffer = pMidBuffer; - #pragma omp parallel for - for (i = 1; i < seekLength; i ++) + #if defined(_OPENMP) + #pragma omp parallel for default(none) shared(refPos, bestCorr, bestOffs, seekLen, nChannels, midBuffer) private(i) schedule(static) + #endif + for (i = 1; i < seekLen; i ++) { double corr; + double localNorm; // Calculates correlation value for the mixing position corresponding to 'i' #if defined(_OPENMP) || defined(ST_SIMD_AVOID_UNALIGNED) // in parallel OpenMP mode, can't use norm accumulator version as parallel executor won't // iterate the loop in sequential order // in SIMD mode, avoid accumulator version to allow avoiding unaligned positions - corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm); + corr = calcCrossCorr(refPos + nChannels * i, midBuffer, localNorm); #else // In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same // as "calcCrossCorr", but saves time by reusing & updating previously stored // "norm" value - corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm); + corr = calcCrossCorrAccumulate(refPos + nChannels * i, midBuffer, norm); #endif // heuristic rule to slightly favour values close to mid of the range - double tmp = (double)(2 * i - seekLength) / (double)seekLength; + double tmp = (double)(2 * i - seekLen) / (double)seekLen; corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp)); // Checks for the highest correlation value @@ -333,7 +339,9 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) // For optimal performance, enter critical section only in case that best value found. // in such case repeat 'if' condition as it's possible that parallel execution may have // updated the bestCorr value in the mean time - #pragma omp critical +#if defined(_OPENMP) + #pragma omp critical(soundtouch_bestcorr) +#endif if (corr > bestCorr) { bestCorr = corr; @@ -910,7 +918,9 @@ double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, do if (lnorm > maxnorm) { // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode - #pragma omp critical + #if defined(_OPENMP) + #pragma omp critical(soundtouch_maxnorm) + #endif if (lnorm > maxnorm) { maxnorm = lnorm; diff --git a/media/libsoundtouch/src/mmx_optimized.cpp b/media/libsoundtouch/src/mmx_optimized.cpp index 0bc7fe86f7..6ce2f635a2 100644 --- a/media/libsoundtouch/src/mmx_optimized.cpp +++ b/media/libsoundtouch/src/mmx_optimized.cpp @@ -119,7 +119,9 @@ double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &d if (norm > (long)maxnorm) { // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode - #pragma omp critical + #if defined(_OPENMP) + #pragma omp critical(soundtouch_maxnorm) + #endif if (norm > (long)maxnorm) { maxnorm = norm; diff --git a/media/libsoundtouch/src/moz.build b/media/libsoundtouch/src/moz.build index dabb2754e1..a4789919fa 100644 --- a/media/libsoundtouch/src/moz.build +++ b/media/libsoundtouch/src/moz.build @@ -41,6 +41,11 @@ else: # Windows need alloca renamed to _alloca DEFINES['alloca'] = '_alloca' +# Use standardized OpenMP parallelization for SoundTouch hot loops. +if CONFIG['CC_TYPE'] == 'gcc': + CXXFLAGS += ['-fopenmp'] + OS_LIBS += ['gomp'] + DEFINES['BUILDING_SOUNDTOUCH'] = 1 # We allow warnings for third-party code that can be updated from upstream. diff --git a/media/libsoundtouch/src/sse_optimized.cpp b/media/libsoundtouch/src/sse_optimized.cpp index 9c16ea8f89..5580be9d94 100644 --- a/media/libsoundtouch/src/sse_optimized.cpp +++ b/media/libsoundtouch/src/sse_optimized.cpp @@ -250,9 +250,13 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n assert((length % 8) == 0); assert(filterCoeffsAlign != NULL); assert(((ulongptr)filterCoeffsAlign) % 16 == 0); + const uint filterLength = length; + const float *coeffsAlign = filterCoeffsAlign; // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' - #pragma omp parallel for +#if defined(_OPENMP) + #pragma omp parallel for default(none) shared(source, dest, count, filterLength, coeffsAlign) private(j) schedule(static) +#endif for (j = 0; j < count; j += 2) { const float *pSrc; @@ -263,11 +267,11 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n pSrc = (const float*)source + j * 2; // source audio data pDest = dest + j * 2; // destination audio data - pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + pFil = (const __m128*)coeffsAlign; // filter coefficients. NOTE: Assumes coefficients // are aligned to 16-byte boundary sum1 = sum2 = _mm_setzero_ps(); - for (i = 0; i < length / 8; i ++) + for (i = 0; i < filterLength / 8; i ++) { // Unroll loop for efficiency & calculate filter for 2*2 stereo samples // at each pass