changeset 136:7cbf40306c10 vamp-fft-revision

Add state to YinUtil, prepare to use the Vamp FFT (but don't actually use it yet)
author Chris Cannam
date Fri, 19 Aug 2016 12:00:13 +0100
parents 2c73618b4067
children 109c3a2ad930
files LocalCandidatePYIN.cpp LocalCandidatePYIN.h Yin.cpp Yin.h YinUtil.cpp YinUtil.h
diffstat 6 files changed, 91 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/LocalCandidatePYIN.cpp	Fri Aug 19 11:31:57 2016 +0100
+++ b/LocalCandidatePYIN.cpp	Fri Aug 19 12:00:13 2016 +0100
@@ -48,12 +48,14 @@
     m_preciseTime(0.0f),
     m_pitchProb(0),
     m_timestamp(0),
-    m_nCandidate(13)
+    m_nCandidate(13),
+    m_yinUtil(0)
 {
 }
 
 LocalCandidatePYIN::~LocalCandidatePYIN()
 {
+    delete m_yinUtil;
 }
 
 string
@@ -268,6 +270,8 @@
     m_channels = channels;
     m_stepSize = stepSize;
     m_blockSize = blockSize;
+
+    m_yinUtil = new YinUtil(m_blockSize/2);
     
     reset();
 
@@ -297,20 +301,19 @@
     
     size_t yinBufferSize = m_blockSize/2;
     double* yinBuffer = new double[yinBufferSize];
-    if (!m_preciseTime) YinUtil::fastDifference(dInputBuffers, yinBuffer, yinBufferSize);
-    else YinUtil::slowDifference(dInputBuffers, yinBuffer, yinBufferSize);    
+    if (!m_preciseTime) m_yinUtil->fastDifference(dInputBuffers, yinBuffer);
+    else m_yinUtil->slowDifference(dInputBuffers, yinBuffer);    
     
     delete [] dInputBuffers;
 
-    YinUtil::cumulativeDifference(yinBuffer, yinBufferSize);
+    m_yinUtil->cumulativeDifference(yinBuffer);
     
     float minFrequency = 60;
     float maxFrequency = 900;
-    vector<double> peakProbability = YinUtil::yinProb(yinBuffer, 
-                                                      m_threshDistr, 
-                                                      yinBufferSize, 
-                                                      m_inputSampleRate/maxFrequency, 
-                                                      m_inputSampleRate/minFrequency);
+    vector<double> peakProbability = m_yinUtil->yinProb(yinBuffer, 
+                                                        m_threshDistr, 
+                                                        m_inputSampleRate/maxFrequency, 
+                                                        m_inputSampleRate/minFrequency);
 
     vector<pair<double, double> > tempPitchProb;
     for (size_t iBuf = 0; iBuf < yinBufferSize; ++iBuf)
@@ -319,7 +322,7 @@
         {
             double currentF0 = 
                 m_inputSampleRate * (1.0 /
-                YinUtil::parabolicInterpolation(yinBuffer, iBuf, yinBufferSize));
+                m_yinUtil->parabolicInterpolation(yinBuffer, iBuf));
             double tempPitch = 12 * std::log(currentF0/440)/std::log(2.) + 69;
             tempPitchProb.push_back(pair<double, double>(tempPitch, peakProbability[iBuf]));
         }
--- a/LocalCandidatePYIN.h	Fri Aug 19 11:31:57 2016 +0100
+++ b/LocalCandidatePYIN.h	Fri Aug 19 12:00:13 2016 +0100
@@ -18,6 +18,8 @@
 
 #include "Yin.h"
 
+class YinUtil;
+
 class LocalCandidatePYIN : public Vamp::Plugin
 {
 public:
@@ -70,6 +72,8 @@
     vector<vector<pair<double, double> > > m_pitchProb;
     vector<Vamp::RealTime> m_timestamp;
     size_t m_nCandidate;
+
+    YinUtil *m_yinUtil;
 };
 
 #endif
