/[pcsx2_0.9.7]/trunk/3rdparty/SoundTouch/TDStretch.cpp
ViewVC logotype

Contents of /trunk/3rdparty/SoundTouch/TDStretch.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Mon Sep 6 13:44:19 2010 UTC (10 years, 2 months ago) by william
File size: 31492 byte(s)
initial checkout of r3113 from upstream repository
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 /// Note : MMX optimized functions reside in a separate, platform-specific
8 /// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
9 ///
10 /// Author : Copyright (c) Olli Parviainen
11 /// Author e-mail : oparviai 'at' iki.fi
12 /// SoundTouch WWW: http://www.surina.net/soundtouch
13 ///
14 ////////////////////////////////////////////////////////////////////////////////
15 //
16 // Last changed : $Date: 2009-12-28 21:27:04 +0200 (Mon, 28 Dec 2009) $
17 // File revision : $Revision: 1.12 $
18 //
19 // $Id: TDStretch.cpp 77 2009-12-28 19:27:04Z oparviai $
20 //
21 ////////////////////////////////////////////////////////////////////////////////
22 //
23 // License :
24 //
25 // SoundTouch audio processing library
26 // Copyright (c) Olli Parviainen
27 //
28 // This library is free software; you can redistribute it and/or
29 // modify it under the terms of the GNU Lesser General Public
30 // License as published by the Free Software Foundation; either
31 // version 2.1 of the License, or (at your option) any later version.
32 //
33 // This library is distributed in the hope that it will be useful,
34 // but WITHOUT ANY WARRANTY; without even the implied warranty of
35 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 // Lesser General Public License for more details.
37 //
38 // You should have received a copy of the GNU Lesser General Public
39 // License along with this library; if not, write to the Free Software
40 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 //
42 ////////////////////////////////////////////////////////////////////////////////
43
44 #include <string.h>
45 #include <limits.h>
46 #include <assert.h>
47 #include <math.h>
48 #include <float.h>
49 #include <stdexcept>
50
51 #include "STTypes.h"
52 #include "cpu_detect.h"
53 #include "TDStretch.h"
54
55 #include <stdio.h>
56
57 using namespace soundtouch;
58
59 #define max(x, y) (((x) > (y)) ? (x) : (y))
60
61
62 /*****************************************************************************
63 *
64 * Constant definitions
65 *
66 *****************************************************************************/
67
68 // Table for the hierarchical mixing position seeking algorithm
69 static const short _scanOffsets[5][24]={
70 { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806,
71 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0},
72 {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
74 { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
76 { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0,
77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
78 { 121, 114, 97, 114, 98, 105, 108, 32, 104, 99, 117, 111,
79 116, 100, 110, 117, 111, 115, 0, 0, 0, 0, 0, 0}};
80
81 /*****************************************************************************
82 *
83 * Implementation of the class 'TDStretch'
84 *
85 *****************************************************************************/
86
87
88 TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)
89 {
90 bQuickSeek = FALSE;
91 channels = 2;
92
93 pMidBuffer = NULL;
94 pRefMidBufferUnaligned = NULL;
95 overlapLength = 0;
96
97 bAutoSeqSetting = TRUE;
98 bAutoSeekSetting = TRUE;
99
100 // outDebt = 0;
101 skipFract = 0;
102
103 tempo = 1.0f;
104 setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS);
105 setTempo(1.0f);
106
107 clear();
108 }
109
110
111
112 TDStretch::~TDStretch()
113 {
114 delete[] pMidBuffer;
115 delete[] pRefMidBufferUnaligned;
116 }
117
118
119
120 // Sets routine control parameters. These control are certain time constants
121 // defining how the sound is stretched to the desired duration.
122 //
123 // 'sampleRate' = sample rate of the sound
124 // 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms)
125 // 'seekwindowMS' = seeking window length for scanning the best overlapping
126 // position (default = 28 ms)
127 // 'overlapMS' = overlapping length (default = 12 ms)
128
129 void TDStretch::setParameters(int aSampleRate, int aSequenceMS,
130 int aSeekWindowMS, int aOverlapMS)
131 {
132 // accept only positive parameter values - if zero or negative, use old values instead
133 if (aSampleRate > 0) this->sampleRate = aSampleRate;
134 if (aOverlapMS > 0) this->overlapMs = aOverlapMS;
135
136 if (aSequenceMS > 0)
137 {
138 this->sequenceMs = aSequenceMS;
139 bAutoSeqSetting = FALSE;
140 }
141 else if (aSequenceMS == 0)
142 {
143 // if zero, use automatic setting
144 bAutoSeqSetting = TRUE;
145 }
146
147 if (aSeekWindowMS > 0)
148 {
149 this->seekWindowMs = aSeekWindowMS;
150 bAutoSeekSetting = FALSE;
151 }
152 else if (aSeekWindowMS == 0)
153 {
154 // if zero, use automatic setting
155 bAutoSeekSetting = TRUE;
156 }
157
158 calcSeqParameters();
159
160 calculateOverlapLength(overlapMs);
161
162 // set tempo to recalculate 'sampleReq'
163 setTempo(tempo);
164
165 }
166
167
168
169 /// Get routine control parameters, see setParameters() function.
170 /// Any of the parameters to this function can be NULL, in such case corresponding parameter
171 /// value isn't returned.
172 void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const
173 {
174 if (pSampleRate)
175 {
176 *pSampleRate = sampleRate;
177 }
178
179 if (pSequenceMs)
180 {
181 *pSequenceMs = (bAutoSeqSetting) ? (USE_AUTO_SEQUENCE_LEN) : sequenceMs;
182 }
183
184 if (pSeekWindowMs)
185 {
186 *pSeekWindowMs = (bAutoSeekSetting) ? (USE_AUTO_SEEKWINDOW_LEN) : seekWindowMs;
187 }
188
189 if (pOverlapMs)
190 {
191 *pOverlapMs = overlapMs;
192 }
193 }
194
195
196 // Overlaps samples in 'midBuffer' with the samples in 'pInput'
197 void TDStretch::overlapMono(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput) const
198 {
199 int i, itemp;
200
201 for (i = 0; i < overlapLength ; i ++)
202 {
203 itemp = overlapLength - i;
204 pOutput[i] = (pInput[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits;
205 }
206 }
207
208
209
210 void TDStretch::clearMidBuffer()
211 {
212 memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength);
213 }
214
215
216 void TDStretch::clearInput()
217 {
218 inputBuffer.clear();
219 clearMidBuffer();
220 }
221
222
223 // Clears the sample buffers
224 void TDStretch::clear()
225 {
226 outputBuffer.clear();
227 clearInput();
228 }
229
230
231
232 // Enables/disables the quick position seeking algorithm. Zero to disable, nonzero
233 // to enable
234 void TDStretch::enableQuickSeek(BOOL enable)
235 {
236 bQuickSeek = enable;
237 }
238
239
240 // Returns nonzero if the quick seeking algorithm is enabled.
241 BOOL TDStretch::isQuickSeekEnabled() const
242 {
243 return bQuickSeek;
244 }
245
246
247 // Seeks for the optimal overlap-mixing position.
248 int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)
249 {
250 if (channels == 2)
251 {
252 // stereo sound
253 if (bQuickSeek)
254 {
255 return seekBestOverlapPositionStereoQuick(refPos);
256 }
257 else
258 {
259 return seekBestOverlapPositionStereo(refPos);
260 }
261 }
262 else
263 {
264 // mono sound
265 if (bQuickSeek)
266 {
267 return seekBestOverlapPositionMonoQuick(refPos);
268 }
269 else
270 {
271 return seekBestOverlapPositionMono(refPos);
272 }
273 }
274 }
275
276
277
278
279 // Overlaps samples in 'midBuffer' with the samples in 'pInputBuffer' at position
280 // of 'ovlPos'.
281 inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, uint ovlPos) const
282 {
283 if (channels == 2)
284 {
285 // stereo sound
286 overlapStereo(pOutput, pInput + 2 * ovlPos);
287 } else {
288 // mono sound.
289 overlapMono(pOutput, pInput + ovlPos);
290 }
291 }
292
293
294
295
296 // Seeks for the optimal overlap-mixing position. The 'stereo' version of the
297 // routine
298 //
299 // The best position is determined as the position where the two overlapped
300 // sample sequences are 'most alike', in terms of the highest cross-correlation
301 // value over the overlapping period
302 int TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos)
303 {
304 int bestOffs;
305 double bestCorr, corr;
306 int i;
307
308 // Slopes the amplitudes of the 'midBuffer' samples
309 precalcCorrReferenceStereo();
310
311 bestCorr = FLT_MIN;
312 bestOffs = 0;
313
314 // Scans for the best correlation value by testing each possible position
315 // over the permitted range.
316 for (i = 0; i < seekLength; i ++)
317 {
318 // Calculates correlation value for the mixing position corresponding
319 // to 'i'
320 corr = (double)calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer);
321 // heuristic rule to slightly favour values close to mid of the range
322 double tmp = (double)(2 * i - seekLength) / (double)seekLength;
323 corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
324
325 // Checks for the highest correlation value
326 if (corr > bestCorr)
327 {
328 bestCorr = corr;
329 bestOffs = i;
330 }
331 }
332 // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
333 clearCrossCorrState();
334
335 return bestOffs;
336 }
337
338
339 // Seeks for the optimal overlap-mixing position. The 'stereo' version of the
340 // routine
341 //
342 // The best position is determined as the position where the two overlapped
343 // sample sequences are 'most alike', in terms of the highest cross-correlation
344 // value over the overlapping period
345 int TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos)
346 {
347 int j;
348 int bestOffs;
349 double bestCorr, corr;
350 int scanCount, corrOffset, tempOffset;
351
352 // Slopes the amplitude of the 'midBuffer' samples
353 precalcCorrReferenceStereo();
354
355 bestCorr = FLT_MIN;
356 bestOffs = _scanOffsets[0][0];
357 corrOffset = 0;
358 tempOffset = 0;
359
360 // Scans for the best correlation value using four-pass hierarchical search.
361 //
362 // The look-up table 'scans' has hierarchical position adjusting steps.
363 // In first pass the routine searhes for the highest correlation with
364 // relatively coarse steps, then rescans the neighbourhood of the highest
365 // correlation with better resolution and so on.
366 for (scanCount = 0;scanCount < 4; scanCount ++)
367 {
368 j = 0;
369 while (_scanOffsets[scanCount][j])
370 {
371 tempOffset = corrOffset + _scanOffsets[scanCount][j];
372 if (tempOffset >= seekLength) break;
373
374 // Calculates correlation value for the mixing position corresponding
375 // to 'tempOffset'
376 corr = (double)calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer);
377 // heuristic rule to slightly favour values close to mid of the range
378 double tmp = (double)(2 * tempOffset - seekLength) / seekLength;
379 corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
380
381 // Checks for the highest correlation value
382 if (corr > bestCorr)
383 {
384 bestCorr = corr;
385 bestOffs = tempOffset;
386 }
387 j ++;
388 }
389 corrOffset = bestOffs;
390 }
391 // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
392 clearCrossCorrState();
393
394 return bestOffs;
395 }
396
397
398
399 // Seeks for the optimal overlap-mixing position. The 'mono' version of the
400 // routine
401 //
402 // The best position is determined as the position where the two overlapped
403 // sample sequences are 'most alike', in terms of the highest cross-correlation
404 // value over the overlapping period
405 int TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos)
406 {
407 int bestOffs;
408 double bestCorr, corr;
409 int tempOffset;
410 const SAMPLETYPE *compare;
411
412 // Slopes the amplitude of the 'midBuffer' samples
413 precalcCorrReferenceMono();
414
415 bestCorr = FLT_MIN;
416 bestOffs = 0;
417
418 // Scans for the best correlation value by testing each possible position
419 // over the permitted range.
420 for (tempOffset = 0; tempOffset < seekLength; tempOffset ++)
421 {
422 compare = refPos + tempOffset;
423
424 // Calculates correlation value for the mixing position corresponding
425 // to 'tempOffset'
426 corr = (double)calcCrossCorrMono(pRefMidBuffer, compare);
427 // heuristic rule to slightly favour values close to mid of the range
428 double tmp = (double)(2 * tempOffset - seekLength) / seekLength;
429 corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
430
431 // Checks for the highest correlation value
432 if (corr > bestCorr)
433 {
434 bestCorr = corr;
435 bestOffs = tempOffset;
436 }
437 }
438 // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
439 clearCrossCorrState();
440
441 return bestOffs;
442 }
443
444
445 // Seeks for the optimal overlap-mixing position. The 'mono' version of the
446 // routine
447 //
448 // The best position is determined as the position where the two overlapped
449 // sample sequences are 'most alike', in terms of the highest cross-correlation
450 // value over the overlapping period
451 int TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos)
452 {
453 int j;
454 int bestOffs;
455 double bestCorr, corr;
456 int scanCount, corrOffset, tempOffset;
457
458 // Slopes the amplitude of the 'midBuffer' samples
459 precalcCorrReferenceMono();
460
461 bestCorr = FLT_MIN;
462 bestOffs = _scanOffsets[0][0];
463 corrOffset = 0;
464 tempOffset = 0;
465
466 // Scans for the best correlation value using four-pass hierarchical search.
467 //
468 // The look-up table 'scans' has hierarchical position adjusting steps.
469 // In first pass the routine searhes for the highest correlation with
470 // relatively coarse steps, then rescans the neighbourhood of the highest
471 // correlation with better resolution and so on.
472 for (scanCount = 0;scanCount < 4; scanCount ++)
473 {
474 j = 0;
475 while (_scanOffsets[scanCount][j])
476 {
477 tempOffset = corrOffset + _scanOffsets[scanCount][j];
478 if (tempOffset >= seekLength) break;
479
480 // Calculates correlation value for the mixing position corresponding
481 // to 'tempOffset'
482 corr = (double)calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer);
483 // heuristic rule to slightly favour values close to mid of the range
484 double tmp = (double)(2 * tempOffset - seekLength) / seekLength;
485 corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
486
487 // Checks for the highest correlation value
488 if (corr > bestCorr)
489 {
490 bestCorr = corr;
491 bestOffs = tempOffset;
492 }
493 j ++;
494 }
495 corrOffset = bestOffs;
496 }
497 // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
498 clearCrossCorrState();
499
500 return bestOffs;
501 }
502
503
504 /// clear cross correlation routine state if necessary
505 void TDStretch::clearCrossCorrState()
506 {
507 // default implementation is empty.
508 }
509
510
511 /// Calculates processing sequence length according to tempo setting
512 void TDStretch::calcSeqParameters()
513 {
514 // Adjust tempo param according to tempo, so that variating processing sequence length is used
515 // at varius tempo settings, between the given low...top limits
516 #define AUTOSEQ_TEMPO_LOW 0.5 // auto setting low tempo range (-50%)
517 #define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%)
518
519 // sequence-ms setting values at above low & top tempo
520 #define AUTOSEQ_AT_MIN 125.0
521 #define AUTOSEQ_AT_MAX 50.0
522 #define AUTOSEQ_K ((AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW))
523 #define AUTOSEQ_C (AUTOSEQ_AT_MIN - (AUTOSEQ_K) * (AUTOSEQ_TEMPO_LOW))
524
525 // seek-window-ms setting values at above low & top tempo
526 #define AUTOSEEK_AT_MIN 25.0
527 #define AUTOSEEK_AT_MAX 15.0
528 #define AUTOSEEK_K ((AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW))
529 #define AUTOSEEK_C (AUTOSEEK_AT_MIN - (AUTOSEEK_K) * (AUTOSEQ_TEMPO_LOW))
530
531 #define CHECK_LIMITS(x, mi, ma) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x)))
532
533 double seq, seek;
534
535 if (bAutoSeqSetting)
536 {
537 seq = AUTOSEQ_C + AUTOSEQ_K * tempo;
538 seq = CHECK_LIMITS(seq, AUTOSEQ_AT_MAX, AUTOSEQ_AT_MIN);
539 sequenceMs = (int)(seq + 0.5);
540 }
541
542 if (bAutoSeekSetting)
543 {
544 seek = AUTOSEEK_C + AUTOSEEK_K * tempo;
545 seek = CHECK_LIMITS(seek, AUTOSEEK_AT_MAX, AUTOSEEK_AT_MIN);
546 seekWindowMs = (int)(seek + 0.5);
547 }
548
549 // Update seek window lengths
550 seekWindowLength = (sampleRate * sequenceMs) / 1000;
551 if (seekWindowLength < 2 * overlapLength)
552 {
553 seekWindowLength = 2 * overlapLength;
554 }
555 seekLength = (sampleRate * seekWindowMs) / 1000;
556 }
557
558
559
560 // Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
561 // tempo, larger faster tempo.
562 void TDStretch::setTempo(float newTempo)
563 {
564 int intskip;
565
566 tempo = newTempo;
567
568 // Calculate new sequence duration
569 calcSeqParameters();
570
571 // Calculate ideal skip length (according to tempo value)
572 nominalSkip = tempo * (seekWindowLength - overlapLength);
573 intskip = (int)(nominalSkip + 0.5f);
574
575 // Calculate how many samples are needed in the 'inputBuffer' to
576 // process another batch of samples
577 //sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2;
578 sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength;
579 }
580
581
582
583 // Sets the number of channels, 1 = mono, 2 = stereo
584 void TDStretch::setChannels(int numChannels)
585 {
586 assert(numChannels > 0);
587 if (channels == numChannels) return;
588 assert(numChannels == 1 || numChannels == 2);
589
590 channels = numChannels;
591 inputBuffer.setChannels(channels);
592 outputBuffer.setChannels(channels);
593 }
594
595
596 // nominal tempo, no need for processing, just pass the samples through
597 // to outputBuffer
598 /*
599 void TDStretch::processNominalTempo()
600 {
601 assert(tempo == 1.0f);
602
603 if (bMidBufferDirty)
604 {
605 // If there are samples in pMidBuffer waiting for overlapping,
606 // do a single sliding overlapping with them in order to prevent a
607 // clicking distortion in the output sound
608 if (inputBuffer.numSamples() < overlapLength)
609 {
610 // wait until we've got overlapLength input samples
611 return;
612 }
613 // Mix the samples in the beginning of 'inputBuffer' with the
614 // samples in 'midBuffer' using sliding overlapping
615 overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0);
616 outputBuffer.putSamples(overlapLength);
617 inputBuffer.receiveSamples(overlapLength);
618 clearMidBuffer();
619 // now we've caught the nominal sample flow and may switch to
620 // bypass mode
621 }
622
623 // Simply bypass samples from input to output
624 outputBuffer.moveSamples(inputBuffer);
625 }
626 */
627
628 #include <stdio.h>
629
630 // Processes as many processing frames of the samples 'inputBuffer', store
631 // the result into 'outputBuffer'
632 void TDStretch::processSamples()
633 {
634 int ovlSkip, offset;
635 int temp;
636
637 /* Removed this small optimization - can introduce a click to sound when tempo setting
638 crosses the nominal value
639 if (tempo == 1.0f)
640 {
641 // tempo not changed from the original, so bypass the processing
642 processNominalTempo();
643 return;
644 }
645 */
646
647 // Process samples as long as there are enough samples in 'inputBuffer'
648 // to form a processing frame.
649 // while ((int)inputBuffer.numSamples() >= sampleReq - (outDebt / 4))
650 while ((int)inputBuffer.numSamples() >= sampleReq)
651 {
652 // If tempo differs from the normal ('SCALE'), scan for the best overlapping
653 // position
654 offset = seekBestOverlapPosition(inputBuffer.ptrBegin());
655
656 // Mix the samples in the 'inputBuffer' at position of 'offset' with the
657 // samples in 'midBuffer' using sliding overlapping
658 // ... first partially overlap with the end of the previous sequence
659 // (that's in 'midBuffer')
660 overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset);
661 outputBuffer.putSamples((uint)overlapLength);
662
663 // ... then copy sequence samples from 'inputBuffer' to output:
664 temp = (seekLength / 2 - offset);
665
666 // compensate cumulated output length diff vs. ideal output
667 // temp -= outDebt / 4;
668
669 // update ideal vs. true output difference
670 // outDebt += temp;
671
672 // length of sequence
673 // temp += (seekWindowLength - 2 * overlapLength);
674 temp = (seekWindowLength - 2 * overlapLength);
675
676 // crosscheck that we don't have buffer overflow...
677 if ((int)inputBuffer.numSamples() < (offset + temp + overlapLength * 2))
678 {
679 continue; // just in case, shouldn't really happen
680 }
681
682 outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), (uint)temp);
683
684 // Copies the end of the current sequence from 'inputBuffer' to
685 // 'midBuffer' for being mixed with the beginning of the next
686 // processing sequence and so on
687 assert((offset + temp + overlapLength * 2) <= (int)inputBuffer.numSamples());
688 memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp + overlapLength),
689 channels * sizeof(SAMPLETYPE) * overlapLength);
690
691 // Remove the processed samples from the input buffer. Update
692 // the difference between integer & nominal skip step to 'skipFract'
693 // in order to prevent the error from accumulating over time.
694 skipFract += nominalSkip; // real skip size
695 ovlSkip = (int)skipFract; // rounded to integer skip
696 skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip
697 inputBuffer.receiveSamples((uint)ovlSkip);
698 }
699 }
700
701
702 // Adds 'numsamples' pcs of samples from the 'samples' memory position into
703 // the input of the object.
704 void TDStretch::putSamples(const SAMPLETYPE *samples, uint nSamples)
705 {
706 // Add the samples into the input buffer
707 inputBuffer.putSamples(samples, nSamples);
708 // Process the samples in input buffer
709 processSamples();
710 }
711
712
713
714 /// Set new overlap length parameter & reallocate RefMidBuffer if necessary.
715 void TDStretch::acceptNewOverlapLength(int newOverlapLength)
716 {
717 int prevOvl;
718
719 assert(newOverlapLength >= 0);
720 prevOvl = overlapLength;
721 overlapLength = newOverlapLength;
722
723 if (overlapLength > prevOvl)
724 {
725 delete[] pMidBuffer;
726 delete[] pRefMidBufferUnaligned;
727
728 pMidBuffer = new SAMPLETYPE[overlapLength * 2];
729 clearMidBuffer();
730
731 pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)];
732 // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency
733 pRefMidBuffer = (SAMPLETYPE *)((((ulong)pRefMidBufferUnaligned) + 15) & (ulong)-16);
734 }
735 }
736
737
738 // Operator 'new' is overloaded so that it automatically creates a suitable instance
739 // depending on if we've a MMX/SSE/etc-capable CPU available or not.
740 void * TDStretch::operator new(size_t s)
741 {
742 // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
743 throw std::runtime_error("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!");
744 return NULL;
745 }
746
747
748 TDStretch * TDStretch::newInstance()
749 {
750 uint uExtensions;
751
752 uExtensions = detectCPUextensions();
753
754 // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
755
756 #ifdef ALLOW_MMX
757 // MMX routines available only with integer sample types
758 if (uExtensions & SUPPORT_MMX)
759 {
760 return ::new TDStretchMMX;
761 }
762 else
763 #endif // ALLOW_MMX
764
765
766 #ifdef ALLOW_SSE
767 if (uExtensions & SUPPORT_SSE)
768 {
769 // SSE support
770 return ::new TDStretchSSE;
771 }
772 else
773 #endif // ALLOW_SSE
774
775
776 #ifdef ALLOW_3DNOW
777 if (uExtensions & SUPPORT_3DNOW)
778 {
779 // 3DNow! support
780 return ::new TDStretch3DNow;
781 }
782 else
783 #endif // ALLOW_3DNOW
784
785 {
786 // ISA optimizations not supported, use plain C version
787 return ::new TDStretch;
788 }
789 }
790
791
792 //////////////////////////////////////////////////////////////////////////////
793 //
794 // Integer arithmetics specific algorithm implementations.
795 //
796 //////////////////////////////////////////////////////////////////////////////
797
798 #ifdef INTEGER_SAMPLES
799
800 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation
801 // is faster to calculate
802 void TDStretch::precalcCorrReferenceStereo()
803 {
804 int i, cnt2;
805 int temp, temp2;
806
807 for (i=0 ; i < (int)overlapLength ;i ++)
808 {
809 temp = i * (overlapLength - i);
810 cnt2 = i * 2;
811
812 temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider;
813 pRefMidBuffer[cnt2] = (short)(temp2);
814 temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider;
815 pRefMidBuffer[cnt2 + 1] = (short)(temp2);
816 }
817 }
818
819
820 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation
821 // is faster to calculate
822 void TDStretch::precalcCorrReferenceMono()
823 {
824 int i;
825 long temp;
826 long temp2;
827
828 for (i=0 ; i < (int)overlapLength ;i ++)
829 {
830 temp = i * (overlapLength - i);
831 temp2 = (pMidBuffer[i] * temp) / slopingDivider;
832 pRefMidBuffer[i] = (short)temp2;
833 }
834 }
835
836
837 // Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo'
838 // version of the routine.
839 void TDStretch::overlapStereo(short *poutput, const short *input) const
840 {
841 int i;
842 short temp;
843 int cnt2;
844
845 for (i = 0; i < overlapLength ; i ++)
846 {
847 temp = (short)(overlapLength - i);
848 cnt2 = 2 * i;
849 poutput[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength;
850 poutput[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength;
851 }
852 }
853
854 // Calculates the x having the closest 2^x value for the given value
855 static int _getClosest2Power(double value)
856 {
857 return (int)(log(value) / log(2.0) + 0.5);
858 }
859
860
861 /// Calculates overlap period length in samples.
862 /// Integer version rounds overlap length to closest power of 2
863 /// for a divide scaling operation.
864 void TDStretch::calculateOverlapLength(int aoverlapMs)
865 {
866 int newOvl;
867
868 assert(aoverlapMs >= 0);
869
870 // calculate overlap length so that it's power of 2 - thus it's easy to do
871 // integer division by right-shifting. Term "-1" at end is to account for
872 // the extra most significatnt bit left unused in result by signed multiplication
873 overlapDividerBits = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1;
874 if (overlapDividerBits > 9) overlapDividerBits = 9;
875 if (overlapDividerBits < 3) overlapDividerBits = 3;
876 newOvl = (int)pow(2.0, (int)overlapDividerBits + 1); // +1 => account for -1 above
877
878 acceptNewOverlapLength(newOvl);
879
880 // calculate sloping divider so that crosscorrelation operation won't
881 // overflow 32-bit register. Max. sum of the crosscorrelation sum without
882 // divider would be 2^30*(N^3-N)/3, where N = overlap length
883 slopingDivider = (newOvl * newOvl - 1) / 3;
884 }
885
886
887 long TDStretch::calcCrossCorrMono(const short *mixingPos, const short *compare) const
888 {
889 long corr;
890 long norm;
891 int i;
892
893 corr = norm = 0;
894 for (i = 1; i < overlapLength; i ++)
895 {
896 corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
897 norm += (mixingPos[i] * mixingPos[i]) >> overlapDividerBits;
898 }
899
900 // Normalize result by dividing by sqrt(norm) - this step is easiest
901 // done using floating point operation
902 if (norm == 0) norm = 1; // to avoid div by zero
903 return (long)((double)corr * SHRT_MAX / sqrt((double)norm));
904 }
905
906
907 long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const
908 {
909 long corr;
910 long norm;
911 int i;
912
913 corr = norm = 0;
914 for (i = 2; i < 2 * overlapLength; i += 2)
915 {
916 corr += (mixingPos[i] * compare[i] +
917 mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits;
918 norm += (mixingPos[i] * mixingPos[i] + mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBits;
919 }
920
921 // Normalize result by dividing by sqrt(norm) - this step is easiest
922 // done using floating point operation
923 if (norm == 0) norm = 1; // to avoid div by zero
924 return (long)((double)corr * SHRT_MAX / sqrt((double)norm));
925 }
926
927 #endif // INTEGER_SAMPLES
928
929 //////////////////////////////////////////////////////////////////////////////
930 //
931 // Floating point arithmetics specific algorithm implementations.
932 //
933
934 #ifdef FLOAT_SAMPLES
935
936
937 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation
938 // is faster to calculate
939 void TDStretch::precalcCorrReferenceStereo()
940 {
941 int i, cnt2;
942 float temp;
943
944 for (i=0 ; i < (int)overlapLength ;i ++)
945 {
946 temp = (float)i * (float)(overlapLength - i);
947 cnt2 = i * 2;
948 pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp);
949 pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp);
950 }
951 }
952
953
954 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation
955 // is faster to calculate
956 void TDStretch::precalcCorrReferenceMono()
957 {
958 int i;
959 float temp;
960
961 for (i=0 ; i < (int)overlapLength ;i ++)
962 {
963 temp = (float)i * (float)(overlapLength - i);
964 pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp);
965 }
966 }
967
968
969 // Overlaps samples in 'midBuffer' with the samples in 'pInput'
970 void TDStretch::overlapStereo(float *pOutput, const float *pInput) const
971 {
972 int i;
973 int cnt2;
974 float fTemp;
975 float fScale;
976 float fi;
977
978 fScale = 1.0f / (float)overlapLength;
979
980 for (i = 0; i < (int)overlapLength ; i ++)
981 {
982 fTemp = (float)(overlapLength - i) * fScale;
983 fi = (float)i * fScale;
984 cnt2 = 2 * i;
985 pOutput[cnt2 + 0] = pInput[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp;
986 pOutput[cnt2 + 1] = pInput[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp;
987 }
988 }
989
990
991 /// Calculates overlapInMsec period length in samples.
992 void TDStretch::calculateOverlapLength(int overlapInMsec)
993 {
994 int newOvl;
995
996 assert(overlapInMsec >= 0);
997 newOvl = (sampleRate * overlapInMsec) / 1000;
998 if (newOvl < 16) newOvl = 16;
999
1000 // must be divisible by 8
1001 newOvl -= newOvl % 8;
1002
1003 acceptNewOverlapLength(newOvl);
1004 }
1005
1006
1007
1008 double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const
1009 {
1010 double corr;
1011 double norm;
1012 int i;
1013
1014 corr = norm = 0;
1015 for (i = 1; i < overlapLength; i ++)
1016 {
1017 corr += mixingPos[i] * compare[i];
1018 norm += mixingPos[i] * mixingPos[i];
1019 }
1020
1021 if (norm < 1e-9) norm = 1.0; // to avoid div by zero
1022 return corr / sqrt(norm);
1023 }
1024
1025
1026 double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const
1027 {
1028 double corr;
1029 double norm;
1030 int i;
1031
1032 corr = norm = 0;
1033 for (i = 2; i < 2 * overlapLength; i += 2)
1034 {
1035 corr += mixingPos[i] * compare[i] +
1036 mixingPos[i + 1] * compare[i + 1];
1037 norm += mixingPos[i] * mixingPos[i] +
1038 mixingPos[i + 1] * mixingPos[i + 1];
1039 }
1040
1041 if (norm < 1e-9) norm = 1.0; // to avoid div by zero
1042 return corr / sqrt(norm);
1043 }
1044
1045 #endif // FLOAT_SAMPLES

  ViewVC Help
Powered by ViewVC 1.1.22