|
MythTV
0.26-pre
|
00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 00014 00015 // 00016 // Last changed : $Date$ 00017 // File revision : $Revision$ 00018 // 00019 // $Id$ 00020 // 00022 // 00023 // License : 00024 // 00025 // SoundTouch audio processing library 00026 // Copyright (c) Olli Parviainen 00027 // 00028 // This library is free software; you can redistribute it and/or 00029 // modify it under the terms of the GNU Lesser General Public 00030 // License as published by the Free Software Foundation; either 00031 // version 2.1 of the License, or (at your option) any later version. 00032 // 00033 // This library is distributed in the hope that it will be useful, 00034 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00035 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00036 // Lesser General Public License for more details. 00037 // 00038 // You should have received a copy of the GNU Lesser General Public 00039 // License along with this library; if not, write to the Free Software 00040 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 * Constant definitions 00067 * 00068 *****************************************************************************/ 00069 00070 00071 #define MAX_SCAN_DELTA 124 00072 00073 // Table for the hierarchical mixing position seeking algorithm 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 * Implementation of the class 'TDStretch' 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 // Calculates the x having the closest 2^x value for the given value 00123 static int _getClosest2Power(double value) 00124 { 00125 return (int)(log(value) / log(2.0) + 0.5); 00126 } 00127 00128 00129 00130 // Sets routine control parameters. These control are certain time constants 00131 // defining how the sound is stretched to the desired duration. 00132 // 00133 // 'sampleRate' = sample rate of the sound 00134 // 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) 00135 // 'seekwindowMS' = seeking window length for scanning the best overlapping 00136 // position (default = 28 ms) 00137 // 'overlapMS' = overlapping length (default = 12 ms) 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 // set tempo to recalculate 'sampleReq' 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 // Overlaps samples in 'midBuffer' with the samples in 'input' 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; // >> overlapDividerBits; 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 // Clears the sample buffers 00220 void TDStretch::clear() 00221 { 00222 outputBuffer.clear(); 00223 inputBuffer.clear(); 00224 clearMidBuffer(); 00225 } 00226 00227 00228 00229 // Enables/disables the quick position seeking algorithm. Zero to disable, nonzero 00230 // to enable 00231 void TDStretch::enableQuickSeek(BOOL enable) 00232 { 00233 bQuickseek = enable; 00234 } 00235 00236 00237 // Returns nonzero if the quick seeking algorithm is enabled. 00238 BOOL TDStretch::isQuickSeekEnabled() const 00239 { 00240 return bQuickseek; 00241 } 00242 00243 00244 // Seeks for the optimal overlap-mixing position. 00245 uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) 00246 { 00247 #ifdef MULTICHANNEL 00248 if (channels > 2) 00249 { 00250 // stereo sound 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 // stereo sound 00265 if (bQuickseek) 00266 { 00267 return seekBestOverlapPositionStereoQuick(refPos); 00268 } 00269 else 00270 { 00271 return seekBestOverlapPositionStereo(refPos); 00272 } 00273 } 00274 else 00275 { 00276 // mono sound 00277 if (bQuickseek) 00278 { 00279 return seekBestOverlapPositionMonoQuick(refPos); 00280 } 00281 else 00282 { 00283 return seekBestOverlapPositionMono(refPos); 00284 } 00285 } 00286 } 00287 00288 00289 00290 00291 // Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position 00292 // of 'ovlPos'. 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 // stereo sound 00305 overlapStereo(output, input + 2 * ovlPos); 00306 } else { 00307 // mono sound. 00308 overlapMono(output, input + ovlPos); 00309 } 00310 } 00311 00312 00313 00314 00315 #ifdef MULTICHANNEL 00316 // Seeks for the optimal overlap-mixing position. The 'stereo' version of the 00317 // routine 00318 // 00319 // The best position is determined as the position where the two overlapped 00320 // sample sequences are 'most alike', in terms of the highest cross-correlation 00321 // value over the overlapping period 00322 uint TDStretch::seekBestOverlapPositionMulti(const SAMPLETYPE *refPos) 00323 { 00324 uint bestOffs; 00325 LONG_SAMPLETYPE bestCorr, corr; 00326 uint i; 00327 00328 // Slopes the amplitudes of the 'midBuffer' samples 00329 precalcCorrReference(); 00330 00331 bestCorr = INT_MIN; 00332 bestOffs = 0; 00333 00334 // Scans for the best correlation value by testing each possible position 00335 // over the permitted range. 00336 for (i = 0; i < seekLength; i ++) 00337 { 00338 // Calculates correlation value for the mixing position corresponding 00339 // to 'i' 00340 corr = calcCrossCorrMulti(refPos + channels * i, pRefMidBuffer); 00341 00342 // Checks for the highest correlation value 00343 if (corr > bestCorr) 00344 { 00345 bestCorr = corr; 00346 bestOffs = i; 00347 } 00348 } 00349 // clear cross correlation routine state if necessary (is so e.g. in MMX routines). 00350 clearCrossCorrState(); 00351 00352 return bestOffs; 00353 } 00354 00355 00356 // Seeks for the optimal overlap-mixing position. The 'stereo' version of the 00357 // routine 00358 // 00359 // The best position is determined as the position where the two overlapped 00360 // sample sequences are 'most alike', in terms of the highest cross-correlation 00361 // value over the overlapping period 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 // Slopes the amplitude of the 'midBuffer' samples 00370 precalcCorrReference(); 00371 00372 bestCorr = INT_MIN; 00373 bestOffs = 0; 00374 corrOffset = 0; 00375 tempOffset = 0; 00376 00377 // Scans for the best correlation value using four-pass hierarchical search. 00378 // 00379 // The look-up table 'scans' has hierarchical position adjusting steps. 00380 // In first pass the routine searhes for the highest correlation with 00381 // relatively coarse steps, then rescans the neighbourhood of the highest 00382 // correlation with better resolution and so on. 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 // Calculates correlation value for the mixing position corresponding 00392 // to 'tempOffset' 00393 corr = calcCrossCorrMulti(refPos + channels * tempOffset, pRefMidBuffer); 00394 00395 // Checks for the highest correlation value 00396 if (corr > bestCorr) 00397 { 00398 bestCorr = corr; 00399 bestOffs = tempOffset; 00400 } 00401 j ++; 00402 } 00403 corrOffset = bestOffs; 00404 } 00405 // clear cross correlation routine state if necessary (is so e.g. in MMX routines). 00406 clearCrossCorrState(); 00407 00408 return bestOffs; 00409 } 00410 #endif 00411 00412 // Seeks for the optimal overlap-mixing position. The 'stereo' version of the 00413 // routine 00414 // 00415 // The best position is determined as the position where the two overlapped 00416 // sample sequences are 'most alike', in terms of the highest cross-correlation 00417 // value over the overlapping period 00418 uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) 00419 { 00420 uint bestOffs; 00421 LONG_SAMPLETYPE bestCorr, corr; 00422 uint i; 00423 00424 // Slopes the amplitudes of the 'midBuffer' samples 00425 precalcCorrReferenceStereo(); 00426 00427 bestCorr = INT_MIN; 00428 bestOffs = 0; 00429 00430 // Scans for the best correlation value by testing each possible position 00431 // over the permitted range. 00432 for (i = 0; i < seekLength; i ++) 00433 { 00434 // Calculates correlation value for the mixing position corresponding 00435 // to 'i' 00436 corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); 00437 00438 // Checks for the highest correlation value 00439 if (corr > bestCorr) 00440 { 00441 bestCorr = corr; 00442 bestOffs = i; 00443 } 00444 } 00445 // clear cross correlation routine state if necessary (is so e.g. in MMX routines). 00446 clearCrossCorrState(); 00447 00448 return bestOffs; 00449 } 00450 00451 00452 // Seeks for the optimal overlap-mixing position. The 'stereo' version of the 00453 // routine 00454 // 00455 // The best position is determined as the position where the two overlapped 00456 // sample sequences are 'most alike', in terms of the highest cross-correlation 00457 // value over the overlapping period 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 // Slopes the amplitude of the 'midBuffer' samples 00466 precalcCorrReferenceStereo(); 00467 00468 bestCorr = INT_MIN; 00469 bestOffs = 0; 00470 corrOffset = 0; 00471 tempOffset = 0; 00472 00473 // Scans for the best correlation value using four-pass hierarchical search. 00474 // 00475 // The look-up table 'scans' has hierarchical position adjusting steps. 00476 // In first pass the routine searhes for the highest correlation with 00477 // relatively coarse steps, then rescans the neighbourhood of the highest 00478 // correlation with better resolution and so on. 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 // Calculates correlation value for the mixing position corresponding 00488 // to 'tempOffset' 00489 corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); 00490 00491 // Checks for the highest correlation value 00492 if (corr > bestCorr) 00493 { 00494 bestCorr = corr; 00495 bestOffs = tempOffset; 00496 } 00497 j ++; 00498 } 00499 corrOffset = bestOffs; 00500 } 00501 // clear cross correlation routine state if necessary (is so e.g. in MMX routines). 00502 clearCrossCorrState(); 00503 00504 return bestOffs; 00505 } 00506 00507 00508 00509 // Seeks for the optimal overlap-mixing position. The 'mono' version of the 00510 // routine 00511 // 00512 // The best position is determined as the position where the two overlapped 00513 // sample sequences are 'most alike', in terms of the highest cross-correlation 00514 // value over the overlapping period 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 // Slopes the amplitude of the 'midBuffer' samples 00523 precalcCorrReferenceMono(); 00524 00525 bestCorr = INT_MIN; 00526 bestOffs = 0; 00527 00528 // Scans for the best correlation value by testing each possible position 00529 // over the permitted range. 00530 for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) 00531 { 00532 compare = refPos + tempOffset; 00533 00534 // Calculates correlation value for the mixing position corresponding 00535 // to 'tempOffset' 00536 corr = calcCrossCorrMono(pRefMidBuffer, compare); 00537 00538 // Checks for the highest correlation value 00539 if (corr > bestCorr) 00540 { 00541 bestCorr = corr; 00542 bestOffs = tempOffset; 00543 } 00544 } 00545 // clear cross correlation routine state if necessary (is so e.g. in MMX routines). 00546 clearCrossCorrState(); 00547 00548 return bestOffs; 00549 } 00550 00551 00552 // Seeks for the optimal overlap-mixing position. The 'mono' version of the 00553 // routine 00554 // 00555 // The best position is determined as the position where the two overlapped 00556 // sample sequences are 'most alike', in terms of the highest cross-correlation 00557 // value over the overlapping period 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 // Slopes the amplitude of the 'midBuffer' samples 00566 precalcCorrReferenceMono(); 00567 00568 bestCorr = INT_MIN; 00569 bestOffs = 0; 00570 corrOffset = 0; 00571 tempOffset = 0; 00572 00573 // Scans for the best correlation value using four-pass hierarchical search. 00574 // 00575 // The look-up table 'scans' has hierarchical position adjusting steps. 00576 // In first pass the routine searhes for the highest correlation with 00577 // relatively coarse steps, then rescans the neighbourhood of the highest 00578 // correlation with better resolution and so on. 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 // Calculates correlation value for the mixing position corresponding 00588 // to 'tempOffset' 00589 corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); 00590 00591 // Checks for the highest correlation value 00592 if (corr > bestCorr) 00593 { 00594 bestCorr = corr; 00595 bestOffs = tempOffset; 00596 } 00597 j ++; 00598 } 00599 corrOffset = bestOffs; 00600 } 00601 // clear cross correlation routine state if necessary (is so e.g. in MMX routines). 00602 clearCrossCorrState(); 00603 00604 return bestOffs; 00605 } 00606 00607 00609 void TDStretch::clearCrossCorrState() 00610 { 00611 // default implementation is empty. 00612 } 00613 00614 00615 // Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower 00616 // tempo, larger faster tempo. 00617 void TDStretch::setTempo(float newTempo) 00618 { 00619 uint intskip; 00620 00621 tempo = newTempo; 00622 00623 // Calculate ideal skip length (according to tempo value) 00624 nominalSkip = tempo * (seekWindowLength - overlapLength); 00625 skipFract = 0; 00626 intskip = (int)(nominalSkip + 0.5f); 00627 00628 // Calculate how many samples are needed in the 'inputBuffer' to 00629 // process another batch of samples 00630 sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; 00631 } 00632 00633 00634 00635 // Sets the number of channels, 1 = mono, 2 = stereo 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 // nominal tempo, no need for processing, just pass the samples through 00652 // to outputBuffer 00653 void TDStretch::processNominalTempo() 00654 { 00655 assert(tempo == 1.0f); 00656 00657 if (bMidBufferDirty) 00658 { 00659 // If there are samples in pMidBuffer waiting for overlapping, 00660 // do a single sliding overlapping with them in order to prevent a 00661 // clicking distortion in the output sound 00662 if (inputBuffer.numSamples() < overlapLength) 00663 { 00664 // wait until we've got overlapLength input samples 00665 return; 00666 } 00667 // Mix the samples in the beginning of 'inputBuffer' with the 00668 // samples in 'midBuffer' using sliding overlapping 00669 overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); 00670 outputBuffer.putSamples(overlapLength); 00671 inputBuffer.receiveSamples(overlapLength); 00672 clearMidBuffer(); 00673 // now we've caught the nominal sample flow and may switch to 00674 // bypass mode 00675 } 00676 00677 // Simply bypass samples from input to output 00678 outputBuffer.moveSamples(inputBuffer); 00679 } 00680 00681 00682 // Processes as many processing frames of the samples 'inputBuffer', store 00683 // the result into 'outputBuffer' 00684 void TDStretch::processSamples() 00685 { 00686 uint ovlSkip, offset; 00687 int temp; 00688 00689 if (tempo == 1.0f) 00690 { 00691 // tempo not changed from the original, so bypass the processing 00692 processNominalTempo(); 00693 return; 00694 } 00695 00696 if (bMidBufferDirty == FALSE) 00697 { 00698 // if midBuffer is empty, move the first samples of the input stream 00699 // into it 00700 if (inputBuffer.numSamples() < overlapLength) 00701 { 00702 // wait until we've got overlapLength samples 00703 return; 00704 } 00705 memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); 00706 inputBuffer.receiveSamples(overlapLength); 00707 bMidBufferDirty = TRUE; 00708 } 00709 00710 // Process samples as long as there are enough samples in 'inputBuffer' 00711 // to form a processing frame. 00712 while (inputBuffer.numSamples() >= sampleReq) 00713 { 00714 // If tempo differs from the normal ('SCALE'), scan for the best overlapping 00715 // position 00716 offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); 00717 00718 // Mix the samples in the 'inputBuffer' at position of 'offset' with the 00719 // samples in 'midBuffer' using sliding overlapping 00720 // ... first partially overlap with the end of the previous sequence 00721 // (that's in 'midBuffer') 00722 overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); 00723 outputBuffer.putSamples(overlapLength); 00724 00725 // ... then copy sequence samples from 'inputBuffer' to output 00726 temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; 00727 if (temp > 0) 00728 { 00729 outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); 00730 } 00731 00732 // Copies the end of the current sequence from 'inputBuffer' to 00733 // 'midBuffer' for being mixed with the beginning of the next 00734 // processing sequence and so on 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 // Remove the processed samples from the input buffer. Update 00741 // the difference between integer & nominal skip step to 'skipFract' 00742 // in order to prevent the error from accumulating over time. 00743 skipFract += nominalSkip; // real skip size 00744 ovlSkip = (int)skipFract; // rounded to integer skip 00745 skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip 00746 inputBuffer.receiveSamples(ovlSkip); 00747 } 00748 } 00749 00750 00751 // Adds 'numsamples' pcs of samples from the 'samples' memory position into 00752 // the input of the object. 00753 void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) 00754 { 00755 // Add the samples into the input buffer 00756 inputBuffer.putSamples(samples, numSamples); 00757 // Process the samples in input buffer 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 // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency 00784 pRefMidBuffer = (SAMPLETYPE *)((((ulong)pRefMidBufferUnaligned) + 15) & -16); 00785 } 00786 } 00787 00788 00789 // Operator 'new' is overloaded so that it automatically creates a suitable instance 00790 // depending on if we've a MMX/SSE/etc-capable CPU available or not. 00791 void * TDStretch::operator new(size_t s) 00792 { 00793 // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! 00794 assert(FALSE); 00795 return NULL; 00796 } 00797 00798 00799 TDStretch * TDStretch::newInstance() 00800 { 00801 uint uExtensions; 00802 00803 uExtensions = detectCPUextensions(); 00804 00805 // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU 00806 #ifdef ALLOW_SSE3 00807 if (uExtensions & MM_SSE3) 00808 { 00809 // SSE support 00810 return ::new TDStretchSSE3; 00811 } 00812 else 00813 #endif // ALLOW_SSE3 00814 #ifdef ALLOW_SSE2 00815 if (uExtensions & MM_SSE2) 00816 { 00817 // SSE support 00818 return ::new TDStretchSSE2; 00819 } 00820 else 00821 #endif // ALLOW_SSE2 00822 { 00823 // ISA optimizations not supported, use plain C version 00824 return ::new TDStretch; 00825 } 00826 } 00827 00828 00830 // 00831 // Integer arithmetics specific algorithm implementations. 00832 // 00834 00835 #ifdef INTEGER_SAMPLES 00836 00837 #ifdef MULTICHANNEL 00838 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation 00839 // is faster to calculate 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 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation 00861 // is faster to calculate 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 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation 00881 // is faster to calculate 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 // Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' 00898 // version of the routine. 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 // Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' 00916 // version of the routine. 00917 void TDStretch::overlapMulti(short *output, const short *input) const 00918 { 00919 int i,j; 00920 short temp; 00921 //uint cnt2; 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 // calculate sloping divider so that crosscorrelation operation won't 00951 // overflow 32-bit register. Max. sum of the crosscorrelation sum without 00952 // divider would be 2^30*(N^3-N)/3, where N = overlap length 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 // Floating point arithmetics specific algorithm implementations. 01008 // 01009 01010 #ifdef FLOAT_SAMPLES 01011 01012 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation 01013 // is faster to calculate 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 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation 01030 // is faster to calculate 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 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation 01052 // is faster to calculate 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 // SSE-optimized version of the function overlapStereo 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 // Overlaps samples in 'midBuffer' with the samples in 'input'. 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 // must be divisible by 8 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
1.7.6.1