/external/pysoundtouch14/libsoundtouch/TDStretch.cpp
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