/[pcsx2_0.9.7]/trunk/3rdparty/SoundTouch/TDStretch.cpp
ViewVC logotype

Annotation of /trunk/3rdparty/SoundTouch/TDStretch.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22