MythTV  0.26-pre
TDStretch.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends