PageRenderTime 85ms CodeModel.GetById 36ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/external/pysoundtouch14/libsoundtouch/TDStretch.cpp

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