Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libsoundtouch/src/./../../../../media/libsoundtouch/src/TDStretch.cpp
Warning:line 283, column 5
Value stored to 'bestCorr' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_libsoundtouch_src0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libsoundtouch/src -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libsoundtouch/src -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -include /root/firefox-clang/media/libsoundtouch/src/soundtouch_perms.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D BUILDING_SOUNDTOUCH=1 -D ST_NO_EXCEPTION_HANDLING=1 -D MOZ_HAS_MOZGLUE -I /root/firefox-clang/media/libsoundtouch/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libsoundtouch/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/security/rlbox -I /root/firefox-clang/config/external/rlbox_wasm2c_sandbox -I /root/firefox-clang/third_party/simde -I /root/firefox-clang/third_party/wasm2c/wasm2c -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_libsoundtouch_src0.cpp
1///////////////////////////////////////////////////////////////////////////////
2///
3/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
4/// while maintaining the original pitch by using a time domain WSOLA-like
5/// method with several performance-increasing tweaks.
6///
7/// Notes : MMX optimized functions reside in a separate, platform-specific
8/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'.
9///
10/// This source file contains OpenMP optimizations that allow speeding up the
11/// corss-correlation algorithm by executing it in several threads / CPU cores
12/// in parallel. See the following article link for more detailed discussion
13/// about SoundTouch OpenMP optimizations:
14/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices
15///
16/// Author : Copyright (c) Olli Parviainen
17/// Author e-mail : oparviai 'at' iki.fi
18/// SoundTouch WWW: http://www.surina.net/soundtouch
19///
20////////////////////////////////////////////////////////////////////////////////
21//
22// License :
23//
24// SoundTouch audio processing library
25// Copyright (c) Olli Parviainen
26//
27// This library is free software; you can redistribute it and/or
28// modify it under the terms of the GNU Lesser General Public
29// License as published by the Free Software Foundation; either
30// version 2.1 of the License, or (at your option) any later version.
31//
32// This library is distributed in the hope that it will be useful,
33// but WITHOUT ANY WARRANTY; without even the implied warranty of
34// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35// Lesser General Public License for more details.
36//
37// You should have received a copy of the GNU Lesser General Public
38// License along with this library; if not, write to the Free Software
39// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40//
41////////////////////////////////////////////////////////////////////////////////
42
43#include <string.h>
44#include <limits.h>
45#include <assert.h>
46#include <math.h>
47#include <float.h>
48
49#include "STTypes.h"
50#include "cpu_detect.h"
51#include "TDStretch.h"
52
53using namespace soundtouch;
54
55#define max(x, y)(((x) > (y)) ? (x) : (y)) (((x) > (y)) ? (x) : (y))
56
57/*****************************************************************************
58 *
59 * Implementation of the class 'TDStretch'
60 *
61 *****************************************************************************/
62
63
64TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)
65{
66 bQuickSeek = false;
67 channels = 2;
68
69 pMidBuffer = nullptr;
70 pMidBufferUnaligned = nullptr;
71 overlapLength = 0;
72
73 bAutoSeqSetting = true;
74 bAutoSeekSetting = true;
75
76 tempo = 1.0f;
77 setParameters(44100, DEFAULT_SEQUENCE_MS0, DEFAULT_SEEKWINDOW_MS0, DEFAULT_OVERLAP_MS8);
78 setTempo(1.0f);
79
80 clear();
81}
82
83
84
85TDStretch::~TDStretch()
86{
87 delete[] pMidBufferUnaligned;
88}
89
90
91
92// Sets routine control parameters. These control are certain time constants
93// defining how the sound is stretched to the desired duration.
94//
95// 'sampleRate' = sample rate of the sound
96// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms)
97// 'seekwindowMS' = seeking window length for scanning the best overlapping
98// position (default = 28 ms)
99// 'overlapMS' = overlapping length (default = 12 ms)
100
101void TDStretch::setParameters(int aSampleRate, int aSequenceMS,
102 int aSeekWindowMS, int aOverlapMS)
103{
104 // accept only positive parameter values - if zero or negative, use old values instead
105 if (aSampleRate > 0)
106 {
107 if (aSampleRate > 192000) ST_THROW_RT_ERROR("Error: Excessive samplerate"){(static_cast <bool> ((const char *)"Error: Excessive samplerate"
) ? void (0) : __assert_fail ("(const char *)\"Error: Excessive samplerate\""
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
));}
;
108 this->sampleRate = aSampleRate;
109 }
110
111 if (aOverlapMS > 0) this->overlapMs = aOverlapMS;
112
113 if (aSequenceMS > 0)
114 {
115 this->sequenceMs = aSequenceMS;
116 bAutoSeqSetting = false;
117 }
118 else if (aSequenceMS == 0)
119 {
120 // if zero, use automatic setting
121 bAutoSeqSetting = true;
122 }
123
124 if (aSeekWindowMS > 0)
125 {
126 this->seekWindowMs = aSeekWindowMS;
127 bAutoSeekSetting = false;
128 }
129 else if (aSeekWindowMS == 0)
130 {
131 // if zero, use automatic setting
132 bAutoSeekSetting = true;
133 }
134
135 calcSeqParameters();
136
137 calculateOverlapLength(overlapMs);
138
139 // set tempo to recalculate 'sampleReq'
140 setTempo(tempo);
141}
142
143
144
145/// Get routine control parameters, see setParameters() function.
146/// Any of the parameters to this function can be nullptr, in such case corresponding parameter
147/// value isn't returned.
148void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const
149{
150 if (pSampleRate)
151 {
152 *pSampleRate = sampleRate;
153 }
154
155 if (pSequenceMs)
156 {
157 *pSequenceMs = (bAutoSeqSetting) ? (USE_AUTO_SEQUENCE_LEN0) : sequenceMs;
158 }
159
160 if (pSeekWindowMs)
161 {
162 *pSeekWindowMs = (bAutoSeekSetting) ? (USE_AUTO_SEEKWINDOW_LEN0) : seekWindowMs;
163 }
164
165 if (pOverlapMs)
166 {
167 *pOverlapMs = overlapMs;
168 }
169}
170
171
172// Overlaps samples in 'midBuffer' with the samples in 'pInput'
173void TDStretch::overlapMono(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput) const
174{
175 int i;
176 SAMPLETYPE m1, m2;
177
178 m1 = (SAMPLETYPE)0;
179 m2 = (SAMPLETYPE)overlapLength;
180
181 for (i = 0; i < overlapLength ; i ++)
182 {
183 pOutput[i] = (pInput[i] * m1 + pMidBuffer[i] * m2 ) / overlapLength;
184 m1 += 1;
185 m2 -= 1;
186 }
187}
188
189
190
191void TDStretch::clearMidBuffer()
192{
193 memset(pMidBuffer, 0, channels * sizeof(SAMPLETYPE) * overlapLength);
194}
195
196
197void TDStretch::clearInput()
198{
199 inputBuffer.clear();
200 clearMidBuffer();
201 isBeginning = true;
202 maxnorm = 0;
203 maxnormf = 1e8;
204 skipFract = 0;
205}
206
207
208// Clears the sample buffers
209void TDStretch::clear()
210{
211 outputBuffer.clear();
212 clearInput();
213}
214
215
216
217// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero
218// to enable
219void TDStretch::enableQuickSeek(bool enable)
220{
221 bQuickSeek = enable;
222}
223
224
225// Returns nonzero if the quick seeking algorithm is enabled.
226bool TDStretch::isQuickSeekEnabled() const
227{
228 return bQuickSeek;
229}
230
231
232// Seeks for the optimal overlap-mixing position.
233int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)
234{
235 if (bQuickSeek)
236 {
237 return seekBestOverlapPositionQuick(refPos);
238 }
239 else
240 {
241 return seekBestOverlapPositionFull(refPos);
242 }
243}
244
245
246// Overlaps samples in 'midBuffer' with the samples in 'pInputBuffer' at position
247// of 'ovlPos'.
248inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, uint ovlPos) const
249{
250#ifndef USE_MULTICH_ALWAYS
251 if (channels == 1)
252 {
253 // mono sound.
254 overlapMono(pOutput, pInput + ovlPos);
255 }
256 else if (channels == 2)
257 {
258 // stereo sound
259 overlapStereo(pOutput, pInput + 2 * ovlPos);
260 }
261 else
262#endif // USE_MULTICH_ALWAYS
263 {
264 assert(channels > 0)(static_cast <bool> (channels > 0) ? void (0) : __assert_fail
("channels > 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
265 overlapMulti(pOutput, pInput + channels * ovlPos);
266 }
267}
268
269
270// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
271// routine
272//
273// The best position is determined as the position where the two overlapped
274// sample sequences are 'most alike', in terms of the highest cross-correlation
275// value over the overlapping period
276int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
277{
278 int bestOffs;
279 double bestCorr;
280 int i;
281 double norm;
282
283 bestCorr = -FLT_MAX3.40282347e+38F;
Value stored to 'bestCorr' is never read
284 bestOffs = 0;
285
286 // Scans for the best correlation value by testing each possible position
287 // over the permitted range.
288 bestCorr = calcCrossCorr(refPos, pMidBuffer, norm);
289 bestCorr = (bestCorr + 0.1) * 0.75;
290
291 #pragma omp parallel for
292 for (i = 1; i < seekLength; i ++)
293 {
294 double corr;
295 // Calculates correlation value for the mixing position corresponding to 'i'
296#if defined(_OPENMP) || defined(ST_SIMD_AVOID_UNALIGNED)
297 // in parallel OpenMP mode, can't use norm accumulator version as parallel executor won't
298 // iterate the loop in sequential order
299 // in SIMD mode, avoid accumulator version to allow avoiding unaligned positions
300 corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm);
301#else
302 // In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same
303 // as "calcCrossCorr", but saves time by reusing & updating previously stored
304 // "norm" value
305 corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm);
306#endif
307 // heuristic rule to slightly favour values close to mid of the range
308 double tmp = (double)(2 * i - seekLength) / (double)seekLength;
309 corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
310
311 // Checks for the highest correlation value
312 if (corr > bestCorr)
313 {
314 // For optimal performance, enter critical section only in case that best value found.
315 // in such case repeat 'if' condition as it's possible that parallel execution may have
316 // updated the bestCorr value in the mean time
317 #pragma omp critical
318 if (corr > bestCorr)
319 {
320 bestCorr = corr;
321 bestOffs = i;
322 }
323 }
324 }
325
326#ifdef SOUNDTOUCH_INTEGER_SAMPLES
327 adaptNormalizer();
328#endif
329
330 // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
331 clearCrossCorrState();
332
333 return bestOffs;
334}
335
336
337// Quick seek algorithm for improved runtime-performance: First roughly scans through the
338// correlation area, and then scan surroundings of two best preliminary correlation candidates
339// with improved precision
340//
341// Based on testing:
342// - This algorithm gives on average 99% as good match as the full algorithm
343// - this quick seek algorithm finds the best match on ~90% of cases
344// - on those 10% of cases when this algorithm doesn't find best match,
345// it still finds on average ~90% match vs. the best possible match
346int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)
347{
348#define _MIN(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b))
349#define SCANSTEP16 16
350#define SCANWIND8 8
351
352 int bestOffs;
353 int i;
354 int bestOffs2;
355 float bestCorr, corr;
356 float bestCorr2;
357 double norm;
358
359 // note: 'float' types used in this function in case that the platform would need to use software-fp
360
361 bestCorr =
362 bestCorr2 = -FLT_MAX3.40282347e+38F;
363 bestOffs =
364 bestOffs2 = SCANWIND8;
365
366 // Scans for the best correlation value by testing each possible position
367 // over the permitted range. Look for two best matches on the first pass to
368 // increase possibility of ideal match.
369 //
370 // Begin from "SCANSTEP" instead of SCANWIND to make the calculation
371 // catch the 'middlepoint' of seekLength vector as that's the a-priori
372 // expected best match position
373 //
374 // Roughly:
375 // - 15% of cases find best result directly on the first round,
376 // - 75% cases find better match on 2nd round around the best match from 1st round
377 // - 10% cases find better match on 2nd round around the 2nd-best-match from 1st round
378 for (i = SCANSTEP16; i < seekLength - SCANWIND8 - 1; i += SCANSTEP16)
379 {
380 // Calculates correlation value for the mixing position corresponding
381 // to 'i'
382 corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm);
383 // heuristic rule to slightly favour values close to mid of the seek range
384 float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength;
385 corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp));
386
387 // Checks for the highest correlation value
388 if (corr > bestCorr)
389 {
390 // found new best match. keep the previous best as 2nd best match
391 bestCorr2 = bestCorr;
392 bestOffs2 = bestOffs;
393 bestCorr = corr;
394 bestOffs = i;
395 }
396 else if (corr > bestCorr2)
397 {
398 // not new best, but still new 2nd best match
399 bestCorr2 = corr;
400 bestOffs2 = i;
401 }
402 }
403
404 // Scans surroundings of the found best match with small stepping
405 int end = _MIN(bestOffs + SCANWIND + 1, seekLength)(((bestOffs + 8 + 1) < (seekLength)) ? (bestOffs + 8 + 1) :
(seekLength))
;
406 for (i = bestOffs - SCANWIND8; i < end; i++)
407 {
408 if (i == bestOffs) continue; // this offset already calculated, thus skip
409
410 // Calculates correlation value for the mixing position corresponding
411 // to 'i'
412 corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm);
413 // heuristic rule to slightly favour values close to mid of the range
414 float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength;
415 corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp));
416
417 // Checks for the highest correlation value
418 if (corr > bestCorr)
419 {
420 bestCorr = corr;
421 bestOffs = i;
422 }
423 }
424
425 // Scans surroundings of the 2nd best match with small stepping
426 end = _MIN(bestOffs2 + SCANWIND + 1, seekLength)(((bestOffs2 + 8 + 1) < (seekLength)) ? (bestOffs2 + 8 + 1
) : (seekLength))
;
427 for (i = bestOffs2 - SCANWIND8; i < end; i++)
428 {
429 if (i == bestOffs2) continue; // this offset already calculated, thus skip
430
431 // Calculates correlation value for the mixing position corresponding
432 // to 'i'
433 corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm);
434 // heuristic rule to slightly favour values close to mid of the range
435 float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength;
436 corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp));
437
438 // Checks for the highest correlation value
439 if (corr > bestCorr)
440 {
441 bestCorr = corr;
442 bestOffs = i;
443 }
444 }
445
446 // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
447 clearCrossCorrState();
448
449#ifdef SOUNDTOUCH_INTEGER_SAMPLES
450 adaptNormalizer();
451#endif
452
453 return bestOffs;
454}
455
456
457
458
459/// For integer algorithm: adapt normalization factor divider with music so that
460/// it'll not be pessimistically restrictive that can degrade quality on quieter sections
461/// yet won't cause integer overflows either
462void TDStretch::adaptNormalizer()
463{
464 // Do not adapt normalizer over too silent sequences to avoid averaging filter depleting to
465 // too low values during pauses in music
466 if ((maxnorm > 1000) || (maxnormf > 40000000))
467 {
468 //norm averaging filter
469 maxnormf = 0.9f * maxnormf + 0.1f * (float)maxnorm;
470
471 if ((maxnorm > 800000000) && (overlapDividerBitsNorm < 16))
472 {
473 // large values, so increase divider
474 overlapDividerBitsNorm++;
475 if (maxnorm > 1600000000) overlapDividerBitsNorm++; // extra large value => extra increase
476 }
477 else if ((maxnormf < 1000000) && (overlapDividerBitsNorm > 0))
478 {
479 // extra small values, decrease divider
480 overlapDividerBitsNorm--;
481 }
482 }
483
484 maxnorm = 0;
485}
486
487
488/// clear cross correlation routine state if necessary
489void TDStretch::clearCrossCorrState()
490{
491 // default implementation is empty.
492}
493
494
495/// Calculates processing sequence length according to tempo setting
496void TDStretch::calcSeqParameters()
497{
498 // Adjust tempo param according to tempo, so that variating processing sequence length is used
499 // at various tempo settings, between the given low...top limits
500 #define AUTOSEQ_TEMPO_LOW0.5 0.5 // auto setting low tempo range (-50%)
501 #define AUTOSEQ_TEMPO_TOP2.0 2.0 // auto setting top tempo range (+100%)
502
503 // sequence-ms setting values at above low & top tempo
504 #define AUTOSEQ_AT_MIN90.0 90.0
505 #define AUTOSEQ_AT_MAX40.0 40.0
506 #define AUTOSEQ_K((40.0 - 90.0) / (2.0 - 0.5)) ((AUTOSEQ_AT_MAX40.0 - AUTOSEQ_AT_MIN90.0) / (AUTOSEQ_TEMPO_TOP2.0 - AUTOSEQ_TEMPO_LOW0.5))
507 #define AUTOSEQ_C(90.0 - (((40.0 - 90.0) / (2.0 - 0.5))) * (0.5)) (AUTOSEQ_AT_MIN90.0 - (AUTOSEQ_K((40.0 - 90.0) / (2.0 - 0.5))) * (AUTOSEQ_TEMPO_LOW0.5))
508
509 // seek-window-ms setting values at above low & top tempoq
510 #define AUTOSEEK_AT_MIN20.0 20.0
511 #define AUTOSEEK_AT_MAX15.0 15.0
512 #define AUTOSEEK_K((15.0 - 20.0) / (2.0 - 0.5)) ((AUTOSEEK_AT_MAX15.0 - AUTOSEEK_AT_MIN20.0) / (AUTOSEQ_TEMPO_TOP2.0 - AUTOSEQ_TEMPO_LOW0.5))
513 #define AUTOSEEK_C(20.0 - (((15.0 - 20.0) / (2.0 - 0.5))) * (0.5)) (AUTOSEEK_AT_MIN20.0 - (AUTOSEEK_K((15.0 - 20.0) / (2.0 - 0.5))) * (AUTOSEQ_TEMPO_LOW0.5))
514
515 #define CHECK_LIMITS(x, mi, ma)(((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x))) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x)))
516
517 double seq, seek;
518
519 if (bAutoSeqSetting)
520 {
521 seq = AUTOSEQ_C(90.0 - (((40.0 - 90.0) / (2.0 - 0.5))) * (0.5)) + AUTOSEQ_K((40.0 - 90.0) / (2.0 - 0.5)) * tempo;
522 seq = CHECK_LIMITS(seq, AUTOSEQ_AT_MAX, AUTOSEQ_AT_MIN)(((seq) < (40.0)) ? (40.0) : (((seq) > (90.0)) ? (90.0)
: (seq)))
;
523 sequenceMs = (int)(seq + 0.5);
524 }
525
526 if (bAutoSeekSetting)
527 {
528 seek = AUTOSEEK_C(20.0 - (((15.0 - 20.0) / (2.0 - 0.5))) * (0.5)) + AUTOSEEK_K((15.0 - 20.0) / (2.0 - 0.5)) * tempo;
529 seek = CHECK_LIMITS(seek, AUTOSEEK_AT_MAX, AUTOSEEK_AT_MIN)(((seek) < (15.0)) ? (15.0) : (((seek) > (20.0)) ? (20.0
) : (seek)))
;
530 seekWindowMs = (int)(seek + 0.5);
531 }
532
533 // Update seek window lengths
534 seekWindowLength = (sampleRate * sequenceMs) / 1000;
535 if (seekWindowLength < 2 * overlapLength)
536 {
537 seekWindowLength = 2 * overlapLength;
538 }
539 seekLength = (sampleRate * seekWindowMs) / 1000;
540}
541
542
543
544// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
545// tempo, larger faster tempo.
546void TDStretch::setTempo(double newTempo)
547{
548 int intskip;
549
550 tempo = newTempo;
551
552 // Calculate new sequence duration
553 calcSeqParameters();
554
555 // Calculate ideal skip length (according to tempo value)
556 nominalSkip = tempo * (seekWindowLength - overlapLength);
557 intskip = (int)(nominalSkip + 0.5);
558
559 // Calculate how many samples are needed in the 'inputBuffer' to
560 // process another batch of samples
561 //sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2;
562 sampleReq = max(intskip + overlapLength, seekWindowLength)(((intskip + overlapLength) > (seekWindowLength)) ? (intskip
+ overlapLength) : (seekWindowLength))
+ seekLength;
563}
564
565
566
567// Sets the number of channels, 1 = mono, 2 = stereo
568void TDStretch::setChannels(int numChannels)
569{
570 if (!verifyNumberOfChannels(numChannels) ||
571 (channels == numChannels)) return;
572
573 channels = numChannels;
574 inputBuffer.setChannels(channels);
575 outputBuffer.setChannels(channels);
576
577 // re-init overlap/buffer
578 overlapLength=0;
579 setParameters(sampleRate);
580}
581
582
583// nominal tempo, no need for processing, just pass the samples through
584// to outputBuffer
585/*
586void TDStretch::processNominalTempo()
587{
588 assert(tempo == 1.0f);
589
590 if (bMidBufferDirty)
591 {
592 // If there are samples in pMidBuffer waiting for overlapping,
593 // do a single sliding overlapping with them in order to prevent a
594 // clicking distortion in the output sound
595 if (inputBuffer.numSamples() < overlapLength)
596 {
597 // wait until we've got overlapLength input samples
598 return;
599 }
600 // Mix the samples in the beginning of 'inputBuffer' with the
601 // samples in 'midBuffer' using sliding overlapping
602 overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0);
603 outputBuffer.putSamples(overlapLength);
604 inputBuffer.receiveSamples(overlapLength);
605 clearMidBuffer();
606 // now we've caught the nominal sample flow and may switch to
607 // bypass mode
608 }
609
610 // Simply bypass samples from input to output
611 outputBuffer.moveSamples(inputBuffer);
612}
613*/
614
615
616// Processes as many processing frames of the samples 'inputBuffer', store
617// the result into 'outputBuffer'
618void TDStretch::processSamples()
619{
620 int ovlSkip;
621 int offset = 0;
622 int temp;
623
624 /* Removed this small optimization - can introduce a click to sound when tempo setting
625 crosses the nominal value
626 if (tempo == 1.0f)
627 {
628 // tempo not changed from the original, so bypass the processing
629 processNominalTempo();
630 return;
631 }
632 */
633
634 // Process samples as long as there are enough samples in 'inputBuffer'
635 // to form a processing frame.
636 while ((int)inputBuffer.numSamples() >= sampleReq)
637 {
638 if (isBeginning == false)
639 {
640 // apart from the very beginning of the track,
641 // scan for the best overlapping position & do overlap-add
642 offset = seekBestOverlapPosition(inputBuffer.ptrBegin());
643
644 // Mix the samples in the 'inputBuffer' at position of 'offset' with the
645 // samples in 'midBuffer' using sliding overlapping
646 // ... first partially overlap with the end of the previous sequence
647 // (that's in 'midBuffer')
648 overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset);
649 outputBuffer.putSamples((uint)overlapLength);
650 offset += overlapLength;
651 }
652 else
653 {
654 // Adjust processing offset at beginning of track by not perform initial overlapping
655 // and compensating that in the 'input buffer skip' calculation
656 isBeginning = false;
657 int skip = (int)(tempo * overlapLength + 0.5 * seekLength + 0.5);
658
659 #ifdef ST_SIMD_AVOID_UNALIGNED
660 // in SIMD mode, round the skip amount to value corresponding to aligned memory address
661 if (channels == 1)
662 {
663 skip &= -4;
664 }
665 else if (channels == 2)
666 {
667 skip &= -2;
668 }
669 #endif
670 skipFract -= skip;
671 if (skipFract <= -nominalSkip)
672 {
673 skipFract = -nominalSkip;
674 }
675 }
676
677 // ... then copy sequence samples from 'inputBuffer' to output:
678
679 // crosscheck that we don't have buffer overflow...
680 if ((int)inputBuffer.numSamples() < (offset + seekWindowLength - overlapLength))
681 {
682 continue; // just in case, shouldn't really happen
683 }
684
685 // length of sequence
686 temp = (seekWindowLength - 2 * overlapLength);
687 outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * offset, (uint)temp);
688
689 // Copies the end of the current sequence from 'inputBuffer' to
690 // 'midBuffer' for being mixed with the beginning of the next
691 // processing sequence and so on
692 assert((offset + temp + overlapLength) <= (int)inputBuffer.numSamples())(static_cast <bool> ((offset + temp + overlapLength) <=
(int)inputBuffer.numSamples()) ? void (0) : __assert_fail ("(offset + temp + overlapLength) <= (int)inputBuffer.numSamples()"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
693 memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp),
694 channels * sizeof(SAMPLETYPE) * overlapLength);
695
696 // Remove the processed samples from the input buffer. Update
697 // the difference between integer & nominal skip step to 'skipFract'
698 // in order to prevent the error from accumulating over time.
699 skipFract += nominalSkip; // real skip size
700 ovlSkip = (int)skipFract; // rounded to integer skip
701 skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip
702 inputBuffer.receiveSamples((uint)ovlSkip);
703 }
704}
705
706
707// Adds 'numsamples' pcs of samples from the 'samples' memory position into
708// the input of the object.
709void TDStretch::putSamples(const SAMPLETYPE *samples, uint nSamples)
710{
711 // Add the samples into the input buffer
712 inputBuffer.putSamples(samples, nSamples);
713 // Process the samples in input buffer
714 processSamples();
715}
716
717
718
719/// Set new overlap length parameter & reallocate RefMidBuffer if necessary.
720void TDStretch::acceptNewOverlapLength(int newOverlapLength)
721{
722 int prevOvl;
723
724 assert(newOverlapLength >= 0)(static_cast <bool> (newOverlapLength >= 0) ? void (
0) : __assert_fail ("newOverlapLength >= 0", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
725 prevOvl = overlapLength;
726 overlapLength = newOverlapLength;
727
728 if (overlapLength > prevOvl)
729 {
730 delete[] pMidBufferUnaligned;
731
732 pMidBufferUnaligned = new SAMPLETYPE[overlapLength * channels + 16 / sizeof(SAMPLETYPE)];
733 // ensure that 'pMidBuffer' is aligned to 16 byte boundary for efficiency
734 pMidBuffer = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(pMidBufferUnaligned)( ( (ulongptr)(pMidBufferUnaligned) + 15 ) & ~(ulongptr)15
)
;
735
736 clearMidBuffer();
737 }
738}
739
740
741// Operator 'new' is overloaded so that it automatically creates a suitable instance
742// depending on if we've a MMX/SSE/etc-capable CPU available or not.
743void * TDStretch::operator new(size_t)
744{
745 // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
746 ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!"){(static_cast <bool> ((const char *)"Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!"
) ? void (0) : __assert_fail ("(const char *)\"Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!\""
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
));}
;
747 return newInstance();
748}
749
750
751TDStretch * TDStretch::newInstance()
752{
753#if defined(SOUNDTOUCH_ALLOW_MMX) || defined(SOUNDTOUCH_ALLOW_SSE1)
754 uint uExtensions;
755
756 uExtensions = detectCPUextensions();
757#endif
758
759 // Check if MMX/SSE instruction set extensions supported by CPU
760
761#ifdef SOUNDTOUCH_ALLOW_MMX
762 // MMX routines available only with integer sample types
763 if (uExtensions & SUPPORT_MMX0x0001)
764 {
765 return ::new TDStretchMMX;
766 }
767 else
768#endif // SOUNDTOUCH_ALLOW_MMX
769
770
771#ifdef SOUNDTOUCH_ALLOW_SSE1
772 if (uExtensions & SUPPORT_SSE0x0008)
773 {
774 // SSE support
775 return ::new TDStretchSSE;
776 }
777 else
778#endif // SOUNDTOUCH_ALLOW_SSE
779
780 {
781 // ISA optimizations not supported, use plain C version
782 return ::new TDStretch;
783 }
784}
785
786
787//////////////////////////////////////////////////////////////////////////////
788//
789// Integer arithmetic specific algorithm implementations.
790//
791//////////////////////////////////////////////////////////////////////////////
792
793#ifdef SOUNDTOUCH_INTEGER_SAMPLES
794
795// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo'
796// version of the routine.
797void TDStretch::overlapStereo(short *poutput, const short *input) const
798{
799 int i;
800 short temp;
801 int cnt2;
802
803 for (i = 0; i < overlapLength ; i ++)
804 {
805 temp = (short)(overlapLength - i);
806 cnt2 = 2 * i;
807 poutput[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength;
808 poutput[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength;
809 }
810}
811
812
813// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Multi'
814// version of the routine.
815void TDStretch::overlapMulti(short *poutput, const short *input) const
816{
817 short m1;
818 int i = 0;
819
820 for (m1 = 0; m1 < overlapLength; m1 ++)
821 {
822 short m2 = (short)(overlapLength - m1);
823 for (int c = 0; c < channels; c ++)
824 {
825 poutput[i] = (input[i] * m1 + pMidBuffer[i] * m2) / overlapLength;
826 i++;
827 }
828 }
829}
830
831// Calculates the x having the closest 2^x value for the given value
832static int _getClosest2Power(double value)
833{
834 return (int)(log(value) / log(2.0) + 0.5);
835}
836
837
838/// Calculates overlap period length in samples.
839/// Integer version rounds overlap length to closest power of 2
840/// for a divide scaling operation.
841void TDStretch::calculateOverlapLength(int aoverlapMs)
842{
843 int newOvl;
844
845 assert(aoverlapMs >= 0)(static_cast <bool> (aoverlapMs >= 0) ? void (0) : __assert_fail
("aoverlapMs >= 0", __builtin_FILE (), __builtin_LINE (),
__extension__ __PRETTY_FUNCTION__))
;
846
847 // calculate overlap length so that it's power of 2 - thus it's easy to do
848 // integer division by right-shifting. Term "-1" at end is to account for
849 // the extra most significatnt bit left unused in result by signed multiplication
850 overlapDividerBitsPure = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1;
851 if (overlapDividerBitsPure > 9) overlapDividerBitsPure = 9;
852 if (overlapDividerBitsPure < 3) overlapDividerBitsPure = 3;
853 newOvl = (int)pow(2.0, (int)overlapDividerBitsPure + 1); // +1 => account for -1 above
854
855 acceptNewOverlapLength(newOvl);
856
857 overlapDividerBitsNorm = overlapDividerBitsPure;
858
859 // calculate sloping divider so that crosscorrelation operation won't
860 // overflow 32-bit register. Max. sum of the crosscorrelation sum without
861 // divider would be 2^30*(N^3-N)/3, where N = overlap length
862 slopingDivider = (newOvl * newOvl - 1) / 3;
863}
864
865
866double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, double &norm)
867{
868 long corr;
869 unsigned long lnorm;
870 int i;
871
872 #ifdef ST_SIMD_AVOID_UNALIGNED
873 // in SIMD mode skip 'mixingPos' positions that aren't aligned to 16-byte boundary
874 if (((ulongptr)mixingPos) & 15) return -1e50;
875 #endif
876
877 // hint compiler autovectorization that loop length is divisible by 8
878 int ilength = (channels * overlapLength) & -8;
879
880 corr = lnorm = 0;
881 // Same routine for stereo and mono
882 for (i = 0; i < ilength; i += 2)
883 {
884 corr += (mixingPos[i] * compare[i] +
885 mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm;
886 lnorm += (mixingPos[i] * mixingPos[i] +
887 mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBitsNorm;
888 // do intermediate scalings to avoid integer overflow
889 }
890
891 if (lnorm > maxnorm)
892 {
893 // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode
894 #pragma omp critical
895 if (lnorm > maxnorm)
896 {
897 maxnorm = lnorm;
898 }
899 }
900 // Normalize result by dividing by sqrt(norm) - this step is easiest
901 // done using floating point operation
902 norm = (double)lnorm;
903 return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm);
904}
905
906
907/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value
908double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm)
909{
910 long corr;
911 long lnorm;
912 int i;
913
914 // hint compiler autovectorization that loop length is divisible by 8
915 int ilength = (channels * overlapLength) & -8;
916
917 // cancel first normalizer tap from previous round
918 lnorm = 0;
919 for (i = 1; i <= channels; i ++)
920 {
921 lnorm -= (mixingPos[-i] * mixingPos[-i]) >> overlapDividerBitsNorm;
922 }
923
924 corr = 0;
925 // Same routine for stereo and mono.
926 for (i = 0; i < ilength; i += 2)
927 {
928 corr += (mixingPos[i] * compare[i] +
929 mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm;
930 }
931
932 // update normalizer with last samples of this round
933 for (int j = 0; j < channels; j ++)
934 {
935 i --;
936 lnorm += (mixingPos[i] * mixingPos[i]) >> overlapDividerBitsNorm;
937 }
938
939 norm += (double)lnorm;
940 if (norm > maxnorm)
941 {
942 maxnorm = (unsigned long)norm;
943 }
944
945 // Normalize result by dividing by sqrt(norm) - this step is easiest
946 // done using floating point operation
947 return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm);
948}
949
950#endif // SOUNDTOUCH_INTEGER_SAMPLES
951
952//////////////////////////////////////////////////////////////////////////////
953//
954// Floating point arithmetic specific algorithm implementations.
955//
956
957#ifdef SOUNDTOUCH_FLOAT_SAMPLES1
958
959// Overlaps samples in 'midBuffer' with the samples in 'pInput'
960void TDStretch::overlapStereo(float *pOutput, const float *pInput) const
961{
962 int i;
963 float fScale;
964 float f1;
965 float f2;
966
967 fScale = 1.0f / (float)overlapLength;
968
969 f1 = 0;
970 f2 = 1.0f;
971
972 for (i = 0; i < 2 * (int)overlapLength ; i += 2)
973 {
974 pOutput[i + 0] = pInput[i + 0] * f1 + pMidBuffer[i + 0] * f2;
975 pOutput[i + 1] = pInput[i + 1] * f1 + pMidBuffer[i + 1] * f2;
976
977 f1 += fScale;
978 f2 -= fScale;
979 }
980}
981
982
983// Overlaps samples in 'midBuffer' with the samples in 'input'.
984void TDStretch::overlapMulti(float *pOutput, const float *pInput) const
985{
986 int i;
987 float fScale;
988 float f1;
989 float f2;
990
991 fScale = 1.0f / (float)overlapLength;
992
993 f1 = 0;
994 f2 = 1.0f;
995
996 i=0;
997 for (int i2 = 0; i2 < overlapLength; i2 ++)
998 {
999 // note: Could optimize this slightly by taking into account that always channels > 2
1000 for (int c = 0; c < channels; c ++)
1001 {
1002 pOutput[i] = pInput[i] * f1 + pMidBuffer[i] * f2;
1003 i++;
1004 }
1005 f1 += fScale;
1006 f2 -= fScale;
1007 }
1008}
1009
1010
1011/// Calculates overlapInMsec period length in samples.
1012void TDStretch::calculateOverlapLength(int overlapInMsec)
1013{
1014 int newOvl;
1015
1016 assert(overlapInMsec >= 0)(static_cast <bool> (overlapInMsec >= 0) ? void (0) :
__assert_fail ("overlapInMsec >= 0", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
1017 newOvl = (sampleRate * overlapInMsec) / 1000;
1018 if (newOvl < 16) newOvl = 16;
1019
1020 // must be divisible by 8
1021 newOvl -= newOvl % 8;
1022
1023 acceptNewOverlapLength(newOvl);
1024}
1025
1026
1027/// Calculate cross-correlation
1028double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare, double &anorm)
1029{
1030 float corr;
1031 float norm;
1032 int i;
1033
1034 #ifdef ST_SIMD_AVOID_UNALIGNED
1035 // in SIMD mode skip 'mixingPos' positions that aren't aligned to 16-byte boundary
1036 if (((ulongptr)mixingPos) & 15) return -1e50;
1037 #endif
1038
1039 // hint compiler autovectorization that loop length is divisible by 8
1040 int ilength = (channels * overlapLength) & -8;
1041
1042 corr = norm = 0;
1043 // Same routine for stereo and mono
1044 for (i = 0; i < ilength; i ++)
1045 {
1046 corr += mixingPos[i] * compare[i];
1047 norm += mixingPos[i] * mixingPos[i];
1048 }
1049
1050 anorm = norm;
1051 return corr / sqrt((norm < 1e-9 ? 1.0 : norm));
1052}
1053
1054
1055/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value
1056double TDStretch::calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm)
1057{
1058 float corr;
1059 int i;
1060
1061 corr = 0;
1062
1063 // cancel first normalizer tap from previous round
1064 for (i = 1; i <= channels; i ++)
1065 {
1066 norm -= mixingPos[-i] * mixingPos[-i];
1067 }
1068
1069 // hint compiler autovectorization that loop length is divisible by 8
1070 int ilength = (channels * overlapLength) & -8;
1071
1072 // Same routine for stereo and mono
1073 for (i = 0; i < ilength; i ++)
1074 {
1075 corr += mixingPos[i] * compare[i];
1076 }
1077
1078 // update normalizer with last samples of this round
1079 for (int j = 0; j < channels; j ++)
1080 {
1081 i --;
1082 norm += mixingPos[i] * mixingPos[i];
1083 }
1084
1085 return corr / sqrt((norm < 1e-9 ? 1.0 : norm));
1086}
1087
1088
1089#endif // SOUNDTOUCH_FLOAT_SAMPLES