xue@11
|
1
|
xue@9
|
2 /*
|
xue@9
|
3 Sample program: analysis of harmonic sinusoid in low-noise monophonic context.
|
xue@9
|
4
|
xue@9
|
5 Syntax:
|
xue@9
|
6 (executable path) filename <setting=value> <setting=value> ... <setting=value>
|
xue@9
|
7
|
xue@9
|
8 filename: path input wave form audio file, 16-bit PCM
|
xue@9
|
9 setting: optional algorithmic parameters; search "stricmp" in the source code for a complete list
|
xue@9
|
10 value: non-default values given to the algorithmic parameters
|
xue@9
|
11
|
xue@9
|
12 Output:
|
xue@9
|
13 a *.evt file containing RIFF chunks, each starting with id "EVT\0" and hosting a harmonic sinusoid.
|
xue@9
|
14
|
xue@9
|
15 The "EVT\0" chunk body contains a header ("HDR\0") chunk followed by atom ("ATM\0") chunks.
|
xue@9
|
16
|
xue@9
|
17 The "HDR\0" chunk body contains 4 __int32 values: channel index, number of partials, number of
|
xue@9
|
18 measurement points (frames), and a tag.
|
xue@9
|
19
|
xue@9
|
20 The "ATM\0" chunk body contains an atom structure (see hs.h).
|
xue@9
|
21
|
xue@9
|
22 */
|
xue@9
|
23
|
xue@9
|
24 #include <QtCore/QCoreApplication>
|
xue@9
|
25 #include "arrayalloc.h"
|
xue@9
|
26 #include "hs.h"
|
xue@9
|
27 #include "matrix.h"
|
xue@9
|
28 #include "quickspec.h"
|
xue@9
|
29 #include "procedures.h"
|
xue@9
|
30 #include "vibrato.h"
|
xue@9
|
31 #include <string.h>
|
xue@9
|
32 #include <stdio.h>
|
xue@9
|
33 #include <conio.h>
|
xue@9
|
34
|
xue@9
|
35 //structure hosting wave header data
|
xue@9
|
36 struct wavehdr
|
xue@9
|
37 {
|
xue@9
|
38 __int16 fmttag;
|
xue@9
|
39 __int16 channels;
|
xue@9
|
40 __int32 samplespersec;
|
xue@9
|
41 __int32 bytespersec;
|
xue@9
|
42 __int16 blockalign;
|
xue@9
|
43 __int16 bitspersample;
|
xue@9
|
44 };
|
xue@9
|
45
|
xue@9
|
46 //tells if a wave header contains consistent data
|
xue@9
|
47 bool isvalidwavehdr(wavehdr* hdr)
|
xue@9
|
48 {
|
xue@9
|
49 if (hdr->fmttag!=1) return false;
|
xue@9
|
50 if (hdr->bitspersample!=8 && hdr->bitspersample!=16) return false;
|
xue@9
|
51 if (hdr->channels*hdr->bitspersample!=hdr->blockalign*8) return false;
|
xue@9
|
52 if (hdr->samplespersec*hdr->blockalign!=hdr->bytespersec) return false;
|
xue@9
|
53 return true;
|
xue@9
|
54 }
|
xue@9
|
55
|
xue@9
|
56 //structure hosting a waveform audio
|
xue@9
|
57 struct waveaudio
|
xue@9
|
58 {
|
xue@9
|
59 union
|
xue@9
|
60 {
|
xue@9
|
61 wavehdr hdr;
|
xue@9
|
62 struct
|
xue@9
|
63 {
|
xue@9
|
64 __int16 fmttag;
|
xue@9
|
65 __int16 channels;
|
xue@9
|
66 __int32 samplespersec;
|
xue@9
|
67 __int32 bytespersec;
|
xue@9
|
68 __int16 blockalign;
|
xue@9
|
69 __int16 bitspersample;
|
xue@9
|
70 };
|
xue@9
|
71 };
|
xue@9
|
72 int length;
|
xue@9
|
73 union
|
xue@9
|
74 {
|
xue@9
|
75 unsigned char* data;
|
xue@9
|
76 unsigned char* data8;
|
xue@9
|
77 __int16* data16;
|
xue@9
|
78 };
|
xue@9
|
79 waveaudio(){memset(this, 0, sizeof(waveaudio));}
|
xue@9
|
80 ~waveaudio(){delete[] data;}
|
xue@9
|
81 };
|
xue@9
|
82
|
xue@9
|
83 void freewaveaudio(waveaudio* wa)
|
xue@9
|
84 {
|
xue@9
|
85 delete[] wa->data;
|
xue@9
|
86 memset(wa, 0, sizeof(waveaudio));
|
xue@9
|
87 }
|
xue@9
|
88
|
xue@9
|
89 //error messages for reading waveform audio file
|
xue@9
|
90 enum err_wavefile
|
xue@9
|
91 {
|
xue@9
|
92 err_success,
|
xue@9
|
93 err_RIFF_hdr,
|
xue@9
|
94 err_wave_hdr,
|
xue@9
|
95 err_data_hdr,
|
xue@9
|
96 err_data_chunk,
|
xue@9
|
97 err_io
|
xue@9
|
98 };
|
xue@9
|
99
|
xue@9
|
100 //reads wave header from file stream
|
xue@9
|
101 int loadwavehdr(wavehdr* hdr, FILE* fp)
|
xue@9
|
102 {
|
xue@9
|
103 int rc, hdrlen;
|
xue@9
|
104 char s[5];
|
xue@9
|
105
|
xue@9
|
106 rc=fread(s, 1, 4, fp); s[4]=0;
|
xue@9
|
107 if (rc<4) return err_wave_hdr;
|
xue@9
|
108 if (strcmp(s, "WAVE")) return err_wave_hdr;
|
xue@9
|
109
|
xue@9
|
110 rc=fread(s, 1, 4, fp); s[4]=0;
|
xue@9
|
111 if (rc<4) return err_wave_hdr;
|
xue@9
|
112 if (strcmp(s, "fmt ")) return err_wave_hdr;
|
xue@9
|
113
|
xue@9
|
114 rc=fread(&hdrlen, 1, 4, fp);
|
xue@9
|
115 if (rc<4) return err_wave_hdr;
|
xue@9
|
116 if (hdrlen<16) return err_wave_hdr;
|
xue@9
|
117
|
xue@9
|
118 rc=fread(hdr, 1, sizeof(wavehdr), fp);
|
xue@9
|
119 if (rc<sizeof(wavehdr)) return err_wave_hdr;
|
xue@9
|
120 if (!isvalidwavehdr(hdr)) return err_wave_hdr;
|
xue@9
|
121
|
xue@9
|
122 if (hdrlen>16)
|
xue@9
|
123 {
|
xue@9
|
124 rc=fseek(fp, hdrlen-16, SEEK_CUR);
|
xue@9
|
125 if (rc!=0) return err_wave_hdr;
|
xue@9
|
126 }
|
xue@9
|
127
|
xue@9
|
128 return err_success;
|
xue@9
|
129 }
|
xue@9
|
130
|
xue@9
|
131 //reads waveform audio, including header, from a file stream
|
xue@9
|
132 int loadwaveaudio(waveaudio* wa, FILE* fp)
|
xue@9
|
133 {
|
xue@9
|
134 int rc, mainlen;
|
xue@9
|
135 char s[5];
|
xue@9
|
136 wavehdr hdr;
|
xue@9
|
137
|
xue@9
|
138 rc=fread(s, 1, 4, fp); s[4]=0;
|
xue@9
|
139 if (rc<4) return err_RIFF_hdr;
|
xue@9
|
140 if (strcmp(s, "RIFF")) return err_RIFF_hdr;
|
xue@9
|
141
|
xue@9
|
142 rc=fread(&mainlen, 1, 4, fp);
|
xue@9
|
143 if (rc<4) return err_RIFF_hdr;
|
xue@9
|
144
|
xue@9
|
145 rc=loadwavehdr(&hdr, fp);
|
xue@9
|
146 if (rc!=err_success) return rc;
|
xue@9
|
147
|
xue@9
|
148 rc=fread(s, 1, 4, fp); s[4]=0;
|
xue@9
|
149 if (rc<4) return err_data_hdr;
|
xue@9
|
150 if (strcmp(s, "data")) return err_data_hdr;
|
xue@9
|
151
|
xue@9
|
152 rc=fread(&mainlen, 1, 4, fp);
|
xue@9
|
153 if (rc<4) return err_data_hdr;
|
xue@9
|
154
|
xue@9
|
155 if (mainlen<=0) return err_data_hdr;
|
xue@9
|
156
|
xue@9
|
157 unsigned char* data=new unsigned char[mainlen];
|
xue@9
|
158 rc=fread(data, 1, mainlen, fp);
|
xue@9
|
159 if (rc<mainlen)
|
xue@9
|
160 {
|
xue@9
|
161 delete[] data;
|
xue@9
|
162 return err_data_chunk;
|
xue@9
|
163 }
|
xue@9
|
164
|
xue@9
|
165 wa->hdr=hdr;
|
xue@9
|
166 wa->length=rc/hdr.blockalign;
|
xue@9
|
167 delete[] wa->data;
|
xue@9
|
168 wa->data=data;
|
xue@9
|
169
|
xue@9
|
170 return err_success;
|
xue@9
|
171 }
|
xue@9
|
172
|
xue@9
|
173 //reads waveform audio, including header, from a file
|
xue@9
|
174 int loadwavefile(waveaudio* wa, char* filename)
|
xue@9
|
175 {
|
xue@9
|
176 FILE* fp;
|
xue@9
|
177 if ((fp=fopen(filename, "rb"))==NULL) return err_io;
|
xue@9
|
178 int result=loadwaveaudio(wa, fp);
|
xue@9
|
179 fclose(fp);
|
xue@9
|
180 return result;
|
xue@9
|
181 }
|
xue@9
|
182
|
xue@9
|
183 //returns new file path with the specific extension replacing the original one
|
xue@9
|
184 char* ChangeFileExt(char* FileName, char* Ext)
|
xue@9
|
185 {
|
xue@9
|
186 char* oldext=strrchr(FileName, '.');
|
xue@9
|
187 int namelen=strlen(FileName)-strlen(oldext);
|
xue@9
|
188 char* dest=new char[namelen+strlen(Ext)+1];
|
xue@9
|
189 memcpy(dest, FileName, namelen); dest[namelen]=0;
|
xue@9
|
190 strcat(dest, Ext);
|
xue@9
|
191 return dest;
|
xue@9
|
192 }
|
xue@9
|
193
|
xue@9
|
194 //ACPower for __int16 data input
|
xue@9
|
195 double ACPower(__int16* data, int Count)
|
xue@9
|
196 {
|
xue@9
|
197 if (Count<=0) return 0;
|
xue@9
|
198 double power=0, avg=0, tmp;
|
xue@9
|
199 for (int i=0; i<Count; i++)
|
xue@9
|
200 {
|
xue@9
|
201 tmp=*(data++);
|
xue@9
|
202 power+=tmp*tmp;
|
xue@9
|
203 avg+=tmp;
|
xue@9
|
204 }
|
xue@9
|
205 power=(power-avg*avg/Count)/Count;
|
xue@9
|
206 return power;
|
xue@9
|
207 }//ACPower
|
xue@9
|
208
|
xue@9
|
209 //double QIE(double* y, double& x){double a=0.5*(y[1]+y[-1])-y[0], b=0.5*(y[1]-y[-1]); x=-0.5*b/a; return y[0]-0.25*b*b/a;}
|
xue@9
|
210
|
xue@9
|
211 //correlation coefficient
|
xue@9
|
212 double InnerC(int N, __int16* x, __int16* y)
|
xue@9
|
213 {
|
xue@9
|
214 double inner=0, inn1=0, inn2=0;
|
xue@9
|
215 for (int n=0; n<N; n++) inner+=1.0*x[n]*y[n], inn1+=1.0*x[n]*x[n], inn2+=1.0*y[n]*y[n];
|
xue@9
|
216 double inn=sqrt(inn1*inn2);
|
xue@9
|
217 return (inn<=0)?0:inner/inn;
|
xue@9
|
218 }
|
xue@9
|
219
|
xue@9
|
220 //monophonic pitch estimation by autocorrelation
|
xue@9
|
221 double pitchautocor(__int16* data, int wid, double minf0bin, double maxf0bin, double& hsr)
|
xue@9
|
222 {
|
xue@9
|
223 int hwid=wid/2, minT=wid/maxf0bin, maxT=wid/minf0bin;
|
xue@9
|
224 double ene=InnerC(wid, data, data);
|
xue@9
|
225 if (ene<=0){hsr=0; return 0;}
|
xue@9
|
226 double* autocor=new double[hwid];
|
xue@9
|
227 for (int i=1; i<maxT+2; i++)
|
xue@9
|
228 {
|
xue@9
|
229 autocor[i]=InnerC(wid-i, data, &data[i]);
|
xue@9
|
230 }
|
xue@9
|
231
|
xue@9
|
232 int prd=0, m=minT;
|
xue@9
|
233 while(m<=maxT)
|
xue@9
|
234 {
|
xue@9
|
235 while (m<=maxT && (autocor[m]<0 || autocor[m]<autocor[m-1] || autocor[m]<autocor[m+1])) m++;
|
xue@9
|
236 if (m<=maxT)
|
xue@9
|
237 {
|
xue@9
|
238 int mm=ceil(m*0.6667), mp=floor(m*1.3333), cont=0;
|
xue@10
|
239 //for (int im=mm; im<=mp; im++) if (m!=im && autocor[im]>=autocor[m]) {cont=1; break;}
|
xue@9
|
240 if (cont==0)
|
xue@9
|
241 {
|
xue@9
|
242 if (prd==0 || autocor[m]>autocor[prd]*1.05) prd=m;
|
xue@9
|
243 }
|
xue@9
|
244 m++;
|
xue@9
|
245 }
|
xue@9
|
246 }
|
xue@9
|
247
|
xue@9
|
248 double pitchbin=0;
|
xue@9
|
249 if (prd>=minT && prd<=maxT)
|
xue@9
|
250 {
|
xue@9
|
251 double mshift; hsr=QIE(&autocor[prd], mshift); pitchbin=wid/(prd+mshift);
|
xue@9
|
252 }
|
xue@9
|
253 else{hsr=0;}
|
xue@9
|
254 delete[] autocor;
|
xue@9
|
255 return pitchbin;
|
xue@9
|
256 }
|
xue@9
|
257
|
xue@9
|
258 //main function
|
xue@9
|
259 int main(int argc, char* argv[])
|
xue@9
|
260 {
|
xue@9
|
261 //read audio file
|
xue@9
|
262 if (argc<2){printf("Please specify input wave file."); getch(); return 0;}
|
xue@9
|
263 printf("Loading wave file %s... ", argv[1]);
|
xue@9
|
264 waveaudio* wa=new waveaudio;
|
xue@9
|
265 int waverr=loadwavefile(wa, argv[1]); printf("[%d]\n", waverr);
|
xue@9
|
266 if (waverr!=err_success){printf("Aborted: error loading wave file."); getch(); return 0;}
|
xue@9
|
267 if (wa->bitspersample!=16){printf("Aborted: this program accepts 16-bit pcm only."); getch(); return 0;}
|
xue@9
|
268
|
xue@9
|
269 int length=wa->length, sps=wa->samplespersec;
|
xue@9
|
270 __int16* data16=wa->data16;
|
xue@9
|
271 if (wa->channels>1)
|
xue@9
|
272 {
|
xue@9
|
273 printf("Extracting channel 0... ");
|
xue@9
|
274 for (int i=1; i<length; i++) data16[i]=data16[i*wa->channels];
|
xue@9
|
275 printf("[0]\n");
|
xue@9
|
276 }
|
xue@9
|
277 wa->data=0;
|
xue@9
|
278 delete wa;
|
xue@9
|
279
|
xue@9
|
280 //default settings
|
xue@9
|
281 int maxhscount=100;
|
xue@9
|
282 float wid_s=0.02, offstwidratio=0.5;
|
xue@9
|
283 float dur_s=0.5;
|
xue@9
|
284 float intv_s=0.05; //duration, in seconds, to scan for peaks
|
xue@9
|
285 float minf0=55, maxf0=3520;
|
xue@9
|
286 WindowType wintype=wtHann;
|
xue@9
|
287
|
xue@9
|
288 NMSettings settings; memset(&settings, 0, sizeof(NMSettings));
|
xue@9
|
289 settings.hB=3; //spectral truncation half width
|
xue@9
|
290 settings.maxp=50; //maximal number of partials
|
xue@9
|
291 settings.maxB=0.001; //stiffness coefficient upper bound
|
xue@9
|
292 settings.epf=1e-4; //frequency estimation error tolerance for LSE estimation
|
xue@9
|
293 settings.epf0=1; //input frequency error bound for harmonic grouping
|
xue@9
|
294 settings.delm=1.1; //frequency error bound for harmonic grouping
|
xue@9
|
295 settings.delp=1.1; //pitch jump upper bound
|
xue@9
|
296
|
xue@9
|
297 double mina=0.5;
|
xue@9
|
298
|
xue@9
|
299 //user settings through commandline arguments
|
xue@9
|
300 for (int i=2; i<argc; i++)
|
xue@9
|
301 {
|
xue@9
|
302 char* s1=strchr(argv[i], '=');
|
xue@9
|
303 if (s1)
|
xue@9
|
304 {
|
xue@9
|
305 s1[0]=0; s1++;
|
xue@9
|
306 if (!stricmp(argv[i], "hB")){settings.hB=atof(s1); continue;}
|
xue@9
|
307 if (!stricmp(argv[i], "maxp")){settings.maxp=atoi(s1); continue;}
|
xue@9
|
308 if (!stricmp(argv[i], "maxB")){settings.maxB=atof(s1); continue;}
|
xue@9
|
309 if (!stricmp(argv[i], "epf")){settings.epf=atof(s1); continue;}
|
xue@9
|
310 if (!stricmp(argv[i], "epf0")){settings.epf0=atof(s1); continue;}
|
xue@9
|
311 if (!stricmp(argv[i], "delm")){settings.delm=atof(s1); continue;}
|
xue@9
|
312 if (!stricmp(argv[i], "delp")){settings.delp=atof(s1); continue;}
|
xue@9
|
313 if (!stricmp(argv[i], "minf0")){minf0=atof(s1); continue;}
|
xue@9
|
314 if (!stricmp(argv[i], "maxf0")){maxf0=atof(s1); continue;}
|
xue@9
|
315 if (!stricmp(argv[i], "wid_s")){wid_s=atof(s1); continue;}
|
xue@9
|
316 if (!stricmp(argv[i], "offstwidratio")){offstwidratio=atof(s1); continue;}
|
xue@9
|
317 if (!stricmp(argv[i], "dur_s")){dur_s=atof(s1); continue;}
|
xue@9
|
318 if (!stricmp(argv[i], "intv_s")){intv_s=atof(s1); continue;}
|
xue@9
|
319 if (!stricmp(argv[i], "maxhscount")){maxhscount=atoi(s1); continue;}
|
xue@9
|
320 if (!stricmp(argv[i], "wintype"))
|
xue@9
|
321 {
|
xue@9
|
322 if (!stricmp(s1, "hann")){wintype=wtHann; continue;}
|
xue@9
|
323 if (!stricmp(s1, "hamming")){wintype=wtHamming; continue;}
|
xue@9
|
324 if (!stricmp(s1, "blackman")){wintype=wtBlackman; continue;}
|
xue@9
|
325 if (!stricmp(s1, "rectangle")){wintype=wtRectangle; continue;}
|
xue@9
|
326 if (!stricmp(s1, "hannsqr")){wintype=wtHannSqr; continue;}
|
xue@9
|
327 }
|
xue@9
|
328 }
|
xue@9
|
329 }
|
xue@9
|
330
|
xue@9
|
331 //
|
xue@9
|
332 MList* List=new MList; List->Add(data16, 1);
|
xue@9
|
333
|
xue@9
|
334 //analysis window size and hop size
|
xue@9
|
335 int wid=1<<((int)floor(log2(wid_s*sps)+1)), offst=wid*offstwidratio;
|
xue@9
|
336
|
xue@9
|
337 //set up the spectrogram
|
xue@9
|
338 TQuickSpectrogram* Sp=new TQuickSpectrogram(0, 0, true, false, 0);
|
xue@9
|
339 Sp->Data=data16; Sp->DataLength=length; Sp->BytesPerSample=2;
|
xue@9
|
340 Sp->Wid=wid; Sp->Offst=offst; Sp->WinType=wintype;
|
xue@9
|
341 Sp->Spec(-1); //this sets Sp->Capacity to the number of accessible frames and does nothing else
|
xue@9
|
342
|
xue@9
|
343 //get number of frames
|
xue@9
|
344 int Fr=Sp->Capacity;
|
xue@9
|
345
|
xue@9
|
346 //the program searches every intv_fr frames over a duration of dur_fr frames for a spectral peak to start tracking.
|
xue@9
|
347 int dur_fr=sps*dur_s/offst, intv_fr=sps*intv_s/offst;
|
xue@9
|
348 if (dur_fr<10) dur_fr=10;
|
xue@9
|
349 if (intv_fr<1) intv_fr=1;
|
xue@9
|
350
|
xue@9
|
351 //minimal and maximal fundamental frequency, in bins
|
xue@9
|
352 settings.minf0=minf0/sps*wid;
|
xue@9
|
353 settings.maxf0=maxf0/sps*wid;
|
xue@9
|
354 if (settings.minf0<settings.hB) settings.minf0=settings.hB;
|
xue@9
|
355
|
xue@9
|
356 windowspec(wintype, wid, &settings.M, settings.c, &settings.iH2);
|
xue@9
|
357 double *fps=new double[wid], *vps=&fps[wid/2]; List->Add(fps, 1);
|
xue@9
|
358 cdouble *x=new cdouble[wid/2+1]; List->Add(x, 1);
|
xue@9
|
359
|
xue@9
|
360 //output file
|
xue@9
|
361 char* filename=ChangeFileExt(argv[1], ".evt"); List->Add(filename, 1);
|
xue@9
|
362 TFileStream* File=new TFileStream(filename, fmWrite);
|
xue@9
|
363
|
xue@9
|
364 double* frames=new double[Fr]; memset(frames, 0, sizeof(double)*Fr); List->Add(frames, 1);
|
xue@9
|
365 double* framesa=new double[Fr]; memset(framesa, 0, sizeof(double)*Fr); List->Add(framesa, 1);
|
xue@9
|
366 double* rsr=new double[Fr]; List->Add(rsr, 1); memset(rsr, 0, sizeof(double)*Fr);
|
xue@9
|
367 double* f0s=new double[Fr]; List->Add(f0s, 1); memset(f0s, 0, sizeof(double)*Fr);
|
xue@9
|
368 for (int fr=0; fr<Fr-1; fr++)
|
xue@9
|
369 {
|
xue@9
|
370 __int16* ldata16=&data16[offst*fr];
|
xue@9
|
371 frames[fr]=ACPower(ldata16, wid);
|
xue@9
|
372 framesa[fr]=1;
|
xue@9
|
373 // f0s[fr]=pitchautocor(ldata16, wid, settings.minf0, settings.maxf0, rsr[fr]); rsr[fr]=1-rsr[fr];
|
xue@9
|
374 }
|
xue@9
|
375 frames[Fr-1]=ACPower(&data16[(Fr-1)*offst], length-(Fr-1)*offst);
|
xue@9
|
376 framesa[Fr-1]=1;
|
xue@9
|
377
|
xue@9
|
378 int start=0, writecount=0;
|
xue@9
|
379
|
xue@9
|
380 while (writecount<maxhscount)
|
xue@9
|
381 {
|
xue@9
|
382 int fr_m=start+intv_fr;
|
xue@9
|
383
|
xue@9
|
384 //search for the highest spectral peak to start tracking
|
xue@9
|
385 double fp_m=0, vp_m=0;
|
xue@9
|
386 for (int fr=start+intv_fr; fr<start+dur_fr && fr<Fr; fr+=intv_fr)
|
xue@9
|
387 {
|
xue@9
|
388 cmplx<QSPEC_FORMAT>* speci=Sp->Spec(fr);
|
xue@9
|
389 for (int k=0; k<=wid/2; k++) x[k]=speci[k];
|
xue@9
|
390 int pc=QuickPeaks(fps, vps, wid, x, settings.M, settings.c, settings.iH2, mina, 0, wid/4);
|
xue@9
|
391
|
xue@9
|
392 for(int p=0; p<pc; p++)
|
xue@9
|
393 if (vps[p]>vp_m)
|
xue@9
|
394 {
|
xue@9
|
395 if (f0s[fr]==0 && rsr[fr]==0) f0s[fr]=pitchautocor(&data16[offst*fr], wid, settings.minf0, settings.maxf0, rsr[fr]); rsr[fr]=1-rsr[fr];
|
xue@9
|
396 if (f0s[fr]>0)
|
xue@9
|
397 {
|
xue@9
|
398 double dpind=fps[p]/f0s[fr], pind=floor(dpind+0.5);
|
xue@9
|
399 if (fabs(dpind-pind)<0.1) vp_m=vps[p], fr_m=fr, fp_m=fps[p];
|
xue@9
|
400 }
|
xue@9
|
401 }
|
xue@9
|
402 }
|
xue@9
|
403
|
xue@9
|
404 if (fp_m<=0){start=start+dur_fr; if (start>Fr) break; continue;}
|
xue@9
|
405
|
xue@9
|
406 f0s[fr_m]=pitchautocor(&data16[offst*fr_m], wid, settings.minf0, settings.maxf0, rsr[fr_m]); rsr[fr_m]=1-rsr[fr_m];
|
xue@9
|
407
|
xue@9
|
408 int _t=fr_m*offst+wid/2;
|
xue@9
|
409 double _f=fp_m/wid;
|
xue@9
|
410 int hsM, hsFr, frst=start, fren=Fr;
|
xue@9
|
411 atom** hsPartials=0;
|
xue@9
|
412
|
xue@9
|
413 settings.pin0=floor(fp_m/f0s[fr_m]+0.5);
|
xue@9
|
414 int tag=FindNote(_t, _f, hsM, hsFr, hsPartials, frst, fren, wid, offst, Sp, settings);
|
xue@9
|
415
|
xue@9
|
416 int fr1=(hsPartials[0][0].t-wid/2)/offst;
|
xue@9
|
417 double consi=1;
|
xue@9
|
418 for (int hsfr=0; hsfr<hsFr; hsfr++)
|
xue@9
|
419 {
|
xue@9
|
420 double ene=0;
|
xue@9
|
421 for (int m=0; m<hsM; m++)
|
xue@9
|
422 {
|
xue@9
|
423 double a=(hsPartials[m][hsfr].f>0)?hsPartials[m][hsfr].a:0;
|
xue@9
|
424
|
xue@9
|
425 if (hsfr==0) ene+=a*a;
|
xue@9
|
426 else
|
xue@9
|
427 {
|
xue@9
|
428 double b=(hsPartials[m][hsfr-1].f>0)?hsPartials[m][hsfr-1].a:0;
|
xue@9
|
429 ene+=(a*a+b*b+a*b)/3;
|
xue@9
|
430 }
|
xue@9
|
431
|
xue@9
|
432 if (hsfr==hsFr-1) ene+=a*a;
|
xue@9
|
433 else
|
xue@9
|
434 {
|
xue@9
|
435 double b=(hsPartials[m][hsfr+1].f>0)?hsPartials[m][hsfr+1].a:0;
|
xue@9
|
436 ene+=(a*a+b*b+a*b)/3;
|
xue@9
|
437 }
|
xue@9
|
438 }
|
xue@9
|
439 framesa[fr1+hsfr]=ene;//*2;
|
xue@9
|
440 if (framesa[fr1+hsfr]<frames[fr1+hsfr]) consi*=frames[fr1+hsfr]/framesa[fr1+hsfr];
|
xue@9
|
441 else consi*=framesa[fr1+hsfr]/frames[fr1+hsfr];
|
xue@9
|
442 if (framesa[fr1+hsfr]>frames[fr1+hsfr]) framesa[fr1+hsfr]=0;
|
xue@9
|
443 else framesa[fr1+hsfr]=1-framesa[fr1+hsfr]/frames[fr1+hsfr];
|
xue@9
|
444 }
|
xue@9
|
445 consi=pow(consi, 1.0/hsFr);
|
xue@9
|
446
|
xue@9
|
447 THS* HS=new THS;
|
xue@9
|
448 HS->M=hsM; HS->Fr=hsFr; HS->Partials=hsPartials;
|
xue@9
|
449 printf("%d (%.2fs), %d (%.2fs), inconsistency %f\n", start, start*offst*1.0/sps, hsFr, hsFr*offst*1.0/sps, consi-1);
|
xue@9
|
450 if (consi<1.5)
|
xue@9
|
451 {
|
xue@9
|
452 HS->WriteToStream(File);
|
xue@9
|
453 printf("Write note %d\n", writecount++);
|
xue@9
|
454 }
|
xue@9
|
455 delete HS;
|
xue@9
|
456
|
xue@9
|
457 start=fr1+hsFr;
|
xue@9
|
458
|
xue@9
|
459 }
|
xue@9
|
460 delete File; delete Sp;
|
xue@9
|
461 delete List;
|
xue@9
|
462 printf("Completed\n"); getch(); return 0;
|
xue@9
|
463 }
|