1 // Copyright 2004 "Gilles Degottex"
3 // This file is part of "Music"
5 // "Music" is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 2.1 of the License, or
8 // (at your option) any later version.
10 // "Music" is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "TimeAnalysis.h"
28 #include <CppAddons/CAMath.h>
35 double InterpolatedPeriod(const std::deque<double>& queue, int left, int right)
37 double l = left - queue[left]/(queue[left+1]-queue[left]);
39 double r = right - queue[right]/(queue[right+1]-queue[right]);
45 * on peut imaginer des cas qui mettent en échec cette procédure:
46 * on selectionne un zéro qui n'en n'est pas un une periode plus
47 * tard et si un autre zéro se trouve dans la zone de tolérance la longeur
48 * ainsi calculée entre ces deux zéro (qui ne se correspondent donc pas) sera fausse.
49 * example: une fréquence très basse avec une seule harmonique très très
51 * - il faut utiliser des zéros significatifs ... et ... et ... et voilà .
52 * - ou encore écarter les solutions trop élognées de la moyenne
54 double GetAveragePeriodFromApprox(const std::deque<double>& queue, int approx, int n)
56 if(GetAFreq()<=0.0 || GetSamplingRate()<=0.0 || int(queue.size())<approx)
59 deque<int> ups; // the upper peeks
61 // parse the whole buffer, for n zeros
62 for(int i=0; int(ups.size())<n && i+1<int(queue.size()); i++)
63 if(queue[i]<0 && queue[i+1]>0) // if it cross the axis
66 // cerr << "approx=" << approx << " ups.size()=" << ups.size();
70 double ht = f2hf(double(GetSamplingRate())/approx);
71 int period_low_bound = int(GetSamplingRate()/h2f(ht+1))-2;
72 int period_high_bound = int(GetSamplingRate()/h2f(ht-1))+2;
74 // cerr << " ht=" << ht << " lb=" << period_low_bound << " rb=" << period_high_bound;
76 // cerr << " periods=(";
81 for(int i=0; i<int(ups.size()) && count<n; i++)
83 int i_seek = ups[i] + approx;
85 int lower_i_seek = i_seek;
86 int low_bound = ups[i] + period_low_bound;
87 int higher_i_seek = i_seek;
88 int high_bound = min(int(queue.size())-1, ups[i]+period_high_bound);
90 // cerr << "{" << low_bound << ":" << i_seek << ":" << high_bound << "}";
92 if(low_bound+1>=int(queue.size()))
93 i = ups.size(); // stop loop
96 if(!(queue[i_seek]<=0.0 && queue[i_seek+1]>0.0))
98 while(lower_i_seek>low_bound &&
99 !(queue[lower_i_seek]<=0.0 && queue[lower_i_seek+1]>0.0))
102 while(higher_i_seek<high_bound &&
103 !(queue[higher_i_seek]<=0.0 && queue[higher_i_seek+1]>0.0))
106 if(i_seek-lower_i_seek < higher_i_seek-i_seek) // take the nearest to i_seek
107 i_seek = lower_i_seek;
109 i_seek = higher_i_seek;
112 // cerr << i_seek << "=>";
114 if(low_bound<i_seek && i_seek<high_bound)
116 double per = InterpolatedPeriod(queue, ups[i], i_seek);
118 // cerr << "f=" << GetSamplingRate()/per << " ";
131 // cerr << ")=" << GetSamplingRate()/period << "(" << count << ")" << endl;
136 void GetWaveSample(const std::deque<double>& queue, size_t wave_length, std::deque<double>& sample)
138 assert(wave_length>0);
139 if(queue.size()<2*wave_length) return;
141 // find the highest peek in the second period
144 for(int i=int(wave_length); i<int(queue.size()) && i<int(2*wave_length); i++)
153 // adjust the right bound to the nearest minima
154 int left_right = int(left + 0.9*wave_length);
155 int right_right = int(left + wave_length/0.9);
157 int right = int(left + wave_length); // init to a default value
159 if(right_right>=int(queue.size()))
163 for(int i=left_right; i<=right_right; i++)
172 // fill in the sample
174 for(int i=left; i<int(queue.size()) && i<right; i++)
175 sample.push_back(queue[i]);
178 double GetAverageWaveLengthFromApproxEnergy(const std::deque<double>& queue, double approx, int n)
180 assert(GetSamplingRate()>0);
182 if(queue.size()<approx*1.5)
185 // cerr << queue.size() << "=>" << approx << " n=" << n << endl;
187 double wave_length = 0.0;
190 while(count<n && seek<int(queue.size()) && seek!=-1)
192 // cerr << "new " << flush;
194 // in one period, compute the energy over approx/4
195 int w = int(approx/4); // TODO ptr un peu long
198 for(int i=0; i<w/2; i++)
200 for(int i=w/2; int(en.size())<int(1.25*approx); i++)
203 for(int j=-w/2; j<=w/2 && seek+i+j<int(queue.size()); j++)
204 en.back() += queue[seek+i+j]; //*queue[seek+i+j]
207 // find the highest energy peak
210 for(int i=0; i<int(en.size()); i++)
220 // cerr << "max-seek=" << seek << " " << flush;
223 // go back to the previous zero
224 while(seek>=0 && !(queue[seek]<=0 && queue[seek+1]>0) && seek>old_seek-approx/2)
227 // cerr << "zero-seek=" << seek << " " << flush;
229 if(seek<0 || seek<=old_seek-approx/2)
237 int right = int(left + approx);
239 int downlimit = int(left + 0.75*approx);
241 int uplimit = int(left + 1.25*approx);
243 // look for the nearest zero of right
244 while(sright+1<int(queue.size()) && sright>downlimit &&
245 !(queue[sright]<=0 && queue[sright+1]>0))
247 while(bright+1<int(queue.size()) && bright<uplimit &&
248 !(queue[bright]<=0 && queue[bright+1]>0))
251 if(sright>=int(queue.size()) || bright>=int(queue.size()))
258 double sw = InterpolatedPeriod(queue, left, sright);
259 double bw = InterpolatedPeriod(queue, left, bright);
260 // keep the nearest one after approx
262 if(abs(sw-approx)<abs(bw-approx)) wl = sw;
265 // cerr << "wl=" << wl << flush;
270 seek += int(0.9*approx);
275 // cerr << "("<<count<<")"<< flush;
277 if(count==0) return 0.0;
279 wave_length /= count;
281 // cerr << GetSamplingRate()/wave_length << endl;