--- a/Yin.cpp	Fri Aug 19 11:31:57 2016 +0100
+++ b/Yin.cpp	Fri Aug 19 12:00:13 2016 +0100
@@ -31,7 +31,8 @@
     m_thresh(thresh),
     m_threshDistr(2),
     m_yinBufferSize(frameSize/2),
-    m_fast(fast)
+    m_fast(fast),
+    m_yinUtil(new YinUtil(m_yinBufferSize))
 {
     if (frameSize & (frameSize-1)) {
       //  throw "N must be a power of two";
@@ -40,6 +41,7 @@
 
 Yin::~Yin() 
 {
+    delete m_yinUtil;
 }
 
 Yin::YinOutput
@@ -48,13 +50,13 @@
     double* yinBuffer = new double[m_yinBufferSize];
 
     // calculate aperiodicity function for all periods
-    if (m_fast) YinUtil::fastDifference(in, yinBuffer, m_yinBufferSize);
-    else YinUtil::slowDifference(in, yinBuffer, m_yinBufferSize);
+    if (m_fast) m_yinUtil->fastDifference(in, yinBuffer);
+    else m_yinUtil->slowDifference(in, yinBuffer);
 
-    YinUtil::cumulativeDifference(yinBuffer, m_yinBufferSize);
+    m_yinUtil->cumulativeDifference(yinBuffer);
 
     int tau = 0;
-    tau = YinUtil::absoluteThreshold(yinBuffer, m_yinBufferSize, m_thresh);
+    tau = m_yinUtil->absoluteThreshold(yinBuffer, m_thresh);
         
     double interpolatedTau;
     double aperiodicity;
@@ -62,13 +64,13 @@
     
     if (tau!=0)
     {
-        interpolatedTau = YinUtil::parabolicInterpolation(yinBuffer, abs(tau), m_yinBufferSize);
+        interpolatedTau = m_yinUtil->parabolicInterpolation(yinBuffer, abs(tau));
         f0 = m_inputSampleRate * (1.0 / interpolatedTau);
     } else {
         interpolatedTau = 0;
         f0 = 0;
     }
-    double rms = std::sqrt(YinUtil::sumSquare(in, 0, m_yinBufferSize)/m_yinBufferSize);
+    double rms = std::sqrt(m_yinUtil->sumSquare(in, 0, m_yinBufferSize)/m_yinBufferSize);
     aperiodicity = yinBuffer[abs(tau)];
     // std::cerr << aperiodicity << std::endl;
     if (tau < 0) f0 = -f0;
@@ -89,12 +91,12 @@
     double* yinBuffer = new double[m_yinBufferSize];
 
     // calculate aperiodicity function for all periods
-    if (m_fast) YinUtil::fastDifference(in, yinBuffer, m_yinBufferSize);
-    else YinUtil::slowDifference(in, yinBuffer, m_yinBufferSize);
+    if (m_fast) m_yinUtil->fastDifference(in, yinBuffer);
+    else m_yinUtil->slowDifference(in, yinBuffer);
 
-    YinUtil::cumulativeDifference(yinBuffer, m_yinBufferSize);
+    m_yinUtil->cumulativeDifference(yinBuffer);
 
-    vector<double> peakProbability = YinUtil::yinProb(yinBuffer, m_threshDistr, m_yinBufferSize);
+    vector<double> peakProbability = m_yinUtil->yinProb(yinBuffer, m_threshDistr);
     
     // calculate overall "probability" from peak probability
     double probSum = 0;
@@ -102,7 +104,7 @@
     {
         probSum += peakProbability[iBin];
     }
-    double rms = std::sqrt(YinUtil::sumSquare(in, 0, m_yinBufferSize)/m_yinBufferSize);
+    double rms = std::sqrt(m_yinUtil->sumSquare(in, 0, m_yinBufferSize)/m_yinBufferSize);
     Yin::YinOutput yo(0,0,rms);
     for (size_t iBuf = 0; iBuf < m_yinBufferSize; ++iBuf)
     {
@@ -111,7 +113,7 @@
         {
             double currentF0 = 
                 m_inputSampleRate * (1.0 /
-                YinUtil::parabolicInterpolation(yinBuffer, iBuf, m_yinBufferSize));
+                m_yinUtil->parabolicInterpolation(yinBuffer, iBuf));
             yo.freqProb.push_back(pair<double, double>(currentF0, peakProbability[iBuf]));
         }
     }
--- a/Yin.h	Fri Aug 19 11:31:57 2016 +0100
+++ b/Yin.h	Fri Aug 19 12:00:13 2016 +0100
@@ -26,6 +26,8 @@
 using std::vector;
 using std::pair;
 
+class YinUtil;
+
 class Yin
 {
 public:
@@ -64,6 +66,7 @@
     mutable size_t m_yinBufferSize;
     mutable bool   m_fast;
     // mutable bool m_removeUnvoiced;
+    YinUtil *m_yinUtil;
 };
 
 #endif
--- a/YinUtil.cpp	Fri Aug 19 11:31:57 2016 +0100
+++ b/YinUtil.cpp	Fri Aug 19 12:00:13 2016 +0100
@@ -21,17 +21,27 @@
 
 #include <boost/math/distributions.hpp>
 
+YinUtil::YinUtil(size_t yinBufferSize) :
+    m_yinBufferSize(yinBufferSize),
+    m_fft(yinBufferSize * 2)
+{
+}
+
+YinUtil::~YinUtil()
+{
+}
+
 void 
-YinUtil::slowDifference(const double *in, double *yinBuffer, const size_t yinBufferSize) 
+YinUtil::slowDifference(const double *in, double *yinBuffer) 
 {
     yinBuffer[0] = 0;
     double delta ;
     int startPoint = 0;
     int endPoint = 0;
-    for (int i = 1; i < yinBufferSize; ++i) {
+    for (int i = 1; i < m_yinBufferSize; ++i) {
         yinBuffer[i] = 0;
-        startPoint = yinBufferSize/2 - i/2;
-        endPoint = startPoint + yinBufferSize;
+        startPoint = m_yinBufferSize/2 - i/2;
+        endPoint = startPoint + m_yinBufferSize;
         for (int j = startPoint; j < endPoint; ++j) {
             delta = in[i+j] - in[j];
             yinBuffer[i] += delta * delta;
@@ -40,14 +50,14 @@
 }
 
 void 
-YinUtil::fastDifference(const double *in, double *yinBuffer, const size_t yinBufferSize) 
+YinUtil::fastDifference(const double *in, double *yinBuffer) 
 {
     
     // DECLARE AND INITIALISE
     // initialisation of most of the arrays here was done in a separate function,
     // with all the arrays as members of the class... moved them back here.
     
-    size_t frameSize = 2 * yinBufferSize;
+    size_t frameSize = 2 * m_yinBufferSize;
     
     double *audioTransformedReal = new double[frameSize];
     double *audioTransformedImag = new double[frameSize];
@@ -57,9 +67,9 @@
     double *kernelTransformedImag = new double[frameSize];
     double *yinStyleACFReal = new double[frameSize];
     double *yinStyleACFImag = new double[frameSize];
-    double *powerTerms = new double[yinBufferSize];
+    double *powerTerms = new double[m_yinBufferSize];
     
-    for (size_t j = 0; j < yinBufferSize; ++j)
+    for (size_t j = 0; j < m_yinBufferSize; ++j)
     {
         yinBuffer[j] = 0.; // set to zero
         powerTerms[j] = 0.; // set to zero
@@ -80,13 +90,13 @@
     // POWER TERM CALCULATION
     // ... for the power terms in equation (7) in the Yin paper
     powerTerms[0] = 0.0;
-    for (size_t j = 0; j < yinBufferSize; ++j) {
+    for (size_t j = 0; j < m_yinBufferSize; ++j) {
         powerTerms[0] += in[j] * in[j];
     }
 
     // now iteratively calculate all others (saves a few multiplications)
-    for (size_t tau = 1; tau < yinBufferSize; ++tau) {
-        powerTerms[tau] = powerTerms[tau-1] - in[tau-1] * in[tau-1] + in[tau+yinBufferSize] * in[tau+yinBufferSize];  
+    for (size_t tau = 1; tau < m_yinBufferSize; ++tau) {
+        powerTerms[tau] = powerTerms[tau-1] - in[tau-1] * in[tau-1] + in[tau+m_yinBufferSize] * in[tau+m_yinBufferSize];  
     }
 
     // YIN-STYLE AUTOCORRELATION via FFT
@@ -94,8 +104,8 @@
     Vamp::FFT::forward(frameSize, in, nullImag, audioTransformedReal, audioTransformedImag);
     
     // 2. half of the data, disguised as a convolution kernel
-    for (size_t j = 0; j < yinBufferSize; ++j) {
-        kernel[j] = in[yinBufferSize-1-j];
+    for (size_t j = 0; j < m_yinBufferSize; ++j) {
+        kernel[j] = in[m_yinBufferSize-1-j];
     }
     Vamp::FFT::forward(frameSize, kernel, nullImag, kernelTransformedReal, kernelTransformedImag);
 
@@ -108,9 +118,9 @@
     
     // CALCULATION OF difference function
     // ... according to (7) in the Yin paper.
-    for (size_t j = 0; j < yinBufferSize; ++j) {
+    for (size_t j = 0; j < m_yinBufferSize; ++j) {
         // taking only the real part
-        yinBuffer[j] = powerTerms[0] + powerTerms[j] - 2 * audioTransformedReal[j+yinBufferSize-1];
+        yinBuffer[j] = powerTerms[0] + powerTerms[j] - 2 * audioTransformedReal[j+m_yinBufferSize-1];
     }
     delete [] audioTransformedReal;
     delete [] audioTransformedImag;
@@ -124,7 +134,7 @@
 }
 
 void 
-YinUtil::cumulativeDifference(double *yinBuffer, const size_t yinBufferSize)
+YinUtil::cumulativeDifference(double *yinBuffer)
 {    
     size_t tau;
     
@@ -132,7 +142,7 @@
     
     double runningSum = 0;
     
-    for (tau = 1; tau < yinBufferSize; ++tau) {
+    for (tau = 1; tau < m_yinBufferSize; ++tau) {
         runningSum += yinBuffer[tau];
         if (runningSum == 0)
         {
@@ -144,7 +154,7 @@
 }
 
 int 
-YinUtil::absoluteThreshold(const double *yinBuffer, const size_t yinBufferSize, const double thresh)
+YinUtil::absoluteThreshold(const double *yinBuffer, const double thresh)
 {
     size_t tau;
     size_t minTau = 0;
@@ -152,11 +162,11 @@
     
     // using Joren Six's "loop construct" from TarsosDSP
     tau = 2;
-    while (tau < yinBufferSize)
+    while (tau < m_yinBufferSize)
     {
         if (yinBuffer[tau] < thresh)
         {
-            while (tau+1 < yinBufferSize && yinBuffer[tau+1] < yinBuffer[tau])
+            while (tau+1 < m_yinBufferSize && yinBuffer[tau+1] < yinBuffer[tau])
             {
                 ++tau;
             }
@@ -187,20 +197,20 @@
 static float single20[100] = {0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,1.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000};
 
 std::vector<double>
-YinUtil::yinProb(const double *yinBuffer, const size_t prior, const size_t yinBufferSize, const size_t minTau0, const size_t maxTau0) 
+YinUtil::yinProb(const double *yinBuffer, const size_t prior, const size_t minTau0, const size_t maxTau0) 
 {
     size_t minTau = 2;
-    size_t maxTau = yinBufferSize;
+    size_t maxTau = m_yinBufferSize;
 
     // adapt period range, if necessary
     if (minTau0 > 0 && minTau0 < maxTau0) minTau = minTau0;
-    if (maxTau0 > 0 && maxTau0 < yinBufferSize && maxTau0 > minTau) maxTau = maxTau0;
+    if (maxTau0 > 0 && maxTau0 < m_yinBufferSize && maxTau0 > minTau) maxTau = maxTau0;
 
     double minWeight = 0.01;
     size_t tau;
     std::vector<float> thresholds;
     std::vector<float> distribution;
-    std::vector<double> peakProb = std::vector<double>(yinBufferSize);
+    std::vector<double> peakProb = std::vector<double>(m_yinBufferSize);
     
     size_t nThreshold = 100;
     int nThresholdInt = nThreshold;
@@ -303,7 +313,7 @@
     
     if (peakProb[minInd] > 1) {
         std::cerr << "WARNING: yin has prob > 1 ??? I'm returning all zeros instead." << std::endl;
-        return(std::vector<double>(yinBufferSize));
+        return(std::vector<double>(m_yinBufferSize));
     }
     
     double nonPeakProb = 1;
@@ -324,16 +334,16 @@
 }
 
 double
-YinUtil::parabolicInterpolation(const double *yinBuffer, const size_t tau, const size_t yinBufferSize) 
+YinUtil::parabolicInterpolation(const double *yinBuffer, const size_t tau) 
 {
     // this is taken almost literally from Joren Six's Java implementation
-    if (tau == yinBufferSize) // not valid anyway.
+    if (tau == m_yinBufferSize) // not valid anyway.
     {
         return static_cast<double>(tau);
     }
     
     double betterTau = 0.0;
-    if (tau > 0 && tau < yinBufferSize-1) {
+    if (tau > 0 && tau < m_yinBufferSize-1) {
         float s0, s1, s2;
         s0 = yinBuffer[tau-1];
         s1 = yinBuffer[tau];
--- a/YinUtil.h	Fri Aug 19 11:31:57 2016 +0100
+++ b/YinUtil.h	Fri Aug 19 12:00:13 2016 +0100
@@ -14,29 +14,35 @@
 #ifndef _YINUTIL_H_
 #define _YINUTIL_H_
 
-#include "vamp-sdk/FFT.h"
-#include "MeanFilter.h"
-
 #include <cmath>
 
 #include <iostream>
 #include <vector>
 #include <exception>
 
+#include "vamp-sdk/FFT.h"
+
 using std::vector;
 
 class YinUtil
 {
 public:
-    static double sumSquare(const double *in, const size_t startInd, const size_t endInd);
-    static void difference(const double *in, double *yinBuffer, const size_t yinBufferSize);
-    static void fastDifference(const double *in, double *yinBuffer, const size_t yinBufferSize);
-    static void slowDifference(const double *in, double *yinBuffer, const size_t yinBufferSize);
-    static void cumulativeDifference(double *yinBuffer, const size_t yinBufferSize);
-    static int absoluteThreshold(const double *yinBuffer, const size_t yinBufferSize, const double thresh);
-    static vector<double> yinProb(const double *yinBuffer, const size_t prior, const size_t yinBufferSize, size_t minTau = 0, size_t maxTau = 0);
-    static double parabolicInterpolation(const double *yinBuffer, const size_t tau,
-                                         const size_t yinBufferSize);
+    YinUtil(size_t yinBufferSize);
+    ~YinUtil();
+    
+    double sumSquare(const double *in, const size_t startInd, const size_t endInd);
+    void difference(const double *in, double *yinBuffer);
+    void fastDifference(const double *in, double *yinBuffer);
+    void slowDifference(const double *in, double *yinBuffer);
+    void cumulativeDifference(double *yinBuffer);
+    int absoluteThreshold(const double *yinBuffer, const double thresh);
+    vector<double> yinProb(const double *yinBuffer, const size_t prior,
+                           size_t minTau = 0, size_t maxTau = 0);
+    double parabolicInterpolation(const double *yinBuffer, const size_t tau);
+
+private:
+    const size_t m_yinBufferSize;
+    Vamp::FFTReal m_fft;
 };
 
 #endif