use a note tracker to resolve notes cut off during render by the end of the region
[ardour.git] / libs / vamp-pyin / Yin.cpp
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */\r
2 \r
3 /*\r
4     pYIN - A fundamental frequency estimator for monophonic audio\r
5     Centre for Digital Music, Queen Mary, University of London.\r
6 \r
7     This program is free software; you can redistribute it and/or\r
8     modify it under the terms of the GNU General Public License as\r
9     published by the Free Software Foundation; either version 2 of the\r
10     License, or (at your option) any later version.  See the file\r
11     COPYING included with this distribution for more information.\r
12 */\r
13 \r
14 #include "Yin.h"\r
15 \r
16 #include "vamp-sdk/FFT.h"\r
17 #include "MeanFilter.h"\r
18 #include "YinUtil.h"\r
19 \r
20 #include <vector>\r
21 #include <cstdlib>\r
22 #include <cstdio>\r
23 #include <cmath>\r
24 #include <complex>\r
25 \r
26 using std::vector;\r
27 \r
28 Yin::Yin(size_t frameSize, size_t inputSampleRate, double thresh, bool fast) :\r
29     m_frameSize(frameSize),\r
30     m_inputSampleRate(inputSampleRate),\r
31     m_thresh(thresh),\r
32     m_threshDistr(2),\r
33     m_yinBufferSize(frameSize/2),\r
34     m_fast(fast)\r
35 {\r
36     if (frameSize & (frameSize-1)) {\r
37       //  throw "N must be a power of two";\r
38     }\r
39 }\r
40 \r
41 Yin::~Yin()\r
42 {\r
43 }\r
44 \r
45 Yin::YinOutput\r
46 Yin::process(const double *in) const {\r
47 \r
48     double* yinBuffer = new double[m_yinBufferSize];\r
49 \r
50     // calculate aperiodicity function for all periods\r
51     if (m_fast) YinUtil::fastDifference(in, yinBuffer, m_yinBufferSize);\r
52     else YinUtil::slowDifference(in, yinBuffer, m_yinBufferSize);\r
53 \r
54     YinUtil::cumulativeDifference(yinBuffer, m_yinBufferSize);\r
55 \r
56     int tau = 0;\r
57     tau = YinUtil::absoluteThreshold(yinBuffer, m_yinBufferSize, m_thresh);\r
58 \r
59     double interpolatedTau;\r
60     double aperiodicity;\r
61     double f0;\r
62 \r
63     if (tau!=0)\r
64     {\r
65         interpolatedTau = YinUtil::parabolicInterpolation(yinBuffer, abs(tau), m_yinBufferSize);\r
66         f0 = m_inputSampleRate * (1.0 / interpolatedTau);\r
67     } else {\r
68         interpolatedTau = 0;\r
69         f0 = 0;\r
70     }\r
71     double rms = std::sqrt(YinUtil::sumSquare(in, 0, m_yinBufferSize)/m_yinBufferSize);\r
72     aperiodicity = yinBuffer[abs(tau)];\r
73     // std::cerr << aperiodicity << std::endl;\r
74     if (tau < 0) f0 = -f0;\r
75 \r
76     Yin::YinOutput yo(f0, 1-aperiodicity, rms);\r
77     for (size_t iBuf = 0; iBuf < m_yinBufferSize; ++iBuf)\r
78     {\r
79         yo.salience.push_back(yinBuffer[iBuf] < 1 ? 1-yinBuffer[iBuf] : 0); // why are the values sometimes < 0 if I don't check?\r
80     }\r
81 \r
82     delete [] yinBuffer;\r
83     return yo;\r
84 }\r
85 \r
86 Yin::YinOutput\r
87 Yin::processProbabilisticYin(const double *in) const {\r
88 \r
89     double* yinBuffer = new double[m_yinBufferSize];\r
90 \r
91     // calculate aperiodicity function for all periods\r
92     if (m_fast) YinUtil::fastDifference(in, yinBuffer, m_yinBufferSize);\r
93     else YinUtil::slowDifference(in, yinBuffer, m_yinBufferSize);\r
94 \r
95     YinUtil::cumulativeDifference(yinBuffer, m_yinBufferSize);\r
96 \r
97     vector<double> peakProbability = YinUtil::yinProb(yinBuffer, m_threshDistr, m_yinBufferSize);\r
98 \r
99     // calculate overall "probability" from peak probability\r
100     double probSum = 0;\r
101     for (size_t iBin = 0; iBin < m_yinBufferSize; ++iBin)\r
102     {\r
103         probSum += peakProbability[iBin];\r
104     }\r
105     double rms = std::sqrt(YinUtil::sumSquare(in, 0, m_yinBufferSize)/m_yinBufferSize);\r
106     Yin::YinOutput yo(0,0,rms);\r
107     for (size_t iBuf = 0; iBuf < m_yinBufferSize; ++iBuf)\r
108     {\r
109         yo.salience.push_back(peakProbability[iBuf]);\r
110         if (peakProbability[iBuf] > 0)\r
111         {\r
112             double currentF0 =\r
113                 m_inputSampleRate * (1.0 /\r
114                 YinUtil::parabolicInterpolation(yinBuffer, iBuf, m_yinBufferSize));\r
115             yo.freqProb.push_back(pair<double, double>(currentF0, peakProbability[iBuf]));\r
116         }\r
117     }\r
118 \r
119     // std::cerr << yo.freqProb.size() << std::endl;\r
120 \r
121     delete [] yinBuffer;\r
122     return yo;\r
123 }\r
124 \r
125 \r
126 int\r
127 Yin::setThreshold(double parameter)\r
128 {\r
129     m_thresh = static_cast<float>(parameter);\r
130     return 0;\r
131 }\r
132 \r
133 int\r
134 Yin::setThresholdDistr(float parameter)\r
135 {\r
136     m_threshDistr = static_cast<size_t>(parameter);\r
137     return 0;\r
138 }\r
139 \r
140 int\r
141 Yin::setFrameSize(size_t parameter)\r
142 {\r
143     m_frameSize = parameter;\r
144     m_yinBufferSize = m_frameSize/2;\r
145     return 0;\r
146 }\r
147 \r
148 int\r
149 Yin::setFast(bool parameter)\r
150 {\r
151     m_fast = parameter;\r
152     return 0;\r
153 }\r