00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00043
00044 #include <string.h>
00045 #include <stdlib.h>
00046 #include <memory.h>
00047 #include <limits.h>
00048 #include <math.h>
00049 #include <assert.h>
00050
00051 #include "STTypes.h"
00052 #include "cpu_detect.h"
00053 #include "TDStretch.h"
00054
00055 using namespace soundtouch;
00056
00057 #ifndef min
00058 #define min(a,b) ((a > b) ? b : a)
00059 #define max(a,b) ((a < b) ? b : a)
00060 #endif
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #define MAX_SCAN_DELTA 124
00072
00073
00074 int scanOffsets[4][24]={
00075 { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806,
00076 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0},
00077 {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0,
00078 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00079 { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0,
00080 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00081 { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0,
00082 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
00083
00084
00085
00086
00087
00088
00089
00090
00091 TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)
00092 {
00093 bQuickseek = FALSE;
00094 channels = 2;
00095 bMidBufferDirty = FALSE;
00096
00097 pMidBuffer = NULL;
00098 pRefMidBufferUnaligned = NULL;
00099 midBufferLength = 0;
00100 overlapLength = 0;
00101
00102 setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS);
00103
00104 setTempo(1.0f);
00105 }
00106
00107
00108
00109
00110 TDStretch::~TDStretch()
00111 {
00112 if (midBufferLength)
00113 {
00114 delete[] pMidBuffer;
00115 delete[] pRefMidBufferUnaligned;
00116 midBufferLength = 0;
00117 }
00118 }
00119
00120
00121
00122
00123 static int _getClosest2Power(double value)
00124 {
00125 return (int)(log(value) / log(2.0) + 0.5);
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS,
00140 uint aSeekWindowMS, uint aOverlapMS)
00141 {
00142 this->sampleRate = aSampleRate;
00143 this->sequenceMs = aSequenceMS;
00144 this->seekWindowMs = aSeekWindowMS;
00145 this->overlapMs = aOverlapMS;
00146
00147 seekLength = (sampleRate * seekWindowMs) / 1000;
00148 seekWindowLength = (sampleRate * sequenceMs) / 1000;
00149
00150 maxOffset = seekLength;
00151
00152 calculateOverlapLength(overlapMs);
00153
00154
00155 setTempo(tempo);
00156
00157 }
00158
00159
00160
00164 void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs)
00165 {
00166 if (pSampleRate)
00167 {
00168 *pSampleRate = sampleRate;
00169 }
00170
00171 if (pSequenceMs)
00172 {
00173 *pSequenceMs = sequenceMs;
00174 }
00175
00176 if (pSeekWindowMs)
00177 {
00178 *pSeekWindowMs = seekWindowMs;
00179 }
00180
00181 if (pOverlapMs)
00182 {
00183 *pOverlapMs = overlapMs;
00184 }
00185 }
00186
00187
00188
00189 void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const
00190 {
00191 int i, itemp;
00192
00193 for (i = 0; i < (int)overlapLength ; i ++)
00194 {
00195 itemp = overlapLength - i;
00196 output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength;
00197 }
00198 }
00199
00200
00201
00202 void TDStretch::clearMidBuffer()
00203 {
00204 if (bMidBufferDirty && midBufferLength)
00205 {
00206 memset(pMidBuffer, 0, channels * sizeof(SAMPLETYPE) * overlapLength);
00207 bMidBufferDirty = FALSE;
00208 }
00209 }
00210
00211
00212 void TDStretch::clearInput()
00213 {
00214 inputBuffer.clear();
00215 clearMidBuffer();
00216 }
00217
00218
00219
00220 void TDStretch::clear()
00221 {
00222 outputBuffer.clear();
00223 inputBuffer.clear();
00224 clearMidBuffer();
00225 }
00226
00227
00228
00229
00230
00231 void TDStretch::enableQuickSeek(BOOL enable)
00232 {
00233 bQuickseek = enable;
00234 }
00235
00236
00237
00238 BOOL TDStretch::isQuickSeekEnabled() const
00239 {
00240 return bQuickseek;
00241 }
00242
00243
00244
00245 uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)
00246 {
00247 #ifdef MULTICHANNEL
00248 if (channels > 2)
00249 {
00250
00251 if (bQuickseek)
00252 {
00253 return seekBestOverlapPositionMultiQuick(refPos);
00254 }
00255 else
00256 {
00257 return seekBestOverlapPositionMulti(refPos);
00258 }
00259 }
00260 else
00261 #endif
00262 if (channels == 2)
00263 {
00264
00265 if (bQuickseek)
00266 {
00267 return seekBestOverlapPositionStereoQuick(refPos);
00268 }
00269 else
00270 {
00271 return seekBestOverlapPositionStereo(refPos);
00272 }
00273 }
00274 else
00275 {
00276
00277 if (bQuickseek)
00278 {
00279 return seekBestOverlapPositionMonoQuick(refPos);
00280 }
00281 else
00282 {
00283 return seekBestOverlapPositionMono(refPos);
00284 }
00285 }
00286 }
00287
00288
00289
00290
00291
00292
00293 inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const
00294 {
00295 #ifdef MULTICHANNEL
00296 if (channels > 2)
00297 {
00298 overlapMulti(output, input + channels * ovlPos);
00299 }
00300 else
00301 #endif
00302 if (channels == 2)
00303 {
00304
00305 overlapStereo(output, input + 2 * ovlPos);
00306 } else {
00307
00308 overlapMono(output, input + ovlPos);
00309 }
00310 }
00311
00312
00313
00314
00315 #ifdef MULTICHANNEL
00316
00317
00318
00319
00320
00321
00322 uint TDStretch::seekBestOverlapPositionMulti(const SAMPLETYPE *refPos)
00323 {
00324 uint bestOffs;
00325 LONG_SAMPLETYPE bestCorr, corr;
00326 uint i;
00327
00328
00329 precalcCorrReference();
00330
00331 bestCorr = INT_MIN;
00332 bestOffs = 0;
00333
00334
00335
00336 for (i = 0; i < seekLength; i ++)
00337 {
00338
00339
00340 corr = calcCrossCorrMulti(refPos + channels * i, pRefMidBuffer);
00341
00342
00343 if (corr > bestCorr)
00344 {
00345 bestCorr = corr;
00346 bestOffs = i;
00347 }
00348 }
00349
00350 clearCrossCorrState();
00351
00352 return bestOffs;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361
00362 uint TDStretch::seekBestOverlapPositionMultiQuick(const SAMPLETYPE *refPos)
00363 {
00364 uint j;
00365 uint bestOffs;
00366 LONG_SAMPLETYPE bestCorr, corr;
00367 uint scanCount, corrOffset, tempOffset;
00368
00369
00370 precalcCorrReference();
00371
00372 bestCorr = INT_MIN;
00373 bestOffs = 0;
00374 corrOffset = 0;
00375 tempOffset = 0;
00376
00377
00378
00379
00380
00381
00382
00383 for (scanCount = 0;scanCount < 4; scanCount ++)
00384 {
00385 j = 0;
00386 while (scanOffsets[scanCount][j])
00387 {
00388 tempOffset = corrOffset + scanOffsets[scanCount][j];
00389 if (tempOffset >= seekLength) break;
00390
00391
00392
00393 corr = calcCrossCorrMulti(refPos + channels * tempOffset, pRefMidBuffer);
00394
00395
00396 if (corr > bestCorr)
00397 {
00398 bestCorr = corr;
00399 bestOffs = tempOffset;
00400 }
00401 j ++;
00402 }
00403 corrOffset = bestOffs;
00404 }
00405
00406 clearCrossCorrState();
00407
00408 return bestOffs;
00409 }
00410 #endif
00411
00412
00413
00414
00415
00416
00417
00418 uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos)
00419 {
00420 uint bestOffs;
00421 LONG_SAMPLETYPE bestCorr, corr;
00422 uint i;
00423
00424
00425 precalcCorrReferenceStereo();
00426
00427 bestCorr = INT_MIN;
00428 bestOffs = 0;
00429
00430
00431
00432 for (i = 0; i < seekLength; i ++)
00433 {
00434
00435
00436 corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer);
00437
00438
00439 if (corr > bestCorr)
00440 {
00441 bestCorr = corr;
00442 bestOffs = i;
00443 }
00444 }
00445
00446 clearCrossCorrState();
00447
00448 return bestOffs;
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458 uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos)
00459 {
00460 uint j;
00461 uint bestOffs;
00462 LONG_SAMPLETYPE bestCorr, corr;
00463 uint scanCount, corrOffset, tempOffset;
00464
00465
00466 precalcCorrReferenceStereo();
00467
00468 bestCorr = INT_MIN;
00469 bestOffs = 0;
00470 corrOffset = 0;
00471 tempOffset = 0;
00472
00473
00474
00475
00476
00477
00478
00479 for (scanCount = 0;scanCount < 4; scanCount ++)
00480 {
00481 j = 0;
00482 while (scanOffsets[scanCount][j])
00483 {
00484 tempOffset = corrOffset + scanOffsets[scanCount][j];
00485 if (tempOffset >= seekLength) break;
00486
00487
00488
00489 corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer);
00490
00491
00492 if (corr > bestCorr)
00493 {
00494 bestCorr = corr;
00495 bestOffs = tempOffset;
00496 }
00497 j ++;
00498 }
00499 corrOffset = bestOffs;
00500 }
00501
00502 clearCrossCorrState();
00503
00504 return bestOffs;
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos)
00516 {
00517 uint bestOffs;
00518 LONG_SAMPLETYPE bestCorr, corr;
00519 uint tempOffset;
00520 const SAMPLETYPE *compare;
00521
00522
00523 precalcCorrReferenceMono();
00524
00525 bestCorr = INT_MIN;
00526 bestOffs = 0;
00527
00528
00529
00530 for (tempOffset = 0; tempOffset < seekLength; tempOffset ++)
00531 {
00532 compare = refPos + tempOffset;
00533
00534
00535
00536 corr = calcCrossCorrMono(pRefMidBuffer, compare);
00537
00538
00539 if (corr > bestCorr)
00540 {
00541 bestCorr = corr;
00542 bestOffs = tempOffset;
00543 }
00544 }
00545
00546 clearCrossCorrState();
00547
00548 return bestOffs;
00549 }
00550
00551
00552
00553
00554
00555
00556
00557
00558 uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos)
00559 {
00560 uint j;
00561 uint bestOffs;
00562 LONG_SAMPLETYPE bestCorr, corr;
00563 uint scanCount, corrOffset, tempOffset;
00564
00565
00566 precalcCorrReferenceMono();
00567
00568 bestCorr = INT_MIN;
00569 bestOffs = 0;
00570 corrOffset = 0;
00571 tempOffset = 0;
00572
00573
00574
00575
00576
00577
00578
00579 for (scanCount = 0;scanCount < 4; scanCount ++)
00580 {
00581 j = 0;
00582 while (scanOffsets[scanCount][j])
00583 {
00584 tempOffset = corrOffset + scanOffsets[scanCount][j];
00585 if (tempOffset >= seekLength) break;
00586
00587
00588
00589 corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer);
00590
00591
00592 if (corr > bestCorr)
00593 {
00594 bestCorr = corr;
00595 bestOffs = tempOffset;
00596 }
00597 j ++;
00598 }
00599 corrOffset = bestOffs;
00600 }
00601
00602 clearCrossCorrState();
00603
00604 return bestOffs;
00605 }
00606
00607
00609 void TDStretch::clearCrossCorrState()
00610 {
00611
00612 }
00613
00614
00615
00616
00617 void TDStretch::setTempo(float newTempo)
00618 {
00619 uint intskip;
00620
00621 tempo = newTempo;
00622
00623
00624 nominalSkip = tempo * (seekWindowLength - overlapLength);
00625 skipFract = 0;
00626 intskip = (int)(nominalSkip + 0.5f);
00627
00628
00629
00630 sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset;
00631 }
00632
00633
00634
00635
00636 void TDStretch::setChannels(uint numChannels)
00637 {
00638 if (channels == numChannels) return;
00639 #ifdef MULTICHANNEL
00640 assert(numChannels >= 1 && numChannels <= MULTICHANNEL);
00641 #else
00642 assert(numChannels == 1 || numChannels == 2);
00643 #endif
00644
00645 channels = numChannels;
00646 inputBuffer.setChannels(channels);
00647 outputBuffer.setChannels(channels);
00648 }
00649
00650
00651
00652
00653 void TDStretch::processNominalTempo()
00654 {
00655 assert(tempo == 1.0f);
00656
00657 if (bMidBufferDirty)
00658 {
00659
00660
00661
00662 if (inputBuffer.numSamples() < overlapLength)
00663 {
00664
00665 return;
00666 }
00667
00668
00669 overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0);
00670 outputBuffer.putSamples(overlapLength);
00671 inputBuffer.receiveSamples(overlapLength);
00672 clearMidBuffer();
00673
00674
00675 }
00676
00677
00678 outputBuffer.moveSamples(inputBuffer);
00679 }
00680
00681
00682
00683
00684 void TDStretch::processSamples()
00685 {
00686 uint ovlSkip, offset;
00687 int temp;
00688
00689 if (tempo == 1.0f)
00690 {
00691
00692 processNominalTempo();
00693 return;
00694 }
00695
00696 if (bMidBufferDirty == FALSE)
00697 {
00698
00699
00700 if (inputBuffer.numSamples() < overlapLength)
00701 {
00702
00703 return;
00704 }
00705 memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE));
00706 inputBuffer.receiveSamples(overlapLength);
00707 bMidBufferDirty = TRUE;
00708 }
00709
00710
00711
00712 while (inputBuffer.numSamples() >= sampleReq)
00713 {
00714
00715
00716 offset = seekBestOverlapPosition(inputBuffer.ptrBegin());
00717
00718
00719
00720
00721
00722 overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset);
00723 outputBuffer.putSamples(overlapLength);
00724
00725
00726 temp = (seekWindowLength - 2 * overlapLength);
00727 if (temp > 0)
00728 {
00729 outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp);
00730 }
00731
00732
00733
00734
00735 assert(offset + seekWindowLength <= inputBuffer.numSamples());
00736 memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength),
00737 channels * sizeof(SAMPLETYPE) * overlapLength);
00738 bMidBufferDirty = TRUE;
00739
00740
00741
00742
00743 skipFract += nominalSkip;
00744 ovlSkip = (int)skipFract;
00745 skipFract -= ovlSkip;
00746 inputBuffer.receiveSamples(ovlSkip);
00747 }
00748 }
00749
00750
00751
00752
00753 void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples)
00754 {
00755
00756 inputBuffer.putSamples(samples, numSamples);
00757
00758 processSamples();
00759 }
00760
00761
00762
00764 void TDStretch::acceptNewOverlapLength(uint newOverlapLength)
00765 {
00766 overlapLength = newOverlapLength;
00767
00768 if (overlapLength*channels > midBufferLength)
00769 {
00770 if (midBufferLength)
00771 {
00772 delete[] pMidBuffer;
00773 delete[] pRefMidBufferUnaligned;
00774 midBufferLength = 0;
00775 }
00776
00777 midBufferLength = overlapLength * channels;
00778 pMidBuffer = new SAMPLETYPE[midBufferLength];
00779 bMidBufferDirty = TRUE;
00780 clearMidBuffer();
00781
00782 pRefMidBufferUnaligned = new SAMPLETYPE[midBufferLength + 16 / sizeof(SAMPLETYPE)];
00783
00784 pRefMidBuffer = (SAMPLETYPE *)((((ulong)pRefMidBufferUnaligned) + 15) & -16);
00785 }
00786 }
00787
00788
00789
00790
00791 void * TDStretch::operator new(size_t s)
00792 {
00793
00794 assert(FALSE);
00795 return NULL;
00796 }
00797
00798
00799 TDStretch * TDStretch::newInstance()
00800 {
00801 uint uExtensions;
00802
00803 uExtensions = detectCPUextensions();
00804
00805
00806
00807 #ifdef ALLOW_MMX
00808
00809 if (uExtensions & MM_MMX)
00810 {
00811 return ::new TDStretchMMX;
00812 }
00813 else
00814 #endif // ALLOW_MMX
00815
00816
00817 #ifdef ALLOW_SSE
00818 if (uExtensions & MM_SSE)
00819 {
00820
00821 return ::new TDStretchSSE;
00822 }
00823 else
00824 #endif // ALLOW_SSE
00825
00826
00827 #ifdef ALLOW_3DNOW
00828 if (uExtensions & MM_3DNOW)
00829 {
00830
00831 return ::new TDStretch3DNow;
00832 }
00833 else
00834 #endif // ALLOW_3DNOW
00835
00836 {
00837
00838 return ::new TDStretch;
00839 }
00840 }
00841
00842
00844
00845
00846
00848
00849 #ifdef INTEGER_SAMPLES
00850
00851 #ifdef MULTICHANNEL
00852
00853
00854 void TDStretch::precalcCorrReference()
00855 {
00856 int i,j;
00857 int temp, temp2;
00858 short *src = pMidBuffer;
00859 short *dest = pRefMidBuffer;
00860
00861 for (i=0 ; i < (int)overlapLength ;i ++)
00862 {
00863 temp = i * (overlapLength - i);
00864
00865 for(j=0;j<channels;j++)
00866 {
00867 temp2 = (*src++ * temp) / slopingDivider;
00868 *dest++ = (short)(temp2);
00869 }
00870 }
00871 }
00872 #endif
00873
00874
00875
00876 void TDStretch::precalcCorrReferenceStereo()
00877 {
00878 int i, cnt2;
00879 int temp, temp2;
00880
00881 for (i=0 ; i < (int)overlapLength ;i ++)
00882 {
00883 temp = i * (overlapLength - i);
00884 cnt2 = i * 2;
00885
00886 temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider;
00887 pRefMidBuffer[cnt2] = (short)(temp2);
00888 temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider;
00889 pRefMidBuffer[cnt2 + 1] = (short)(temp2);
00890 }
00891 }
00892
00893
00894
00895
00896 void TDStretch::precalcCorrReferenceMono()
00897 {
00898 int i;
00899 long temp;
00900 long temp2;
00901
00902 for (i=0 ; i < (int)overlapLength ;i ++)
00903 {
00904 temp = i * (overlapLength - i);
00905 temp2 = (pMidBuffer[i] * temp) / slopingDivider;
00906 pRefMidBuffer[i] = (short)temp2;
00907 }
00908 }
00909
00910
00911
00912
00913 void TDStretch::overlapStereo(short *output, const short *input) const
00914 {
00915 int i;
00916 short temp;
00917 uint cnt2;
00918
00919 for (i = 0; i < (int)overlapLength ; i ++)
00920 {
00921 temp = (short)(overlapLength - i);
00922 cnt2 = 2 * i;
00923 output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength;
00924 output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength;
00925 }
00926 }
00927
00928 #ifdef MULTICHANNEL
00929
00930
00931 void TDStretch::overlapMulti(short *output, const short *input) const
00932 {
00933 int i,j;
00934 short temp;
00935
00936 const short *ip = input;
00937 short *op = output;
00938 const short *md = pMidBuffer;
00939
00940 for (i = 0; i < (int)overlapLength ; i ++)
00941 {
00942 temp = (short)(overlapLength - i);
00943 for(j=0;j<channels;j++)
00944 *op++ = (*ip++ * i + *md++ * temp ) / overlapLength;
00945 }
00946 }
00947 #endif
00948
00949
00953 void TDStretch::calculateOverlapLength(uint overlapMs)
00954 {
00955 uint newOvl;
00956
00957 overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0);
00958 if (overlapDividerBits > 9) overlapDividerBits = 9;
00959 if (overlapDividerBits < 4) overlapDividerBits = 4;
00960 newOvl = (uint)pow(2, overlapDividerBits);
00961
00962 acceptNewOverlapLength(newOvl);
00963
00964
00965
00966
00967 slopingDivider = (newOvl * newOvl - 1) / 3;
00968 }
00969
00970
00971 long TDStretch::calcCrossCorrMono(const short *mixingPos, const short *compare) const
00972 {
00973 long corr;
00974 uint i;
00975
00976 corr = 0;
00977 for (i = 1; i < overlapLength; i ++)
00978 {
00979 corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
00980 }
00981
00982 return corr;
00983 }
00984
00985
00986 long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const
00987 {
00988 long corr;
00989 uint i;
00990
00991 corr = 0;
00992 for (i = 2; i < 2 * overlapLength; i += 2)
00993 {
00994 corr += (mixingPos[i] * compare[i] +
00995 mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits;
00996 }
00997
00998 return corr;
00999 }
01000
01001 #ifdef MULTICHANNEL
01002 long TDStretch::calcCrossCorrMulti(const short *mixingPos, const short *compare) const
01003 {
01004 long corr;
01005 uint i;
01006
01007 corr = 0;
01008 for (i = channels; i < channels * overlapLength; i++)
01009 {
01010 corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
01011 }
01012
01013 return corr;
01014 }
01015 #endif
01016
01017 #endif // INTEGER_SAMPLES
01018
01020
01021
01022
01023
01024 #ifdef FLOAT_SAMPLES
01025
01026
01027
01028
01029 void TDStretch::precalcCorrReferenceStereo()
01030 {
01031 int i, cnt2;
01032 float temp;
01033
01034 for (i=0 ; i < (int)overlapLength ;i ++)
01035 {
01036 temp = (float)i * (float)(overlapLength - i);
01037 cnt2 = i * 2;
01038 pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp);
01039 pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp);
01040 }
01041 }
01042
01043
01044
01045
01046 void TDStretch::precalcCorrReferenceMono()
01047 {
01048 int i;
01049 float temp;
01050
01051 for (i=0 ; i < (int)overlapLength ;i ++)
01052 {
01053 temp = (float)i * (float)(overlapLength - i);
01054 pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp);
01055 }
01056 }
01057
01058
01059
01060 void TDStretch::overlapStereo(float *output, const float *input) const
01061 {
01062 int i;
01063 uint cnt2;
01064 float fTemp;
01065 float fScale;
01066 float fi;
01067
01068 fScale = 1.0f / (float)overlapLength;
01069
01070 for (i = 0; i < (int)overlapLength ; i ++)
01071 {
01072 fTemp = (float)(overlapLength - i) * fScale;
01073 fi = (float)i * fScale;
01074 cnt2 = 2 * i;
01075 output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp;
01076 output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp;
01077 }
01078 }
01079
01080
01082 void TDStretch::calculateOverlapLength(uint overlapMs)
01083 {
01084 uint newOvl;
01085
01086 newOvl = (sampleRate * overlapMs) / 1000;
01087 if (newOvl < 16) newOvl = 16;
01088
01089
01090 newOvl -= newOvl % 8;
01091
01092 acceptNewOverlapLength(newOvl);
01093 }
01094
01095
01096
01097 double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const
01098 {
01099 double corr;
01100 uint i;
01101
01102 corr = 0;
01103 for (i = 1; i < overlapLength; i ++)
01104 {
01105 corr += mixingPos[i] * compare[i];
01106 }
01107
01108 return corr;
01109 }
01110
01111
01112 double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const
01113 {
01114 double corr;
01115 uint i;
01116
01117 corr = 0;
01118 for (i = 2; i < 2 * overlapLength; i += 2)
01119 {
01120 corr += mixingPos[i] * compare[i] +
01121 mixingPos[i + 1] * compare[i + 1];
01122 }
01123
01124 return corr;
01125 }
01126
01127 #endif // FLOAT_SAMPLES