00001 #ifndef YINACF_H
00002 #define YINACF_H
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00034
00035 #define YIN_EMMSUPPORT
00036 #ifdef YIN_EMMSUPPORT
00037 # include <emmintrin.h>
00038 #endif
00039
00056 template <class Sample>
00057 class YinACF {
00058 private:
00059
00070 class Solution {
00071 public:
00072 Sample* diff;
00073 Sample* cmndiff;
00074 unsigned est;
00075 Sample freq;
00077 public:
00078
00085 Solution() {
00086 diff = 0;
00087 cmndiff = 0;
00088 est = 0;
00089 freq = 0;
00090 }
00091
00100 Solution(unsigned W) {
00101 diff = new Sample[W];
00102 cmndiff = new Sample[W];
00103 est = 0;
00104 freq = 0;
00105 }
00106
00113 ~Solution() {
00114 if (diff) delete [] diff;
00115 if (cmndiff) delete [] cmndiff;
00116 }
00117 };
00118
00119 private:
00120 Sample* in;
00121 unsigned head;
00122 unsigned N;
00123 unsigned W;
00124 Sample THRESHOLD;
00125 unsigned TMAX;
00126 Solution* sol;
00127 unsigned ho;
00129 public:
00139 YinACF() {
00140 THRESHOLD = Sample(1.e-1);
00141 in = 0;
00142 head = 0;
00143 N = 0;
00144 W = 0;
00145 TMAX = 0;
00146 ho = 0;
00147 sol = 0;
00148 }
00149
00156 ~YinACF() {
00157 destroy();
00158 }
00159
00177 bool build (unsigned windowSize, unsigned tmax) {
00178
00179 destroy();
00180
00181 W = windowSize;
00182 N = (2 * W);
00183 TMAX = tmax | 1;
00184
00185 head = 0;
00186 in = new Sample[N];
00187
00188 ho = 0;
00189 sol = new Solution[TMAX];
00190
00191 for (unsigned i = 0; i < TMAX; ++i)
00192 sol[i].Solution::Solution(W);
00193
00194 reset();
00195 return true;
00196 }
00197
00206 void destroy() {
00207 N = 0;
00208 W = 0;
00209 TMAX = 0;
00210
00211 if (in) delete [] in;
00212 if (sol) delete[] sol;
00213 head = 0;
00214 in = 0;
00215
00216 ho = 0;
00217 sol = 0;
00218 }
00219
00226 void reset() {
00227 unsigned i, j;
00228 if (N) {
00229 head = 0;
00230 for (i = 0; i < N; ++i)
00231 in[i] = 0;
00232
00233 ho = 0;
00234 for (i = 0; i < TMAX; ++i) {
00235 sol[i].est = 0;
00236 sol[i].freq = 0;
00237 sol[i].diff[0] = 0;
00238 sol[i].cmndiff[0] = 1;
00239 for (j = 1; j < W; ++j) {
00240 sol[i].diff[j] = 0;
00241 sol[i].cmndiff[j] = 0;
00242 }
00243 }
00244 }
00245 }
00246
00260 virtual Sample tick(const Sample& s) {
00261 Sample freq = 0;
00262 pushSolution();
00263 Solution* psin = getSolution(TMAX - 1);
00264 Solution* psprev = getSolution(TMAX - 2);
00265
00266 psin->est = 0;
00267 psin->freq = 0;
00268
00269 computeDiff(s, psin, psprev);
00270
00271
00272 estimateFreq(psin, 0, W);
00273
00274
00275 return getBestLocalEstimate();
00276 }
00277
00286 inline unsigned getLatency() const {
00287 return N + (TMAX / 2);
00288 }
00289
00298 inline unsigned getWindowSize() const {
00299 return W;
00300 }
00301
00315 inline const Sample* getDiff(int offset = 0) const {
00316 return getSolution(offset)->diff;
00317 }
00318
00332 inline const Sample* getCMNDiff(int offset = 0) const {
00333 return getSolution(offset)->cmndiff;
00334 }
00335
00349 inline const getFrequency(int offset = 0) const {
00350 return getSolution(offset)->freq;
00351 }
00352
00361 inline Sample getThreshold() const {
00362 return THRESHOLD;
00363 }
00364
00371 inline void setThreshold(const Sample& threshold) {
00372 THRESHOLD = threshold;
00373 }
00374
00383 inline unsigned getMaxPeriod() const {
00384 return TMAX;
00385 }
00386
00387 private:
00388 inline void pushInput(const Sample& s) {
00389 in[head++] = s;
00390 if (head >= N) head = 0;
00391 }
00392
00393 inline void pushSolution() {
00394 if (++ho >= (int)TMAX) ho = 0;
00395 }
00396
00397 const Sample& getSample(unsigned delay) const {
00398 unsigned n = head + delay;
00399 if (n >= N) n -= N;
00400 return in[n];
00401 }
00402
00403 const void getSamples(unsigned delay, unsigned n, Sample* p) const {
00404 unsigned o = head + delay;
00405 while(n--) {
00406 if (o >= N) o -= N;
00407 *(p++) = in[o++];
00408 }
00409 }
00410
00411 Solution* getSolution(unsigned n) const {
00412 n = n + ho;
00413 if (n >= TMAX) n -= TMAX;
00414 return (Solution*)&sol[n];
00415 }
00416
00417 virtual void computeDiff(const Sample& s, Solution* pscur, Solution* psprev) {
00418
00419 computeDiff(this, s, pscur, psprev);
00420 }
00421
00422 virtual void estimateFreq(Solution* ps, unsigned mn, unsigned mx) {
00423
00424 unsigned est = getDip(ps, mn, mx);
00425 if (est) ps->est = est;
00426 }
00427
00428 virtual unsigned getDip(Solution* ps, int mn, int mx) const {
00429 static const int MIN_WL = 2;
00430 int i;
00431 Sample *cmndiff = ps->cmndiff;
00432 Sample mindip = Sample(10000);
00433 unsigned mini = 0;
00434 bool lt1, lt2;
00435
00436 if (mn < MIN_WL) mn = MIN_WL;
00437 if (mx >= (int)W) mx = (int)(W - 1);
00438
00439 lt2 = (cmndiff[mn - 1] < cmndiff[mn]);
00440 for (i = mn; i <= mx; ++i) {
00441 lt1 = lt2;
00442 lt2 = (cmndiff[i] < cmndiff[i + 1]);
00443 if (!lt1 && lt2) {
00444 if (cmndiff[i] < mindip) {
00445 mindip = cmndiff[i];
00446 mini = i;
00447 if (mindip < THRESHOLD)
00448 break;
00449 }
00450 }
00451 }
00452 return mini;
00453 }
00454
00455 virtual Sample parabolicInterpolation(unsigned est, Solution* ps) {
00456
00457
00458
00459 Sample d1, d2;
00460 unsigned i = 0;
00461 Sample* p = &ps->diff[est];
00462
00463
00464 while(1) {
00465 if (*(p - 1) < *p) {
00466 --est;
00467 --p;
00468 }
00469 else if (*(p + 1) <= *p) {
00470 ++est;
00471 ++p;
00472 }
00473 else
00474 break;
00475 if (++i > 4 || est >= W - 1)
00476 return 0;
00477 }
00478
00479
00480
00481
00482
00483
00484 d1 = *p - *(p - 1);
00485 d2 = *p - *(p + 1);
00486 Sample b = Sample(est);
00487 Sample num = (d2 - d1);
00488 Sample div = (d2 + d1);
00489 if (div == 0)
00490 return Sample(1) / b;
00491 return Sample(1) / (b - (num / (2 * div)));
00492 }
00493
00494 virtual Sample getBestLocalEstimate() {
00495 Solution* pscur = getSolution(TMAX / 2);
00496 Sample dmin = pscur->cmndiff[pscur->est];
00497 Solution* psmin = pscur;
00498
00499 for (unsigned i = 0; i < TMAX; ++i) {
00500 Solution* ps = getSolution(i);
00501 if (ps->est && ps->cmndiff[ps->est] < dmin) {
00502 dmin = ps->cmndiff[ps->est];
00503 psmin = ps;
00504 }
00505 }
00506
00507 if (psmin != pscur) {
00508
00509 unsigned est = getDip(pscur, (int)psmin->est - TMAX / 5, (int)psmin->est + TMAX / 5);
00510 if (est && (!pscur->est || pscur->cmndiff[est] < pscur->cmndiff[pscur->est])) {
00511 pscur->est = est;
00512 }
00513 }
00514
00515 if (pscur->est)
00516 pscur->freq = parabolicInterpolation(pscur->est, pscur);
00517 else
00518 pscur->freq = 0;
00519 return pscur->freq;
00520 }
00521
00522 template<class T>
00523 inline static void computeDiff(YinACF<T>* that, const Sample& s, typename YinACF<T>::Solution* pscur, typename YinACF<T>::Solution* psprev) {
00524 Sample sum = 1;
00525 Sample ii = 1;
00526 Sample sm1 = that->getSample(0);
00527 that->pushInput(s);
00528 Sample sw = that->getSample(that->W - 1);
00529 Sample* d = pscur->diff;
00530 Sample* p = psprev->diff;
00531 Sample* c = pscur->cmndiff;
00532 for (unsigned i = 1; i < that->W; ++i) {
00533 Sample d2 = sw - that->getSample(i + that->W - 1);
00534 Sample d1 = sm1 - that->getSample(i - 1);
00535 d[i] = p[i] + ((d2 + d1) * (d2 - d1));
00536 sum += d[i];
00537 c[i] = ii * (d[i] / sum);
00538 ii += Sample(1);
00539 }
00540 }
00541
00542 #ifdef YIN_EMMSUPPORT
00543 #pragma optimize("s", on)
00544 const void getSamples(unsigned delay, __m128& f) const {
00545 float p[4];
00546 unsigned n = head + delay;
00547 if (n >= N) n -= N;
00548 int x = (int)N - (int)(n + 4);
00549 if (x >= 0)
00550 f = _mm_loadu_ps(&in[n]);
00551 else {
00552 if (x == -1) {
00553 *(long*)&p[0] = *(long*)&in[N-3];
00554 *(long*)&p[1] = *(long*)&in[N-2];
00555 *(long*)&p[2] = *(long*)&in[N-1];
00556 *(long*)&p[3] = *(long*)&in[0];
00557 }
00558 else if (x == -2) {
00559 *(long*)&p[0] = *(long*)&in[N-2];
00560 *(long*)&p[1] = *(long*)&in[N-1];
00561 *(long*)&p[2] = *(long*)&in[0];
00562 *(long*)&p[3] = *(long*)&in[1];
00563 }
00564 else {
00565 *(long*)&p[0] = *(long*)&in[N-1];
00566 *(long*)&p[1] = *(long*)&in[0];
00567 *(long*)&p[2] = *(long*)&in[1];
00568 *(long*)&p[3] = *(long*)&in[2];
00569 }
00570 f = _mm_loadu_ps(p);
00571 }
00572 }
00573
00574 inline static void computeDiff(YinACF<Sample>* that, const float& s, typename YinACF<Sample>::Solution* pscur, typename YinACF<Sample>::Solution* psprev) {
00575 static const __m128 ZERO = _mm_set_ps1(0.f);
00576 static const __m128 ONE = _mm_set_ps(1.f, 2.f, 3.f, 4.f);
00577 static const __m128 FOUR = _mm_set_ps1(4.f);
00578 __m128 sums = _mm_set_ps1(1.f), t;
00579 __m128 ii = ONE;
00580 __m128 sm1 = _mm_set_ps1(that->getSample(0));
00581 that->pushInput(s);
00582 __m128 sw = _mm_set_ps1(that->getSample(that->W - 1));
00583
00584 float* d = pscur->diff;
00585 float* p = psprev->diff;
00586 float* c = pscur->cmndiff;
00587
00588 unsigned i;
00589 for (i = 1; i < that->W - 4; i += 4) {
00590 __m128 smp1, smp2;
00591 that->getSamples(i + that->W - 1, smp1);
00592 that->getSamples(i - 1, smp2);
00593
00594 __m128 d2 = _mm_sub_ps(sw, smp1);
00595 __m128 d1 = _mm_sub_ps(sm1, smp2);
00596 __m128 di = _mm_add_ps(_mm_loadu_ps(p + i), _mm_mul_ps(_mm_add_ps(d2, d1), _mm_sub_ps(d2, d1)));
00597 _mm_storeu_ps(d + i, di);
00598
00599 sums = _mm_shuffle_ps(sums, sums, _MM_SHUFFLE(3,3,3,3));
00600 sums = _mm_add_ps(sums, di);
00601 sums = _mm_add_ps(sums, _mm_movelh_ps(ZERO, di));
00602 t = _mm_shuffle_ps(di, di, _MM_SHUFFLE(2,1,0,3));
00603 t = _mm_move_ss(t, ZERO);
00604 sums = _mm_add_ps(sums, t);
00605 sums = _mm_add_ps(sums, _mm_movelh_ps(ZERO, t));
00606
00607 _mm_storeu_ps(c + i, _mm_mul_ps(ii, _mm_div_ps(di, sums)));
00608 ii = _mm_add_ps(ii, FOUR);
00609 }
00610 }
00611 #endif
00612 };
00613
00614 #endif // YINACF_H