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 #ifdef ALLOW_SSE3
00807 if (uExtensions & MM_SSE3)
00808 {
00809
00810 return ::new TDStretchSSE3;
00811 }
00812 else
00813 #endif // ALLOW_SSE3
00814 #ifdef ALLOW_SSE2
00815 if (uExtensions & MM_SSE2)
00816 {
00817
00818 return ::new TDStretchSSE2;
00819 }
00820 else
00821 #endif // ALLOW_SSE2
00822 {
00823
00824 return ::new TDStretch;
00825 }
00826 }
00827
00828
00830
00831
00832
00834
00835 #ifdef INTEGER_SAMPLES
00836
00837 #ifdef MULTICHANNEL
00838
00839
00840 void TDStretch::precalcCorrReference()
00841 {
00842 int i,j;
00843 int temp, temp2;
00844 short *src = pMidBuffer;
00845 short *dest = pRefMidBuffer;
00846
00847 for (i=0 ; i < (int)overlapLength ;i ++)
00848 {
00849 temp = i * (overlapLength - i);
00850
00851 for(j=0;j<channels;j++)
00852 {
00853 temp2 = (*src++ * temp) / slopingDivider;
00854 *dest++ = (short)(temp2);
00855 }
00856 }
00857 }
00858 #endif
00859
00860
00861
00862 void TDStretch::precalcCorrReferenceStereo()
00863 {
00864 int i, cnt2;
00865 int temp, temp2;
00866
00867 for (i=0 ; i < (int)overlapLength ;i ++)
00868 {
00869 temp = i * (overlapLength - i);
00870 cnt2 = i * 2;
00871
00872 temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider;
00873 pRefMidBuffer[cnt2] = (short)(temp2);
00874 temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider;
00875 pRefMidBuffer[cnt2 + 1] = (short)(temp2);
00876 }
00877 }
00878
00879
00880
00881
00882 void TDStretch::precalcCorrReferenceMono()
00883 {
00884 int i;
00885 long temp;
00886 long temp2;
00887
00888 for (i=0 ; i < (int)overlapLength ;i ++)
00889 {
00890 temp = i * (overlapLength - i);
00891 temp2 = (pMidBuffer[i] * temp) / slopingDivider;
00892 pRefMidBuffer[i] = (short)temp2;
00893 }
00894 }
00895
00896
00897
00898
00899 void TDStretch::overlapStereo(short *output, const short *input) const
00900 {
00901 int i;
00902 short temp;
00903 uint cnt2;
00904
00905 for (i = 0; i < (int)overlapLength ; i ++)
00906 {
00907 temp = (short)(overlapLength - i);
00908 cnt2 = 2 * i;
00909 output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength;
00910 output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength;
00911 }
00912 }
00913
00914 #ifdef MULTICHANNEL
00915
00916
00917 void TDStretch::overlapMulti(short *output, const short *input) const
00918 {
00919 int i,j;
00920 short temp;
00921
00922 const short *ip = input;
00923 short *op = output;
00924 const short *md = pMidBuffer;
00925
00926 for (i = 0; i < (int)overlapLength ; i ++)
00927 {
00928 temp = (short)(overlapLength - i);
00929 for(j=0;j<channels;j++)
00930 *op++ = (*ip++ * i + *md++ * temp ) / overlapLength;
00931 }
00932 }
00933 #endif
00934
00935
00939 void TDStretch::calculateOverlapLength(uint overlapMs)
00940 {
00941 uint newOvl;
00942
00943 overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0);
00944 if (overlapDividerBits > 9) overlapDividerBits = 9;
00945 if (overlapDividerBits < 4) overlapDividerBits = 4;
00946 newOvl = (uint)pow(2, overlapDividerBits);
00947
00948 acceptNewOverlapLength(newOvl);
00949
00950
00951
00952
00953 slopingDivider = (newOvl * newOvl - 1) / 3;
00954 }
00955
00956
00957 long TDStretch::calcCrossCorrMono(const short *mixingPos, const short *compare) const
00958 {
00959 long corr;
00960 uint i;
00961
00962 corr = 0;
00963 for (i = 1; i < overlapLength; i ++)
00964 {
00965 corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
00966 }
00967
00968 return corr;
00969 }
00970
00971
00972 long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const
00973 {
00974 long corr;
00975 uint i;
00976
00977 corr = 0;
00978 for (i = 2; i < 2 * overlapLength; i += 2)
00979 {
00980 corr += (mixingPos[i] * compare[i] +
00981 mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits;
00982 }
00983
00984 return corr;
00985 }
00986
00987 #ifdef MULTICHANNEL
00988 long TDStretch::calcCrossCorrMulti(const short *mixingPos, const short *compare) const
00989 {
00990 long corr;
00991 uint i;
00992
00993 corr = 0;
00994 for (i = channels; i < channels * overlapLength; i++)
00995 {
00996 corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
00997 }
00998
00999 return corr;
01000 }
01001 #endif
01002
01003 #endif // INTEGER_SAMPLES
01004
01006
01007
01008
01009
01010 #ifdef FLOAT_SAMPLES
01011
01012
01013
01014 void TDStretch::precalcCorrReferenceStereo()
01015 {
01016 int i, cnt2;
01017 float temp;
01018
01019 for (i=0 ; i < (int)overlapLength ;i ++)
01020 {
01021 temp = (float)i * (float)(overlapLength - i);
01022 cnt2 = i * 2;
01023 pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp);
01024 pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp);
01025 }
01026 }
01027
01028 #ifdef MULTICHANNEL
01029
01030
01031 void TDStretch::precalcCorrReference()
01032 {
01033 int i,j;
01034 float temp, temp2;
01035 float *src = pMidBuffer;
01036 float *dest = pRefMidBuffer;
01037
01038 for (i = 0 ; i < (int)overlapLength ; i++)
01039 {
01040 temp = (float)i * (float)(overlapLength - i);
01041
01042 for(j = 0; j < channels; j++)
01043 {
01044 temp2 = (float)(*src++ * temp);
01045 *dest++ = temp2;
01046 }
01047 }
01048 }
01049 #endif
01050
01051
01052
01053 void TDStretch::precalcCorrReferenceMono()
01054 {
01055 int i;
01056 float temp;
01057
01058 for (i=0 ; i < (int)overlapLength ;i ++)
01059 {
01060 temp = (float)i * (float)(overlapLength - i);
01061 pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp);
01062 }
01063 }
01064
01065
01066 void TDStretch::overlapStereo(float *output, const float *input) const
01067 {
01068 int i;
01069 uint cnt2;
01070 float fTemp;
01071 float fScale;
01072 float fi;
01073
01074 fScale = 1.0f / (float)overlapLength;
01075
01076 for (i = 0; i < (int)overlapLength ; i ++)
01077 {
01078 fTemp = (float)(overlapLength - i) * fScale;
01079 fi = (float)i * fScale;
01080 cnt2 = 2 * i;
01081 output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp;
01082 output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp;
01083 }
01084 }
01085
01086 #ifdef MULTICHANNEL
01087
01088 void TDStretch::overlapMulti(float *output, const float *input) const
01089 {
01090 int i,j;
01091 float temp;
01092 const float *ip = input;
01093 float *op = output;
01094 const float *md = pMidBuffer;
01095 float fScale = 1.0f / (float)overlapLength;
01096 float fi;
01097
01098 for (i = 0; i < (int)overlapLength ; i ++)
01099 {
01100 temp = (float)(overlapLength - i) * fScale;
01101 fi = (float)i * fScale;
01102 for(j = 0; j < channels; j++)
01103 *op++ = (*ip++ * fi + *md++ * temp);
01104 }
01105 }
01106 #endif
01107
01109 void TDStretch::calculateOverlapLength(uint overlapMs)
01110 {
01111 uint newOvl;
01112
01113 newOvl = (sampleRate * overlapMs) / 1000;
01114 if (newOvl < 16) newOvl = 16;
01115
01116
01117 newOvl -= newOvl % 8;
01118
01119 acceptNewOverlapLength(newOvl);
01120 }
01121
01122
01123
01124 double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const
01125 {
01126 double corr;
01127 uint i;
01128
01129 corr = 0;
01130 for (i = 1; i < overlapLength; i ++)
01131 {
01132 corr += mixingPos[i] * compare[i];
01133 }
01134
01135 return corr;
01136 }
01137
01138
01139 double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const
01140 {
01141 double corr;
01142 uint i;
01143
01144 corr = 0;
01145 for (i = 2; i < 2 * overlapLength; i += 2)
01146 {
01147 corr += mixingPos[i] * compare[i] +
01148 mixingPos[i + 1] * compare[i + 1];
01149 }
01150
01151 return corr;
01152 }
01153
01154 #ifdef MULTICHANNEL
01155 double TDStretch::calcCrossCorrMulti(const float *mixingPos, const float *compare) const
01156 {
01157 double corr;
01158 uint i;
01159
01160 corr = 0;
01161 for (i = channels; i < channels * overlapLength; i++)
01162 {
01163 corr += mixingPos[i] * compare[i];
01164 }
01165
01166 return corr;
01167 }
01168 #endif
01169
01170 #endif // FLOAT_SAMPLES