xue@11
|
1 /*
|
xue@11
|
2 Harmonic sinusoidal modelling and tools
|
xue@11
|
3
|
xue@11
|
4 C++ code package for harmonic sinusoidal modelling and relevant signal processing.
|
xue@11
|
5 Centre for Digital Music, Queen Mary, University of London.
|
xue@11
|
6 This file copyright 2011 Wen Xue.
|
xue@11
|
7
|
xue@11
|
8 This program is free software; you can redistribute it and/or
|
xue@11
|
9 modify it under the terms of the GNU General Public License as
|
xue@11
|
10 published by the Free Software Foundation; either version 2 of the
|
xue@11
|
11 License, or (at your option) any later version.
|
xue@11
|
12 */
|
xue@1
|
13 //---------------------------------------------------------------------------
|
xue@1
|
14 #include <math.h>
|
xue@1
|
15 #include "hs.h"
|
xue@1
|
16 #include "align8.h"
|
xue@1
|
17 #include "arrayalloc.h"
|
xue@1
|
18 #include "procedures.h"
|
Chris@2
|
19 #include "sinest.h"
|
Chris@2
|
20 #include "sinsyn.h"
|
xue@1
|
21 #include "splines.h"
|
xue@1
|
22 #include "xcomplex.h"
|
xue@1
|
23 #ifdef I
|
xue@1
|
24 #undef I
|
xue@1
|
25 #endif
|
xue@1
|
26
|
Chris@5
|
27 /** \file hs.h */
|
Chris@5
|
28
|
xue@1
|
29 //---------------------------------------------------------------------------
|
xue@1
|
30 //stiffcandid methods
|
xue@1
|
31
|
Chris@5
|
32 /**
|
xue@1
|
33 method stiffcandid::stiffcandid: creates a harmonic atom with minimal info, i.e. fundamantal frequency
|
xue@1
|
34 between 0 and Nyqvist frequency, stiffness coefficient between 0 and STIFF_B_MAX.
|
xue@1
|
35
|
xue@1
|
36 In: Wid: DFT size (frame size, frequency resolution)
|
xue@1
|
37 */
|
xue@1
|
38 stiffcandid::stiffcandid(int Wid)
|
xue@1
|
39 {
|
xue@1
|
40 F=new double[6];
|
xue@1
|
41 G=&F[3];
|
xue@1
|
42 double Fm=Wid*Wid/4; //NyqvistF^2
|
xue@1
|
43 F[0]=0, G[0]=0;
|
xue@1
|
44 F[1]=Fm, G[1]=STIFF_B_MAX*Fm;
|
xue@1
|
45 F[2]=Fm, G[2]=0;
|
xue@1
|
46 N=3;
|
xue@1
|
47 P=0;
|
xue@1
|
48 s=0;
|
xue@1
|
49 p=NULL;
|
xue@1
|
50 f=NULL;
|
xue@1
|
51 }//stiffcandid
|
xue@1
|
52
|
Chris@5
|
53 /**
|
xue@1
|
54 method stiffcandid::stiffcandid: creates a harmonic atom with a frequency range for the $ap-th partial,
|
xue@1
|
55 without actually taking this partial as "known".
|
xue@1
|
56
|
xue@1
|
57 In; Wid: DFT size
|
xue@1
|
58 ap: partial index
|
xue@1
|
59 af, errf: centre and half-width of the frequency range of the ap-th partial, in bins
|
xue@1
|
60 */
|
xue@1
|
61 stiffcandid::stiffcandid(int Wid, int ap, double af, double errf)
|
xue@1
|
62 {
|
xue@1
|
63 F=new double[10];
|
xue@1
|
64 G=&F[5];
|
xue@1
|
65 double Fm=Wid*Wid/4;
|
xue@1
|
66 F[0]=0, G[0]=0;
|
xue@1
|
67 F[1]=Fm, G[1]=STIFF_B_MAX*Fm;
|
xue@1
|
68 F[2]=Fm, G[2]=0;
|
xue@1
|
69 N=3;
|
xue@1
|
70 P=0;
|
xue@1
|
71 s=0;
|
xue@1
|
72 p=NULL;
|
xue@1
|
73 f=NULL;
|
xue@1
|
74 double k=ap*ap-1;
|
xue@1
|
75 double g1=(af-errf)/ap, g2=(af+errf)/ap;
|
xue@1
|
76 if (g1<0) g1=0;
|
xue@1
|
77 g1=g1*g1, g2=g2*g2;
|
xue@1
|
78 //apply constraints F+kG-g2<0 and -F-kG+g1<0
|
xue@1
|
79 cutcvpoly(N, F, G, 1, k, -g2);
|
xue@1
|
80 cutcvpoly(N, F, G, -1, -k, g1);
|
xue@1
|
81 }//stiffcandid
|
xue@1
|
82
|
Chris@5
|
83 /**
|
xue@1
|
84 method stiffcandid::stiffcandid: creates a harmonic atom from one atom.
|
xue@1
|
85
|
xue@1
|
86 In; Wid: DFT size
|
xue@1
|
87 ap: partial index of the atom.
|
xue@1
|
88 af, errf: centre and half-width of the frequency range of the atom, in bins.
|
xue@1
|
89 ds: contribution to candidate score from this atom.
|
xue@1
|
90 */
|
xue@1
|
91 stiffcandid::stiffcandid(int Wid, int ap, double af, double errf, double ds)
|
xue@1
|
92 {
|
xue@1
|
93 //the starting polygon implements the trivial constraints 0<f0<NyqvistF,
|
xue@1
|
94 // 0<B<Bmax. in terms of F and G, 0<F<NF^2, 0<G<FBmax. this is a triangle
|
xue@1
|
95 // with vertices (0, 0), (NF^2, Bmax*NF^2), (NF^2, 0)
|
xue@1
|
96 F=new double[12];
|
xue@1
|
97 G=&F[5], f=&F[10], p=(int*)&F[11];
|
xue@1
|
98 double Fm=Wid*Wid/4; //NyqvistF^2
|
xue@1
|
99 F[0]=0, G[0]=0;
|
xue@1
|
100 F[1]=Fm, G[1]=STIFF_B_MAX*Fm;
|
xue@1
|
101 F[2]=Fm, G[2]=0;
|
xue@1
|
102
|
xue@1
|
103 N=3;
|
xue@1
|
104 P=1;
|
xue@1
|
105 p[0]=ap;
|
xue@1
|
106 f[0]=af;
|
xue@1
|
107 s=ds;
|
xue@1
|
108
|
xue@1
|
109 double k=ap*ap-1;
|
xue@1
|
110 double g1=(af-errf)/ap, g2=(af+errf)/ap;
|
xue@1
|
111 if (g1<0) g1=0;
|
xue@1
|
112 g1=g1*g1, g2=g2*g2;
|
xue@1
|
113 //apply constraints F+kG-g2<0 and -F-kG+g1<0
|
xue@1
|
114 cutcvpoly(N, F, G, 1, k, -g2);
|
xue@1
|
115 cutcvpoly(N, F, G, -1, -k, g1);
|
xue@1
|
116 }//stiffcandid
|
xue@1
|
117
|
xue@1
|
118 /*
|
xue@1
|
119 method stiffcandid::stiffcandid: creates a harmonic atom by adding a new partial to an existing
|
xue@1
|
120 harmonic atom.
|
xue@1
|
121
|
xue@1
|
122 In; prev: initial harmonic atom
|
xue@1
|
123 ap: partial index of new atom
|
xue@1
|
124 af, errf: centre and half-width of the frequency range of the new atom, in bins.
|
xue@1
|
125 ds: contribution to candidate score from this atom.
|
xue@1
|
126 */
|
xue@1
|
127 stiffcandid::stiffcandid(stiffcandid* prev, int ap, double af, double errf, double ds)
|
xue@1
|
128 {
|
xue@1
|
129 N=prev->N, P=prev->P, s=prev->s;
|
xue@1
|
130 int Np2=N+2, Pp1=P+1;
|
xue@1
|
131 F=new double[(Np2+Pp1)*2];
|
xue@1
|
132 G=&F[Np2]; f=&G[Np2]; p=(int*)&f[Pp1];
|
xue@1
|
133 memcpy(F, prev->F, sizeof(double)*N);
|
xue@1
|
134 memcpy(G, prev->G, sizeof(double)*N);
|
xue@1
|
135 if (P>0)
|
xue@1
|
136 {
|
xue@1
|
137 memcpy(f, prev->f, sizeof(double)*P);
|
xue@1
|
138 memcpy(p, prev->p, sizeof(int)*P);
|
xue@1
|
139 }
|
xue@1
|
140 //see if partial ap is already involved
|
xue@1
|
141 int i=0; while (i<P && p[i]!=ap) i++;
|
xue@1
|
142 //if it is not:
|
xue@1
|
143 if (i>=P)
|
xue@1
|
144 {
|
xue@1
|
145 p[P]=ap;
|
xue@1
|
146 f[P]=af;
|
xue@1
|
147 s+=ds;
|
xue@1
|
148 P++;
|
xue@1
|
149
|
xue@1
|
150 double k=ap*ap-1;
|
xue@1
|
151 double g1=(af-errf)/ap, g2=(af+errf)/ap;
|
xue@1
|
152 if (g1<0) g1=0;
|
xue@1
|
153 g1=g1*g1, g2=g2*g2;
|
xue@1
|
154 //apply constraints F+kG-g2<0 and -F-kG+g1<0
|
xue@1
|
155 cutcvpoly(N, F, G, 1, k, -g2);
|
xue@1
|
156 cutcvpoly(N, F, G, -1, -k, g1);
|
xue@1
|
157 }
|
xue@1
|
158 //otherwise, the new candid is simply a copy of prev
|
xue@1
|
159 }//stiffcandid
|
xue@1
|
160
|
xue@1
|
161 //method stiffcandid::~stiffcandid: destructor
|
xue@1
|
162 stiffcandid::~stiffcandid()
|
xue@1
|
163 {
|
xue@1
|
164 delete[] F;
|
xue@1
|
165 }//~stiffcandid
|
xue@1
|
166
|
xue@1
|
167
|
xue@1
|
168 //---------------------------------------------------------------------------
|
xue@1
|
169 //THS methods
|
xue@1
|
170
|
xue@1
|
171 //method THS::THS: default constructor
|
xue@1
|
172 THS::THS()
|
xue@1
|
173 {
|
xue@1
|
174 memset(this, 0, sizeof(THS));
|
xue@1
|
175 memset(BufM, 0, sizeof(void*)*128);
|
xue@1
|
176 }//THS
|
xue@1
|
177
|
xue@1
|
178 /*
|
xue@1
|
179 method THS::THS: creates an HS with given number of partials and frames.
|
xue@1
|
180
|
xue@1
|
181 In: aM, aFr: number of partials and frames
|
xue@1
|
182 */
|
xue@1
|
183 THS::THS(int aM, int aFr)
|
xue@1
|
184 {
|
xue@1
|
185 memset(this, 0, sizeof(THS));
|
xue@1
|
186 M=aM; Fr=aFr; Allocate2(atom, M, Fr, Partials);
|
xue@1
|
187 memset(Partials[0], 0, sizeof(atom)*M*Fr);
|
xue@1
|
188 memset(BufM, 0, sizeof(void*)*128);
|
xue@1
|
189 }//THS
|
xue@1
|
190
|
xue@1
|
191 /*
|
xue@1
|
192 method THS::THS: creates a duplicate HS. This does not duplicate contents of BufM.
|
xue@1
|
193
|
xue@1
|
194 In: HS: the HS to duplicate
|
xue@1
|
195 */
|
xue@1
|
196 THS::THS(THS* HS)
|
xue@1
|
197 {
|
xue@1
|
198 memcpy(this, HS, sizeof(THS));
|
xue@1
|
199 Allocate2(atom, M, Fr, Partials);
|
xue@1
|
200 for (int m=0; m<M; m++) memcpy(Partials[m], HS->Partials[m], sizeof(atom)*Fr);
|
xue@1
|
201 Allocate2(double, M, st_count, startamp);
|
xue@1
|
202 if (st_count) for (int m=0; m<M; m++) memcpy(startamp[m], HS->startamp[m], sizeof(double)*st_count);
|
xue@1
|
203 memset(BufM, 0, sizeof(void*)*128);
|
xue@1
|
204 }//THS
|
xue@1
|
205
|
xue@1
|
206 /*
|
xue@1
|
207 method THS::THS: create a new HS which is a trunction of an existing HS.
|
xue@1
|
208
|
xue@1
|
209 In: HS: the exinting HS from which a sub-HS is to be created
|
xue@1
|
210 start, end: truncation points. Atoms of *HS beyond these points are discarded.
|
xue@1
|
211 */
|
xue@1
|
212 THS::THS(THS* HS, double start, double end)
|
xue@1
|
213 {
|
xue@1
|
214 memset(this, 0, sizeof(THS));
|
xue@1
|
215 M=HS->M; Fr=HS->Fr; isconstf=HS->isconstf;
|
xue@1
|
216 int frst=0, fren=Fr;
|
xue@1
|
217 while (HS->Partials[0][frst].t<start && frst<fren) frst++;
|
xue@1
|
218 while (HS->Partials[0][fren-1].t>end && fren>frst) fren--;
|
xue@1
|
219 Fr=fren-frst;
|
xue@1
|
220 Allocate2(atom, M, Fr, Partials);
|
xue@1
|
221 for (int m=0; m<M; m++)
|
xue@1
|
222 {
|
xue@1
|
223 memcpy(Partials[m], &HS->Partials[m][frst], sizeof(atom)*Fr);
|
xue@1
|
224 for (int fr=0; fr<Fr; fr++) Partials[m][fr].t-=start;
|
xue@1
|
225 }
|
xue@1
|
226 if (frst>0){DeAlloc2(startamp); startamp=0;}
|
xue@1
|
227 }//THS
|
xue@1
|
228
|
xue@1
|
229 //method THS::~THS: default descructor.
|
xue@1
|
230 THS::~THS()
|
xue@1
|
231 {
|
xue@1
|
232 DeAlloc2(Partials);
|
xue@1
|
233 DeAlloc2(startamp);
|
xue@1
|
234 ClearBufM();
|
xue@1
|
235 }//~THS
|
xue@1
|
236
|
xue@1
|
237 /*
|
xue@1
|
238 method THS::ClearBufM: free buffers pointed to by members of BufM.
|
xue@1
|
239 */
|
xue@1
|
240 void THS::ClearBufM()
|
xue@1
|
241 {
|
xue@1
|
242 for (int m=0; m<128; m++) delete[] BufM[m];
|
xue@1
|
243 memset(BufM, 0, sizeof(void*)*128);
|
xue@1
|
244 }//ClearBufM
|
xue@1
|
245
|
xue@1
|
246 /*
|
xue@1
|
247 method THS::EndPos: the end position of an HS.
|
xue@1
|
248
|
xue@1
|
249 Returns the time of the last frame of the first partial.
|
xue@1
|
250 */
|
xue@1
|
251 int THS::EndPos()
|
xue@1
|
252 {
|
xue@1
|
253 return Partials[0][Fr-1].t;
|
xue@1
|
254 }//EndPos
|
xue@1
|
255
|
xue@1
|
256 /*
|
xue@1
|
257 method THS::EndPosEx: the extended end position of an HS.
|
xue@1
|
258
|
xue@1
|
259 Returns the time later than the last frame of the first partial by the interval between the first and
|
xue@1
|
260 second frames of that partial.
|
xue@1
|
261 */
|
xue@1
|
262 int THS::EndPosEx()
|
xue@1
|
263 {
|
xue@1
|
264 return Partials[0][Fr-1].t+Partials[0][1].t-Partials[0][0].t;
|
xue@1
|
265 }//EndPosEx
|
xue@1
|
266
|
xue@1
|
267 /*
|
xue@1
|
268 method THS::ReadAtomFromStream: reads an atom from a stream.
|
xue@1
|
269
|
xue@1
|
270 Returns the number of bytes read, or 0 on failure. The stream pointer is shifted by this value.
|
xue@1
|
271 */
|
xue@1
|
272 int THS::ReadAtomFromStream(TStream* Stream, atom* atm)
|
xue@1
|
273 {
|
xue@1
|
274 int StartPosition=Stream->Position, atomlen; char s[4];
|
xue@1
|
275 if (Stream->Read(s, 4)!=4) goto ret0;
|
xue@1
|
276 if (strcmp(s, "ATM")) goto ret0;
|
xue@1
|
277 if (Stream->Read(&atomlen, sizeof(int))!=sizeof(int)) goto ret0;
|
xue@1
|
278 if (Stream->Read(atm, atomlen)!=atomlen) goto ret0;
|
xue@1
|
279 return atomlen+4+sizeof(int);
|
xue@1
|
280 ret0:
|
xue@1
|
281 Stream->Position=StartPosition;
|
xue@1
|
282 return 0;
|
xue@1
|
283 }//ReadAtomFromStream
|
xue@1
|
284
|
xue@1
|
285 /*
|
xue@1
|
286 method THS::ReadFromStream: reads an HS from a stream.
|
xue@1
|
287
|
xue@1
|
288 Returns the number of bytes read, or 0 on failure. The stream pointer is shifted by this value.
|
xue@1
|
289 */
|
xue@1
|
290 int THS::ReadFromStream(TStream* Stream)
|
xue@1
|
291 {
|
xue@1
|
292 int StartPosition=Stream->Position, lenevt; char s[4];
|
xue@1
|
293 if (Stream->Read(s, 4)!=4) goto ret0;
|
xue@1
|
294 if (strcmp(s, "EVT")) goto ret0;
|
xue@1
|
295 if (Stream->Read(&lenevt, sizeof(int))!=sizeof(int)) goto ret0;
|
xue@1
|
296 if (!ReadHdrFromStream(Stream)) goto ret0;
|
xue@1
|
297 Resize(M, Fr, false, true);
|
xue@1
|
298 for (int m=0; m<M; m++) for (int fr=0; fr<Fr; fr++) if (!ReadAtomFromStream(Stream, &Partials[m][fr])) goto ret0;
|
xue@1
|
299 lenevt=lenevt+4+sizeof(int);
|
xue@1
|
300 if (lenevt!=Stream->Position-StartPosition) goto ret0;
|
xue@1
|
301 return lenevt;
|
xue@1
|
302 ret0:
|
xue@1
|
303 Stream->Position=StartPosition;
|
xue@1
|
304 return 0;
|
xue@1
|
305 }//ReadFromStream
|
xue@1
|
306
|
xue@1
|
307 /*
|
xue@1
|
308 method THS::ReadHdrFromStream: reads header from a stream into this HS.
|
xue@1
|
309
|
xue@1
|
310 Returns the number of bytes read, or 0 on failure. The stream pointer is shifted by this value.
|
xue@1
|
311 */
|
xue@1
|
312 int THS::ReadHdrFromStream(TStream* Stream)
|
xue@1
|
313 {
|
xue@1
|
314 int StartPosition=Stream->Position, hdrlen, tags; char s[4];
|
xue@1
|
315 if (Stream->Read(s, 4)!=4) goto ret0;
|
xue@1
|
316 if (strcmp(s, "HDR")) goto ret0;
|
xue@1
|
317 if (Stream->Read(&hdrlen, sizeof(int))!=sizeof(int)) goto ret0;
|
xue@1
|
318 if (Stream->Read(&Channel, sizeof(int))!=sizeof(int)) goto ret0;
|
xue@1
|
319 if (Stream->Read(&M, sizeof(int))!=sizeof(int)) goto ret0;
|
xue@1
|
320 if (Stream->Read(&Fr, sizeof(int))!=sizeof(int)) goto ret0;
|
xue@1
|
321 if (Stream->Read(&tags, sizeof(int))!=sizeof(int)) goto ret0;
|
xue@1
|
322 isconstf=tags&HS_CONSTF;
|
xue@1
|
323 hdrlen=hdrlen+4+sizeof(int); //expected read count
|
xue@1
|
324 if (hdrlen!=Stream->Position-StartPosition) goto ret0;
|
xue@1
|
325 return hdrlen;
|
xue@1
|
326 ret0:
|
xue@1
|
327 Stream->Position=StartPosition;
|
xue@1
|
328 return 0;
|
xue@1
|
329 }//ReadHdrFromStream
|
xue@1
|
330
|
xue@1
|
331 /*
|
xue@1
|
332 method THS::Resize: change the number of partials or frames of an HS structure. Unless forcealloc is
|
xue@1
|
333 set to true, this allocates new buffers to host HS data only when the new dimensions are larger than
|
xue@1
|
334 current ones.
|
xue@1
|
335
|
xue@1
|
336 In: aM, aFr: new number of partials and frames
|
xue@1
|
337 copydata: specifies if HS data is to be copied to new buffers.
|
xue@1
|
338 forcealloc: specifies if new buffers are to be allocated in all cases.
|
xue@1
|
339 */
|
xue@1
|
340 void THS::Resize(int aM, int aFr, bool copydata, bool forcealloc)
|
xue@1
|
341 {
|
xue@1
|
342 if (forcealloc || M<aM || Fr<aFr)
|
xue@1
|
343 {
|
xue@1
|
344 atom** Allocate2(atom, aM, aFr, NewPartials);
|
xue@1
|
345 if (copydata)
|
xue@1
|
346 {
|
xue@1
|
347 int minM=(M<aM)?M:aM, minFr=(Fr<aFr)?Fr:aFr;
|
xue@1
|
348 for (int m=0; m<minM; m++) memcpy(NewPartials[m], Partials[m], sizeof(atom)*minFr);
|
xue@1
|
349 }
|
xue@1
|
350 DeAlloc2(Partials);
|
xue@1
|
351 Partials=NewPartials;
|
xue@1
|
352 }
|
xue@1
|
353 if (forcealloc || M<aM)
|
xue@1
|
354 {
|
xue@1
|
355 double** Allocate2(double, aM, st_count, newstartamp);
|
xue@1
|
356 if (copydata)
|
xue@1
|
357 {
|
xue@1
|
358 for (int m=0; m<M; m++) memcpy(newstartamp[m], startamp[m], sizeof(double)*st_count);
|
xue@1
|
359 }
|
xue@1
|
360 DeAlloc2(startamp);
|
xue@1
|
361 startamp=newstartamp;
|
xue@1
|
362 }
|
xue@1
|
363 M=aM, Fr=aFr;
|
xue@1
|
364 }//Resize
|
xue@1
|
365
|
xue@1
|
366 /*
|
xue@1
|
367 method THS::StartPos: the start position of an HS.
|
xue@1
|
368
|
xue@1
|
369 Returns the time of the first frame of the first partial.
|
xue@1
|
370 */
|
xue@1
|
371 int THS::StartPos()
|
xue@1
|
372 {
|
xue@1
|
373 return Partials[0][0].t;
|
xue@1
|
374 }//StartPos
|
xue@1
|
375
|
xue@1
|
376 /*
|
xue@1
|
377 method THS::StdOffst: standard hop size of an HS.
|
xue@1
|
378 Returns the interval between the timing of the first and second frames of the first partial, which is
|
xue@1
|
379 the "standard" hop size if all measurement points are uniformly positioned.
|
xue@1
|
380 */
|
xue@1
|
381 int THS::StdOffst()
|
xue@1
|
382 {
|
xue@1
|
383 return Partials[0][1].t-Partials[0][0].t;
|
xue@1
|
384 }//StdOffst
|
xue@1
|
385
|
xue@1
|
386 /*
|
xue@1
|
387 method THS::WriteAtomToStream: writes an atom to a stream. An atom is stored in a stream as an RIFF
|
xue@1
|
388 chunk identified by "ATM\0".
|
xue@1
|
389
|
xue@1
|
390 Returns the number of bytes written. The stream pointer is shifted by this value.
|
xue@1
|
391 */
|
xue@1
|
392 int THS::WriteAtomToStream(TStream* Stream, atom* atm)
|
xue@1
|
393 {
|
xue@1
|
394 Stream->Write((void*)"ATM", 4);
|
xue@1
|
395 int atomlen=sizeof(atom);
|
xue@1
|
396 Stream->Write(&atomlen, sizeof(int));
|
xue@1
|
397 atomlen=Stream->Write(atm, atomlen);
|
xue@1
|
398 return atomlen+4+sizeof(int);
|
xue@1
|
399 }//WriteAtomToStream
|
xue@1
|
400
|
xue@1
|
401 /*
|
xue@1
|
402 method THS::WriteHdrToStream: writes header to a stream. HS header is stored in a stream as an RIFF
|
xue@1
|
403 chunk, identified by "HDR\0".
|
xue@1
|
404
|
xue@1
|
405 Returns the number of bytes written. The stream pointer is shifted by this value.
|
xue@1
|
406 */
|
xue@1
|
407 int THS::WriteHdrToStream(TStream* Stream)
|
xue@1
|
408 {
|
xue@1
|
409 Stream->Write((void*)"HDR", 4);
|
xue@1
|
410 int hdrlen=0, tags=0;
|
xue@1
|
411 if (isconstf) tags=tags|HS_CONSTF;
|
xue@1
|
412 Stream->Write(&hdrlen, sizeof(int));
|
xue@1
|
413 Stream->Write(&Channel, sizeof(int)); hdrlen+=sizeof(int);
|
xue@1
|
414 Stream->Write(&M, sizeof(int)); hdrlen+=sizeof(int);
|
xue@1
|
415 Stream->Write(&Fr, sizeof(int)); hdrlen+=sizeof(int);
|
xue@1
|
416 Stream->Write(&tags, sizeof(int)); hdrlen+=sizeof(int);
|
xue@1
|
417 Stream->Seek(-hdrlen-sizeof(int), soFromCurrent); Stream->Write(&hdrlen, sizeof(int));
|
xue@1
|
418 Stream->Seek(hdrlen, soFromCurrent);
|
xue@1
|
419 return hdrlen+4+sizeof(int);
|
xue@1
|
420 }//WriteHdrToStream
|
xue@1
|
421
|
xue@1
|
422 /*
|
xue@1
|
423 method THS::WriteToStream: write an HS to a stream. An HS is stored in a stream as an RIFF chunk
|
xue@1
|
424 identified by "EVT\0". Its chunk data contains an HS header chunk followed by M*Fr atom chunks, in
|
xue@1
|
425 rising order of m then fr.
|
xue@1
|
426
|
xue@1
|
427 Returns the number of bytes written. The stream pointer is shifted by this value.
|
xue@1
|
428 */
|
xue@1
|
429 int THS::WriteToStream(TStream* Stream)
|
xue@1
|
430 {
|
xue@1
|
431 Stream->Write((void*)"EVT", 4);
|
xue@1
|
432 int lenevt=0;
|
xue@1
|
433 Stream->Write(&lenevt, sizeof(int));
|
xue@1
|
434 lenevt+=WriteHdrToStream(Stream);
|
xue@1
|
435
|
xue@1
|
436 for (int m=0; m<M; m++) for (int fr=0; fr<Fr; fr++) lenevt+=WriteAtomToStream(Stream, &Partials[m][fr]);
|
xue@1
|
437 Stream->Seek(-lenevt-sizeof(int), soFromCurrent);
|
xue@1
|
438 Stream->Write(&lenevt, sizeof(int));
|
xue@1
|
439 Stream->Seek(lenevt, soFromCurrent);
|
xue@1
|
440 return lenevt+4+sizeof(int);
|
xue@1
|
441 }//WriteToStream
|
xue@1
|
442
|
xue@1
|
443
|
xue@1
|
444 //---------------------------------------------------------------------------
|
xue@1
|
445 //TPolygon methods
|
xue@1
|
446
|
xue@1
|
447 /*
|
xue@1
|
448 method TPolygon::TPolygon: create an empty polygon with a storage capacity
|
xue@1
|
449
|
xue@1
|
450 In: cap: number of vertices to allocate memory for.
|
xue@1
|
451 */
|
xue@1
|
452 TPolygon::TPolygon(int cap)
|
xue@1
|
453 {
|
xue@1
|
454 X=(double*)malloc8(sizeof(double)*cap*2);
|
xue@1
|
455 Y=&X[cap];
|
xue@1
|
456 }//TPolygon
|
xue@1
|
457
|
xue@1
|
458 /*
|
xue@1
|
459 method TPolygon::TPolygon: create a duplicate polygon.
|
xue@1
|
460
|
xue@1
|
461 In: cap: number of vertices to allocate memory for.
|
xue@1
|
462 R: the polygon to duplicate.
|
xue@1
|
463
|
xue@1
|
464 If cap is smaller than the number of vertices of R, the latter is used for memory allocation.
|
xue@1
|
465 */
|
xue@1
|
466 TPolygon::TPolygon(int cap, TPolygon* R)
|
xue@1
|
467 {
|
xue@1
|
468 if (cap<R->N) cap=R->N; X=(double*)malloc8(sizeof(double)*cap*2); Y=&X[cap]; N=R->N;
|
xue@1
|
469 memcpy(X, R->X, sizeof(double)*R->N); memcpy(Y, R->Y, sizeof(double)*R->N);
|
xue@1
|
470 }//TPolygon
|
xue@1
|
471
|
xue@1
|
472 //method TPolygon::~TPolygon: default destructor.
|
xue@1
|
473 TPolygon::~TPolygon()
|
xue@1
|
474 {
|
xue@1
|
475 free8(X);
|
xue@1
|
476 }//~TPolygon
|
xue@1
|
477
|
xue@1
|
478 //---------------------------------------------------------------------------
|
xue@1
|
479 //TTempAtom methods
|
xue@1
|
480
|
xue@1
|
481 /*
|
xue@1
|
482 method TTempAtom::TTempAtom: initializes an empty atom with a fundamental frequency range.
|
xue@1
|
483
|
xue@1
|
484 In: af, ef: centre and half width of the fundamental frequency
|
xue@1
|
485 maxB: upper bound of stiffness coefficient
|
xue@1
|
486 */
|
xue@1
|
487 TTempAtom::TTempAtom(double af, double ef, double maxB)
|
xue@1
|
488 {
|
xue@1
|
489 Prev=NULL; pind=f=a=s=acce=0;
|
xue@1
|
490 R=new TPolygon(4);
|
xue@1
|
491 InitializeR(R, af, ef, maxB);
|
xue@1
|
492 }//TTempAtom
|
xue@1
|
493
|
xue@1
|
494 /*
|
xue@1
|
495 method TTempAtom::TTempAtom: initialize an empty atom with a frequency range for a certain partial.
|
xue@1
|
496
|
xue@1
|
497 In: apin: partial index
|
xue@1
|
498 af, ef: centre and half width of the fundamental frequency
|
xue@1
|
499 maxB: upper bound of stiffness coefficient
|
xue@1
|
500 */
|
xue@1
|
501 TTempAtom::TTempAtom(int apin, double af, double ef, double maxB)
|
xue@1
|
502 {
|
xue@1
|
503 Prev=NULL; pind=f=a=s=acce=0;
|
xue@1
|
504 R=new TPolygon(4);
|
xue@1
|
505 InitializeR(R, apin, af, ef, maxB);
|
xue@1
|
506 }//TTempAtom
|
xue@1
|
507
|
xue@1
|
508 /*
|
xue@1
|
509 method TTempAtom::TTempAtom: initialize an empty atom whose F-G polygon is the extension of AR
|
xue@1
|
510
|
xue@1
|
511 In: AR: the F-G polygon to extend
|
xue@1
|
512 delf1, delf2: amount of extension, in semitones, of fundamental frequency
|
xue@1
|
513 minf: minimal fundamental frequency: extension will not go below this value
|
xue@1
|
514 */
|
xue@1
|
515 TTempAtom::TTempAtom(TPolygon* AR, double delf1, double delf2, double minf)
|
xue@1
|
516 {
|
xue@1
|
517 Prev=NULL; pind=f=a=s=acce=0;
|
xue@1
|
518 R=new TPolygon(AR->N+2);
|
xue@1
|
519 R->N=AR->N;
|
xue@1
|
520 memcpy(R->X, AR->X, sizeof(double)*AR->N); memcpy(R->Y, AR->Y, sizeof(double)*AR->N);
|
xue@1
|
521 ExtendR(R, delf1, delf2, minf);
|
xue@1
|
522 }//TTempAtom
|
xue@1
|
523
|
xue@1
|
524 /*
|
xue@1
|
525 method TTempAtom::TTempAtom: initialize a atom as the only partial.
|
xue@1
|
526
|
xue@1
|
527 In: apind: partial index
|
xue@1
|
528 af, ef: partial frequency and its error range
|
xue@1
|
529 aa, as: partial amplitude and measurement scale
|
xue@1
|
530 maxB: stiffness coefficient upper bound
|
xue@1
|
531 */
|
xue@1
|
532 TTempAtom::TTempAtom(int apind, double af, double ef, double aa, double as, double maxB)
|
xue@1
|
533 {
|
xue@1
|
534 Prev=NULL; pind=apind; f=af; a=aa; s=as; acce=aa*aa;
|
xue@1
|
535 R=new TPolygon(4);
|
xue@1
|
536 InitializeR(R, apind, af, ef, maxB);
|
xue@1
|
537 }//TTempAtom
|
xue@1
|
538
|
xue@1
|
539 /*
|
xue@1
|
540 method TTempAtom::TTempAtom: creates a duplicate atom. R can be duplicated or snatched according to
|
xue@1
|
541 DupR.
|
xue@1
|
542
|
xue@1
|
543 In: APrev: the atom to duplicate
|
xue@1
|
544 DupR: specifies if the newly created atom is to have its F-G polygon duplicated from that of APrev
|
xue@1
|
545 or to snatch the F-G polygon from APrev (in the latter case APrev losts its polygon).
|
xue@1
|
546 */
|
xue@1
|
547 TTempAtom::TTempAtom(TTempAtom* APrev, bool DupR)
|
xue@1
|
548 {
|
xue@1
|
549 Prev=APrev; pind=APrev->pind; f=APrev->f; a=APrev->a; s=APrev->s; acce=APrev->acce;
|
xue@1
|
550 TPolygon* PrevR=APrev->R;
|
xue@1
|
551 if (DupR)
|
xue@1
|
552 {//duplicate R
|
xue@1
|
553 R=new TPolygon(PrevR->N);
|
xue@1
|
554 R->N=PrevR->N; memcpy(R->X, PrevR->X, sizeof(double)*PrevR->N); memcpy(R->Y, PrevR->Y, sizeof(double)*PrevR->N);
|
xue@1
|
555 }
|
xue@1
|
556 else
|
xue@1
|
557 {//snatch R from APrev
|
xue@1
|
558 R=APrev->R;
|
xue@1
|
559 APrev->R=0;
|
xue@1
|
560 }
|
xue@1
|
561 }//TTempAtom
|
xue@1
|
562
|
xue@1
|
563 /*
|
xue@1
|
564 method TTempAtom::TTempAtom:: initializes an atom by adding a new partial to an existing group.
|
xue@1
|
565
|
xue@1
|
566 In: APrev: the existing atom.
|
xue@1
|
567 apind: partial index
|
xue@1
|
568 af, ef: partial frequency and its error range
|
xue@1
|
569 aa, as: partial amplitude and measurement scale
|
xue@1
|
570 updateR: specifies if the F-G polygon is updated using (af, ef).
|
xue@1
|
571 */
|
xue@1
|
572 TTempAtom::TTempAtom(TTempAtom* APrev, int apind, double af, double ef, double aa, double as, bool updateR)
|
xue@1
|
573 {
|
xue@1
|
574 Prev=APrev; pind=apind; f=af; a=aa;
|
xue@1
|
575 s=as; acce=APrev->acce+aa*aa;
|
xue@1
|
576 TPolygon* PrevR=APrev->R;
|
xue@1
|
577 R=new TPolygon(PrevR->N+2); // create R
|
xue@1
|
578 R->N=PrevR->N; //
|
xue@1
|
579 memcpy(R->X, PrevR->X, sizeof(double)*PrevR->N); // copy R
|
xue@1
|
580 memcpy(R->Y, PrevR->Y, sizeof(double)*PrevR->N); //
|
xue@1
|
581 if (updateR) CutR(R, apind, af, ef);
|
xue@1
|
582 }//TTempAtom
|
xue@1
|
583
|
xue@1
|
584 //method TTempAtom::~TTempAtom: default destructor
|
xue@1
|
585 TTempAtom::~TTempAtom()
|
xue@1
|
586 {
|
xue@1
|
587 delete R;
|
xue@1
|
588 }//~TTempAtom
|
xue@1
|
589
|
xue@1
|
590
|
xue@1
|
591 //---------------------------------------------------------------------------
|
xue@1
|
592 //functions
|
xue@1
|
593
|
Chris@5
|
594 /**
|
xue@1
|
595 function areaandcentroid: calculates the area and centroid of a convex polygon.
|
xue@1
|
596
|
xue@1
|
597 In: x[N], y[N]: x- and y-coordinates of vertices of a polygon
|
xue@1
|
598 Out: A: area
|
xue@1
|
599 (cx, cy): coordinate of the centroid
|
xue@1
|
600
|
xue@1
|
601 No return value.
|
xue@1
|
602 */
|
xue@1
|
603 void areaandcentroid(double& A, double& cx, double& cy, int N, double* x, double* y)
|
xue@1
|
604 {
|
xue@1
|
605 if (N==0) {A=0;}
|
xue@1
|
606 else if (N==1) {A=0; cx=x[0], cy=y[0];}
|
xue@1
|
607 else if (N==2) {A=0; cx=(x[0]+x[1])/2, cy=(y[0]+y[1])/2;}
|
xue@1
|
608 A=cx=cy=0;
|
xue@1
|
609 for (int i=0; i<N; i++)
|
xue@1
|
610 {
|
xue@1
|
611 double xi1, yi1; //x[i+1], y[i+1], index modular N
|
xue@1
|
612 if (i+1==N) xi1=x[0], yi1=y[0];
|
xue@1
|
613 else xi1=x[i+1], yi1=y[i+1];
|
xue@1
|
614 double tmp=x[i]*yi1-xi1*y[i];
|
xue@1
|
615 A+=tmp;
|
xue@1
|
616 cx+=(x[i]+xi1)*tmp;
|
xue@1
|
617 cy+=(y[i]+yi1)*tmp;
|
xue@1
|
618 }
|
xue@1
|
619 A/=2;
|
xue@1
|
620 cx=cx/6/A;
|
xue@1
|
621 cy=cy/6/A;
|
xue@1
|
622 }//areaandcentroid
|
xue@1
|
623
|
Chris@5
|
624 /**
|
xue@1
|
625 function AtomsToPartials: sort a list of atoms as a number of partials. It is assumed that the atoms
|
xue@1
|
626 are simply those from a harmonic sinusoid in arbitrary order with uniform timing and partial index
|
xue@1
|
627 clearly marked, so that it is easy to sort them into a list of partials. However, the sorting process
|
xue@1
|
628 does not check for harmonicity, missing or duplicate atoms, uniformity of timing, etc.
|
xue@1
|
629
|
xue@1
|
630 In: part[k]: a list of atoms
|
xue@1
|
631 offst: interval between adjacent measurement points (hop size)
|
xue@1
|
632 Out: M, Fr, partials[M][Fr]: a list of partials containing the atoms.
|
xue@1
|
633
|
xue@1
|
634 No return value. partials[][] is allocated anew and must be freed by caller.
|
xue@1
|
635 */
|
xue@1
|
636 void AtomsToPartials(int k, atom* part, int& M, int& Fr, atom**& partials, int offst)
|
xue@1
|
637 {
|
xue@1
|
638 if (k>0)
|
xue@1
|
639 {
|
xue@1
|
640 int t1, t2, i=0;
|
xue@1
|
641 while (i<k && part[i].f<=0) i++;
|
xue@1
|
642 if (i<k)
|
xue@1
|
643 {
|
xue@1
|
644 t1=part[i].t, t2=part[i].t, M=part[i].pin; i++;
|
xue@1
|
645 while (i<k)
|
xue@1
|
646 {
|
xue@1
|
647 if (part[i].f>0)
|
xue@1
|
648 {
|
xue@1
|
649 if (M<part[i].pin) M=part[i].pin;
|
xue@1
|
650 if (t1>part[i].t) t1=part[i].t;
|
xue@1
|
651 if (t2<part[i].t) t2=part[i].t;
|
xue@1
|
652 }
|
xue@1
|
653 i++;
|
xue@1
|
654 }
|
xue@1
|
655 Fr=(t2-t1)/offst+1;
|
xue@1
|
656 Allocate2(atom, M, Fr, partials); memset(partials[0], 0, sizeof(atom)*M*Fr);
|
xue@1
|
657 for (int i=0; i<k; i++)
|
xue@1
|
658 if (part[i].f>0)
|
xue@1
|
659 {
|
xue@1
|
660 int fr=(part[i].t-t1)/offst;
|
xue@1
|
661 int pp=part[i].pin;
|
xue@1
|
662 partials[pp-1][fr]=part[i];
|
xue@1
|
663 }
|
xue@1
|
664 }
|
xue@1
|
665 else M=0, Fr=0;
|
xue@1
|
666 }
|
xue@1
|
667 else M=0, Fr=0;
|
xue@1
|
668 }//AtomsToPartials
|
xue@1
|
669
|
Chris@5
|
670 /**
|
xue@1
|
671 function conta: a continuity measure between two set of amplitudes
|
xue@1
|
672
|
xue@1
|
673 In: a1[N], a2[N]: the amplitudes
|
xue@1
|
674
|
xue@1
|
675 Return the continuity measure, between 0 and 1
|
xue@1
|
676 */
|
xue@1
|
677 double conta(int N, double* a1, double* a2)
|
xue@1
|
678 {
|
xue@1
|
679 double e11=0, e22=0, e12=0;
|
xue@1
|
680 for (int n=0; n<N; n++)
|
xue@1
|
681 {
|
xue@1
|
682 double la1=(a1[n]>0)?a1[n]:0, la2=(a2[n]>0)?a2[n]:0;
|
xue@1
|
683 if (la1>1e10) la1=la2;
|
xue@1
|
684 e11+=la1*la1;
|
xue@1
|
685 e12+=la1*la2;
|
xue@1
|
686 e22+=la2*la2;
|
xue@1
|
687 }
|
xue@1
|
688 return 2*e12/(e11+e22);
|
xue@1
|
689 }//conta
|
xue@1
|
690
|
Chris@5
|
691 /**
|
xue@1
|
692 function cutcvpoly: severs a polygon by a straight line
|
xue@1
|
693
|
xue@1
|
694 In: x[N], y[N]: x- and y-coordinates of vertices of a polygon, starting from the leftmost (x[0]=
|
xue@1
|
695 min x[n]) point clockwise; in case of two leftmost points, x[0] is the upper one and x[N-1] is
|
xue@1
|
696 the lower one.
|
xue@1
|
697 A, B, C: coefficients of a straight line Ax+By+C=0.
|
xue@1
|
698 protect: specifies what to do if the whole polygon satisfy Ax+By+C>0, true=do noting,
|
xue@1
|
699 false=eliminate.
|
xue@1
|
700 Out: N, x[N], y[N]: the polygon severed by the line, retaining that half for which Ax+By+C<=0.
|
xue@1
|
701
|
xue@1
|
702 No return value.
|
xue@1
|
703 */
|
xue@1
|
704 void cutcvpoly(int& N, double* x, double* y, double A, double B, double C, bool protect)
|
xue@1
|
705 {
|
xue@1
|
706 int n=0, ns;
|
xue@1
|
707 while (n<N && A*x[n]+B*y[n]+C<=0) n++;
|
xue@1
|
708 if (n==N) //all points satisfies the constraint, do nothing
|
xue@1
|
709 {}
|
xue@1
|
710 else if (n>0) //points 0, 1, ..., n-1 satisfies the constraint, point n does not
|
xue@1
|
711 {
|
xue@1
|
712 ns=n;
|
xue@1
|
713 n++;
|
xue@1
|
714 while (n<N && A*x[n]+B*y[n]+C>0) n++;
|
xue@1
|
715 //points 0, ..., ns-1 and n, ..., N-1 satisfy the constraint,
|
xue@1
|
716 //points ns, ..., n-1 do not satisfy the constraint,
|
xue@1
|
717 // ns>0, n>ns, however, it's possible that n-1=ns
|
xue@1
|
718 int pts, pte; //indicates (by 0/1) whether or now a new point is to be added for xs/xe
|
xue@1
|
719 double xs, ys, xe, ye;
|
xue@1
|
720
|
xue@1
|
721 //find intersection of x:y[ns-1:ns] and A:B:C
|
xue@1
|
722 double x1=x[ns-1], x2=x[ns], y1=y[ns-1], y2=y[ns];
|
xue@1
|
723 double z1=A*x1+B*y1+C, z2=A*x2+B*y2+C; //z1<=0, z2>0
|
xue@1
|
724 if (z1==0) pts=0; //as point ns-1 IS point s
|
xue@1
|
725 else
|
xue@1
|
726 {
|
xue@1
|
727 pts=1, xs=(x1*z2-x2*z1)/(z2-z1), ys=(y1*z2-y2*z1)/(z2-z1);
|
xue@1
|
728 }
|
xue@1
|
729
|
xue@1
|
730 //find intersection of x:y[n-1:n] and A:B:C
|
xue@1
|
731 x1=x[n-1], y1=y[n-1];
|
xue@1
|
732 if (n==N) x2=x[0], y2=y[0];
|
xue@1
|
733 else x2=x[n], y2=y[n];
|
xue@1
|
734 z1=A*x1+B*y1+C, z2=A*x2+B*y2+C; //z1>0, z2<=0
|
xue@1
|
735 if (z2==0) pte=0; //as point n is point e
|
xue@1
|
736 else
|
xue@1
|
737 {
|
xue@1
|
738 pte=1, xe=(x1*z2-x2*z1)/(z2-z1), ye=(y1*z2-y2*z1)/(z2-z1);
|
xue@1
|
739 }
|
xue@1
|
740
|
xue@1
|
741 //the new polygon is formed by points 0, 1, ..., ns-1, (s), (e), n, ..., N-1
|
xue@1
|
742 memmove(&x[ns+pts+pte], &x[n], sizeof(double)*(N-n));
|
xue@1
|
743 memmove(&y[ns+pts+pte], &y[n], sizeof(double)*(N-n));
|
xue@1
|
744 if (pts) x[ns]=xs, y[ns]=ys;
|
xue@1
|
745 if (pte) x[ns+pts]=xe, y[ns+pts]=ye;
|
xue@1
|
746 N=ns+pts+pte+N-n;
|
xue@1
|
747 }
|
xue@1
|
748 else //n=0, point 0 does not satisfy the constraint
|
xue@1
|
749 {
|
xue@1
|
750 n++;
|
xue@1
|
751 while (n<N && A*x[n]+B*y[n]+C>0) n++;
|
xue@1
|
752 if (n==N) //no point satisfies the constraint
|
xue@1
|
753 {
|
xue@1
|
754 if (!protect) N=0;
|
xue@1
|
755 }
|
xue@1
|
756 else
|
xue@1
|
757 {
|
xue@1
|
758 //points 0, 1, ..., n-1 do not satisfy the constraint, point n does
|
xue@1
|
759 ns=n;
|
xue@1
|
760 n++;
|
xue@1
|
761 while (n<N && A*x[n]+B*y[n]+C<=0) n++;
|
xue@1
|
762 //points 0, ..., ns-1 and n, ..., N-1 do not satisfy constraint,
|
xue@1
|
763 //points ns, ..., n-1 satisfy the constraint
|
xue@1
|
764 // ns>0, n>ns, however ns can be equal to n-1
|
xue@1
|
765 int pts, pte; //indicates (by 0/1) whether or now a new point is to be added for xs/xe
|
xue@1
|
766 double xs, ys, xe, ye;
|
xue@1
|
767
|
xue@1
|
768 //find intersection of x:y[ns-1:ns] and A:B:C
|
xue@1
|
769 double x1=x[ns-1], x2=x[ns], y1=y[ns-1], y2=y[ns];
|
xue@1
|
770 double z1=A*x1+B*y1+C, z2=A*x2+B*y2+C; //z1>0, z2<=0
|
xue@1
|
771 if (z2==0) pts=0; //as point ns IS point s
|
xue@1
|
772 else pts=1;
|
xue@1
|
773 xs=(x1*z2-x2*z1)/(z2-z1), ys=(y1*z2-y2*z1)/(z2-z1);
|
xue@1
|
774
|
xue@1
|
775 //find intersection of x:y[n-1:n] and A:B:C
|
xue@1
|
776 x1=x[n-1], y1=y[n-1];
|
xue@1
|
777 if (n==N) x2=x[0], y2=y[0];
|
xue@1
|
778 else x2=x[n], y2=y[n];
|
xue@1
|
779 z1=A*x1+B*y1+C, z2=A*x2+B*y2+C; //z1<=0, z2>0
|
xue@1
|
780 if (z1==0) pte=0; //as point n-1 is point e
|
xue@1
|
781 else pte=1;
|
xue@1
|
782 xe=(x1*z2-x2*z1)/(z2-z1), ye=(y1*z2-y2*z1)/(z2-z1);
|
xue@1
|
783
|
xue@1
|
784 //the new polygon is formed of points (s), ns, ..., n-1, (e)
|
xue@1
|
785 if (xs<=xe)
|
xue@1
|
786 {
|
xue@1
|
787 //the point sequence comes as (s), ns, ..., n-1, (e)
|
xue@1
|
788 memmove(&x[pts], &x[ns], sizeof(double)*(n-ns));
|
xue@1
|
789 memmove(&y[pts], &y[ns], sizeof(double)*(n-ns));
|
xue@1
|
790 if (pts) x[0]=xs, y[0]=ys;
|
xue@1
|
791 N=n-ns+pts+pte;
|
xue@1
|
792 if (pte) x[N-1]=xe, y[N-1]=ye;
|
xue@1
|
793 }
|
xue@1
|
794 else //xe<xs
|
xue@1
|
795 {
|
xue@1
|
796 //the sequence comes as e, (s), ns, ..., n-2 if pte=0 (notice point e<->n-1)
|
xue@1
|
797 //or e, (s), ns, ..., n-1 if pte=1
|
xue@1
|
798 if (pte==0)
|
xue@1
|
799 {
|
xue@1
|
800 memmove(&x[pts+1], &x[ns], sizeof(double)*(n-ns-1));
|
xue@1
|
801 memmove(&y[pts+1], &y[ns], sizeof(double)*(n-ns-1));
|
xue@1
|
802 if (pts) x[1]=xs, y[1]=ys;
|
xue@1
|
803 }
|
xue@1
|
804 else
|
xue@1
|
805 {
|
xue@1
|
806 memmove(&x[pts+1], &x[ns], sizeof(double)*(n-ns));
|
xue@1
|
807 memmove(&y[pts+1], &y[ns], sizeof(double)*(n-ns));
|
xue@1
|
808 if (pts) x[1]=xs, y[1]=ys;
|
xue@1
|
809 }
|
xue@1
|
810 x[0]=xe, y[0]=ye;
|
xue@1
|
811 N=n-ns+pts+pte;
|
xue@1
|
812 }
|
xue@1
|
813 }
|
xue@1
|
814 }
|
xue@1
|
815 }//cutcvpoly
|
xue@1
|
816
|
xue@1
|
817 /*
|
xue@1
|
818 funciton CutR: update an F-G polygon with an new partial
|
xue@1
|
819
|
xue@1
|
820 In: R: F-G polygon
|
xue@1
|
821 apind: partial index
|
xue@1
|
822 af, ef: partial frequency and error bound
|
xue@1
|
823 protect: specifies what to do if the new partial has no intersection with R, true=do noting,
|
xue@1
|
824 false=eliminate R
|
xue@1
|
825 Out: R: the updated F-G polygon
|
xue@1
|
826
|
xue@1
|
827 No return value.
|
xue@1
|
828 */
|
xue@1
|
829 void CutR(TPolygon* R, int apind, double af, double ef, bool protect)
|
xue@1
|
830 {
|
xue@1
|
831 double k=apind*apind-1;
|
xue@1
|
832 double g1=(af-ef)/apind, g2=(af+ef)/apind;
|
xue@1
|
833 if (g1<0) g1=0;
|
xue@1
|
834 g1=g1*g1, g2=g2*g2;
|
xue@1
|
835 //apply constraints F+kG-g2<0 and -F-kG+g1<0
|
xue@1
|
836 cutcvpoly(R->N, R->X, R->Y, 1, k, -g2, protect); // update R
|
xue@1
|
837 cutcvpoly(R->N, R->X, R->Y, -1, -k, g1, protect); //
|
xue@1
|
838 }//CutR
|
xue@1
|
839
|
Chris@5
|
840 /**
|
xue@1
|
841 function DeleteByHalf: reduces a list of stiffcandid objects by half, retaining those with higher s
|
xue@1
|
842 and delete the others, freeing their memory.
|
xue@1
|
843
|
xue@1
|
844 In: cands[pcs]: the list of stiffcandid objects
|
xue@1
|
845 Out: cands[return value]: the list of retained ones
|
xue@1
|
846
|
xue@1
|
847 Returns the size of the new list.
|
xue@1
|
848 */
|
xue@1
|
849 int DeleteByHalf(stiffcandid** cands, int pcs)
|
xue@1
|
850 {
|
xue@1
|
851 int newpcs=pcs/2;
|
xue@1
|
852 double* tmp=new double[newpcs];
|
xue@1
|
853 memset(tmp, 0, sizeof(double)*newpcs);
|
xue@1
|
854 for (int j=0; j<pcs; j++) InsertDec(cands[j]->s, tmp, newpcs);
|
xue@1
|
855 int k=0;
|
xue@1
|
856 for (int j=0; j<pcs; j++)
|
xue@1
|
857 {
|
xue@1
|
858 if (cands[j]->s>=tmp[newpcs-1]) cands[k++]=cands[j];
|
xue@1
|
859 else delete cands[j];
|
xue@1
|
860 }
|
xue@1
|
861 return k;
|
xue@1
|
862 }//DeleteByHalf
|
xue@1
|
863
|
Chris@5
|
864 /**
|
xue@1
|
865 function DeleteByHalf: reduces a list of TTempAtom objects by half, retaining those with higher s and
|
xue@1
|
866 delete the others, freeing their memory.
|
xue@1
|
867
|
xue@1
|
868 In: cands[pcs]: the list of TTempAtom objects
|
xue@1
|
869 Out: cands[return value]: the list of retained ones
|
xue@1
|
870
|
xue@1
|
871 Returns the size of the new list.
|
xue@1
|
872 */
|
xue@1
|
873 int DeleteByHalf(TTempAtom** cands, int pcs)
|
xue@1
|
874 {
|
xue@1
|
875 int newpcs=pcs/2;
|
xue@1
|
876 double* tmp=new double[newpcs];
|
xue@1
|
877 memset(tmp, 0, sizeof(double)*newpcs);
|
xue@1
|
878 for (int j=0; j<pcs; j++) InsertDec(cands[j]->s, tmp, newpcs);
|
xue@1
|
879 int k=0;
|
xue@1
|
880 for (int j=0; j<pcs; j++)
|
xue@1
|
881 {
|
xue@1
|
882 if (cands[j]->s>=tmp[newpcs-1]) cands[k++]=cands[j];
|
xue@1
|
883 else delete cands[j];
|
xue@1
|
884 }
|
xue@1
|
885 delete[] tmp;
|
xue@1
|
886 return k;
|
xue@1
|
887 }//DeleteByHalf
|
xue@1
|
888
|
Chris@5
|
889 /**
|
xue@1
|
890 function ds0: atom score 0 - energy
|
xue@1
|
891
|
xue@1
|
892 In: a: atom amplitude
|
xue@1
|
893
|
xue@1
|
894 Returns a^2, or s[0]+a^2 is s is not NULL, as atom score.
|
xue@1
|
895 */
|
xue@1
|
896 double ds0(double a, void* s)
|
xue@1
|
897 {
|
xue@1
|
898 if (s) return *(double*)s+a*a;
|
xue@1
|
899 else return a*a;
|
xue@1
|
900 }//ds0
|
xue@1
|
901
|
Chris@5
|
902 /**
|
xue@1
|
903 function ds2: atom score 1 - cross-correlation coefficient with another HA, e.g. from previous frame
|
xue@1
|
904
|
xue@1
|
905 In: a: atom amplitude
|
xue@1
|
906 params: pointer to dsprams1 structure supplying other inputs.
|
xue@1
|
907 Out: cross-correlation coefficient as atom score.
|
xue@1
|
908
|
xue@1
|
909 Returns the cross-correlation coefficient.
|
xue@1
|
910 */
|
xue@1
|
911 double ds1(double a, void* params)
|
xue@1
|
912 {
|
xue@1
|
913 dsparams1* lparams=(dsparams1*)params;
|
xue@1
|
914 double hs=lparams->lastene+lparams->currentacce, hsaa=hs+a*a;
|
xue@1
|
915 if (lparams->p<=lparams->lastP) return (lparams->s*hs+a*lparams->lastvfp[lparams->p-1])/hsaa;
|
xue@1
|
916 else return (lparams->s*hs+a*a)/hsaa;
|
xue@1
|
917 }//ds1
|
xue@1
|
918
|
Chris@5
|
919 /**
|
xue@1
|
920 function ExBStiff: finds the minimal and maximal values of stiffness coefficient B given a F-G polygon
|
xue@1
|
921
|
xue@1
|
922 In: F[N], G[N]: vertices of a F-G polygon
|
xue@1
|
923 Out: Bmin, Bmax: minimal and maximal values of the stiffness coefficient
|
xue@1
|
924
|
xue@1
|
925 No reutrn value.
|
xue@1
|
926 */
|
xue@1
|
927 void ExBStiff(double& Bmin, double& Bmax, int N, double* F, double* G)
|
xue@1
|
928 {
|
xue@1
|
929 Bmax=G[0]/F[0];
|
xue@1
|
930 Bmin=Bmax;
|
xue@1
|
931 for (int i=1; i<N; i++)
|
xue@1
|
932 {
|
xue@1
|
933 double vi=G[i]/F[i];
|
xue@1
|
934 if (Bmin>vi) Bmin=vi;
|
xue@1
|
935 else if (Bmax<vi) Bmax=vi;
|
xue@1
|
936 }
|
xue@1
|
937 }//ExBStiff
|
xue@1
|
938
|
Chris@5
|
939 /**
|
xue@1
|
940 function ExFmStiff: finds the minimal and maximal frequecies of partial m given a F-G polygon
|
xue@1
|
941
|
xue@1
|
942 In: F[N], G[N]: vertices of a F-G polygon
|
xue@1
|
943 m: partial index, fundamental=1
|
xue@1
|
944 Out: Fmin, Fmax: minimal and maximal frequencies of partial m
|
xue@1
|
945
|
xue@1
|
946 No return value.
|
xue@1
|
947 */
|
xue@1
|
948 void ExFmStiff(double& Fmin, double& Fmax, int m, int N, double* F, double* G)
|
xue@1
|
949 {
|
xue@1
|
950 int k=m*m-1;
|
xue@1
|
951 double vmax=F[0]+k*G[0];
|
xue@1
|
952 double vmin=vmax;
|
xue@1
|
953 for (int i=1; i<N; i++)
|
xue@1
|
954 {
|
xue@1
|
955 double vi=F[i]+k*G[i];
|
xue@1
|
956 if (vmin>vi) vmin=vi;
|
xue@1
|
957 else if (vmax<vi) vmax=vi;
|
xue@1
|
958 }
|
xue@1
|
959 testnn(vmin); Fmin=m*sqrt(vmin);
|
xue@1
|
960 testnn(vmax); Fmax=m*sqrt(vmax);
|
xue@1
|
961 }//ExFmStiff
|
xue@1
|
962
|
Chris@5
|
963 /**
|
xue@1
|
964 function ExtendR: extends a F-G polygon on the f axis (to allow a larger pitch range)
|
xue@1
|
965
|
xue@1
|
966 In: R: the F-G polygon
|
xue@1
|
967 delp1: amount of extension to the low end, in semitones
|
xue@1
|
968 delpe: amount of extension to the high end, in semitones
|
xue@1
|
969 minf: minimal fundamental frequency
|
xue@1
|
970 Out: R: the extended F-G polygon
|
xue@1
|
971
|
xue@1
|
972 No return value.
|
xue@1
|
973 */
|
xue@1
|
974 void ExtendR(TPolygon* R, double delp1, double delp2, double minf)
|
xue@1
|
975 {
|
xue@1
|
976 double mdelf1=pow(2, -delp1/12), mdelf2=pow(2, delp2/12);
|
xue@1
|
977 int N=R->N;
|
xue@1
|
978 double *G=R->Y, *F=R->X, slope, prevslope, f, ftmp;
|
xue@1
|
979 if (N==0) {}
|
xue@1
|
980 else if (N==1)
|
xue@1
|
981 {
|
xue@1
|
982 R->N=2;
|
xue@1
|
983 slope=G[0]/F[0];
|
xue@1
|
984 testnn(F[0]); f=sqrt(F[0]);
|
xue@1
|
985 ftmp=f*mdelf2;
|
xue@1
|
986 F[1]=ftmp*ftmp;
|
xue@1
|
987 ftmp=f*mdelf1;
|
xue@1
|
988 if (ftmp<minf) ftmp=minf;
|
xue@1
|
989 F[0]=ftmp*ftmp;
|
xue@1
|
990 G[0]=F[0]*slope;
|
xue@1
|
991 G[1]=F[1]*slope;
|
xue@1
|
992 }
|
xue@1
|
993 else if (N==2)
|
xue@1
|
994 {
|
xue@1
|
995 prevslope=G[0]/F[0];
|
xue@1
|
996 slope=G[1]/F[1];
|
xue@1
|
997 if (fabs((slope-prevslope)/prevslope)<1e-10)
|
xue@1
|
998 {
|
xue@1
|
999 testnn(F[0]); ftmp=sqrt(F[0])*mdelf1; if (ftmp<0) ftmp=0; F[0]=ftmp*ftmp; G[0]=F[0]*prevslope;
|
xue@1
|
1000 testnn(F[1]); ftmp=sqrt(F[1])*mdelf2; F[1]=ftmp*ftmp; G[1]=F[1]*slope;
|
xue@1
|
1001 }
|
xue@1
|
1002 else
|
xue@1
|
1003 {
|
xue@1
|
1004 if (prevslope>slope)
|
xue@1
|
1005 {
|
xue@1
|
1006 R->N=4;
|
xue@1
|
1007 testnn(F[1]); f=sqrt(F[1]); ftmp=f*mdelf1; if (ftmp<minf) ftmp=minf; F[3]=ftmp*ftmp; G[3]=F[3]*slope;
|
xue@1
|
1008 ftmp=f*mdelf2; F[2]=ftmp*ftmp; G[2]=F[2]*slope;
|
xue@1
|
1009 testnn(F[0]); f=sqrt(F[0]); ftmp=f*mdelf1; if (ftmp<minf) ftmp=minf; F[0]=ftmp*ftmp; G[0]=F[0]*prevslope;
|
xue@1
|
1010 ftmp=f*mdelf2; F[1]=ftmp*ftmp; G[1]=F[1]*prevslope;
|
xue@1
|
1011 if (F[0]==0 && F[3]==0) R->N=3;
|
xue@1
|
1012 }
|
xue@1
|
1013 else
|
xue@1
|
1014 {
|
xue@1
|
1015 R->N=4;
|
xue@1
|
1016 testnn(F[1]); f=sqrt(F[1]); ftmp=f*mdelf1; if (ftmp<minf) ftmp=minf; F[1]=ftmp*ftmp; G[1]=F[1]*slope;
|
xue@1
|
1017 ftmp=f*mdelf2; F[2]=ftmp*ftmp; G[2]=F[2]*slope;
|
xue@1
|
1018 testnn(F[0]); f=sqrt(F[0]); ftmp=f*mdelf1; if (ftmp<minf) ftmp=minf; F[0]=ftmp*ftmp; G[0]=F[0]*prevslope;
|
xue@1
|
1019 ftmp=f*mdelf2; F[4]=ftmp*ftmp; G[4]=F[4]*prevslope;
|
xue@1
|
1020 if (F[0]==0 && F[1]==0) {R->N=3; F[1]=F[2]; F[2]=F[3]; G[1]=G[2]; G[3]=G[3];}
|
xue@1
|
1021 }
|
xue@1
|
1022 }
|
xue@1
|
1023 }
|
xue@1
|
1024 else
|
xue@1
|
1025 {
|
xue@1
|
1026 //find the minimal and maximal angles of R
|
xue@1
|
1027 //maximal slope is taken at Ms if Mt=1, or Ms-1 and Ms if Mt=0
|
xue@1
|
1028 //minimal slope is taken at ms if mt=1, or ms-1 and ms if mt=0
|
xue@1
|
1029 int Ms, ms, Mt=-1, mt=-1;
|
xue@1
|
1030 double prevslope=G[0]/F[0], dslope;
|
xue@1
|
1031 for (int n=1; n<N; n++)
|
xue@1
|
1032 {
|
xue@1
|
1033 double slope=G[n]/F[n];
|
xue@1
|
1034 dslope=atan(slope)-atan(prevslope);
|
xue@1
|
1035 if (Mt==-1)
|
xue@1
|
1036 {
|
xue@1
|
1037 if (dslope<-1e-10) Ms=n-1, Mt=1;
|
xue@1
|
1038 else if (dslope<1e-10) Ms=n, Mt=0;
|
xue@1
|
1039 }
|
xue@1
|
1040 else if (mt==-1)
|
xue@1
|
1041 {
|
xue@1
|
1042 if (dslope>1e-10) ms=n-1, mt=1;
|
xue@1
|
1043 else if (dslope>-1e-10) ms=n, mt=0;
|
xue@1
|
1044 }
|
xue@1
|
1045 prevslope=slope;
|
xue@1
|
1046 }
|
xue@1
|
1047 if (mt==-1)
|
xue@1
|
1048 {
|
xue@1
|
1049 slope=G[0]/F[0];
|
xue@1
|
1050 dslope=atan(slope)-atan(prevslope);
|
xue@1
|
1051 if (dslope>1e-10) ms=N-1, mt=1;
|
xue@1
|
1052 else if (dslope>-1e-10) ms=0, mt=0;
|
xue@1
|
1053 }
|
xue@1
|
1054 R->N=N+mt+Mt;
|
xue@1
|
1055 int newn=R->N-1;
|
xue@1
|
1056 if (ms==0 && mt==1)
|
xue@1
|
1057 {
|
xue@1
|
1058 slope=G[0]/F[0];
|
xue@1
|
1059 testnn(F[0]); ftmp=sqrt(F[0])*mdelf2; F[newn]=ftmp*ftmp; G[newn]=F[newn]*slope; newn--;
|
xue@1
|
1060 mt=-1;
|
xue@1
|
1061 }
|
xue@1
|
1062 else if (ms==0)
|
xue@1
|
1063 mt=-1;
|
xue@1
|
1064 for (int n=N-1; n>=0; n--)
|
xue@1
|
1065 {
|
xue@1
|
1066 if (mt!=-1)
|
xue@1
|
1067 {
|
xue@1
|
1068 slope=G[n]/F[n];
|
xue@1
|
1069 testnn(F[n]); f=sqrt(F[n]); ftmp=f*mdelf1; if (ftmp<minf) ftmp=minf; F[newn]=ftmp*ftmp; G[newn]=F[newn]*slope; newn--;
|
xue@1
|
1070 if (ms==n && mt==1)
|
xue@1
|
1071 {
|
xue@1
|
1072 ftmp=f*mdelf2; F[newn]=ftmp*ftmp; G[newn]=F[newn]*slope; newn--;
|
xue@1
|
1073 mt=-1;
|
xue@1
|
1074 }
|
xue@1
|
1075 else if (ms==n) //mt=0
|
xue@1
|
1076 mt=-1;
|
xue@1
|
1077 }
|
xue@1
|
1078 else if (Mt!=-1)
|
xue@1
|
1079 {
|
xue@1
|
1080 slope=G[n]/F[n];
|
xue@1
|
1081 testnn(F[n]); f=sqrt(F[n]); ftmp=f*mdelf2; F[newn]=ftmp*ftmp; G[newn]=F[newn]*slope; newn--;
|
xue@1
|
1082 if (Ms==n && Mt==1)
|
xue@1
|
1083 {
|
xue@1
|
1084 ftmp=f*mdelf1; if (ftmp<minf) ftmp=minf; F[newn]=ftmp*ftmp; G[newn]=F[newn]*slope; newn--;
|
xue@1
|
1085 Mt=-1;
|
xue@1
|
1086 }
|
xue@1
|
1087 else if (Ms==n)
|
xue@1
|
1088 Mt=-1;
|
xue@1
|
1089 }
|
xue@1
|
1090 else
|
xue@1
|
1091 {
|
xue@1
|
1092 slope=G[n]/F[n];
|
xue@1
|
1093 testnn(F[n]); f=sqrt(F[n]); ftmp=f*mdelf1; if (ftmp<minf) ftmp=minf; F[newn]=ftmp*ftmp; G[newn]=F[newn]*slope; newn--;
|
xue@1
|
1094 }
|
xue@1
|
1095 }
|
xue@1
|
1096 //merge multiple vertices at the origin
|
xue@1
|
1097 N=R->N;
|
xue@1
|
1098 while (N>0 && F[N-1]==0) N--;
|
xue@1
|
1099 R->N=N;
|
xue@1
|
1100 int n=1;
|
xue@1
|
1101 while (n<N && F[n]==0) n++;
|
xue@1
|
1102 if (n!=1)
|
xue@1
|
1103 {
|
xue@1
|
1104 R->N=N-(n-1);
|
xue@1
|
1105 memcpy(&F[1], &F[n], sizeof(double)*(N-n));
|
xue@1
|
1106 memcpy(&G[1], &G[n], sizeof(double)*(N-n));
|
xue@1
|
1107 }
|
xue@1
|
1108 }
|
xue@1
|
1109 }//ExtendR
|
xue@1
|
1110
|
Chris@5
|
1111 /**
|
xue@1
|
1112 function FGFrom2: solves the following equation system given m[2], f[2], norm[2]. This is interpreted
|
xue@1
|
1113 as searching from (F0, G0) down direction (dF, dG) until the first equation is satisfied, where
|
xue@1
|
1114 k[*]=m[*]^2-1.
|
xue@1
|
1115
|
xue@1
|
1116 m[0](F+k[0]G)^0.5-f[0] m[1](F+k[1]G)^0.5-f[1]
|
xue@1
|
1117 ------------------------ = ------------------------ >0
|
xue@1
|
1118 norm[0] norm[1]
|
xue@1
|
1119
|
xue@1
|
1120 F=F0+lmd*dF
|
xue@1
|
1121 G=G0+lmd*dG
|
xue@1
|
1122
|
xue@1
|
1123 In: (F0, G0): search origin
|
xue@1
|
1124 (dF, dG): search direction
|
xue@1
|
1125 m[2], f[2], norm[2]: coefficients in the first equation
|
xue@1
|
1126 Out: F[return value], G[return value]: solutions.
|
xue@1
|
1127
|
xue@1
|
1128 Returns the number of solutions for (F, G).
|
xue@1
|
1129 */
|
xue@1
|
1130 int FGFrom2(double* F, double* G, double F0, double dF, double G0, double dG, int* m, double* f, double* norm)
|
xue@1
|
1131 {
|
xue@1
|
1132 double m1=m[0]/norm[0], m2=m[1]/norm[1],
|
xue@1
|
1133 f1=f[0]/norm[0], f2=f[1]/norm[1],
|
xue@1
|
1134 k1=m[0]*m[0]-1, k2=m[1]*m[1]-1;
|
xue@1
|
1135 double A=m1*m1-m2*m2*(dF+k2*dG)/(dF+k1*dG),
|
xue@1
|
1136 B=2*m1*(f2-f1),
|
xue@1
|
1137 C=(f2-f1)*(f2-f1)-(k1-k2)*(F0*dG-G0*dF)/(dF+k1*dG)*m2*m2;
|
xue@1
|
1138 if (A==0)
|
xue@1
|
1139 {
|
xue@1
|
1140 double x=-C/B;
|
xue@1
|
1141 if (x<0) return 0;
|
xue@1
|
1142 else if (m1*x-f1<0) return 0;
|
xue@1
|
1143 else
|
xue@1
|
1144 {
|
xue@1
|
1145 double lmd=(x*x-(F0+k1*G0))/(dF+k1*dG);
|
xue@1
|
1146 F[0]=F0+lmd*dF;
|
xue@1
|
1147 G[0]=G0+lmd*dG;
|
xue@1
|
1148 return 1;
|
xue@1
|
1149 }
|
xue@1
|
1150 }
|
xue@1
|
1151 else
|
xue@1
|
1152 {
|
xue@1
|
1153 double delta=B*B-4*A*C;
|
xue@1
|
1154 if (delta<0) return 0;
|
xue@1
|
1155 else if (delta==0)
|
xue@1
|
1156 {
|
xue@1
|
1157 double x=-B/2/A;
|
xue@1
|
1158 if (x<0) return 0;
|
xue@1
|
1159 else if (m1*x-f1<0) return 0;
|
xue@1
|
1160 else
|
xue@1
|
1161 {
|
xue@1
|
1162 double lmd=(x*x-(F0+k1*G0))/(dF+k1*dG);
|
xue@1
|
1163 F[0]=F0+lmd*dF;
|
xue@1
|
1164 G[0]=G0+lmd*dG;
|
xue@1
|
1165 return 1;
|
xue@1
|
1166 }
|
xue@1
|
1167 }
|
xue@1
|
1168 else
|
xue@1
|
1169 {
|
xue@1
|
1170 int roots=0;
|
xue@1
|
1171 double x=(-B+sqrt(delta))/2/A;
|
xue@1
|
1172 if (x<0) {}
|
xue@1
|
1173 else if (m1*x-f1<0) {}
|
xue@1
|
1174 else
|
xue@1
|
1175 {
|
xue@1
|
1176 double lmd=(x*x-(F0+k1*G0))/(dF+k1*dG);
|
xue@1
|
1177 F[0]=F0+lmd*dF;
|
xue@1
|
1178 G[0]=G0+lmd*dG;
|
xue@1
|
1179 roots++;
|
xue@1
|
1180 }
|
xue@1
|
1181 x=(-B-sqrt(delta))/2/A;
|
xue@1
|
1182 if (x<0) {}
|
xue@1
|
1183 else if (m1*x-f1<0) {}
|
xue@1
|
1184 else
|
xue@1
|
1185 {
|
xue@1
|
1186 double lmd=(x*x-(F0+k1*G0))/(dF+k1*dG);
|
xue@1
|
1187 F[roots]=F0+lmd*dF;
|
xue@1
|
1188 G[roots]=G0+lmd*dG;
|
xue@1
|
1189 roots++;
|
xue@1
|
1190 }
|
xue@1
|
1191 return roots;
|
xue@1
|
1192 }
|
xue@1
|
1193 }
|
xue@1
|
1194 }//FGFrom2
|
xue@1
|
1195
|
Chris@5
|
1196 /**
|
xue@1
|
1197 function FGFrom2: solves the following equation system given m[2], f[2], k[2]. This is interpreted as
|
xue@1
|
1198 searching from (F0, G0) down direction (dF, dG) until the first equation is satisfied. Functionally
|
xue@1
|
1199 this is the same as the version using norm[2], with m[] anf f[] normalized by norm[] beforehand so
|
xue@1
|
1200 that norm[] is no longer needed. However, k[2] cannot be computed from normalized m[2] so that it must
|
xue@1
|
1201 be specified explicitly.
|
xue@1
|
1202
|
xue@1
|
1203 m[0](F+k[0]G)^0.5-f[0] = m[1](F+k[1]G)^0.5-f[1] > 0
|
xue@1
|
1204
|
xue@1
|
1205 F=F0+lmd*dF
|
xue@1
|
1206 G=G0+lmd*dG
|
xue@1
|
1207
|
xue@1
|
1208 In: (F0, G0): search origin
|
xue@1
|
1209 (dF, dG): search direction
|
xue@1
|
1210 m[2], f[2], k[2]: coefficients in the first equation
|
xue@1
|
1211 Out: F[return value], G[return value]: solutions.
|
xue@1
|
1212
|
xue@1
|
1213 Returns the number of solutions for (F, G).
|
xue@1
|
1214 */
|
xue@1
|
1215 int FGFrom2(double* F, double* G, double* lmd, double F0, double dF, double G0, double dG, double* m, double* f, int* k)
|
xue@1
|
1216 {
|
xue@1
|
1217 double m1=m[0], m2=m[1],
|
xue@1
|
1218 f1=f[0], f2=f[1],
|
xue@1
|
1219 k1=k[0], k2=k[1];
|
xue@1
|
1220 double A=m1*m1-m2*m2*(dF+k2*dG)/(dF+k1*dG),
|
xue@1
|
1221 B=2*m1*(f2-f1),
|
xue@1
|
1222 C=(f2-f1)*(f2-f1)-(k1-k2)*(F0*dG-G0*dF)/(dF+k1*dG)*m2*m2;
|
xue@1
|
1223 //x is obtained by solving Axx+Bx+C=0
|
xue@1
|
1224 if (fabs(A)<1e-6) //A==0
|
xue@1
|
1225 {
|
xue@1
|
1226 double x=-C/B;
|
xue@1
|
1227 if (x<0) return 0;
|
xue@1
|
1228 else if (m1*x-f1<0) return 0;
|
xue@1
|
1229 else
|
xue@1
|
1230 {
|
xue@1
|
1231 lmd[0]=(x*x-(F0+k1*G0))/(dF+k1*dG);
|
xue@1
|
1232 F[0]=F0+lmd[0]*dF;
|
xue@1
|
1233 G[0]=G0+lmd[0]*dG;
|
xue@1
|
1234 return 1;
|
xue@1
|
1235 }
|
xue@1
|
1236 }
|
xue@1
|
1237 else
|
xue@1
|
1238 {
|
xue@1
|
1239 int roots=0;
|
xue@1
|
1240 double delta=B*B-4*A*C;
|
xue@1
|
1241 if (delta<0) return 0;
|
xue@1
|
1242 else if (delta==0)
|
xue@1
|
1243 {
|
xue@1
|
1244 double x=-B/2/A;
|
xue@1
|
1245 if (x<0) return 0;
|
xue@1
|
1246 else if (m1*x-f1<0) return 0;
|
xue@1
|
1247 else if ((m1*x-f1+f2)*m2<0) {}
|
xue@1
|
1248 else
|
xue@1
|
1249 {
|
xue@1
|
1250 lmd[0]=(x*x-(F0+k1*G0))/(dF+k1*dG);
|
xue@1
|
1251 F[0]=F0+lmd[0]*dF;
|
xue@1
|
1252 G[0]=G0+lmd[0]*dG;
|
xue@1
|
1253 roots++;
|
xue@1
|
1254 }
|
xue@1
|
1255 return roots;
|
xue@1
|
1256 }
|
xue@1
|
1257 else
|
xue@1
|
1258 {
|
xue@1
|
1259 int roots=0;
|
xue@1
|
1260 double x=(-B+sqrt(delta))/2/A;
|
xue@1
|
1261 if (x<0) {}
|
xue@1
|
1262 else if (m1*x-f1<0) {}
|
xue@1
|
1263 else if ((m1*x-f1+f2)*m2<0) {}
|
xue@1
|
1264 else
|
xue@1
|
1265 {
|
xue@1
|
1266 lmd[0]=(x*x-(F0+k1*G0))/(dF+k1*dG);
|
xue@1
|
1267 F[0]=F0+lmd[0]*dF;
|
xue@1
|
1268 G[0]=G0+lmd[0]*dG;
|
xue@1
|
1269 roots++;
|
xue@1
|
1270 }
|
xue@1
|
1271 x=(-B-sqrt(delta))/2/A;
|
xue@1
|
1272 if (x<0) {}
|
xue@1
|
1273 else if (m1*x-f1<0) {}
|
xue@1
|
1274 else if ((m1*x-f1+f2)*m2<0) {}
|
xue@1
|
1275 else
|
xue@1
|
1276 {
|
xue@1
|
1277 lmd[roots]=(x*x-(F0+k1*G0))/(dF+k1*dG);
|
xue@1
|
1278 F[roots]=F0+lmd[roots]*dF;
|
xue@1
|
1279 G[roots]=G0+lmd[roots]*dG;
|
xue@1
|
1280 roots++;
|
xue@1
|
1281 }
|
xue@1
|
1282 return roots;
|
xue@1
|
1283 }
|
xue@1
|
1284 }
|
xue@1
|
1285 }//FGFrom2
|
xue@1
|
1286
|
Chris@5
|
1287 /**
|
xue@1
|
1288 function FGFrom3: solves the following equation system given m[3], f[3], norm[3].
|
xue@1
|
1289
|
xue@1
|
1290 m[0](F+k[0]G)^0.5-f[0] m[1](F+k[1]G)^0.5-f[1] m[2](F+k[2]G)^0.5-f[2]
|
xue@1
|
1291 ------------------------ = ------------------------ = ------------------------ > 0
|
xue@1
|
1292 norm[0] norm[1] norm[2]
|
xue@1
|
1293
|
xue@1
|
1294 In: m[3], f[3], norm[3]: coefficients in the above
|
xue@1
|
1295 Out: F[return value], G[return value]: solutions.
|
xue@1
|
1296
|
xue@1
|
1297 Returns the number of solutions for (F, G).
|
xue@1
|
1298 */
|
xue@1
|
1299 int FGFrom3(double* F, double* G, int* m, double* f, double* norm)
|
xue@1
|
1300 {
|
xue@1
|
1301 double m1=m[0]/norm[0], m2=m[1]/norm[1], m3=m[2]/norm[2],
|
xue@1
|
1302 f1=f[0]/norm[0], f2=f[1]/norm[1], f3=f[2]/norm[2],
|
xue@1
|
1303 k1=m[0]*m[0]-1, k2=m[1]*m[1]-1, k3=m[2]*m[2]-1;
|
xue@1
|
1304 double h21=k2-k1, h31=k3-k1; //h21 and h31
|
xue@1
|
1305 double h12=m1*m1-m2*m2, h13=m1*m1-m3*m3; //h12' and h13'
|
xue@1
|
1306 double a=m2*m2*h13*h21-m3*m3*h12*h31;
|
xue@1
|
1307 if (a==0)
|
xue@1
|
1308 {
|
xue@1
|
1309 double x=h12*(f3-f1)*(f3-f1)-h13*(f2-f1)*(f2-f1),
|
xue@1
|
1310 b=h13*(f2-f1)-h12*(f3-f1);
|
xue@1
|
1311 x=x/(2*m1*b);
|
xue@1
|
1312 if (x<0) return 0; //x must the square root of something
|
xue@1
|
1313 else if (m1*x-f1<0) return 0; //discarded because we are solving e1=e2=e3>0
|
xue@1
|
1314 else
|
xue@1
|
1315 {
|
xue@1
|
1316 if (h21!=0)
|
xue@1
|
1317 {
|
xue@1
|
1318 G[0]=(h12*x*x+2*m1*(f2-f1)*x+(f2-f1)*(f2-f1))/(m2*m2*h21);
|
xue@1
|
1319 }
|
xue@1
|
1320 else
|
xue@1
|
1321 {
|
xue@1
|
1322 G[0]=(h13*x*x+2*m1*(f3-f1)*x+(f3-f1)*(f3-f1))/(m3*m3*h31);
|
xue@1
|
1323 }
|
xue@1
|
1324 F[0]=x*x-k1*G[0];
|
xue@1
|
1325 return 1;
|
xue@1
|
1326 }
|
xue@1
|
1327 }
|
xue@1
|
1328 else
|
xue@1
|
1329 {
|
xue@1
|
1330 double b=(h13*(f2-f1)*(f2-f1)-h12*(f3-f1)*(f3-f1))/a;
|
xue@1
|
1331 a=2*m1*(h13*(f2-f1)-h12*(f3-f1))/a;
|
xue@1
|
1332 double A=h12,
|
xue@1
|
1333 B=2*m1*(f2-f1)-m2*m2*h21*a,
|
xue@1
|
1334 C=(f2-f1)*(f2-f1)-m2*m2*h21*b;
|
xue@1
|
1335 double delta=B*B-4*A*C;
|
xue@1
|
1336 if (delta<0) return 0;
|
xue@1
|
1337 else if (delta==0)
|
xue@1
|
1338 {
|
xue@1
|
1339 double x=-B/2/A;
|
xue@1
|
1340 if (x<0) return 0; //x must the square root of something
|
xue@1
|
1341 else if (m1*x-f1<0) return 0; //discarded because we are solving e1=e2=e3>0
|
xue@1
|
1342 else
|
xue@1
|
1343 {
|
xue@1
|
1344 G[0]=a*x+b;
|
xue@1
|
1345 F[0]=x*x-k1*G[0];
|
xue@1
|
1346 return 1;
|
xue@1
|
1347 }
|
xue@1
|
1348 }
|
xue@1
|
1349 else
|
xue@1
|
1350 {
|
xue@1
|
1351 int roots=0;
|
xue@1
|
1352 double x=(-B+sqrt(delta))/2/A;
|
xue@1
|
1353 if (x<0) {}
|
xue@1
|
1354 else if (m1*x-f1<0) {}
|
xue@1
|
1355 else
|
xue@1
|
1356 {
|
xue@1
|
1357 G[0]=a*x+b;
|
xue@1
|
1358 F[0]=x*x-k1*G[0];
|
xue@1
|
1359 roots++;
|
xue@1
|
1360 }
|
xue@1
|
1361 x=(-B-sqrt(delta))/2/A;
|
xue@1
|
1362 if (x<0) {}
|
xue@1
|
1363 else if (m1*x-f1<0) {}
|
xue@1
|
1364 else
|
xue@1
|
1365 {
|
xue@1
|
1366 G[roots]=a*x+b;
|
xue@1
|
1367 F[roots]=x*x-k1*G[roots];
|
xue@1
|
1368 roots++;
|
xue@1
|
1369 }
|
xue@1
|
1370 return roots;
|
xue@1
|
1371 }
|
xue@1
|
1372 }
|
xue@1
|
1373 }//FGFrom3
|
xue@1
|
1374
|
Chris@5
|
1375 /**
|
xue@1
|
1376 function FGFrom3: solves the following equation system given m[3], f[3], k[3]. Functionally this is
|
xue@1
|
1377 the same as the version using norm[3], with m[] anf f[] normalized by norm[] beforehand so that norm[]
|
xue@1
|
1378 is no longer needed. However, k[3] cannot be computed from normalized m[3] so that it must be
|
xue@1
|
1379 specified explicitly.
|
xue@1
|
1380
|
xue@1
|
1381 m[0](F+k[0]G)^0.5-f[0] = m[1](F+k[1]G)^0.5-f[1] = m[2](F+k[2]G)^0.5-f[2] >0
|
xue@1
|
1382
|
xue@1
|
1383 In: m[3], f[3], k[3]: coefficients in the above
|
xue@1
|
1384 Out: F[return value], G[return value]: solutions.
|
xue@1
|
1385
|
xue@1
|
1386 Returns the number of solutions for (F, G).
|
xue@1
|
1387 */
|
xue@1
|
1388 int FGFrom3(double* F, double* G, double* e, double* m, double* f, int* k)
|
xue@1
|
1389 {
|
xue@1
|
1390 double m1=m[0], m2=m[1], m3=m[2],
|
xue@1
|
1391 f1=f[0], f2=f[1], f3=f[2],
|
xue@1
|
1392 k1=k[0], k2=k[1], k3=k[2];
|
xue@1
|
1393 double h21=k2-k1, h31=k3-k1; //h21 and h31
|
xue@1
|
1394 double h12=m1*m1-m2*m2, h13=m1*m1-m3*m3; //h12' and h13'
|
xue@1
|
1395 double a=m2*m2*h13*h21-m3*m3*h12*h31;
|
xue@1
|
1396 if (a==0)
|
xue@1
|
1397 {
|
xue@1
|
1398 //a==0 implies two the e's are conjugates
|
xue@1
|
1399 double x=h12*(f3-f1)*(f3-f1)-h13*(f2-f1)*(f2-f1),
|
xue@1
|
1400 b=h13*(f2-f1)-h12*(f3-f1);
|
xue@1
|
1401 x=x/(2*m1*b);
|
xue@1
|
1402 if (x<0) return 0; //x must the square root of something
|
xue@1
|
1403 else if (m1*x-f1<-1e-6) return 0; //discarded because we are solving e1=e2=e3>0
|
xue@1
|
1404 else if ((m1*x-f1+f2)*m2<0) return 0;
|
xue@1
|
1405 else if ((m1*x-f1+f3)*m3<0) return 0;
|
xue@1
|
1406 else
|
xue@1
|
1407 {
|
xue@1
|
1408 if (h21!=0)
|
xue@1
|
1409 {
|
xue@1
|
1410 G[0]=(h12*x*x+2*m1*(f2-f1)*x+(f2-f1)*(f2-f1))/(m2*m2*h21);
|
xue@1
|
1411 }
|
xue@1
|
1412 else
|
xue@1
|
1413 {
|
xue@1
|
1414 G[0]=(h13*x*x+2*m1*(f3-f1)*x+(f3-f1)*(f3-f1))/(m3*m3*h31);
|
xue@1
|
1415 }
|
xue@1
|
1416 F[0]=x*x-k1*G[0];
|
xue@1
|
1417 double tmp=F[0]+G[0]*k[0]; testnn(tmp);
|
xue@1
|
1418 e[0]=m1*sqrt(tmp)-f[0];
|
xue@1
|
1419 return 1;
|
xue@1
|
1420 }
|
xue@1
|
1421 }
|
xue@1
|
1422 else
|
xue@1
|
1423 {
|
xue@1
|
1424 double b=(h13*(f2-f1)*(f2-f1)-h12*(f3-f1)*(f3-f1))/a;
|
xue@1
|
1425 a=2*m1*(h13*(f2-f1)-h12*(f3-f1))/a;
|
xue@1
|
1426 double A=h12,
|
xue@1
|
1427 B=2*m1*(f2-f1)-m2*m2*h21*a,
|
xue@1
|
1428 C=(f2-f1)*(f2-f1)-m2*m2*h21*b;
|
xue@1
|
1429 double delta=B*B-4*A*C;
|
xue@1
|
1430 if (delta<0) return 0;
|
xue@1
|
1431 else if (delta==0)
|
xue@1
|
1432 {
|
xue@1
|
1433 int roots=0;
|
xue@1
|
1434 double x=-B/2/A;
|
xue@1
|
1435 if (x<0) return 0; //x must the square root of something
|
xue@1
|
1436 else if (m1*x-f1<0) return 0; //discarded because we are solving e1=e2=e3>0
|
xue@1
|
1437 else if ((m1*x-f1+f2)*m2<0) return 0;
|
xue@1
|
1438 else if ((m1*x-f1+f3)*m3<0) return 0;
|
xue@1
|
1439 else
|
xue@1
|
1440 {
|
xue@1
|
1441 G[0]=a*x+b;
|
xue@1
|
1442 F[0]=x*x-k1*G[0];
|
xue@1
|
1443 double tmp=F[0]+G[0]*k[0]; testnn(tmp);
|
xue@1
|
1444 e[0]=m1*sqrt(tmp)-f[0];
|
xue@1
|
1445 roots++;
|
xue@1
|
1446 }
|
xue@1
|
1447 return roots;
|
xue@1
|
1448 }
|
xue@1
|
1449 else
|
xue@1
|
1450 {
|
xue@1
|
1451 int roots=0;
|
xue@1
|
1452 double x=(-B+sqrt(delta))/2/A;
|
xue@1
|
1453 if (x<0) {}
|
xue@1
|
1454 else if (m1*x-f1<0) {}
|
xue@1
|
1455 else if ((m1*x-f1+f2)*m2<0) {}
|
xue@1
|
1456 else if ((m1*x-f1+f3)*m3<0) {}
|
xue@1
|
1457 else
|
xue@1
|
1458 {
|
xue@1
|
1459 G[0]=a*x+b;
|
xue@1
|
1460 F[0]=x*x-k1*G[0];
|
xue@1
|
1461 double tmp=F[0]+G[0]*k1; testnn(tmp);
|
xue@1
|
1462 e[0]=m1*sqrt(tmp)-f1;
|
xue@1
|
1463 roots++;
|
xue@1
|
1464 }
|
xue@1
|
1465 x=(-B-sqrt(delta))/2/A;
|
xue@1
|
1466 if (x<0) {}
|
xue@1
|
1467 else if (m1*x-f1<0) {}
|
xue@1
|
1468 else if ((m1*x-f1+f2)*m2<0) {}
|
xue@1
|
1469 else if ((m1*x-f1+f3)*m3<0) {}
|
xue@1
|
1470 else
|
xue@1
|
1471 {
|
xue@1
|
1472 G[roots]=a*x+b;
|
xue@1
|
1473 F[roots]=x*x-k1*G[roots];
|
xue@1
|
1474 double tmp=F[roots]+G[roots]*k1; testnn(tmp);
|
xue@1
|
1475 e[roots]=m1*sqrt(tmp)-f1;
|
xue@1
|
1476 roots++;
|
xue@1
|
1477 }
|
xue@1
|
1478 return roots;
|
xue@1
|
1479 }
|
xue@1
|
1480 }
|
xue@1
|
1481 }//FGFrom3
|
xue@1
|
1482
|
Chris@5
|
1483 /**
|
xue@1
|
1484 function FindNote: harmonic sinusoid tracking from a starting point in time-frequency plane forward
|
xue@1
|
1485 and backward.
|
xue@1
|
1486
|
xue@1
|
1487 In: _t, _f: start time and frequency
|
xue@1
|
1488 frst, fren: tracking range, in frames
|
xue@1
|
1489 Spec: spectrogram
|
xue@1
|
1490 wid, offst: atom scale and hop size, must be consistent with Spec
|
xue@1
|
1491 settings: note match settings
|
xue@1
|
1492 brake: tracking termination threshold
|
xue@1
|
1493 Out: M, Fr, partials[M][Fr]: HS partials
|
xue@1
|
1494
|
xue@1
|
1495 Returns 0 if tracking is done by FindNoteF(), 1 if tracking is done by FindNoteConst()
|
xue@1
|
1496 */
|
xue@1
|
1497 int FindNote(int _t, double _f, int& M, int& Fr, atom**& partials, int frst, int fren, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings)
|
xue@1
|
1498 {
|
xue@1
|
1499 double brake=0.02;
|
xue@1
|
1500 if (settings.delp==0) return FindNoteConst(_t, _f, M, Fr, partials, frst, fren, wid, offst, Spec, settings, brake*5);
|
xue@1
|
1501
|
xue@1
|
1502 atom* part=new atom[(fren-frst)*settings.maxp];
|
xue@1
|
1503 double fpp[1024]; double *vfpp=&fpp[256], *pfpp=&fpp[512]; atomtype *ptype=(atomtype*)&fpp[768]; NMResults results={fpp, vfpp, pfpp, ptype};
|
xue@1
|
1504
|
xue@1
|
1505 int trst=floor((_t-wid/2)*1.0/offst+0.5);
|
xue@1
|
1506 if (trst<0) trst=0;
|
xue@1
|
1507
|
xue@1
|
1508 TPolygon* R=new TPolygon(1024); R->N=0;
|
xue@1
|
1509
|
xue@1
|
1510 cmplx<QSPEC_FORMAT>* spec=Spec->Spec(trst);
|
xue@1
|
1511 double f0=_f*wid;
|
xue@1
|
1512 cdouble *x=new cdouble[wid/2+1]; for (int i=0; i<=wid/2; i++) x[i]=spec[i];
|
xue@1
|
1513
|
xue@1
|
1514 settings.forcepin0=true; settings.pcount=0; settings.pin0asanchor=true;
|
xue@1
|
1515 double B, starts=NoteMatchStiff3(R, f0, B, 1, &x, wid, 0, &settings, &results, 0, 0, ds0);
|
xue@1
|
1516
|
xue@1
|
1517 int k=0;
|
xue@1
|
1518 if (starts>0)
|
xue@1
|
1519 {
|
xue@1
|
1520 int startp=NMResultToAtoms(settings.maxp, part, trst*offst+wid/2, wid, results);
|
xue@1
|
1521 settings.pin0asanchor=false;
|
xue@1
|
1522 double* startvfp=new double[startp]; memcpy(startvfp, vfpp, sizeof(double)*startp);
|
xue@1
|
1523 k=startp;
|
xue@1
|
1524 k+=FindNoteF(&part[k], starts, R, startp, startvfp, trst, fren, wid, offst, Spec, settings, brake);
|
xue@1
|
1525 k+=FindNoteF(&part[k], starts, R, startp, startvfp, trst, frst-1, wid, offst, Spec, settings, brake);
|
xue@1
|
1526 delete[] startvfp;
|
xue@1
|
1527 }
|
xue@1
|
1528 delete R; delete[] x;
|
xue@1
|
1529
|
xue@1
|
1530 AtomsToPartials(k, part, M, Fr, partials, offst);
|
xue@1
|
1531 delete[] part;
|
xue@1
|
1532
|
xue@1
|
1533 // ReEst1(M, frst, fren, partials, WV->Data16[channel], wid, offst);
|
xue@1
|
1534
|
xue@1
|
1535 return 0;
|
xue@1
|
1536 }//Findnote*/
|
xue@1
|
1537
|
Chris@5
|
1538 /**
|
xue@1
|
1539 function FindNoteConst: constant-pitch harmonic sinusoid tracking
|
xue@1
|
1540
|
xue@1
|
1541 In: _t, _f: start time and frequency
|
xue@1
|
1542 frst, fren: tracking range, in frames
|
xue@1
|
1543 Spec: spectrogram
|
xue@1
|
1544 wid, offst: atom scale and hop size, must be consistent with Spec
|
xue@1
|
1545 settings: note match settings
|
xue@1
|
1546 brake: tracking termination threshold
|
xue@1
|
1547 Out: M, Fr, partials[M][Fr]: HS partials
|
xue@1
|
1548
|
xue@1
|
1549 Returns 1.
|
xue@1
|
1550 */
|
xue@1
|
1551 int FindNoteConst(int _t, double _f, int& M, int& Fr, atom**& partials, int frst, int fren, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings, double brake)
|
xue@1
|
1552 {
|
xue@1
|
1553 atom* part=new atom[(fren-frst)*settings.maxp];
|
xue@1
|
1554 double fpp[1024]; double *vfpp=&fpp[256], *pfpp=&fpp[512]; atomtype *ptype=(atomtype*)&fpp[768]; NMResults results={fpp, vfpp, pfpp, ptype};
|
xue@1
|
1555
|
xue@1
|
1556 //trst: the frame index to start tracking
|
xue@1
|
1557 int trst=floor((_t-wid/2)*1.0/offst+0.5), maxp=settings.maxp;
|
xue@1
|
1558 if (trst<0) trst=0;
|
xue@1
|
1559
|
xue@1
|
1560 //find a note candidate for the starting frame at _t
|
xue@1
|
1561 TPolygon* R=new TPolygon(1024); R->N=0;
|
xue@1
|
1562 cmplx<QSPEC_FORMAT>* spec=Spec->Spec(trst);
|
xue@1
|
1563 double f0=_f*wid;
|
xue@1
|
1564 cdouble *x=new cdouble[wid/2+1]; for (int i=0; i<=wid/2; i++) x[i]=spec[i];
|
xue@1
|
1565
|
xue@1
|
1566 settings.forcepin0=true; settings.pcount=0; settings.pin0asanchor=true;
|
xue@1
|
1567 double B, *starts=new double[maxp];
|
xue@1
|
1568 NoteMatchStiff3(R, f0, B, 1, &x, wid, 0, &settings, &results, 0, 0);
|
xue@1
|
1569
|
xue@1
|
1570 //read the energy vector of this candidate HA to starts[]. starts[] will contain the highest single-frame
|
xue@1
|
1571 //energy of each partial during the tracking.
|
xue@1
|
1572 int P=0; while(P<maxp && f0*(P+1)*sqrt(1+B*((P+1)*(P+1)-1))<wid/2) P++;
|
xue@1
|
1573 for (int m=0; m<P; m++) starts[m]=results.vfp[m]*results.vfp[m];
|
xue@1
|
1574 int atomcount=0;
|
xue@1
|
1575
|
xue@1
|
1576 cdouble* ipw=new cdouble[maxp];
|
xue@1
|
1577
|
xue@1
|
1578 //find the ends of tracking by constant-pitch extension of the starting HA until
|
xue@1
|
1579 //at a frame at least half of the partials fall below starts[]*brake.
|
xue@1
|
1580
|
xue@1
|
1581 //first find end of the note by forward extension from the frame at _t
|
xue@1
|
1582 int fr1=trst;
|
xue@1
|
1583 while (fr1<fren)
|
xue@1
|
1584 {
|
xue@1
|
1585 spec=Spec->Spec(fr1);
|
xue@1
|
1586 for (int i=0; i<=wid/2; i++) x[i]=spec[i];
|
xue@1
|
1587 double ls=0;
|
xue@1
|
1588 for (int m=0; m<P; m++)
|
xue@1
|
1589 {
|
xue@1
|
1590 double fm=f0*(m+1)*sqrt(1+B*((m+1)*(m+1)-1));
|
xue@1
|
1591 int K1=floor(fm-settings.hB), K2=ceil(fm+settings.hB);
|
xue@1
|
1592 if (K1<0) K1=0; if (K2>=wid/2) K2=wid/2-1;
|
xue@1
|
1593 ipw[m]=IPWindowC(fm, x, wid, settings.M, settings.c, settings.iH2, K1, K2);
|
xue@1
|
1594 ls+=~ipw[m];
|
xue@1
|
1595 if (starts[m]<~ipw[m]) starts[m]=~ipw[m];
|
xue@1
|
1596 }
|
xue@1
|
1597 double sumstart=0, sumstop=0;
|
xue@1
|
1598 for (int m=0; m<P; m++)
|
xue@1
|
1599 {
|
xue@1
|
1600 if (~ipw[m]<starts[m]*brake) sumstop+=1;// sqrt(starts[m]);
|
xue@1
|
1601 sumstart+=1; //sqrt(starts[m]);
|
xue@1
|
1602 }
|
xue@1
|
1603 double lstop=sumstop/sumstart;
|
xue@1
|
1604 if (lstop>0.5) break;
|
xue@1
|
1605
|
xue@1
|
1606 fr1++;
|
xue@1
|
1607 }
|
xue@1
|
1608 //note find the start of note by backward extension from the frame at _t
|
xue@1
|
1609 int fr0=trst-1;
|
xue@1
|
1610 while(fr0>frst)
|
xue@1
|
1611 {
|
xue@1
|
1612 spec=Spec->Spec(fr0);
|
xue@1
|
1613 for (int i=0; i<=wid/2; i++) x[i]=spec[i];
|
xue@1
|
1614 double ls=0;
|
xue@1
|
1615 for (int m=0; m<P; m++)
|
xue@1
|
1616 {
|
xue@1
|
1617 double fm=f0*(m+1)*sqrt(1+B*((m+1)*(m+1)-1));
|
xue@1
|
1618 int K1=floor(fm-settings.hB), K2=ceil(fm+settings.hB);
|
xue@1
|
1619 if (K1<0) K1=0; if (K2>=wid/2) K2=wid/2-1;
|
xue@1
|
1620 ipw[m]=IPWindowC(fm, x, wid, settings.M, settings.c, settings.iH2, K1, K2);
|
xue@1
|
1621 ls+=~ipw[m];
|
xue@1
|
1622 if (starts[m]<~ipw[m]) starts[m]=~ipw[m];
|
xue@1
|
1623 }
|
xue@1
|
1624
|
xue@1
|
1625 double sumstart=0, sumstop=0;
|
xue@1
|
1626 for (int m=0; m<P; m++)
|
xue@1
|
1627 {
|
xue@1
|
1628 if (~ipw[m]<starts[m]*brake) sumstop+=1; //sqrt(starts[m]);
|
xue@1
|
1629 sumstart+=1; //sqrt(starts[m]);
|
xue@1
|
1630 }
|
xue@1
|
1631 double lstop=sumstop/sumstart;
|
xue@1
|
1632 if (lstop>0.5) {fr0++; break;}
|
xue@1
|
1633
|
xue@1
|
1634 fr0--;
|
xue@1
|
1635 }
|
xue@1
|
1636
|
xue@1
|
1637 //now fr0 and fr1 are the first and last (excl.) frame indices
|
xue@1
|
1638 Fr=fr1-fr0;
|
xue@1
|
1639 cdouble* ipfr=new cdouble[Fr];
|
xue@1
|
1640 double *as=new double[Fr*2], *phs=&as[Fr];
|
xue@1
|
1641 cdouble** Allocate2(cdouble, Fr, wid/2+1, xx);
|
xue@1
|
1642 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
1643 {
|
xue@1
|
1644 spec=Spec->Spec(fr0+fr);
|
xue@1
|
1645 for (int i=0; i<=wid/2; i++) xx[fr][i]=spec[i];
|
xue@1
|
1646 }
|
xue@1
|
1647
|
xue@1
|
1648 //reestimate partial frequencies, amplitudes and phase angles using all frames. In case of frequency estimation
|
xue@1
|
1649 //failure, the original frequency is used and all atoms of that partial are typed "atInfered".
|
xue@1
|
1650 for (int m=0; m<P; m++)
|
xue@1
|
1651 {
|
xue@1
|
1652 double fm=f0*(m+1)*sqrt(1+B*((m+1)*(m+1)-1)), dfm=(settings.delm<1)?settings.delm:1;
|
xue@1
|
1653 double errf=LSESinusoidMP(fm, fm-dfm, fm+dfm, xx, Fr, wid, 3, settings.M, settings.c, settings.iH2, as, phs, 1e-6);
|
xue@1
|
1654 // LSESinusoidMPC(fm, fm-1, fm+1, xx, Fr, wid, offst, 3, settings.M, settings.c, settings.iH2, as, phs, 1e-6);
|
xue@1
|
1655 atomtype type=(errf<0)?atInfered:atPeak;
|
xue@1
|
1656 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
1657 {
|
xue@1
|
1658 double tfr=(fr0+fr)*offst+wid/2;
|
xue@1
|
1659 atom tmpatom={tfr, wid, fm/wid, as[fr], phs[fr], m+1, type, 0};
|
xue@1
|
1660 part[atomcount++]=tmpatom;
|
xue@1
|
1661 }
|
xue@1
|
1662 }
|
xue@1
|
1663
|
xue@1
|
1664 //Tag the atom at initial input (_t, _f) as anchor.
|
xue@1
|
1665 AtomsToPartials(atomcount, part, M, Fr, partials, offst);
|
xue@1
|
1666 partials[settings.pin0-1][trst-fr0].type=atAnchor;
|
xue@1
|
1667 delete[] ipfr;
|
xue@1
|
1668 delete[] ipw;
|
xue@1
|
1669 delete[] part;
|
xue@1
|
1670 delete R; delete[] x; delete[] as; DeAlloc2(xx);
|
xue@1
|
1671 delete[] starts;
|
xue@1
|
1672 return 1;
|
xue@1
|
1673 }//FindNoteConst
|
xue@1
|
1674
|
Chris@5
|
1675 /**
|
xue@1
|
1676 function FindNoteF: forward harmonic sinusoid tracking starting from a given harmonic atom until an
|
xue@1
|
1677 endpoint is detected or a search boundary is reached.
|
xue@1
|
1678
|
xue@1
|
1679 In: starts: harmonic atom score of the start HA
|
xue@1
|
1680 startvfp[startp]: amplitudes of partials of start HA
|
xue@1
|
1681 R: F-G polygon of the start HA
|
xue@1
|
1682 frst, frst: frame index of the start and end frames of tracking.
|
xue@1
|
1683 Spec: spectrogram
|
xue@1
|
1684 wid, offst: atom scale and hop size, must be consistent with Spec
|
xue@1
|
1685 settings: note match settings
|
xue@1
|
1686 brake: tracking termination threshold.
|
xue@1
|
1687 Out: part[return value]: list of atoms tracked.
|
xue@1
|
1688 starts: maximal HA score of tracked frames. Its product with brake is used as the tracking threshold.
|
xue@1
|
1689
|
xue@1
|
1690 Returns the number of atoms found.
|
xue@1
|
1691 */
|
xue@1
|
1692 int FindNoteF(atom* part, double& starts, TPolygon* R, int startp, double* startvfp, int frst, int fren, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings, double brake)
|
xue@1
|
1693 {
|
xue@1
|
1694 settings.forcepin0=false, settings.pin0=0;
|
xue@1
|
1695
|
xue@1
|
1696 int k=0, maxp=settings.maxp;
|
xue@1
|
1697
|
xue@1
|
1698 TPolygon* RR=new TPolygon(1024, R);
|
xue@1
|
1699 int lastp=startp;
|
xue@1
|
1700 double *lastvfp=new double[settings.maxp]; memcpy(lastvfp, startvfp, sizeof(double)*startp);
|
xue@1
|
1701
|
xue@1
|
1702 cdouble *x=new cdouble[wid/2+1];
|
xue@1
|
1703 double *fpp=new double[maxp*4], *vfpp=&fpp[maxp], *pfpp=&fpp[maxp*2]; atomtype* ptype=(atomtype*)&fpp[maxp*3];
|
xue@1
|
1704 NMResults results={fpp, vfpp, pfpp, ptype};
|
xue@1
|
1705 int step=(fren>frst)?1:(-1);
|
xue@1
|
1706 for (int h=frst+step; (h-fren)*step<0; h+=step)
|
xue@1
|
1707 {
|
xue@1
|
1708 cmplx<QSPEC_FORMAT>* spec=Spec->Spec(h);
|
xue@1
|
1709 for (int i=0; i<=wid/2; i++) x[i]=spec[i];
|
xue@1
|
1710 double f0=0, B=0;
|
xue@1
|
1711 double tmp=NoteMatchStiff3(RR, f0, B, 1, &x, wid, 0, &settings, &results, lastp, lastvfp);
|
xue@1
|
1712 if (starts<tmp) starts=tmp;
|
xue@1
|
1713 if (tmp<starts*brake) break; //end condition: power drops by ??dB
|
xue@1
|
1714
|
xue@1
|
1715 lastp=NMResultToAtoms(settings.maxp, &part[k], h*offst+wid/2, wid, results); k+=lastp;
|
xue@1
|
1716 memcpy(lastvfp, vfpp, sizeof(double)*lastp);
|
xue@1
|
1717 }
|
xue@1
|
1718 delete RR; delete[] lastvfp; delete[] x; delete[] fpp;
|
xue@1
|
1719 return k;
|
xue@1
|
1720 }//FindNoteF
|
xue@1
|
1721
|
Chris@5
|
1722 /**
|
xue@1
|
1723 function FindNoteFB: forward-backward harmonic sinusid tracking.
|
xue@1
|
1724
|
xue@1
|
1725 In: frst, fren: index of start and end frames
|
xue@1
|
1726 Rst, Ren: F-G polygons of start and end harmonic atoms
|
xue@1
|
1727 vfpst[M], vfpen[M]: amplitude vectors of start and end harmonic atoms
|
xue@1
|
1728 Spec: spectrogram
|
xue@1
|
1729 wid, offst: atom scale and hop size, must be consistent with Spec
|
xue@1
|
1730 settings: note match settings
|
xue@1
|
1731 Out: partials[0:fren-frst][M], hosting tracked HS between frst and fren (inc).
|
xue@1
|
1732
|
xue@1
|
1733 Returns 0 if successful, 1 if failure in pitch tracking stage (no feasible HA candidate at some frame).
|
xue@1
|
1734 On start partials[0:fren-frst][M] shall be prepared to receive fren-frst+1 harmonic atoms
|
xue@1
|
1735 */
|
xue@1
|
1736 int FindNoteFB(int frst, TPolygon* Rst, double* vfpst, int fren, TPolygon* Ren, double* vfpen, int M, atom** partials, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings)
|
xue@1
|
1737 { //*
|
xue@1
|
1738 if (frst>fren) return -1;
|
xue@1
|
1739 int result=0;
|
xue@1
|
1740 if (settings.maxp>M) settings.maxp=M;
|
xue@1
|
1741 else M=settings.maxp;
|
xue@1
|
1742 int Fr=fren-frst+1;
|
xue@1
|
1743 double B, fpp[1024], delm=settings.delm, delp=settings.delp, iH2=settings.iH2;
|
xue@1
|
1744 double *vfpp=&fpp[256], *pfpp=&fpp[512]; atomtype *ptype=(atomtype*)&fpp[768];
|
xue@1
|
1745 int maxpitch=50;
|
xue@1
|
1746
|
xue@1
|
1747 NMResults results={fpp, vfpp, pfpp, ptype};
|
xue@1
|
1748
|
xue@1
|
1749 cmplx<QSPEC_FORMAT>* spec;
|
xue@1
|
1750
|
xue@1
|
1751 cdouble *x=new cdouble[wid/2+1];
|
xue@1
|
1752 TPolygon **Ra=new TPolygon*[maxpitch], **Rb=new TPolygon*[maxpitch], ***R; memset(Ra, 0, sizeof(TPolygon*)*maxpitch), memset(Rb, 0, sizeof(TPolygon*)*maxpitch);
|
xue@1
|
1753 double *sca=new double[maxpitch], *scb=new double[maxpitch], **sc; sca[0]=scb[0]=0;
|
xue@1
|
1754 double** Allocate2(double, maxpitch, M, vfpa); memcpy(vfpa[0], vfpst, sizeof(double)*M);
|
xue@1
|
1755 double** Allocate2(double, maxpitch, M, vfpb); memcpy(vfpb[0], vfpen, sizeof(double)*M);
|
xue@1
|
1756 double*** vfp;
|
xue@1
|
1757
|
xue@1
|
1758 double** Allocate2(double, Fr, wid/2, fps);
|
xue@1
|
1759 double** Allocate2(double, Fr, wid/2, vps);
|
xue@1
|
1760 int* pc=new int[Fr];
|
xue@1
|
1761
|
xue@1
|
1762 Ra[0]=new TPolygon(M*2+4, Rst);
|
xue@1
|
1763 Rb[0]=new TPolygon(M*2+4, Ren);
|
xue@1
|
1764 int pitchcounta=1, pitchcountb=1, pitchcount;
|
xue@1
|
1765
|
xue@1
|
1766 //pitch tracking
|
xue@1
|
1767 int** Allocate2(int, Fr, maxpitch, prev);
|
xue@1
|
1768 int** Allocate2(int, Fr, maxpitch, pitches);
|
xue@1
|
1769 int* pitchres=new int[Fr];
|
xue@1
|
1770 int fra=frst, frb=fren, fr;
|
xue@1
|
1771 while (fra<frb-1)
|
xue@1
|
1772 {
|
xue@1
|
1773 if (pitchcounta<pitchcountb){fra++; fr=fra; pitchcount=pitchcounta; vfp=&vfpa; sc=&sca; R=&Ra;}
|
xue@1
|
1774 else {frb--; fr=frb; pitchcount=pitchcountb; vfp=&vfpb; sc=&scb, R=&Rb;}
|
xue@1
|
1775 int fr_frst=fr-frst;
|
xue@1
|
1776
|
xue@1
|
1777 int absfr=(partials[0][fr].t-wid/2)/offst;
|
xue@1
|
1778 spec=Spec->Spec(absfr); for (int i=0; i<=wid/2; i++) x[i]=spec[i];
|
xue@1
|
1779 pc[fr_frst]=QuickPeaks(fps[fr_frst], vps[fr_frst], wid, x, settings.M, settings.c, iH2, 0.0005);
|
xue@1
|
1780 NoteMatchStiff3FB(pitchcount, *R, *vfp, *sc, pitches[fr_frst], prev[fr_frst], pc[fr_frst], fps[fr_frst], vps[fr_frst], x, wid, maxpitch, &settings);
|
xue@1
|
1781 if (fr==fra) pitchcounta=pitchcount;
|
xue@1
|
1782 else pitchcountb=pitchcount;
|
xue@1
|
1783 if (pitchcount<=0)
|
xue@1
|
1784 {result=1; goto cleanup;}
|
xue@1
|
1785 }
|
xue@1
|
1786 {
|
xue@1
|
1787 //now fra=frb-1
|
xue@1
|
1788 int fra_frst=fra-frst, frb_frst=frb-frst, maxpitcha=0, maxpitchb=0;
|
xue@1
|
1789 double maxs=0;
|
xue@1
|
1790 for (int i=0; i<pitchcounta; i++)
|
xue@1
|
1791 {
|
xue@1
|
1792 double f0a, f0b;
|
xue@1
|
1793 if (fra==frst) f0a=partials[0][frst].f*wid;
|
xue@1
|
1794 else
|
xue@1
|
1795 {
|
xue@1
|
1796 int peak0a=((__int16*)&pitches[fra_frst][i])[0], pin0a=((__int16*)&pitches[fra_frst][i])[1];
|
xue@1
|
1797 f0a=fps[fra_frst][peak0a]/pin0a;
|
xue@1
|
1798 }
|
xue@1
|
1799 for (int j=0; j<pitchcountb; j++)
|
xue@1
|
1800 {
|
xue@1
|
1801 if (frb==fren) f0b=partials[0][fren].f*wid;
|
xue@1
|
1802 else
|
xue@1
|
1803 {
|
xue@1
|
1804 int peak0b=((__int16*)&pitches[frb_frst][j])[0], pin0b=((__int16*)&pitches[frb_frst][j])[1];
|
xue@1
|
1805 f0b=fps[frb_frst][peak0b]/pin0b;
|
xue@1
|
1806 }
|
xue@1
|
1807 double pow2delp=pow(2, delp/12);
|
xue@1
|
1808 if (f0b<f0a*pow2delp+delm && f0b>f0a/pow2delp-delm)
|
xue@1
|
1809 {
|
xue@1
|
1810 double s=sca[i]+scb[j]+conta(M, vfpa[i], vfpb[j]);
|
xue@1
|
1811 if (maxs<s) maxs=s, maxpitcha=i, maxpitchb=j;
|
xue@1
|
1812 }
|
xue@1
|
1813 }
|
xue@1
|
1814 }
|
xue@1
|
1815 //get pitch tracking result
|
xue@1
|
1816 pitchres[fra_frst]=pitches[fra_frst][maxpitcha];
|
xue@1
|
1817 for (int fr=fra; fr>frst; fr--)
|
xue@1
|
1818 {
|
xue@1
|
1819 maxpitcha=prev[fr-frst][maxpitcha];
|
xue@1
|
1820 pitchres[fr-frst-1]=pitches[fr-frst-1][maxpitcha];
|
xue@1
|
1821 }
|
xue@1
|
1822 pitchres[frb_frst]=pitches[frb_frst][maxpitchb];
|
xue@1
|
1823 for (int fr=frb; fr<fren; fr++)
|
xue@1
|
1824 {
|
xue@1
|
1825 maxpitchb=prev[fr-frst][maxpitchb];
|
xue@1
|
1826 pitchres[fr-frst+1]=pitches[fr-frst+1][maxpitchb];
|
xue@1
|
1827 }
|
xue@1
|
1828 }
|
xue@1
|
1829 {
|
xue@1
|
1830 double f0s[1024]; memset(f0s, 0, sizeof(double)*1024);
|
xue@1
|
1831 for (int i=frst+1; i<fren; i++)
|
xue@1
|
1832 {
|
xue@1
|
1833 int pitch=pitchres[i-frst];
|
xue@1
|
1834 int peak0=((__int16*)&pitch)[0], pin0=((__int16*)&pitch)[1];
|
xue@1
|
1835 f0s[i]=fps[i-frst][peak0]/pin0;
|
xue@1
|
1836 }
|
xue@1
|
1837 f0s[frst]=sqrt(Rst->X[0]), f0s[fren]=sqrt(Ren->X[0]);
|
xue@1
|
1838
|
xue@1
|
1839 //partial tracking
|
xue@1
|
1840 int lastp=0; while (lastp<M && vfpst[lastp]>0) lastp++;
|
xue@1
|
1841 double* lastvfp=new double[M]; memcpy(lastvfp, vfpst, sizeof(double)*M);
|
xue@1
|
1842 delete Ra[0]; Ra[0]=new TPolygon(M*2+4, Rst);
|
xue@1
|
1843 for (int h=frst+1; h<fren; h++)
|
xue@1
|
1844 {
|
xue@1
|
1845 int absfr=(partials[0][h].t-wid/2)/offst;
|
xue@1
|
1846 int h_frst=h-frst, pitch=pitchres[h_frst];
|
xue@1
|
1847 int peak0=((__int16*)&pitch)[0], pin0=((__int16*)&pitch)[1];
|
xue@1
|
1848 spec=Spec->Spec(absfr);
|
xue@1
|
1849 double f0=fpp[0];//, B=Form11->BEdit->Text.ToDouble();
|
xue@1
|
1850 //double deltaf=f0*(pow(2, settings.delp/12)-1);
|
xue@1
|
1851 for (int i=0; i<=wid/2; i++) x[i]=spec[i];
|
xue@1
|
1852 memset(fpp, 0, sizeof(double)*1024);
|
xue@1
|
1853 //settings.epf0=deltaf,
|
xue@1
|
1854 settings.forcepin0=true; settings.pin0=pin0; f0=fps[h_frst][peak0]; settings.pin0asanchor=false;
|
xue@1
|
1855 if (NoteMatchStiff3(Ra[0], f0, B, pc[h_frst], fps[h_frst], vps[h_frst], 1, &x, wid, 0, &settings, &results, lastp, lastvfp)>0)
|
xue@1
|
1856 {
|
xue@1
|
1857 lastp=NMResultToPartials(M, h, partials, partials[0][h].t, wid, results);
|
xue@1
|
1858 memcpy(lastvfp, vfpp, sizeof(double)*lastp);
|
xue@1
|
1859 }
|
xue@1
|
1860 }
|
xue@1
|
1861 delete[] lastvfp;
|
xue@1
|
1862 }
|
xue@1
|
1863 cleanup:
|
xue@1
|
1864 delete[] x;
|
xue@1
|
1865 for (int i=0; i<pitchcounta; i++) delete Ra[i]; delete[] Ra;
|
xue@1
|
1866 for (int i=0; i<pitchcountb; i++) delete Rb[i]; delete[] Rb;
|
xue@1
|
1867 delete[] sca; delete[] scb;
|
xue@1
|
1868 DeAlloc2(vfpa); DeAlloc2(vfpb);
|
xue@1
|
1869 DeAlloc2(fps); DeAlloc2(vps);
|
xue@1
|
1870 DeAlloc2(pitches); DeAlloc2(prev);
|
xue@1
|
1871 delete[] pitchres; delete[] pc;
|
xue@1
|
1872 return result; //*/
|
xue@1
|
1873 }//FindNoteFB
|
xue@1
|
1874
|
Chris@5
|
1875 /**
|
xue@1
|
1876 function GetResultsSingleFr: used by NoteMatchStiff3 to obtain final note match results after harmonic
|
xue@1
|
1877 grouping of peaks with rough frequency estimates, including a screening of found peaks based on shape
|
xue@1
|
1878 and consistency with other peak frequencies, reestimating sinusoid parameters using LSE, estimating
|
xue@1
|
1879 atoms without peaks by inferring their frequencies, and translating internal peak type to atom type.
|
xue@1
|
1880
|
xue@1
|
1881 In: R0: F-G polygon of primitive (=rough estimates) partial frequencies
|
xue@1
|
1882 x[N]: spectrum
|
xue@1
|
1883 ps[P], fs[P]; partial indices and frequencies, may miss partials
|
xue@1
|
1884 rsrs[P]: peak shape factors, used for evaluating peak validity
|
xue@1
|
1885 psb[P]: peak type flags, related to atom::ptype.
|
xue@1
|
1886 settings: note match settings
|
xue@1
|
1887 numsam: number of partials to evaluate (=number of atoms to return)
|
xue@1
|
1888 Out: results: note match results as a NMResult structure
|
xue@1
|
1889 f0, B: fundamental frequency and stiffness coefficient
|
xue@1
|
1890 Rret: F-G polygon of reestimated set of partial frequencies
|
xue@1
|
1891
|
xue@1
|
1892 Return the total energy of the harmonic atom.
|
xue@1
|
1893 */
|
xue@1
|
1894 double GetResultsSingleFr(double& f0, double& B, TPolygon* Rret, TPolygon* R0, int P, int* ps, double* fs, double* rsrs, cdouble* x, int N, int* psb, int numsam, NMSettings* settings, NMResults* results)
|
xue@1
|
1895 {
|
xue@1
|
1896 Rret->N=0;
|
xue@1
|
1897 double delm=settings->delm, *c=settings->c, iH2=settings->iH2, epf=settings->epf, maxB=settings->maxB, hB=settings->hB;
|
xue@1
|
1898 int M=settings->M, maxp=settings->maxp;
|
xue@1
|
1899 double *fp=results->fp; memset(fp, 0, sizeof(double)*maxp);
|
xue@1
|
1900
|
xue@1
|
1901 double result=0;
|
xue@1
|
1902 if (P>0)
|
xue@1
|
1903 {
|
xue@1
|
1904 double *vfp=results->vfp, *pfp=results->pfp;
|
xue@1
|
1905 atomtype *ptype=results->ptype; //memset(ptype, 0, sizeof(int)*maxp);
|
xue@1
|
1906
|
xue@1
|
1907 double *f1=new double[(maxp+1)*4], *f2=&f1[maxp+1], *ft=&f2[maxp+1], *fdep=&ft[maxp+1], tmpa, cF, cG;
|
xue@1
|
1908 areaandcentroid(tmpa, cF, cG, R0->N, R0->X, R0->Y);
|
xue@1
|
1909 for (int p=1; p<=maxp; p++) ExFmStiff(f1[p], f2[p], p, R0->N, R0->X, R0->Y), ft[p]=p*sqrt(cF+(p*p-1)*cG);
|
xue@1
|
1910 //sort peaks by rsr and departure from model so that most reliable ones are found at the start
|
xue@1
|
1911 double* values=new double[P]; int* indices=new int[P];
|
xue@1
|
1912 for (int i=0; i<P; i++)
|
xue@1
|
1913 {
|
xue@1
|
1914 values[i]=1e200;
|
xue@1
|
1915 int lp=ps[i]; double lf=fs[i];
|
xue@1
|
1916 if (lf>=f1[lp] && lf<=f2[lp]) fdep[lp]=0;
|
xue@1
|
1917 else if (lf<f1[lp]) fdep[lp]=f1[lp]-lf;
|
xue@1
|
1918 else if (lf>f2[lp]) fdep[lp]=lf-f2[lp];
|
xue@1
|
1919 double tmpv=(fdep[lp]>0.5)?(fdep[lp]-0.5)*2:0;
|
xue@1
|
1920 tmpv+=rsrs?rsrs[i]:0;
|
xue@1
|
1921 tmpv*=pow(lp, 0.2);
|
xue@1
|
1922 InsertInc(tmpv, i, values, indices, i+1);
|
xue@1
|
1923 }
|
xue@1
|
1924
|
xue@1
|
1925 for (int i=0; i<P; i++)
|
xue@1
|
1926 {
|
xue@1
|
1927 int ind=indices[i];
|
xue@1
|
1928 int lp=ps[ind]; //partial index
|
xue@1
|
1929 //Get LSE estimation of atoms
|
xue@1
|
1930 double lf=fs[ind], f1, f2, la, lph;//, lrsr=rsrs?rsrs[ind]:0
|
xue@1
|
1931 if (lp==0 || lf==0) continue;
|
xue@1
|
1932 ExFmStiff(f1, f2, lp, R0->N, R0->X, R0->Y);
|
xue@1
|
1933 LSESinusoid(lf, f1-delm, f2+delm, x, N, 3, M, c, iH2, la, lph, epf);
|
xue@1
|
1934 //lrsr=PeakShapeC(lf, 1, N, &x, 6, M, c, iH2);
|
xue@1
|
1935 if (Rret->N>0) ExFmStiff(f1, f2, lp, Rret->N, Rret->X, Rret->Y);
|
xue@1
|
1936 if (Rret->N==0 || (lf>=f1 && lf<=f2))
|
xue@1
|
1937 {
|
xue@1
|
1938 fp[lp-1]=lf;
|
xue@1
|
1939 vfp[lp-1]=la;
|
xue@1
|
1940 pfp[lp-1]=lph;
|
xue@1
|
1941 if (psb[lp]==1 || (psb[lp]==2 && settings->pin0asanchor)) ptype[lp-1]=atAnchor; //0 for anchor points
|
xue@1
|
1942 else ptype[lp-1]=atPeak; //1 for local maximum
|
xue@1
|
1943 //update R using found partails with amplitude>1
|
xue@1
|
1944 if (Rret->N==0) InitializeR(Rret, lp, lf, delm, maxB);
|
xue@1
|
1945 else if (la>1) CutR(Rret, lp, lf, delm, true);
|
xue@1
|
1946 }
|
xue@1
|
1947 }
|
xue@1
|
1948 //*
|
xue@1
|
1949 for (int p=1; p<=maxp; p++)
|
xue@1
|
1950 {
|
xue@1
|
1951 if (fp[p-1]>0)
|
xue@1
|
1952 {
|
xue@1
|
1953 double f1, f2;
|
xue@1
|
1954 ExFmStiff(f1, f2, p, Rret->N, Rret->X, Rret->Y);
|
xue@1
|
1955 if (fp[p-1]<f1-0.3 || fp[p-1]>f2+0.3)
|
xue@1
|
1956 fp[p-1]=0;
|
xue@1
|
1957 }
|
xue@1
|
1958 }// */
|
xue@1
|
1959
|
xue@1
|
1960
|
xue@1
|
1961 //estimate f0 and B
|
xue@1
|
1962 double norm[1024]; for (int i=0; i<1024; i++) norm[i]=1;
|
xue@1
|
1963 areaandcentroid(tmpa, cF, cG, Rret->N, Rret->X, Rret->Y); //minimaxstiff(cF, cG, P, ps, fs, norm, R->N, R->X, R->Y);
|
xue@1
|
1964 testnn(cF); f0=sqrt(cF); B=cG/cF;
|
xue@1
|
1965
|
xue@1
|
1966 //Get LSE estimates for unfound partials
|
xue@1
|
1967 for (int i=0; i<numsam; i++)
|
xue@1
|
1968 {
|
xue@1
|
1969 if (fp[i]==0) //no peak is found for this partial in lcand
|
xue@1
|
1970 {
|
xue@1
|
1971 int m=i+1;
|
xue@1
|
1972 double tmp=cF+(m*m-1)*cG; testnn(tmp);
|
xue@1
|
1973 double lf=m*sqrt(tmp);
|
xue@1
|
1974 if (lf<N/2.1)
|
xue@1
|
1975 {
|
xue@1
|
1976 fp[i]=lf;
|
xue@1
|
1977 ptype[i]=atInfered; //2 for non peak
|
xue@1
|
1978 cdouble r=IPWindowC(lf, x, N, M, c, iH2, lf-hB, lf+hB);
|
xue@1
|
1979 vfp[i]=sqrt(r.x*r.x+r.y*r.y);
|
xue@1
|
1980 pfp[i]=Atan2(r.y, r.x);//*/
|
xue@1
|
1981 }
|
xue@1
|
1982 }
|
xue@1
|
1983 }
|
xue@1
|
1984 if (f0>0) for (int i=0; i<numsam; i++) if (fp[i]>0) result+=vfp[i]*vfp[i];
|
xue@1
|
1985
|
xue@1
|
1986 delete[] f1; delete[] values; delete[] indices;
|
xue@1
|
1987 }
|
xue@1
|
1988 return result;
|
xue@1
|
1989 }//GetResultsSingleFr
|
xue@1
|
1990
|
Chris@5
|
1991 /**
|
xue@1
|
1992 function GetResultsMultiFr: the constant-pitch multi-frame version of GetResultsSingleFr.
|
xue@1
|
1993
|
xue@1
|
1994 In: x[Fr][N]: spectrogram
|
xue@1
|
1995 ps[P], fs[P]; partial indices and frequencies, may miss partials
|
xue@1
|
1996 psb[P]: peak type flags, related to atom::ptype.
|
xue@1
|
1997 settings: note match settings
|
xue@1
|
1998 forceinputlocalfr: specifies if partial settings->pin0 is taken for granted ("pinned")
|
xue@1
|
1999 numsam: number of partials to evaluate (=number of atoms to return)
|
xue@1
|
2000 Out: results[Fr]: note match results as Fr NMResult structures
|
xue@1
|
2001 f0, B: fundamental frequency and stiffness coefficient
|
xue@1
|
2002 Rret: F-G polygon of reestimated set of partial frequencies
|
xue@1
|
2003
|
xue@1
|
2004 Return the total energy of the harmonic sinusoid.
|
xue@1
|
2005 */
|
xue@1
|
2006 double GetResultsMultiFr(double& f0, double& B, TPolygon* Rret, TPolygon* R0, int P, int* ps, double* fs, double* rsrs, int Fr, cdouble** x, int N, int offst, int* psb, int numsam, NMSettings* settings, NMResults* results, int forceinputlocalfr)
|
xue@1
|
2007 {
|
xue@1
|
2008 Rret->N=0;
|
xue@1
|
2009 double delm=settings->delm, *c=settings->c, iH2=settings->iH2, epf=settings->epf, maxB=settings->maxB, hB=settings->hB;// *pinf=settings->pinf;
|
xue@1
|
2010
|
xue@1
|
2011 int M=settings->M, maxp=settings->maxp, pincount=settings->pcount, *pin=settings->pin, *pinfr=settings->pinfr;
|
xue@1
|
2012 // double *fp=results->fp, *vfp=results->vfp, *pfp=results->pfp;
|
xue@1
|
2013 // int *ptype=results->ptype;
|
xue@1
|
2014 for (int fr=0; fr<Fr; fr++) memset(results[fr].fp, 0, sizeof(double)*maxp);
|
xue@1
|
2015 int* pclass=new int[maxp+1]; memset(pclass, 0, sizeof(int)*(maxp+1));
|
xue@1
|
2016 for (int i=0; i<pincount; i++) if (pinfr[i]>=0) pclass[pin[i]]=1;
|
xue@1
|
2017 if (forceinputlocalfr>=0) pclass[settings->pin0]=1;
|
xue@1
|
2018 double result=0;
|
xue@1
|
2019 if (P>0)
|
xue@1
|
2020 {
|
xue@1
|
2021 double tmpa, cF, cG;
|
xue@1
|
2022 //found atoms
|
xue@1
|
2023 double *as=new double[Fr*2], *phs=&as[Fr];
|
xue@1
|
2024 for (int i=P-1; i>=0; i--)
|
xue@1
|
2025 {
|
xue@1
|
2026 int lp=ps[i];
|
xue@1
|
2027 double lf=fs[i];
|
xue@1
|
2028 if (lp==0 || lf==0) continue;
|
xue@1
|
2029
|
xue@1
|
2030 if (!pclass[lp])
|
xue@1
|
2031 {
|
xue@1
|
2032 //Get LSE estimation of atoms
|
xue@1
|
2033 double startlf=lf;
|
xue@1
|
2034 LSESinusoidMP(lf, lf-1, lf+1, x, Fr, N, 3, M, c, iH2, as, phs, epf);
|
xue@1
|
2035 //LSESinusoidMPC(lf, lf-1, lf+1, x, Fr, N, offst, 3, M, c, iH2, as, phs, epf);
|
xue@1
|
2036 if (fabs(lf-startlf)>0.6)
|
xue@1
|
2037 {
|
xue@1
|
2038 lf=startlf;
|
xue@1
|
2039 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
2040 {
|
xue@1
|
2041 cdouble r=IPWindowC(lf, x[fr], N, M, c, iH2, lf-settings->hB, lf+settings->hB);
|
xue@1
|
2042 as[fr]=abs(r);
|
xue@1
|
2043 phs[fr]=arg(r);
|
xue@1
|
2044 }
|
xue@1
|
2045 }
|
xue@1
|
2046 }
|
xue@1
|
2047 else //frequencies of local anchor atoms are not re-estimated
|
xue@1
|
2048 {
|
xue@1
|
2049 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
2050 {
|
xue@1
|
2051 cdouble r=IPWindowC(lf, x[fr], N, M, c, iH2, lf-settings->hB, lf+settings->hB);
|
xue@1
|
2052 as[fr]=abs(r);
|
xue@1
|
2053 phs[fr]=arg(r);
|
xue@1
|
2054 }
|
xue@1
|
2055 }
|
xue@1
|
2056
|
xue@1
|
2057 //LSESinusoid(lf, f1-delm, f2+delm, x, N, 3, M, c, iH2, la, lph, epf);
|
xue@1
|
2058 //fp[lp-1]=lf; vfp[lp-1]=la; pfp[lp-1]=lph;
|
xue@1
|
2059 for (int fr=0; fr<Fr; fr++) results[fr].fp[lp-1]=lf, results[fr].vfp[lp-1]=as[fr], results[fr].pfp[lp-1]=phs[fr];
|
xue@1
|
2060 if (psb[lp]==1 || (psb[lp]==2 && settings->pin0asanchor)) for (int fr=0; fr<Fr; fr++) results[fr].ptype[lp-1]=atAnchor; //0 for anchor points
|
xue@1
|
2061 else for (int fr=0; fr<Fr; fr++) results[fr].ptype[lp-1]=atPeak; //1 for local maximum
|
xue@1
|
2062 //update R using found partails with amplitude>1
|
xue@1
|
2063 if (Rret->N==0)
|
xue@1
|
2064 {
|
xue@1
|
2065 //temporary treatment: +0.5 should be +rsr or something similar
|
xue@1
|
2066 InitializeR(Rret, lp, lf, delm+0.5, maxB);
|
xue@1
|
2067 areaandcentroid(tmpa, cF, cG, Rret->N, Rret->X, Rret->Y); //minimaxstiff(cF, cG, P, ps, fs, norm, R->N, R->X, R->Y);
|
xue@1
|
2068 }
|
xue@1
|
2069 else //if (la>1)
|
xue@1
|
2070 {
|
xue@1
|
2071 CutR(Rret, lp, lf, delm+0.5, true);
|
xue@1
|
2072 areaandcentroid(tmpa, cF, cG, Rret->N, Rret->X, Rret->Y); //minimaxstiff(cF, cG, P, ps, fs, norm, R->N, R->X, R->Y);
|
xue@1
|
2073 }
|
xue@1
|
2074 }
|
xue@1
|
2075 //estimate f0 and B
|
xue@1
|
2076 double norm[1024]; for (int i=0; i<1024; i++) norm[i]=1;
|
xue@1
|
2077 areaandcentroid(tmpa, cF, cG, Rret->N, Rret->X, Rret->Y); //minimaxstiff(cF, cG, P, ps, fs, norm, R->N, R->X, R->Y);
|
xue@1
|
2078 testnn(cF); f0=sqrt(cF); B=cG/cF;
|
xue@1
|
2079
|
xue@1
|
2080 //Get LSE estimates for unfound partials
|
xue@1
|
2081 for (int i=0; i<numsam; i++)
|
xue@1
|
2082 {
|
xue@1
|
2083 if (results[0].fp[i]==0) //no peak is found for this partial in lcand
|
xue@1
|
2084 {
|
xue@1
|
2085 int m=i+1;
|
xue@1
|
2086 double tmp=cF+(m*m-1)*cG; testnn(tmp);
|
xue@1
|
2087 double lf=m*sqrt(tmp);
|
xue@1
|
2088 if (lf<N/2.1)
|
xue@1
|
2089 {
|
xue@1
|
2090 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
2091 {
|
xue@1
|
2092 results[fr].fp[i]=lf, results[fr].ptype[i]=atInfered; //2 for non peak
|
xue@1
|
2093 int k1=ceil(lf-hB); if (k1<0) k1=0;
|
xue@1
|
2094 int k2=floor(lf+hB); if (k2>=N/2) k2=N/2-1;
|
xue@1
|
2095 cdouble r=IPWindowC(lf, x[fr], N, M, c, iH2, k1, k2);
|
xue@1
|
2096 results[fr].vfp[i]=abs(r);
|
xue@1
|
2097 results[fr].pfp[i]=arg(r);
|
xue@1
|
2098 }
|
xue@1
|
2099 }
|
xue@1
|
2100 }
|
xue@1
|
2101 }
|
xue@1
|
2102 delete[] as;
|
xue@1
|
2103 if (f0>0) for (int fr=0; fr<Fr; fr++) for (int i=0; i<numsam; i++) if (results[fr].fp[i]>0) result+=results[fr].vfp[i]*results[fr].vfp[i];
|
xue@1
|
2104 result/=Fr;
|
xue@1
|
2105 }
|
xue@1
|
2106 delete[] pclass;
|
xue@1
|
2107 return result;
|
xue@1
|
2108 }//GetResultsMultiFr
|
xue@1
|
2109
|
Chris@5
|
2110 /**
|
xue@1
|
2111 function InitailizeR: initializes a F-G polygon with a fundamental frequency range and stiffness coefficient bound
|
xue@1
|
2112
|
xue@1
|
2113 In: af, ef: centre and half width of the fundamental frequency range
|
xue@1
|
2114 maxB: maximal value of stiffness coefficient (the minimal is set to 0)
|
xue@1
|
2115 Out: R: the initialized F-G polygon.
|
xue@1
|
2116
|
xue@1
|
2117 No reutrn value.
|
xue@1
|
2118 */
|
xue@1
|
2119 void InitializeR(TPolygon* R, double af, double ef, double maxB)
|
xue@1
|
2120 {
|
xue@1
|
2121 R->N=4;
|
xue@1
|
2122 double *X=R->X, *Y=R->Y;
|
xue@1
|
2123 double g1=af-ef, g2=af+ef;
|
xue@1
|
2124 if (g1<0) g1=0;
|
xue@1
|
2125 g1=g1*g1, g2=g2*g2;
|
xue@1
|
2126 X[0]=X[3]=g1, X[1]=X[2]=g2;
|
xue@1
|
2127 Y[0]=X[0]*maxB, Y[1]=X[1]*maxB, Y[2]=Y[3]=0;
|
xue@1
|
2128 }//InitializeR
|
xue@1
|
2129
|
Chris@5
|
2130 /**
|
xue@1
|
2131 function InitialzeR: initializes a F-G polygon with a frequency range for a given partial and
|
xue@1
|
2132 stiffness coefficient bound
|
xue@1
|
2133
|
xue@1
|
2134 In: apind: partial index
|
xue@1
|
2135 af, ef: centre and half width of the frequency range of the apind-th partial
|
xue@1
|
2136 maxB; maximal value of stiffness coefficient (the minimal is set to 0)
|
xue@1
|
2137 Out: R: the initialized F-G polygon.
|
xue@1
|
2138
|
xue@1
|
2139 No return value.
|
xue@1
|
2140 */
|
xue@1
|
2141 void InitializeR(TPolygon* R, int apind, double af, double ef, double maxB)
|
xue@1
|
2142 {
|
xue@1
|
2143 R->N=4;
|
xue@1
|
2144 double *X=R->X, *Y=R->Y;
|
xue@1
|
2145 double k=apind*apind-1;
|
xue@1
|
2146 double g1=(af-ef)/apind, g2=(af+ef)/apind;
|
xue@1
|
2147 if (g1<0) g1=0;
|
xue@1
|
2148 g1=g1*g1, g2=g2*g2;
|
xue@1
|
2149 double kb1=1+k*maxB;
|
xue@1
|
2150 X[0]=g1/kb1, X[1]=g2/kb1, X[2]=g2, X[3]=g1;
|
xue@1
|
2151 Y[0]=X[0]*maxB, Y[1]=X[1]*maxB, Y[2]=Y[3]=0;
|
xue@1
|
2152 }//InitializeR
|
xue@1
|
2153
|
Chris@5
|
2154 /**
|
xue@1
|
2155 function maximalminimum: finds the point within a polygon that maximizes its minimal distance to the
|
xue@1
|
2156 sides.
|
xue@1
|
2157
|
xue@1
|
2158 In: sx[N], sy[N]: x- and y-coordinates of vertices of a polygon
|
xue@1
|
2159 Out: (x, y): point within the polygon with maximal minimal distance to the sides
|
xue@1
|
2160
|
xue@1
|
2161 Returns the maximial minimal distance. A circle centred at (x, y) with the return value as the radius
|
xue@1
|
2162 is the maximum inscribed circle of the polygon.
|
xue@1
|
2163 */
|
xue@1
|
2164 double maximalminimum(double& x, double& y, int N, double* sx, double* sy)
|
xue@1
|
2165 {
|
xue@1
|
2166 //at the beginning let (x, y) be (sx[0], sy[0]), then the mininum distance d is 0.
|
xue@1
|
2167 double dm=0;
|
xue@1
|
2168 x=sx[0], y=sy[0];
|
xue@1
|
2169 double *A=new double[N*3];
|
xue@1
|
2170 double *B=&A[N], *C=&A[N*2];
|
xue@1
|
2171 //calcualte equations of all sides A[k]x+B[k]y+C[k]=0, with signs adjusted so that for
|
xue@1
|
2172 // any (x, y) within the polygon, A[k]x+B[k]y+C[k]>0. A[k]^2+B[k]^2=1.
|
xue@1
|
2173 for (int n=0; n<N; n++)
|
xue@1
|
2174 {
|
xue@1
|
2175 double x1=sx[n], y1=sy[n], x2, y2, AA, BB, CC;
|
xue@1
|
2176 if (n+1!=N) x2=sx[n+1], y2=sy[n+1];
|
xue@1
|
2177 else x2=sx[0], y2=sy[0];
|
xue@1
|
2178 double dx=x1-x2, dy=y1-y2;
|
xue@1
|
2179 double ds=sqrt(dx*dx+dy*dy);
|
xue@1
|
2180 AA=dy/ds, BB=-dx/ds;
|
xue@1
|
2181 CC=-AA*x1-BB*y1;
|
xue@1
|
2182 //adjust signs
|
xue@1
|
2183 if (n+2<N) x2=sx[n+2], y2=sy[n+2];
|
xue@1
|
2184 else x2=sx[n+2-N], y2=sy[n+2-N];
|
xue@1
|
2185 if (AA*x2+BB*y2+CC<0) A[n]=-AA, B[n]=-BB, C[n]=-CC;
|
xue@1
|
2186 else A[n]=AA, B[n]=BB, C[n]=CC;
|
xue@1
|
2187 }
|
xue@1
|
2188
|
xue@1
|
2189 //during the whole process (x, y) is always equal-distance to at least two sides,
|
xue@1
|
2190 // namely l1--(l1+1) and l2--(l2+1). there equations are A1x+B1y+C1=0 and A2x+B2y+C2=0,
|
xue@1
|
2191 // where A^2+B^2=1.
|
xue@1
|
2192 int l1=0, l2=N-1;
|
xue@1
|
2193
|
xue@1
|
2194 double a, b;
|
xue@1
|
2195 b=A[l1]-A[l2], a=B[l2]-B[l1];
|
xue@1
|
2196 double ds=sqrt(a*a+b*b);
|
xue@1
|
2197 a/=ds, b/=ds;
|
xue@1
|
2198 //the line (x+at, y+bt) passes (x, y), and points on this line are equal-distance to l1 and l2.
|
xue@1
|
2199 //along this line at point (x, y), we have dx=ads, dy=bds
|
xue@1
|
2200 //now find the signs so that dm increases as ds>0
|
xue@1
|
2201 double ddmds=A[l1]*a+B[l1]*b;
|
xue@1
|
2202 if (ddmds<0) a=-a, b=-b, ddmds=-ddmds;
|
xue@1
|
2203
|
xue@1
|
2204 while (true)
|
xue@1
|
2205 {
|
xue@1
|
2206 //now the vector starting from (x, y) pointing in (a, b) is equi-distance-to-l1-and-l2 and
|
xue@1
|
2207 // dm-increasing. actually at s from (x,y), d=dm+ddmds*s.
|
xue@1
|
2208
|
xue@1
|
2209 //it is now guaranteed that the distance of (x, y) to l1 (=l2) is smaller than to any other
|
xue@1
|
2210 // sides. along direction (A, B) the distance of (x, y) to l1 (=l2) is increasing and
|
xue@1
|
2211 // the distance to at least one other sides is increasing, so that at some value of s the
|
xue@1
|
2212 // distances equal. we find the smallest s>0 where this happens.
|
xue@1
|
2213 int l3=-1;
|
xue@1
|
2214 double s=-1;
|
xue@1
|
2215 for (int n=0; n<N; n++)
|
xue@1
|
2216 {
|
xue@1
|
2217 if (n==l1 || n==l2) continue;
|
xue@1
|
2218 //distance of (x,y) to the side
|
xue@1
|
2219 double ldm=A[n]*x+B[n]*y+C[n]; //ldm>dm
|
xue@1
|
2220 double dldmds=A[n]*a+B[n]*b;
|
xue@1
|
2221 //so ld=ldm+lddmds*s, the equality is dm+ddmds*s=ldm+lddmds*s
|
xue@1
|
2222 if (ddmds-dldmds>0)
|
xue@1
|
2223 {
|
xue@1
|
2224 ds=(ldm-dm)/(ddmds-dldmds);
|
xue@1
|
2225 if (l3==-1) l3=n, s=ds;
|
xue@1
|
2226 else if (ds<s) l3=n, s=ds;
|
xue@1
|
2227 }
|
xue@1
|
2228 }
|
xue@1
|
2229 if (ddmds==0) s/=2;
|
xue@1
|
2230 x=x+a*s, y=y+b*s;
|
xue@1
|
2231 dm=A[l1]*x+B[l1]*y+C[l1];
|
xue@1
|
2232 // Form1->Canvas->Ellipse(x-dm, y-dm, x+dm, y+dm);
|
xue@1
|
2233 //(x, y) is equal-distance to l1, l2 and l3
|
xue@1
|
2234 //try use l3 to substitute l2
|
xue@1
|
2235 b=A[l1]-A[l3], a=B[l3]-B[l1];
|
xue@1
|
2236 ds=sqrt(a*a+b*b);
|
xue@1
|
2237 a/=ds, b/=ds;
|
xue@1
|
2238 ddmds=A[l1]*a+B[l1]*b;
|
xue@1
|
2239 if (ddmds<0) a=-a, b=-b, ddmds=-ddmds;
|
xue@1
|
2240 if (ddmds==0 || A[l2]*a+B[l2]*b>0)
|
xue@1
|
2241 {
|
xue@1
|
2242 l2=l3;
|
xue@1
|
2243 }
|
xue@1
|
2244 else //l1<-l3 fails, then try use l3 to substitute l2
|
xue@1
|
2245 {
|
xue@1
|
2246 b=A[l3]-A[l2], a=B[l2]-B[l3];
|
xue@1
|
2247 ds=sqrt(a*a+b*b);
|
xue@1
|
2248 a/=ds, b/=ds;
|
xue@1
|
2249 ddmds=A[l3]*a+B[l3]*b;
|
xue@1
|
2250 if (ddmds<0) a=-a, b=-b, ddmds=-ddmds;
|
xue@1
|
2251 if (ddmds==0 || A[l1]*a+B[l1]*b>0)
|
xue@1
|
2252 {
|
xue@1
|
2253 l1=l3;
|
xue@1
|
2254 }
|
xue@1
|
2255 else break;
|
xue@1
|
2256 }
|
xue@1
|
2257 }
|
xue@1
|
2258
|
xue@1
|
2259 delete[] A;
|
xue@1
|
2260 return dm;
|
xue@1
|
2261 }//maximalminimum
|
xue@1
|
2262
|
Chris@5
|
2263 /**
|
xue@1
|
2264 function minimaxstiff: finds the point in polygon (N; F, G) that minimizes the maximal value of the
|
xue@1
|
2265 function
|
xue@1
|
2266
|
xue@1
|
2267 | m[l]sqrt(F+(m[l]^2-1)*G)-f[l] |
|
xue@1
|
2268 e_l = | ----------------------------- | regarding l=0, ..., L-1
|
xue@1
|
2269 | norm[l] |
|
xue@1
|
2270
|
xue@1
|
2271 In: _m[L], _f[L], norm[L]: coefficients in the above
|
xue@1
|
2272 F[N], G[N]: vertices of a F-G polygon
|
xue@1
|
2273 Out: (F1, G1): the mini-maximum.
|
xue@1
|
2274
|
xue@1
|
2275 Returns the minimized maximum value.
|
xue@1
|
2276
|
xue@1
|
2277 Further reading: Wen X, "Estimating model parameters", Ch.3.2.6 from "Harmonic sinusoid modeling of
|
xue@1
|
2278 tonal music events", PhD thesis, University of London, 2007.
|
xue@1
|
2279 */
|
xue@1
|
2280 double minimaxstiff(double& F1, double& G1, int L, int* _m, double* _f, double* norm, int N, double* F, double* G)
|
xue@1
|
2281 {
|
xue@1
|
2282 if (L==0 || N<=2)
|
xue@1
|
2283 {
|
xue@1
|
2284 F1=F[0], G1=G[0];
|
xue@1
|
2285 return 0;
|
xue@1
|
2286 }
|
xue@1
|
2287 //normalizing
|
xue@1
|
2288 double* m=(double*)malloc(sizeof(double)*L*6);//new double[L*6];
|
xue@1
|
2289 double* f=&m[L*2];
|
xue@1
|
2290 int* k=(int*)&m[L*4];
|
xue@1
|
2291 for (int l=0; l<L; l++)
|
xue@1
|
2292 {
|
xue@1
|
2293 k[2*l]=_m[l]*_m[l]-1;
|
xue@1
|
2294 k[2*l+1]=k[2*l];
|
xue@1
|
2295 m[2*l]=_m[l]/norm[l];
|
xue@1
|
2296 m[2*l+1]=-m[2*l];
|
xue@1
|
2297 f[2*l]=_f[l]/norm[l];
|
xue@1
|
2298 f[2*l+1]=-f[2*l];
|
xue@1
|
2299 }
|
xue@1
|
2300 //From this point on the L distance functions with absolute value is replace by 2L distance functions
|
xue@1
|
2301 L*=2;
|
xue@1
|
2302 double* vmnl=new double[N*2];
|
xue@1
|
2303 int* mnl=(int*)&vmnl[N];
|
xue@1
|
2304 start:
|
xue@1
|
2305 //Initialize (F0, G0) to be the polygon vertex that has the minimal max_l(e_l)
|
xue@1
|
2306 // maxn: the vertex index
|
xue@1
|
2307 // maxl: the l that maximizes e_l at that vertex
|
xue@1
|
2308 // maxsg: the sign of e_l before taking the abs. value
|
xue@1
|
2309 int nc=-1, nd;
|
xue@1
|
2310 int l1=-1, l2=0, l3=0;
|
xue@1
|
2311 double vmax=0;
|
xue@1
|
2312
|
xue@1
|
2313 for (int n=0; n<N; n++)
|
xue@1
|
2314 {
|
xue@1
|
2315 int lmax=-1;
|
xue@1
|
2316 double lvmax=0;
|
xue@1
|
2317 for (int l=0; l<L; l++)
|
xue@1
|
2318 {
|
xue@1
|
2319 double tmp=F[n]+k[l]*G[n]; testnn(tmp);
|
xue@1
|
2320 double e=m[l]*sqrt(tmp)-f[l];
|
xue@1
|
2321 if (e>lvmax) lvmax=e, lmax=l;
|
xue@1
|
2322 }
|
xue@1
|
2323 mnl[n]=lmax, vmnl[n]=lvmax;
|
xue@1
|
2324 if (n==0)
|
xue@1
|
2325 {
|
xue@1
|
2326 vmax=lvmax, nc=n, l1=lmax;
|
xue@1
|
2327 }
|
xue@1
|
2328 else
|
xue@1
|
2329 {
|
xue@1
|
2330 if (lvmax<vmax) vmax=lvmax, nc=n, l1=lmax;
|
xue@1
|
2331 }
|
xue@1
|
2332 }
|
xue@1
|
2333 double F0=F[nc], G0=G[nc];
|
xue@1
|
2334
|
xue@1
|
2335
|
xue@1
|
2336 // start searching the the minimal maximum from (F0, G0)
|
xue@1
|
2337 //
|
xue@1
|
2338 // Each searching step starts from (F0, G0), ends at (F1, G1)
|
xue@1
|
2339 //
|
xue@1
|
2340 // Starting conditions of one step:
|
xue@1
|
2341 //
|
xue@1
|
2342 // (F0, G0) can be
|
xue@1
|
2343 // (1)inside polygon R;
|
xue@1
|
2344 // (2)on one side of R (nc:(nc+1) gives the side)
|
xue@1
|
2345 // (3)a vertex of R (nc being the vertex index)
|
xue@1
|
2346 //
|
xue@1
|
2347 // The maximum at (F0, G0) can be
|
xue@1
|
2348 // (1)vmax=e1=e2=e3>...; (l1, l2, l3)
|
xue@1
|
2349 // (2)vmax=e1=e2>...; (l1, l2)
|
xue@1
|
2350 // (3)vmax=e1>.... (l1)
|
xue@1
|
2351 //
|
xue@1
|
2352 // More complication arise if we have more than 3 equal maxima, i.e.
|
xue@1
|
2353 // vmax=e1=e2=e3=e4>=.... CURRENTLY WE ASSUME THIS NEVER HAPPENS.
|
xue@1
|
2354 //
|
xue@1
|
2355 // These are also the ending conditions of one step.
|
xue@1
|
2356 //
|
xue@1
|
2357 // There are types of basic searching steps, i.e.
|
xue@1
|
2358 //
|
xue@1
|
2359 // (1) e1=e2 search: starting with e1=e2, search down the decreasing direction
|
xue@1
|
2360 // of e1=e2 until at point (F1, G1) there is another l3 so that e1(F1, G1)
|
xue@1
|
2361 // =e2(F1, G1)=e3(F1, G1), or until at point (F1, G1) the search is about
|
xue@1
|
2362 // to go out of R.
|
xue@1
|
2363 // Arguments: l1, l2, (F0, G0, vmax)
|
xue@1
|
2364 // (2) e1!=e2 search: starting with e1=e2 and (F0, G0) being on one side, search
|
xue@1
|
2365 // down the side in the decreasing direction of both e1 and e1 until at point
|
xue@1
|
2366 // (F1, G1) there is a l3 so that e3(F1, G1)=max(e1, e2)(F1, G1), or
|
xue@1
|
2367 // at a the search reaches a vertex of R.
|
xue@1
|
2368 // Arguments: l1, l2, dF, dG, (F0, G0, vmax)
|
xue@1
|
2369 // (3) e1 free search: starting with e1 being the only maximum, search down the decreasing
|
xue@1
|
2370 // direction of e1 until at point (F1, G1) there is another l2 so that
|
xue@1
|
2371 // e1(F1, G1)=e2(F1, G1), or until at point (F1, G1) the search is about
|
xue@1
|
2372 // to go out of R.
|
xue@1
|
2373 // Arguments: l1, dF, dG, (F0, G0, vmax)
|
xue@1
|
2374 // (4) e1 side search: starting with e1 being the only maximum, search down the
|
xue@1
|
2375 // a side of R in the decreasing direction of e1 until at point (F1, G1) there
|
xue@1
|
2376 // is another l2 so that e1=e2, or until point (F1, G1) the search reaches
|
xue@1
|
2377 // a vertex.
|
xue@1
|
2378 // Arguments: l1, destimation vertex nd, (F0, G0, vmax)
|
xue@1
|
2379 //
|
xue@1
|
2380 // At the beginning of each searching step we check the conditions to see which
|
xue@1
|
2381 // basic step to perform, and provide the starting conditions. At the very start of
|
xue@1
|
2382 // the search, (F0, G0) is a vertex of R, e_l1 being the maximum at this point.
|
xue@1
|
2383 //
|
xue@1
|
2384
|
xue@1
|
2385 int condpos=3; //inside, on side, vertex
|
xue@1
|
2386 int condmax=3; //triple max, duo max, solo max
|
xue@1
|
2387 int searchmode;
|
xue@1
|
2388
|
xue@1
|
2389 bool minimax=false; //set to true when the minimal maximum is met
|
xue@1
|
2390
|
xue@1
|
2391 int iter=L*2;
|
xue@1
|
2392 while (!minimax && iter>0)
|
xue@1
|
2393 {
|
xue@1
|
2394 iter--;
|
xue@1
|
2395 double m1=m[l1], m2=m[l2], m3=m[l3], k1=k[l1], k2=k[l2], k3=k[l3];
|
xue@1
|
2396 double tmp, tmp1, tmp2, tmp3;
|
xue@1
|
2397
|
xue@1
|
2398 switch (condmax)
|
xue@1
|
2399 {
|
xue@1
|
2400 case 1:
|
xue@1
|
2401 tmp=F0+k3*G0; testnn(tmp);
|
xue@1
|
2402 tmp3=sqrt(tmp);
|
xue@1
|
2403 case 2:
|
xue@1
|
2404 tmp=F0+k2*G0; testnn(tmp)
|
xue@1
|
2405 tmp2=sqrt(tmp);
|
xue@1
|
2406 case 3:
|
xue@1
|
2407 tmp=F0+k1*G0; testnn(tmp);
|
xue@1
|
2408 tmp1=sqrt(tmp);
|
xue@1
|
2409 }
|
xue@1
|
2410 double dF, dG;
|
xue@1
|
2411 int n0=(nc==0)?(N-1):(nc-1), n1=(nc==N-1)?0:(nc+1);
|
xue@1
|
2412 double x0, y0, x1, y1;
|
xue@1
|
2413 if (n0>=0) x0=F[nc]-F[n0], y0=G[nc]-G[n0];
|
xue@1
|
2414 if (nc>=0) x1=F[n1]-F[nc], y1=G[n1]-G[nc];
|
xue@1
|
2415
|
xue@1
|
2416 if (condpos==1) //(F0, G0) being inside polygon
|
xue@1
|
2417 {
|
xue@1
|
2418 if (condmax==1) //e1=e2=e3 being the maximum
|
xue@1
|
2419 {
|
xue@1
|
2420 //vmax holds the maximum
|
xue@1
|
2421 //l1, l2, l3
|
xue@1
|
2422
|
xue@1
|
2423 //now choose a searching direction, either e1=e2 or e1=e3 or e2=e3.
|
xue@1
|
2424 // choose e1=e2 if (e3-e1) decreases along the decreasing direction of e1=e2
|
xue@1
|
2425 // choose e1=e3 if (e2-e1) decreases along the decreasing direction of e1=e3
|
xue@1
|
2426 // choose e2=e3 if (e1-e2) decreases along the decreasing directino of e2=e3
|
xue@1
|
2427 // if no condition is satisfied, then (F0, G0) is the minimal maximum.
|
xue@1
|
2428 //calculate the decreasing direction of e1=e3 as (dF, dG)
|
xue@1
|
2429 double den=m1*m3*(k1-k3)/2;
|
xue@1
|
2430 dF=-(k1*m1*tmp3-k3*m3*tmp1)/den,
|
xue@1
|
2431 dG=(m1*tmp3-m3*tmp1)/den;
|
xue@1
|
2432 //the negative gradient of e2-e1 is calculated as (gF, gG)
|
xue@1
|
2433 double gF=-(m2/tmp2-m1/tmp1)/2,
|
xue@1
|
2434 gG=-(k2*m2/tmp2-k1*m1/tmp1)/2;
|
xue@1
|
2435 if (dF*gF+dG*gG>0) //so that e2-e1 decreases in the decreasing direction of e1=e3
|
xue@1
|
2436 {
|
xue@1
|
2437 l2=l3;
|
xue@1
|
2438 searchmode=1;
|
xue@1
|
2439 }
|
xue@1
|
2440 else
|
xue@1
|
2441 {
|
xue@1
|
2442 //calculate the decreasing direction of e2=e3 as (dF, dG)
|
xue@1
|
2443 den=m2*m3*(k2-k3)/2;
|
xue@1
|
2444 dF=-(k2*m2*tmp3-k3*m3*tmp2)/den,
|
xue@1
|
2445 dG=(m2*tmp3-m3*tmp2)/den;
|
xue@1
|
2446 //calculate the negative gradient of e1-e2 as (gF, gG)
|
xue@1
|
2447 gF=-gF, gG=-gG;
|
xue@1
|
2448 if (dF*gF+dG*gG>0) //so that e1-e2 decreases in the decreasing direction of e2=e3
|
xue@1
|
2449 {
|
xue@1
|
2450 l1=l3;
|
xue@1
|
2451 searchmode=1;
|
xue@1
|
2452 }
|
xue@1
|
2453 else
|
xue@1
|
2454 {
|
xue@1
|
2455 //calculate the decreasing direction of e1=e2 as (dF, dG)
|
xue@1
|
2456 den=m1*m2*(k1-k2)/2;
|
xue@1
|
2457 dF=-(k1*m1*tmp2-k2*m2*tmp1)/den,
|
xue@1
|
2458 dG=(m1*tmp2-m2*tmp1)/den;
|
xue@1
|
2459 //calculate the negative gradient of (e3-e1) as (gF, gG)
|
xue@1
|
2460 gF=-(m3/tmp3-m1/tmp1)/2,
|
xue@1
|
2461 gG=-(k3*m3/tmp3-k1*m1/tmp1)/2;
|
xue@1
|
2462 if (dF*gF+dG*gG>0) //so that e3-e1 decreases in the decreasing direction of e1=e2
|
xue@1
|
2463 {
|
xue@1
|
2464 searchmode=1;
|
xue@1
|
2465 }
|
xue@1
|
2466 else
|
xue@1
|
2467 {
|
xue@1
|
2468 F1=F0, G1=G0;
|
xue@1
|
2469 searchmode=0; //no search
|
xue@1
|
2470 minimax=true; //quit loop
|
xue@1
|
2471 }
|
xue@1
|
2472 }
|
xue@1
|
2473 }
|
xue@1
|
2474 } //
|
xue@1
|
2475 else if (condmax==2) //e1=e2 being the maximum
|
xue@1
|
2476 {
|
xue@1
|
2477 //vmax holds the maximum
|
xue@1
|
2478 //l1, l2
|
xue@1
|
2479 searchmode=1;
|
xue@1
|
2480 }
|
xue@1
|
2481 else if (condmax==3) //e1 being the maximum
|
xue@1
|
2482 {
|
xue@1
|
2483 //the negative gradient of e1
|
xue@1
|
2484 dF=-0.5*m1/tmp1;
|
xue@1
|
2485 dG=k1*dF;
|
xue@1
|
2486 searchmode=3;
|
xue@1
|
2487 }
|
xue@1
|
2488 }
|
xue@1
|
2489 else if (condpos==2) //(F0, G0) being on side nc:(nc+1)
|
xue@1
|
2490 {
|
xue@1
|
2491 //the vector nc->(nc+1) as (x1, y1)
|
xue@1
|
2492 if (condmax==1) //e1=e2=e3 being the maximum
|
xue@1
|
2493 {
|
xue@1
|
2494 //This case rarely happens.
|
xue@1
|
2495
|
xue@1
|
2496 //First see if a e1=e2 search is possible
|
xue@1
|
2497 //calculate the decreasing direction of e1=e3 as (dF, dG)
|
xue@1
|
2498 double den=m1*m3*(k1-k3)/2;
|
xue@1
|
2499 double dF=-(k1*m1*tmp3-k3*m3*tmp1)/den, dG=(m1*tmp3-m3*tmp1)/den;
|
xue@1
|
2500 //the negative gradient of e2-e1 is calculated as (gF, gG)
|
xue@1
|
2501 double gF=-(m2/tmp2-m1/tmp1)/2, gG=-(k2*m2/tmp2-k1*m1/tmp1)/2;
|
xue@1
|
2502 if (dF*gF+dG*gG>0 && x1*dG-y1*dF<0) //so that e2-e1 decreases in the decreasing direction of e1=e3
|
xue@1
|
2503 { //~~~~~~~~~~~~~and this direction points inward
|
xue@1
|
2504 l2=l3;
|
xue@1
|
2505 searchmode=1;
|
xue@1
|
2506 }
|
xue@1
|
2507 else
|
xue@1
|
2508 {
|
xue@1
|
2509 //calculate the decreasing direction of e2=e3 as (dF, dG)
|
xue@1
|
2510 den=m2*m3*(k2-k3)/2;
|
xue@1
|
2511 dF=-(k2*m2*tmp3-k3*m3*tmp2)/den,
|
xue@1
|
2512 dG=(m2*tmp3-m3*tmp2)/den;
|
xue@1
|
2513 //calculate the negative gradient of e1-e2 as (gF, gG)
|
xue@1
|
2514 gF=-gF, gG=-gG;
|
xue@1
|
2515 if (dF*gF+dG*gG>0 && x1*dG-y1*dF<0) //so that e1-e2 decreases in the decreasing direction of e2=e3
|
xue@1
|
2516 {
|
xue@1
|
2517 l1=l3;
|
xue@1
|
2518 searchmode=1;
|
xue@1
|
2519 }
|
xue@1
|
2520 else
|
xue@1
|
2521 {
|
xue@1
|
2522 //calculate the decreasing direction of e1=e2 as (dF, dG)
|
xue@1
|
2523 den=m1*m2*(k1-k2)/2;
|
xue@1
|
2524 dF=-(k1*m1*tmp2-k2*m2*tmp1)/den,
|
xue@1
|
2525 dG=(m1*tmp2-m2*tmp1)/den;
|
xue@1
|
2526 //calculate the negative gradient of (e3-e1) as (gF, gG)
|
xue@1
|
2527 gF=-(m3/tmp3-m1/tmp1)/2,
|
xue@1
|
2528 gG=-(k3*m3/tmp3-k1*m1/tmp1)/2;
|
xue@1
|
2529 if (dF*gF+dG*gG>0 && x1*dG-y1*dF<0) //so that e3-e1 decreases in the decreasing direction of e1=e2
|
xue@1
|
2530 {
|
xue@1
|
2531 searchmode=1;
|
xue@1
|
2532 }
|
xue@1
|
2533 else
|
xue@1
|
2534 {
|
xue@1
|
2535 //see the possibility of a e1!=e2 search
|
xue@1
|
2536 //calcualte the dot product of the gradients and (x1, y1)
|
xue@1
|
2537 double d1=m1/2/tmp1*(x1+k1*y1),
|
xue@1
|
2538 d2=m2/2/tmp2*(x1+k2*y1),
|
xue@1
|
2539 d3=m3/2/tmp3*(x1+k3*y1);
|
xue@1
|
2540 //we can prove that if there is a direction pointing inward R in which
|
xue@1
|
2541 // e1, e2, e2 decrease, and another direction pointing outside R in
|
xue@1
|
2542 // which e1, e2, e3 decrease, then on one direction along the side
|
xue@1
|
2543 // all the three decrease. (Even more, this direction must be inside
|
xue@1
|
2544 // the <180 angle formed by the two directions.)
|
xue@1
|
2545 //
|
xue@1
|
2546 // On the contrary, if there is a direction
|
xue@1
|
2547 // in which all the three decrease, with two equal, it has to point
|
xue@1
|
2548 // outward for the program to get here. Then if along neither direction
|
xue@1
|
2549 // of side R can the three all descend, then there doesn't exist any
|
xue@1
|
2550 // direction inward R in which the three descend. In that case we
|
xue@1
|
2551 // have a minimal maximum at (F0, G0).
|
xue@1
|
2552 if (d1*d2<=0 || d1*d3<=0 || d2*d3<=0) //so that the three don't decrease in the same direction
|
xue@1
|
2553 {
|
xue@1
|
2554 F1=F0, G1=G0;
|
xue@1
|
2555 searchmode=0; //no search
|
xue@1
|
2556 minimax=true; //quit loop
|
xue@1
|
2557 }
|
xue@1
|
2558 else
|
xue@1
|
2559 {
|
xue@1
|
2560 if (d1>0) //so that d2>0, d3>0, all three decrease in the direction -(x1, y1) towards nc
|
xue@1
|
2561 {
|
xue@1
|
2562 if (d1>d2 && d1>d3) //e1 decreases fastest
|
xue@1
|
2563 {
|
xue@1
|
2564 l1=l3; //keep e2, e3
|
xue@1
|
2565 }
|
xue@1
|
2566 else if (d2>=d1 && d2>d3) //e2 decreases fastest
|
xue@1
|
2567 {
|
xue@1
|
2568 l2=l3; //keep e1, e3
|
xue@1
|
2569 }
|
xue@1
|
2570 else //d3>=d1 && d3>=d2, e3 decreases fastest
|
xue@1
|
2571 {
|
xue@1
|
2572 //keep e1, e2
|
xue@1
|
2573 }
|
xue@1
|
2574 nd=nc;
|
xue@1
|
2575 }
|
xue@1
|
2576 else //d1<0, d2<0, d3<0, all three decrease in the direction (x1, y1)
|
xue@1
|
2577 {
|
xue@1
|
2578 if (d1<d2 && d1<d3) //e1 decreases fastest
|
xue@1
|
2579 {
|
xue@1
|
2580 l1=l3;
|
xue@1
|
2581 }
|
xue@1
|
2582 else if (d2<=d1 && d2<d3) //e2 decreases fastest
|
xue@1
|
2583 {
|
xue@1
|
2584 l2=l3;
|
xue@1
|
2585 }
|
xue@1
|
2586 else //d3<=d1 && d3<=d2
|
xue@1
|
2587 {
|
xue@1
|
2588 //keep e1, e2
|
xue@1
|
2589 }
|
xue@1
|
2590 nd=n1;
|
xue@1
|
2591 }
|
xue@1
|
2592 searchmode=2;
|
xue@1
|
2593 }
|
xue@1
|
2594 }
|
xue@1
|
2595 }
|
xue@1
|
2596 }
|
xue@1
|
2597 }
|
xue@1
|
2598 else if (condmax==2) //e1=e2 being the maximum
|
xue@1
|
2599 {
|
xue@1
|
2600 //first see if the decreasing direction of e1=e2 points to the inside
|
xue@1
|
2601 //calculate the decreasing direction of e1=e2 as (dF, dG)
|
xue@1
|
2602 double den=m1*m2*(k1-k2)/2;
|
xue@1
|
2603 dF=-(k1*m1*tmp2-k2*m2*tmp1)/den,
|
xue@1
|
2604 dG=(m1*tmp2-m2*tmp1)/den;
|
xue@1
|
2605
|
xue@1
|
2606 if (x1*dG-y1*dF<0) //so that (dF, dG) points inward R
|
xue@1
|
2607 {
|
xue@1
|
2608 searchmode=1;
|
xue@1
|
2609 }
|
xue@1
|
2610 else
|
xue@1
|
2611 {
|
xue@1
|
2612 //calcualte the dot product of the gradients and (x1, y1)
|
xue@1
|
2613 double d1=m1/2/tmp1*(x1+k1*y1),
|
xue@1
|
2614 d2=m2/2/tmp2*(x1+k2*y1);
|
xue@1
|
2615 if (d1*d2<=0) //so that along the side e1, e2 descend in opposite directions
|
xue@1
|
2616 {
|
xue@1
|
2617 F1=F0, G1=G0;
|
xue@1
|
2618 searchmode=0;
|
xue@1
|
2619 minimax=true;
|
xue@1
|
2620 }
|
xue@1
|
2621 else
|
xue@1
|
2622 {
|
xue@1
|
2623 if (d1>0) //so that both decrease in direction -(x1, y1)
|
xue@1
|
2624 nd=nc;
|
xue@1
|
2625 else
|
xue@1
|
2626 nd=n1;
|
xue@1
|
2627 searchmode=2;
|
xue@1
|
2628 }
|
xue@1
|
2629 }
|
xue@1
|
2630 }
|
xue@1
|
2631 else if (condmax==3) //e1 being the maximum
|
xue@1
|
2632 {
|
xue@1
|
2633 //calculate the negative gradient of e1 as (dF, dG)
|
xue@1
|
2634 dF=-0.5*m1/tmp1;
|
xue@1
|
2635 dG=k1*dF;
|
xue@1
|
2636
|
xue@1
|
2637 if (x1*dG-y1*dF<0) //so the gradient points inward R
|
xue@1
|
2638 searchmode=3;
|
xue@1
|
2639 else
|
xue@1
|
2640 {
|
xue@1
|
2641 //calculate the dot product of the gradient and (x1, y1)
|
xue@1
|
2642 double d1=m1/2/tmp1*(x1+k1*y1);
|
xue@1
|
2643 if (d1>0) //so that e1 decreases in direction -(x1, y1)
|
xue@1
|
2644 {
|
xue@1
|
2645 nd=nc;
|
xue@1
|
2646 searchmode=4;
|
xue@1
|
2647 }
|
xue@1
|
2648 else if (d1<0)
|
xue@1
|
2649 {
|
xue@1
|
2650 nd=n1;
|
xue@1
|
2651 searchmode=4;
|
xue@1
|
2652 }
|
xue@1
|
2653 else //so that e1 does not change along side nc:(nc+1)
|
xue@1
|
2654 {
|
xue@1
|
2655 F1=F0, G1=G0;
|
xue@1
|
2656 searchmode=0;
|
xue@1
|
2657 minimax=true;
|
xue@1
|
2658 }
|
xue@1
|
2659 }
|
xue@1
|
2660 }
|
xue@1
|
2661 }
|
xue@1
|
2662 else //condpos==3, (F0, G0) being vertex nc
|
xue@1
|
2663 {
|
xue@1
|
2664 //the vector nc->(nc+1) as (x1, y1)
|
xue@1
|
2665 //the vector (nc-1)->nc as (x0, y0)
|
xue@1
|
2666
|
xue@1
|
2667 if (condmax==1) //e1=e2=e3 being the maximum
|
xue@1
|
2668 {
|
xue@1
|
2669 //This case rarely happens.
|
xue@1
|
2670
|
xue@1
|
2671 //First see if a e1=e2 search is possible
|
xue@1
|
2672 //calculate the decreasing direction of e1=e3 as (dF, dG)
|
xue@1
|
2673 double den=m1*m3*(k1-k3)/2;
|
xue@1
|
2674 double dF=-(k1*m1*tmp3-k3*m3*tmp1)/den, dG=(m1*tmp3-m3*tmp1)/den;
|
xue@1
|
2675 //the negative gradient of e2-e1 is calculated as (gF, gG)
|
xue@1
|
2676 double gF=-(m2/tmp2-m1/tmp1)/2, gG=-(k2*m2/tmp2-k1*m1/tmp1)/2;
|
xue@1
|
2677 if (dF*gF+dG*gG>0 && x1*dG-y1*dF<0 && x0*dG-y0*dF<0) //so that e2-e1 decreases in the decreasing direction of e1=e3
|
xue@1
|
2678 { //~~~~~~~~~~~~~and this direction points inward
|
xue@1
|
2679 l2=l3;
|
xue@1
|
2680 searchmode=1;
|
xue@1
|
2681 }
|
xue@1
|
2682 else
|
xue@1
|
2683 {
|
xue@1
|
2684 //calculate the decreasing direction of e2=e3 as (dF, dG)
|
xue@1
|
2685 den=m2*m3*(k2-k3)/2;
|
xue@1
|
2686 dF=-(k2*m2*tmp3-k3*m3*tmp2)/den,
|
xue@1
|
2687 dG=(m2*tmp3-m3*tmp2)/den;
|
xue@1
|
2688 //calculate the negative gradient of e1-e2 as (gF, gG)
|
xue@1
|
2689 gF=-gF, gG=-gG;
|
xue@1
|
2690 if (dF*gF+dG*gG>0 && x1*dG-y1*dF<0 && x0*dG-y0*dF<0) //so that e1-e2 decreases in the decreasing direction of e2=e3
|
xue@1
|
2691 {
|
xue@1
|
2692 l1=l3;
|
xue@1
|
2693 searchmode=1;
|
xue@1
|
2694 }
|
xue@1
|
2695 else
|
xue@1
|
2696 {
|
xue@1
|
2697 //calculate the decreasing direction of e1=e2 as (dF, dG)
|
xue@1
|
2698 den=m1*m2*(k1-k2)/2;
|
xue@1
|
2699 dF=-(k1*m1*tmp2-k2*m2*tmp1)/den,
|
xue@1
|
2700 dG=(m1*tmp2-m2*tmp1)/den;
|
xue@1
|
2701 //calculate the negative gradient of (e3-e1) as (gF, gG)
|
xue@1
|
2702 gF=-(m3/tmp3-m1/tmp1)/2,
|
xue@1
|
2703 gG=-(k3*m3/tmp3-k1*m1/tmp1)/2;
|
xue@1
|
2704 if (dF*gF+dG*gG>0 && x1*dG-y1*dF<0 && x0*dG-y0*dF<0) //so that e3-e1 decreases in the decreasing direction of e1=e2
|
xue@1
|
2705 {
|
xue@1
|
2706 searchmode=1;
|
xue@1
|
2707 }
|
xue@1
|
2708 else
|
xue@1
|
2709 {
|
xue@1
|
2710 //see the possibility of a e1!=e2 search
|
xue@1
|
2711 //calcualte the dot product of the gradients and (x1, y1)
|
xue@1
|
2712 double d1=m1/2/tmp1*(x1+k1*y1),
|
xue@1
|
2713 d2=m2/2/tmp2*(x1+k2*y1),
|
xue@1
|
2714 d3=m3/2/tmp3*(x1+k3*y1);
|
xue@1
|
2715 //we can also prove that if there is a direction pointing inward R in which
|
xue@1
|
2716 // e1, e2, e2 decrease, and another direction pointing outside R in
|
xue@1
|
2717 // which e1, e2, e3 decrease, all the three decrease either on nc->(nc+1)
|
xue@1
|
2718 // direction along side nc:(nc+1), or on nc->(nc-1) direction along side
|
xue@1
|
2719 // nc:(nc-1).
|
xue@1
|
2720 //
|
xue@1
|
2721 // On the contrary, if there is a direction
|
xue@1
|
2722 // in which all the three decrease, with two equal, it has to point
|
xue@1
|
2723 // outward for the program to get here. Then if along neither direction
|
xue@1
|
2724 // of side R can the three all descend, then there doesn't exist any
|
xue@1
|
2725 // direction inward R in which the three descend. In that case we
|
xue@1
|
2726 // have a minimal maximum at (F0, G0).
|
xue@1
|
2727 if (d1<0 && d2<0 && d3<0) //so that all the three decrease in the direction (x1, y1)
|
xue@1
|
2728 {
|
xue@1
|
2729 if (d1<d2 && d1<d3) //e1 decreases fastest
|
xue@1
|
2730 {
|
xue@1
|
2731 l1=l3;
|
xue@1
|
2732 }
|
xue@1
|
2733 else if (d2<=d1 && d2<d3) //e2 decreases fastest
|
xue@1
|
2734 {
|
xue@1
|
2735 l2=l3;
|
xue@1
|
2736 }
|
xue@1
|
2737 else //d3<=d1 && d3<=d2
|
xue@1
|
2738 {
|
xue@1
|
2739 //keep e1, e2
|
xue@1
|
2740 }
|
xue@1
|
2741 nd=n1;
|
xue@1
|
2742 searchmode=2;
|
xue@1
|
2743 }
|
xue@1
|
2744 else
|
xue@1
|
2745 {
|
xue@1
|
2746 d1=m1/2/tmp1*(x0+k1*y0),
|
xue@1
|
2747 d2=m2/2/tmp2*(x0+k2*y0),
|
xue@1
|
2748 d3=m3/2/tmp3*(x0+k3*y0);
|
xue@1
|
2749 if (d1>0 && d2>0 && d3>0) //so that all the three decrease in the direction -(x0, y0)
|
xue@1
|
2750 {
|
xue@1
|
2751 if (d1>d2 && d1>d3) //e1 decreases fastest
|
xue@1
|
2752 {
|
xue@1
|
2753 l1=l3; //keep e2, e3
|
xue@1
|
2754 }
|
xue@1
|
2755 else if (d2>=d1 && d2>d3) //e2 decreases fastest
|
xue@1
|
2756 {
|
xue@1
|
2757 l2=l3; //keep e1, e3
|
xue@1
|
2758 }
|
xue@1
|
2759 else //d3>=d1 && d3>=d2, e3 decreases fastest
|
xue@1
|
2760 {
|
xue@1
|
2761 //keep e1, e2
|
xue@1
|
2762 }
|
xue@1
|
2763 nd=n0;
|
xue@1
|
2764 searchmode=2;
|
xue@1
|
2765 }
|
xue@1
|
2766 else
|
xue@1
|
2767 {
|
xue@1
|
2768 F1=F0, G1=G0;
|
xue@1
|
2769 searchmode=0;
|
xue@1
|
2770 minimax=true;
|
xue@1
|
2771 }
|
xue@1
|
2772 }
|
xue@1
|
2773 }
|
xue@1
|
2774 }
|
xue@1
|
2775 }
|
xue@1
|
2776 }
|
xue@1
|
2777 else if (condmax==2) //e1=e2 being the maximum
|
xue@1
|
2778 {
|
xue@1
|
2779 //first see if the decreasing direction of e1=e2 points to the inside
|
xue@1
|
2780 //calculate the decreasing direction of e1=e2 as (dF, dG)
|
xue@1
|
2781 double den=m1*m2*(k1-k2)/2;
|
xue@1
|
2782 dF=-(k1*m1*tmp2-k2*m2*tmp1)/den,
|
xue@1
|
2783 dG=(m1*tmp2-m2*tmp1)/den;
|
xue@1
|
2784
|
xue@1
|
2785 if (x1*dG-y1*dF<0 && x0*dG-y1*dF<0) //so that (dF, dG) points inward R
|
xue@1
|
2786 {
|
xue@1
|
2787 searchmode=1;
|
xue@1
|
2788 }
|
xue@1
|
2789 else
|
xue@1
|
2790 {
|
xue@1
|
2791 //calcualte the dot product of the gradients and (x1, y1)
|
xue@1
|
2792 double d1=m1/2/tmp1*(x1+k1*y1),
|
xue@1
|
2793 d2=m2/2/tmp2*(x1+k2*y1);
|
xue@1
|
2794 if (d1<0 && d2<0) //so that along side nc:(nc+1) e1, e2 descend in direction (x1, y1)
|
xue@1
|
2795 {
|
xue@1
|
2796 nd=n1;
|
xue@1
|
2797 searchmode=2;
|
xue@1
|
2798 }
|
xue@1
|
2799 else
|
xue@1
|
2800 {
|
xue@1
|
2801 d1=m1/2/tmp1*(x0+k1*y0),
|
xue@1
|
2802 d2=m2/2/tmp2*(x0+k2*y0);
|
xue@1
|
2803 if (d1>0 && d2>0) //so that slong the side (nc-1):nc e1, e2 decend in direction -(x0, y0)
|
xue@1
|
2804 {
|
xue@1
|
2805 nd=n0;
|
xue@1
|
2806 searchmode=2;
|
xue@1
|
2807 }
|
xue@1
|
2808 else
|
xue@1
|
2809 {
|
xue@1
|
2810 F1=F0, G1=G0;
|
xue@1
|
2811 searchmode=0;
|
xue@1
|
2812 minimax=true;
|
xue@1
|
2813 }
|
xue@1
|
2814 }
|
xue@1
|
2815 }
|
xue@1
|
2816 }
|
xue@1
|
2817 else //condmax==3, e1 being the solo maximum
|
xue@1
|
2818 {
|
xue@1
|
2819 //calculate the negative gradient of e1 as (dF, dG)
|
xue@1
|
2820 dF=-0.5*m1/tmp1;
|
xue@1
|
2821 dG=k1*dF;
|
xue@1
|
2822
|
xue@1
|
2823 if (x1*dG-y1*dF<0 && x0*dG-y0*dF<0) //so the gradient points inward R
|
xue@1
|
2824 searchmode=3;
|
xue@1
|
2825 else
|
xue@1
|
2826 {
|
xue@1
|
2827 //calculate the dot product of the gradient and (x1, y1)
|
xue@1
|
2828 double d1=m1/2/tmp1*(x1+k1*y1),
|
xue@1
|
2829 d0=-m1/2/tmp1*(x0+k1*y0);
|
xue@1
|
2830 if (d1<d0) //so that e1 decreases in direction (x1, y1) faster than in -(x0, y0)
|
xue@1
|
2831 {
|
xue@1
|
2832 if (d1<0)
|
xue@1
|
2833 {
|
xue@1
|
2834 nd=n1;
|
xue@1
|
2835 searchmode=4;
|
xue@1
|
2836 }
|
xue@1
|
2837 else
|
xue@1
|
2838 {
|
xue@1
|
2839 F1=F0, G1=G0;
|
xue@1
|
2840 searchmode=0;
|
xue@1
|
2841 minimax=true;
|
xue@1
|
2842 }
|
xue@1
|
2843 }
|
xue@1
|
2844 else //so that e1 decreases in direction -(x0, y0) faster than in (x1, y1)
|
xue@1
|
2845 {
|
xue@1
|
2846 if (d0<0)
|
xue@1
|
2847 {
|
xue@1
|
2848 nd=n0;
|
xue@1
|
2849 searchmode=4;
|
xue@1
|
2850 }
|
xue@1
|
2851 else
|
xue@1
|
2852 {
|
xue@1
|
2853 F1=F0, G1=G0;
|
xue@1
|
2854 searchmode=0;
|
xue@1
|
2855 minimax=true;
|
xue@1
|
2856 }
|
xue@1
|
2857 }
|
xue@1
|
2858 }
|
xue@1
|
2859 }
|
xue@1
|
2860 }
|
xue@1
|
2861 // the conditioning stage ends here
|
xue@1
|
2862 // the searching step starts here
|
xue@1
|
2863 if (searchmode==0)
|
xue@1
|
2864 {}
|
xue@1
|
2865 else if (searchmode==1)
|
xue@1
|
2866 {
|
xue@1
|
2867 //Search mode 1: e1=e2 search
|
xue@1
|
2868 // starting with e1=e2, search down the decreasing direction of
|
xue@1
|
2869 // e1=e2 until at point (F1, G1) there is another l3 so that e1(F1, G1)
|
xue@1
|
2870 // =e2(F1, G1)=e3(F1, G1), or until at point (F1, G1) the search is about
|
xue@1
|
2871 // to go out of R.
|
xue@1
|
2872 //Arguments: l1, l2, (F0, G0, vmax)
|
xue@1
|
2873 double tmp=F0+k[l1]*G0; testnn(tmp);
|
xue@1
|
2874 double e1=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
2875 tmp=F0+k[l2]*G0; testnn(tmp);
|
xue@1
|
2876 double e2=m[l2]*sqrt(tmp)-f[l2];
|
xue@1
|
2877 if (fabs(e1-e2)>1e-4)
|
xue@1
|
2878 {
|
xue@1
|
2879 // int kk=1;
|
xue@1
|
2880 goto start;
|
xue@1
|
2881 }
|
xue@1
|
2882
|
xue@1
|
2883 //find intersections of e1=e2 with other ek's
|
xue@1
|
2884 l3=-1;
|
xue@1
|
2885 loopl3:
|
xue@1
|
2886 double e=-1;
|
xue@1
|
2887 for (int l=0; l<L; l++)
|
xue@1
|
2888 {
|
xue@1
|
2889 if (l==l1 || l==l2) continue;
|
xue@1
|
2890 double lF1[2], lG1[2], lE[2];
|
xue@1
|
2891 double lm[3]={m[l1], m[l2], m[l]};
|
xue@1
|
2892 double lf[3]={f[l1], f[l2], f[l]};
|
xue@1
|
2893 int lk[3]={k[l1], k[l2], k[l]};
|
xue@1
|
2894 int r=FGFrom3(lF1, lG1, lE, lm, lf, lk);
|
xue@1
|
2895 for (int i=0; i<r; i++)
|
xue@1
|
2896 {
|
xue@1
|
2897 if (lE[i]>e && lE[i]<vmax) l3=l, e=lE[i], F1=lF1[i], G1=lG1[i];
|
xue@1
|
2898 }
|
xue@1
|
2899 }
|
xue@1
|
2900 //l3 shall be >=0 at this point
|
xue@1
|
2901 //find intersections of e1=e2 with polygon sides
|
xue@1
|
2902 if (l3<0)
|
xue@1
|
2903 {
|
xue@1
|
2904 ///int kkk=1;
|
xue@1
|
2905 goto loopl3;
|
xue@1
|
2906 }
|
xue@1
|
2907 nc=-1;
|
xue@1
|
2908 double F2, G2;
|
xue@1
|
2909 for (int n=0; n<N; n++)
|
xue@1
|
2910 {
|
xue@1
|
2911 int nn=(n==N-1)?0:(n+1);
|
xue@1
|
2912 double xn1=F[nn]-F[n], yn1=G[nn]-G[n], xn2=F1-F[n], yn2=G1-G[n];
|
xue@1
|
2913 if (xn1*yn2-xn2*yn1>=0) //so that (F1, G1) is on or out of side n:(n+1)
|
xue@1
|
2914 {
|
xue@1
|
2915 nc=n;
|
xue@1
|
2916 break;
|
xue@1
|
2917 }
|
xue@1
|
2918 }
|
xue@1
|
2919
|
xue@1
|
2920 if (nc<0) //(F1, G1) being inside R
|
xue@1
|
2921 {
|
xue@1
|
2922 vmax=e;
|
xue@1
|
2923 condpos=1;
|
xue@1
|
2924 condmax=1;
|
xue@1
|
2925 //l3 shall be >=0 at this point, so l1, l2, l3 are all ok
|
xue@1
|
2926 }
|
xue@1
|
2927 else //(F1, G1) being outside nc:(nc+1) //(F2, G2) being on side nc:(nc+1)
|
xue@1
|
2928 {
|
xue@1
|
2929 //find where e1=e2 crosses a side of R between (F0, G0) and (F1, G1)
|
xue@1
|
2930 double lF2[2], lG2[2], lmd[2];
|
xue@1
|
2931 double lm[2]={m[l1], m[l2]};
|
xue@1
|
2932 double lf[2]={f[l1], f[l2]};
|
xue@1
|
2933 int lk[2]={k[l1], k[l2]};
|
xue@1
|
2934
|
xue@1
|
2935 int ncc=-1;
|
xue@1
|
2936 while (ncc<0)
|
xue@1
|
2937 {
|
xue@1
|
2938 n1=(nc==N-1)?0:(nc+1);
|
xue@1
|
2939 double xn1=F[n1]-F[nc], yn1=G[n1]-G[nc];
|
xue@1
|
2940
|
xue@1
|
2941 int r=FGFrom2(lF2, lG2, lmd, F[nc], xn1, G[nc], yn1, lm, lf, lk);
|
xue@1
|
2942
|
xue@1
|
2943 bool once=false;
|
xue@1
|
2944 for (int i=0; i<r; i++)
|
xue@1
|
2945 {
|
xue@1
|
2946 double tmp=lF2[i]+k[l1]*lG2[i]; testnn(tmp);
|
xue@1
|
2947 double le=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
2948 if (le<=vmax) //this shall be satisfied once
|
xue@1
|
2949 {
|
xue@1
|
2950 once=true;
|
xue@1
|
2951 if (lmd[i]>=0 && lmd[i]<=1) //so that curve e1=e2 does cross the boundry within it
|
xue@1
|
2952 ncc=nc, F2=lF2[i], G2=lG2[i], e=le;
|
xue@1
|
2953 else if (lmd[i]>1) //so that the crossing point is out of vertex n1
|
xue@1
|
2954 nc=n1;
|
xue@1
|
2955 else //lmd[i]<0, so that the crossing point is out of vertex nc-1
|
xue@1
|
2956 nc=(nc==0)?(N-1):(nc-1);
|
xue@1
|
2957 }
|
xue@1
|
2958 }
|
xue@1
|
2959 if (!once)
|
xue@1
|
2960 {
|
xue@1
|
2961 //int kk=0;
|
xue@1
|
2962 goto start;
|
xue@1
|
2963 }
|
xue@1
|
2964 }
|
xue@1
|
2965 nc=ncc;
|
xue@1
|
2966
|
xue@1
|
2967 vmax=e;
|
xue@1
|
2968 condpos=2;
|
xue@1
|
2969 if (F1==F2 && G1==G2)
|
xue@1
|
2970 condmax=1;
|
xue@1
|
2971 else
|
xue@1
|
2972 condmax=2;
|
xue@1
|
2973 F1=F2, G1=G2;
|
xue@1
|
2974 }
|
xue@1
|
2975 }
|
xue@1
|
2976 else if (searchmode==2)
|
xue@1
|
2977 {
|
xue@1
|
2978 // Search mode 2 (e1!=e2 search): starting with e1=e2, and a linear equation
|
xue@1
|
2979 // constraint, search down the decreasing direction until at point (F1, G1)
|
xue@1
|
2980 // there is a l3 so that e3(F1, G1)=max(e1, e2)(F1, G1), or at point (F1, G1)
|
xue@1
|
2981 // the search is about to go out of R.
|
xue@1
|
2982 // Arguments: l1, l2, dF, dG, (F0, G0, vmax)
|
xue@1
|
2983
|
xue@1
|
2984 //The searching direction (dF, dG) is always along some polygon side
|
xue@1
|
2985 // If conpos==2, it is along nc:(nc+1)
|
xue@1
|
2986 // If conpos==3, it is along nc:(nc+1) or (nc-1):nc
|
xue@1
|
2987
|
xue@1
|
2988 //
|
xue@1
|
2989
|
xue@1
|
2990 //first check whether e1>e2 or e2>e1 down (dF, dG)
|
xue@1
|
2991 dF=F[nd]-F0, dG=G[nd]-G0;
|
xue@1
|
2992 //
|
xue@1
|
2993 //the negative gradient of e2-e1 is calculated as (gF, gG)
|
xue@1
|
2994 double gF=-(m2/tmp2-m1/tmp1)/2,
|
xue@1
|
2995 gG=-(k2*m2/tmp2-k1*m1/tmp1)/2;
|
xue@1
|
2996 if (gF*dF+gG*dG>0) //e2-e1 decrease down direction (dF, dG), so that e1>e2
|
xue@1
|
2997 {}
|
xue@1
|
2998 else //e1<e2 down (dF, dG)
|
xue@1
|
2999 {
|
xue@1
|
3000 int ll=l2; l2=l1; l1=ll;
|
xue@1
|
3001 m1=m[l1], m2=m[l2], k1=k[l1], k2=k[l2];
|
xue@1
|
3002 tmp=F0+k1*G0; testnn(tmp); tmp1=sqrt(tmp);
|
xue@1
|
3003 tmp=F0+k2*G0; testnn(tmp); tmp2=sqrt(tmp);
|
xue@1
|
3004 }
|
xue@1
|
3005 //now e1>e2 down (dF, dG) from (F0, G0)
|
xue@1
|
3006 tmp=F[nd]+k1*G[nd]; testnn(tmp);
|
xue@1
|
3007 double e1=m1*sqrt(tmp)-f[l1];
|
xue@1
|
3008 tmp=F[nd]+k2*G[nd]; testnn(tmp);
|
xue@1
|
3009 double e2=m2*sqrt(tmp)-f[l2], FEx, GEx, eEx;
|
xue@1
|
3010 int maxlmd=1;
|
xue@1
|
3011 if (e1>=e2)
|
xue@1
|
3012 {
|
xue@1
|
3013 // then e1 is larger than e2 for the whole searching interval
|
xue@1
|
3014 FEx=F[nd], GEx=G[nd];
|
xue@1
|
3015 eEx=e1;
|
xue@1
|
3016 }
|
xue@1
|
3017 else // the they swap somewhere in between, now find it and make it maxlmd
|
xue@1
|
3018 {
|
xue@1
|
3019 double lF1[2], lG1[2], lmd[2];
|
xue@1
|
3020 double lm[2]={m[l1], m[l2]};
|
xue@1
|
3021 double lf[2]={f[l1], f[l2]};
|
xue@1
|
3022 int lk[2]={k[l1], k[l2]};
|
xue@1
|
3023 int r=FGFrom2(lF1, lG1, lmd, F0, dF, G0, dG, lm, lf, lk);
|
xue@1
|
3024 //process the results
|
xue@1
|
3025 if (r==2) //must be so
|
xue@1
|
3026 {
|
xue@1
|
3027 if (lmd[0]<lmd[1]) lmd[0]=lmd[1], FEx=lF1[1], GEx=lG1[1];
|
xue@1
|
3028 else FEx=lF1[0], GEx=lG1[0];
|
xue@1
|
3029 }
|
xue@1
|
3030 if (lmd[0]>0 && lmd[0]<1) //must be so
|
xue@1
|
3031 maxlmd=lmd[0];
|
xue@1
|
3032 tmp=FEx+k1*GEx; testnn(tmp);
|
xue@1
|
3033 eEx=m1*sqrt(tmp)-f[l1];
|
xue@1
|
3034 }
|
xue@1
|
3035
|
xue@1
|
3036 l3=-1;
|
xue@1
|
3037 // int l4;
|
xue@1
|
3038 double e, llmd=maxlmd;
|
xue@1
|
3039 int *tpl=new int[L], ctpl=0;
|
xue@1
|
3040 for (int l=0; l<L; l++)
|
xue@1
|
3041 {
|
xue@1
|
3042 if (l==l1 || l==l2) continue;
|
xue@1
|
3043 tmp=FEx+k[l]*GEx; testnn(tmp);
|
xue@1
|
3044 double le=m[l]*sqrt(tmp)-f[l];
|
xue@1
|
3045 if (le<eEx)
|
xue@1
|
3046 {
|
xue@1
|
3047 tpl[ctpl]=l;
|
xue@1
|
3048 ctpl++;
|
xue@1
|
3049 continue;
|
xue@1
|
3050 }
|
xue@1
|
3051 //solve for the equation system e1(F1, G1)=el(F1, G1), with (F1, G1) on nc:n1
|
xue@1
|
3052 double lF1[2], lG1[2], lmd[2];
|
xue@1
|
3053 double lm[2]={m[l1], m[l]};
|
xue@1
|
3054 double lf[2]={f[l1], f[l]};
|
xue@1
|
3055 int lk[2]={k[l1], k[l]};
|
xue@1
|
3056 int r=FGFrom2(lF1, lG1, lmd, F0, dF, G0, dG, lm, lf, lk);
|
xue@1
|
3057 //process the results
|
xue@1
|
3058 for (int i=0; i<r; i++)
|
xue@1
|
3059 {
|
xue@1
|
3060 if (lmd[i]<0 || lmd[i]>maxlmd) continue; //the solution is in the wrong direction
|
xue@1
|
3061 if (lmd[i]<llmd)
|
xue@1
|
3062 l3=l, F1=lF1[i], G1=lG1[i], llmd=lmd[i];
|
xue@1
|
3063 }
|
xue@1
|
3064 }
|
xue@1
|
3065 if (ctpl==L-2) //so that at (FEx, GEx) e1 is maximal, equivalent to "l3<0"
|
xue@1
|
3066 {}
|
xue@1
|
3067 else
|
xue@1
|
3068 {
|
xue@1
|
3069 //at this point F1 and G1 must have valid values already
|
xue@1
|
3070 tmp=F1+k[l1]*G1; testnn(tmp);
|
xue@1
|
3071 e=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
3072 //test if e1 is maximal at (F1, G1)
|
xue@1
|
3073 bool lmax=true;
|
xue@1
|
3074 for (int tp=0; tp<ctpl; tp++)
|
xue@1
|
3075 {
|
xue@1
|
3076 tmp=F1+k[tpl[tp]]*G1; testnn(tmp);
|
xue@1
|
3077 double le=m[tpl[tp]]*sqrt(tmp)-f[tpl[tp]];
|
xue@1
|
3078 if (le>e) {lmax=false; break;}
|
xue@1
|
3079 }
|
xue@1
|
3080 if (!lmax)
|
xue@1
|
3081 {
|
xue@1
|
3082 for (int tp=0; tp<ctpl; tp++)
|
xue@1
|
3083 {
|
xue@1
|
3084 double lF1[2], lG1[2], lmd[2];
|
xue@1
|
3085 double lm[2]={m[l1], m[tpl[tp]]};
|
xue@1
|
3086 double lf[2]={f[l1], f[tpl[tp]]};
|
xue@1
|
3087 int lk[2]={k[l1], k[tpl[tp]]};
|
xue@1
|
3088 int r=FGFrom2(lF1, lG1, lmd, F0, dF, G0, dG, lm, lf, lk);
|
xue@1
|
3089 //process the results
|
xue@1
|
3090 for (int i=0; i<r; i++)
|
xue@1
|
3091 {
|
xue@1
|
3092 if (lmd[i]<0 || lmd[i]>maxlmd) continue; //the solution is in the wrong direction
|
xue@1
|
3093 if (lmd[i]<=llmd)
|
xue@1
|
3094 l3=tpl[tp], F1=lF1[i], G1=lG1[i], llmd=lmd[i];
|
xue@1
|
3095 }
|
xue@1
|
3096 }
|
xue@1
|
3097 tmp=F1+k[l1]*G1; testnn(tmp);
|
xue@1
|
3098 e=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
3099 }
|
xue@1
|
3100 }
|
xue@1
|
3101 delete[] tpl;
|
xue@1
|
3102 if (l3>=0) //the solution is found in the right direction
|
xue@1
|
3103 {
|
xue@1
|
3104 vmax=e;
|
xue@1
|
3105 if (llmd==1) //(F1, G1) is a vertex of R
|
xue@1
|
3106 {
|
xue@1
|
3107 nc=nd;
|
xue@1
|
3108 condpos=3;
|
xue@1
|
3109 condmax=2;
|
xue@1
|
3110 l2=l3;
|
xue@1
|
3111 }
|
xue@1
|
3112 else
|
xue@1
|
3113 {
|
xue@1
|
3114 if (condpos==3 && nd==n0) nc=n0;
|
xue@1
|
3115 condpos=2;
|
xue@1
|
3116 condmax=2;
|
xue@1
|
3117 l2=l3;
|
xue@1
|
3118 }
|
xue@1
|
3119 }
|
xue@1
|
3120 else if (maxlmd<1) //so that e1=e2 remains maximal at maxlmd
|
xue@1
|
3121 {
|
xue@1
|
3122 if (condpos==3 && nd==n0) nc=n0;
|
xue@1
|
3123 condpos=2;
|
xue@1
|
3124 condmax=2;
|
xue@1
|
3125 //l1, l2 remain unchanged
|
xue@1
|
3126 F1=FEx, G1=GEx;
|
xue@1
|
3127 vmax=eEx;
|
xue@1
|
3128 }
|
xue@1
|
3129 else //so that e1 remains maximal at vertex nd
|
xue@1
|
3130 {
|
xue@1
|
3131 condpos=3;
|
xue@1
|
3132 condmax=3;
|
xue@1
|
3133 nc=nd;
|
xue@1
|
3134 F1=FEx, G1=GEx; //this shall equal to F0+dF, G0+dG
|
xue@1
|
3135 vmax=eEx;
|
xue@1
|
3136 }
|
xue@1
|
3137 }
|
xue@1
|
3138 else if (searchmode==3)
|
xue@1
|
3139 {
|
xue@1
|
3140 //Search mode 3 (e1 search): starting with e1 being the only maximum, search down
|
xue@1
|
3141 // the decreasing direction of e1 until at point (F1, G1) there is another l2 so
|
xue@1
|
3142 // that e1(F1, G1)=e2(F1, G1), or until at point (F1, G1) the search is about
|
xue@1
|
3143 // to go out of R.
|
xue@1
|
3144 //
|
xue@1
|
3145 // Arguments: l1, dF, dG, (F0, G0, vmax)
|
xue@1
|
3146 //
|
xue@1
|
3147
|
xue@1
|
3148 //first calculate the value of lmd from (F0, G0) to get out of R
|
xue@1
|
3149 double maxlmd=-1, FEx, GEx;
|
xue@1
|
3150 double fdggdf=-F0*dG+G0*dF;
|
xue@1
|
3151 nd=-1;
|
xue@1
|
3152 for (int n=0; n<N; n++)
|
xue@1
|
3153 {
|
xue@1
|
3154 if (condpos==2 && n==nc) continue;
|
xue@1
|
3155 if ((condpos==3 && n==nc) || n==n0) continue;
|
xue@1
|
3156 int nn=(n==N-1)?0:n+1;
|
xue@1
|
3157 double xn1=F[n], xn2=F[nn], yn1=G[n], yn2=G[nn];
|
xue@1
|
3158 double test1=xn1*dG-yn1*dF+fdggdf,
|
xue@1
|
3159 test2=xn2*dG-yn2*dF+fdggdf;
|
xue@1
|
3160 if (test1*test2<=0)
|
xue@1
|
3161 {
|
xue@1
|
3162 //the two following are equivalent. we use the larger denominator.
|
xue@1
|
3163 FEx=(xn1*test2-xn2*test1)/(test2-test1);
|
xue@1
|
3164 GEx=(yn1*test2-yn2*test1)/(test2-test1);
|
xue@1
|
3165 if (fabs(dF)>fabs(dG)) maxlmd=(FEx-F0)/dF;
|
xue@1
|
3166 else maxlmd=(GEx-G0)/dG;
|
xue@1
|
3167 nd=n;
|
xue@1
|
3168 }
|
xue@1
|
3169 }
|
xue@1
|
3170
|
xue@1
|
3171 //maxlmd must be >0 at this point.
|
xue@1
|
3172 l2=-1;
|
xue@1
|
3173 tmp=FEx+k[l1]*GEx; testnn(tmp);
|
xue@1
|
3174 double e, eEx=m[l1]*sqrt(tmp)-f[l1], llmd=maxlmd;
|
xue@1
|
3175 int *tpl=new int[L], ctpl=0;
|
xue@1
|
3176 for (int l=0; l<L; l++)
|
xue@1
|
3177 {
|
xue@1
|
3178 if (l==l1) continue;
|
xue@1
|
3179
|
xue@1
|
3180 //if el does not catch up with e1 at (FEx, GEx), then there is no hope this
|
xue@1
|
3181 // happens in between (F0, G0) and (FEx, GEx)
|
xue@1
|
3182 tmp=FEx+k[l]*GEx; testnn(tmp);
|
xue@1
|
3183 double le=m[l]*sqrt(tmp)-f[l];
|
xue@1
|
3184 if (le<eEx)
|
xue@1
|
3185 {
|
xue@1
|
3186 tpl[ctpl]=l;
|
xue@1
|
3187 ctpl++;
|
xue@1
|
3188 continue;
|
xue@1
|
3189 }
|
xue@1
|
3190 //now the existence of (F1, G1) is guaranteed
|
xue@1
|
3191 double lF1[2], lG1[2], lmd[2];
|
xue@1
|
3192 double lm[2]={m[l1], m[l]};
|
xue@1
|
3193 double lf[2]={f[l1], f[l]};
|
xue@1
|
3194 int lk[2]={k[l1], k[l]};
|
xue@1
|
3195 int r=FGFrom2(lF1, lG1, lmd, F0, dF, G0, dG, lm, lf, lk);
|
xue@1
|
3196 for (int i=0; i<r; i++)
|
xue@1
|
3197 {
|
xue@1
|
3198 if (lmd[i]<0 || lmd[i]>maxlmd) continue;
|
xue@1
|
3199 if (lmd[i]<=llmd) llmd=lmd[i], l2=l, F1=lF1[i], G1=lG1[i];
|
xue@1
|
3200 }
|
xue@1
|
3201 }
|
xue@1
|
3202 if (ctpl==L-1) //e1 is maximal at eEx, equivalent to "l2<0"
|
xue@1
|
3203 {}//l2 must equal -1 at this point
|
xue@1
|
3204 else
|
xue@1
|
3205 {
|
xue@1
|
3206 tmp=F1+k[l1]*G1; testnn(tmp);
|
xue@1
|
3207 e=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
3208 //test if e1 is maximal at (F1, G1)
|
xue@1
|
3209 //e1 is already maximal of those l's not in tpl[ctpl]
|
xue@1
|
3210 bool lmax=true;
|
xue@1
|
3211 for (int tp=0; tp<ctpl; tp++)
|
xue@1
|
3212 {
|
xue@1
|
3213 tmp=F1+k[tpl[tp]]*G1; testnn(tmp);
|
xue@1
|
3214 double le=m[tpl[tp]]*sqrt(tmp)-f[tpl[tp]];
|
xue@1
|
3215 if (le>e) {lmax=false; break;}
|
xue@1
|
3216 }
|
xue@1
|
3217 if (!lmax)
|
xue@1
|
3218 {
|
xue@1
|
3219 for (int tp=0; tp<ctpl; tp++)
|
xue@1
|
3220 {
|
xue@1
|
3221 double lF1[2], lG1[2], lmd[2];
|
xue@1
|
3222 double lm[2]={m[l1], m[tpl[tp]]};
|
xue@1
|
3223 double lf[2]={f[l1], f[tpl[tp]]};
|
xue@1
|
3224 int lk[2]={k[l1], k[tpl[tp]]};
|
xue@1
|
3225 int r=FGFrom2(lF1, lG1, lmd, F0, dF, G0, dG, lm, lf, lk);
|
xue@1
|
3226 for (int i=0; i<r; i++)
|
xue@1
|
3227 {
|
xue@1
|
3228 if (lmd[i]<0 || lmd[i]>maxlmd) continue;
|
xue@1
|
3229 if (llmd>=lmd[i]) llmd=lmd[i], l2=tpl[tp], F1=lF1[i], G1=lG1[i];
|
xue@1
|
3230 }
|
xue@1
|
3231 }
|
xue@1
|
3232 tmp=F1+k[l1]*G1; testnn(tmp);
|
xue@1
|
3233 e=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
3234 }
|
xue@1
|
3235 }
|
xue@1
|
3236 delete[] tpl;
|
xue@1
|
3237
|
xue@1
|
3238 if (l2>=0) //so that e1 meets some other ek during the search
|
xue@1
|
3239 {
|
xue@1
|
3240 vmax=e; //this has to equal m[l2]*sqrt(F1+k[l2]*G1)-f[l2]
|
xue@1
|
3241 if (vmax==eEx)
|
xue@1
|
3242 {
|
xue@1
|
3243 condpos=2;
|
xue@1
|
3244 condmax=2;
|
xue@1
|
3245 nc=nd;
|
xue@1
|
3246 }
|
xue@1
|
3247 else
|
xue@1
|
3248 {
|
xue@1
|
3249 condpos=1;
|
xue@1
|
3250 condmax=2;
|
xue@1
|
3251 }
|
xue@1
|
3252 }
|
xue@1
|
3253 else //l2==-1
|
xue@1
|
3254 {
|
xue@1
|
3255 vmax=eEx;
|
xue@1
|
3256 F1=FEx, G1=GEx;
|
xue@1
|
3257 condpos=2;
|
xue@1
|
3258 condmax=3;
|
xue@1
|
3259 nc=nd;
|
xue@1
|
3260 }
|
xue@1
|
3261 }
|
xue@1
|
3262 else //searchmode==4
|
xue@1
|
3263 {
|
xue@1
|
3264 //Search mode 4: a special case of search mode 3 in which the boundry constraint
|
xue@1
|
3265 // is simply 0<=lmd<=1.
|
xue@1
|
3266 dF=F[nd]-F0, dG=G[nd]-G0;
|
xue@1
|
3267 l2=-1;
|
xue@1
|
3268 int *tpl=new int[L], ctpl=0;
|
xue@1
|
3269 tmp=F[nd]+k[l1]*G[nd]; testnn(tmp);
|
xue@1
|
3270 double e, eEx=m[l1]*sqrt(tmp)-f[l1], llmd=1;
|
xue@1
|
3271 for (int l=0; l<L; l++)
|
xue@1
|
3272 {
|
xue@1
|
3273 if (l==l1) continue;
|
xue@1
|
3274 //if el does not catch up with e1 at (F[nd], G[nd]), then there is no hope this
|
xue@1
|
3275 // happens in between (F0, G0) and vertex nd.
|
xue@1
|
3276 tmp=F[nd]+k[l]*G[nd]; testnn(tmp);
|
xue@1
|
3277 double le=m[l]*sqrt(tmp)-f[l];
|
xue@1
|
3278 if (le<eEx)
|
xue@1
|
3279 {
|
xue@1
|
3280 tpl[ctpl]=l;
|
xue@1
|
3281 ctpl++;
|
xue@1
|
3282 continue;
|
xue@1
|
3283 }
|
xue@1
|
3284 //now the existence of (F1, G1) is guaranteed
|
xue@1
|
3285 double lF1[2], lG1[2], lmd[2];
|
xue@1
|
3286 double lm[2]={m[l1], m[l]};
|
xue@1
|
3287 double lf[2]={f[l1], f[l]};
|
xue@1
|
3288 int lk[2]={k[l1], k[l]};
|
xue@1
|
3289 loop1:
|
xue@1
|
3290 int r=FGFrom2(lF1, lG1, lmd, F0, dF, G0, dG, lm, lf, lk);
|
xue@1
|
3291 for (int i=0; i<r; i++)
|
xue@1
|
3292 {
|
xue@1
|
3293 if (lmd[i]<0 || lmd[i]>1) continue;
|
xue@1
|
3294 if (llmd>=lmd[i])
|
xue@1
|
3295 {
|
xue@1
|
3296 tmp=lF1[i]+k[l1]*lG1[i]; testnn(tmp);
|
xue@1
|
3297 double e1=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
3298 tmp=lF1[i]+k[l]*lG1[i]; testnn(tmp);
|
xue@1
|
3299 double e2=m[l]*sqrt(tmp)-f[l];
|
xue@1
|
3300 if (fabs(e1-e2)>1e-4)
|
xue@1
|
3301 {
|
xue@1
|
3302 //int kk=0;
|
xue@1
|
3303 goto loop1;
|
xue@1
|
3304 }
|
xue@1
|
3305 llmd=lmd[i], l2=l, F1=lF1[i], G1=lG1[i];
|
xue@1
|
3306 }
|
xue@1
|
3307 }
|
xue@1
|
3308 }
|
xue@1
|
3309 if (ctpl==N-1) //so e1 is maximal at (F[nd], G[nd])
|
xue@1
|
3310 {}
|
xue@1
|
3311 else
|
xue@1
|
3312 {
|
xue@1
|
3313 tmp=F1+k[l1]*G1; testnn(tmp);
|
xue@1
|
3314 e=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
3315 //test if e1 is maximal at (F1, G1)
|
xue@1
|
3316 bool lmax=true;
|
xue@1
|
3317 for (int tp=0; tp<ctpl; tp++)
|
xue@1
|
3318 {
|
xue@1
|
3319 tmp=F1+k[tpl[tp]]*G1; testnn(tmp);
|
xue@1
|
3320 double le=m[tpl[tp]]*sqrt(tmp)-f[tpl[tp]];
|
xue@1
|
3321 if (le>e) {lmax=false; break;}
|
xue@1
|
3322 }
|
xue@1
|
3323 if (!lmax)
|
xue@1
|
3324 {
|
xue@1
|
3325 for (int tp=0; tp<ctpl; tp++)
|
xue@1
|
3326 {
|
xue@1
|
3327 double lF1[2], lG1[2], lmd[2];
|
xue@1
|
3328 double lm[2]={m[l1], m[tpl[tp]]};
|
xue@1
|
3329 double lf[2]={f[l1], f[tpl[tp]]};
|
xue@1
|
3330 int lk[2]={k[l1], k[tpl[tp]]};
|
xue@1
|
3331 int r=FGFrom2(lF1, lG1, lmd, F0, dF, G0, dG, lm, lf, lk);
|
xue@1
|
3332 for (int i=0; i<r; i++)
|
xue@1
|
3333 {
|
xue@1
|
3334 if (lmd[i]<0 || lmd[i]>1) continue;
|
xue@1
|
3335 if (llmd>=lmd[i]) llmd=lmd[i], l2=tpl[tp], F1=lF1[i], G1=lG1[i];
|
xue@1
|
3336 }
|
xue@1
|
3337 }
|
xue@1
|
3338 // e=m[l1]*sqrt(F1+k[l1]*G1)-f[l1];
|
xue@1
|
3339 }
|
xue@1
|
3340 }
|
xue@1
|
3341 tmp=F1+k[l1]*G1; testnn(tmp);
|
xue@1
|
3342 e=m[l1]*sqrt(tmp)-f[l1];
|
xue@1
|
3343 delete[] tpl;
|
xue@1
|
3344 if (l2>=0)
|
xue@1
|
3345 {
|
xue@1
|
3346 vmax=e;
|
xue@1
|
3347 if (vmax==eEx)
|
xue@1
|
3348 {
|
xue@1
|
3349 condpos=3;
|
xue@1
|
3350 condmax=2;
|
xue@1
|
3351 nc=nd;
|
xue@1
|
3352 }
|
xue@1
|
3353 else
|
xue@1
|
3354 {
|
xue@1
|
3355 condpos=2;
|
xue@1
|
3356 condmax=2;
|
xue@1
|
3357 //(F1, G1) lies on side n0:nc (nd=n0) or nc:n1 (nd=nc or nd=n1)
|
xue@1
|
3358 if (nd==n0) nc=n0;
|
xue@1
|
3359 //else nc=nc;
|
xue@1
|
3360 }
|
xue@1
|
3361 }
|
xue@1
|
3362 else //l2==-1,
|
xue@1
|
3363 {
|
xue@1
|
3364 vmax=eEx;
|
xue@1
|
3365 condpos=3;
|
xue@1
|
3366 condmax=3;
|
xue@1
|
3367 F1=F[nd], G1=G[nd];
|
xue@1
|
3368 nc=nd; //
|
xue@1
|
3369 }
|
xue@1
|
3370 }
|
xue@1
|
3371 F0=F1, G0=G1;
|
xue@1
|
3372
|
xue@1
|
3373 if (condmax==1 && ((l1^l2)==1 || (l1^l3)==1 || (l2^l3)==1))
|
xue@1
|
3374 minimax=true;
|
xue@1
|
3375 else if (condmax==2 && ((l1^l2)==1))
|
xue@1
|
3376 minimax=true;
|
xue@1
|
3377 else if (vmax<1e-6)
|
xue@1
|
3378 minimax=true;
|
xue@1
|
3379 }
|
xue@1
|
3380
|
xue@1
|
3381 free(m);//delete[] m;
|
xue@1
|
3382 delete[] vmnl;
|
xue@1
|
3383
|
xue@1
|
3384 return vmax;
|
xue@1
|
3385 }//minimaxstiff*/
|
xue@1
|
3386
|
Chris@5
|
3387 /**
|
xue@1
|
3388 function NMResultToAtoms: converts the note-match result hosted in a NMResults structure, i.e.
|
xue@1
|
3389 parameters of a harmonic atom, to a list of atoms. The process retrieves atom parameters from low
|
xue@1
|
3390 partials until a required number of atoms have been retrieved or a non-positive frequency is
|
xue@1
|
3391 encountered (non-positive frequencies are returned by note-match to indicate high partials for which
|
xue@1
|
3392 no informative estimates can be obtained).
|
xue@1
|
3393
|
xue@1
|
3394 In: results: the NMResults structure hosting the harmonic atom
|
xue@1
|
3395 M: number of atoms to request from &results
|
xue@1
|
3396 t: time of this harmonic atom
|
xue@1
|
3397 wid: scale of this harmonic atom with which the note-match was performed
|
xue@1
|
3398 Out: HP[return value]: list of atoms retrieved from $result.
|
xue@1
|
3399
|
xue@1
|
3400 Returns the number of atoms retrieved.
|
xue@1
|
3401 */
|
xue@1
|
3402 int NMResultToAtoms(int M, atom* HP, int t, int wid, NMResults results)
|
xue@1
|
3403 {
|
xue@1
|
3404 double *fpp=results.fp, *vfpp=results.vfp, *pfpp=results.pfp;
|
xue@1
|
3405 atomtype* ptype=results.ptype;
|
xue@1
|
3406 for (int i=0; i<M; i++)
|
xue@1
|
3407 {
|
xue@1
|
3408 if (fpp[i]<=0) {memset(&HP[i], 0, sizeof(atom)*(M-i)); return i;}
|
xue@1
|
3409 HP[i].t=t, HP[i].s=wid, HP[i].f=fpp[i]/wid, HP[i].a=vfpp[i];
|
xue@1
|
3410 HP[i].p=pfpp[i]; HP[i].type=ptype[i]; HP[i].pin=i+1;
|
xue@1
|
3411 }
|
xue@1
|
3412 return M;
|
xue@1
|
3413 }//NMResultToAtoms
|
xue@1
|
3414
|
Chris@5
|
3415 /**
|
xue@1
|
3416 function NMResultToPartials: reads atoms of a harmonic atom in a NMResult structure into HS partials.
|
xue@1
|
3417
|
xue@1
|
3418 In: results: the NMResults structure hosting the harmonic atom
|
xue@1
|
3419 M: number of atoms to request from &results
|
xue@1
|
3420 fr: frame index of this harmonic atom
|
xue@1
|
3421 t: time of this harmonic atom
|
xue@1
|
3422 wid: scale of this harmonic atom with which the note-match was performed
|
xue@1
|
3423 Out: Partials[M][]: HS partials whose fr-th frame is updated to the harmonic partial read from $results
|
xue@1
|
3424
|
xue@1
|
3425 Returns the number of partials retrieved.
|
xue@1
|
3426 */
|
xue@1
|
3427 int NMResultToPartials(int M, int fr, atom** Partials, int t, int wid, NMResults results)
|
xue@1
|
3428 {
|
xue@1
|
3429 double *fpp=results.fp, *vfpp=results.vfp, *pfpp=results.pfp;
|
xue@1
|
3430 atomtype* ptype=results.ptype;
|
xue@1
|
3431 for (int i=0; i<M; i++)
|
xue@1
|
3432 {
|
xue@1
|
3433 atom* part=&Partials[i][fr];
|
xue@1
|
3434 if (fpp[i]<=0) {for (int j=i; j<M; j++) memset(&Partials[j][fr], 0, sizeof(atom)); return i;}
|
xue@1
|
3435 part->t=t, part->s=wid, part->f=fpp[i]/wid, part->a=vfpp[i];
|
xue@1
|
3436 part->p=pfpp[i]; part->type=ptype[i]; part->pin=i+1;
|
xue@1
|
3437 }
|
xue@1
|
3438 return M;
|
xue@1
|
3439 }//NMResultToPartials
|
xue@1
|
3440
|
Chris@5
|
3441 /**
|
xue@1
|
3442 function NoteMatchStiff3: finds harmonic atom from spectrum if Fr=1, or constant-pitch harmonic
|
xue@1
|
3443 sinusoid from spectrogram if Fr>1.
|
xue@1
|
3444
|
xue@1
|
3445 In: x[Fr][N/2+1]: spectrogram
|
xue@1
|
3446 fps[pc], vps[pc]: primitive (rough) peak frequencies and amplitudes
|
xue@1
|
3447 N, offst: atom scale and hop size
|
xue@1
|
3448 R: initial F-G polygon constraint, optional
|
xue@1
|
3449 settings: note match settings
|
xue@1
|
3450 computes: pointer to a function that computes HA score, must be ds0 or ds1
|
xue@1
|
3451 lastvfp[lastp]: amplitude of the previous harmonic atom
|
xue@1
|
3452 forceinputlocalfr: specifies if partial settings->pin0 is taken for granted ("pinned")
|
xue@1
|
3453 Out: results: note match results
|
xue@1
|
3454 f0, B: fundamental frequency and stiffness coefficient
|
xue@1
|
3455 R: F-G polygon of harmonic atom
|
xue@1
|
3456
|
xue@1
|
3457 Returns the total energy of HA or constant-pitch HS.
|
xue@1
|
3458 */
|
xue@1
|
3459 double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int pc, double* fps, double* vps,
|
xue@1
|
3460 int Fr, cdouble** x, int N, int offst, NMSettings* settings, NMResults* results, int lastp,
|
xue@1
|
3461 double* lastvfp, double (*computes)(double a, void* params), int forceinputlocalfr)
|
xue@1
|
3462 {
|
xue@1
|
3463 double result=0;
|
xue@1
|
3464
|
xue@1
|
3465 double maxB=settings->maxB, minf0=settings->minf0, maxf0=settings->maxf0,
|
xue@1
|
3466 delm=settings->delm, delp=settings->delp, *c=settings->c, iH2=settings->iH2,
|
xue@1
|
3467 *pinf=settings->pinf, hB=settings->hB, epf0=settings->epf0;// epf=settings->epf,
|
xue@1
|
3468 int maxp=settings->maxp, *pin=settings->pin, pin0=settings->pin0, *pinfr=settings->pinfr,
|
xue@1
|
3469 pcount=settings->pcount, M=settings->M;
|
xue@1
|
3470
|
xue@1
|
3471 // int *ptype=results->ptype;
|
xue@1
|
3472
|
xue@1
|
3473 //calculate the energy of the last frame (hp)
|
xue@1
|
3474 double lastene=0; for (int i=0; i<lastp; i++) lastene+=lastvfp[i]*lastvfp[i];
|
xue@1
|
3475 //fill frequency and amplitude buffers with 0
|
xue@1
|
3476 //now determine numsam (the maximal number of partials)
|
xue@1
|
3477 bool inputpartial=(f0>0 && settings->pin0>0);
|
xue@1
|
3478 if (!inputpartial)
|
xue@1
|
3479 {
|
xue@1
|
3480 if (pcount>0) f0=pinf[0], pin0=pin[0];
|
xue@1
|
3481 else f0=sqrt(R->X[0]), pin0=1;
|
xue@1
|
3482 }
|
xue@1
|
3483 int numsam=N*pin0/2.1/f0;
|
xue@1
|
3484 if (numsam>maxp) numsam=maxp;
|
xue@1
|
3485 //allocate buffer for candidate atoms
|
xue@1
|
3486 TTempAtom*** Allocate2(TTempAtom*, numsam+1, MAX_CAND, cands);
|
xue@1
|
3487 //pcs[p] records the number of candidates for partial index p
|
xue@1
|
3488 //psb[p] = 1: anchor, 2: user input, 0: normal
|
xue@1
|
3489 int *psb=new int[(numsam+1)*2], *pcs=&psb[numsam+1];
|
xue@1
|
3490 memset(psb, 0, sizeof(int)*(numsam+1)*2);
|
xue@1
|
3491 //if R is not specified, initialize a trivial candidate with maxB
|
xue@1
|
3492 if (R->N==0) cands[0][0]=new TTempAtom(1, (minf0+maxf0)*0.5, (maxf0-minf0)*0.5, maxB);
|
xue@1
|
3493 //if R is, initialize a trivial candidate by extending R by delp
|
xue@1
|
3494 else cands[0][0]=new TTempAtom(R, delp, delp, minf0);
|
xue@1
|
3495
|
xue@1
|
3496 int pm=0, pM=0;
|
xue@1
|
3497 int ind=1; pcs[0]=1;
|
xue@1
|
3498 //anchor partials: highest priority atoms, must have spectral peaks
|
xue@1
|
3499 for (int i=0; i<pcount; i++)
|
xue@1
|
3500 {
|
xue@1
|
3501 //skip out-of-scope atoms
|
xue@1
|
3502 if (pin[i]>=numsam) continue;
|
xue@1
|
3503 //skip user input atom
|
xue@1
|
3504 if (inputpartial && pin[i]==pin0) continue;
|
xue@1
|
3505
|
xue@1
|
3506 void* dsparams;
|
xue@1
|
3507 if (computes==ds0) dsparams=&cands[ind-1][0]->s;
|
xue@1
|
3508 else
|
xue@1
|
3509 {
|
xue@1
|
3510 dsparams1 params={cands[ind-1][0]->s, lastene, cands[ind-1][0]->acce, pin[i], lastp, lastvfp};
|
xue@1
|
3511 dsparams=¶ms;
|
xue@1
|
3512 }
|
xue@1
|
3513
|
xue@1
|
3514 if (pinfr[i]>0) //local anchor
|
xue@1
|
3515 {
|
xue@1
|
3516 double ls=0;
|
xue@1
|
3517 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
3518 {
|
xue@1
|
3519 cdouble r=IPWindowC(pinf[i], x[fr], N, M, c, iH2, pinf[i]-hB, pinf[i]+hB);
|
xue@1
|
3520 ls+=~r;
|
xue@1
|
3521 }
|
xue@1
|
3522 ls=sqrt(ls/Fr);
|
xue@1
|
3523 cands[ind][0]=new TTempAtom(cands[ind-1][0], pin[i], pinf[i], delm, ls, computes(ls, dsparams));
|
xue@1
|
3524 }
|
xue@1
|
3525 else
|
xue@1
|
3526 {
|
xue@1
|
3527 //find the nearest peak to pinf[i]
|
xue@1
|
3528 while (pm<pc-1 && fps[pm]<pinf[i]) pm++; while (pm>0 && fps[pm]>=pinf[i]) pm--;
|
xue@1
|
3529 if (pm<pc-1 && pinf[i]-fps[pm]>fps[pm+1]-pinf[i]) pm++;
|
xue@1
|
3530 cands[ind][0]=new TTempAtom(cands[ind-1][0], pin[i], fps[pm], delm, vps[pm], computes(vps[pm], dsparams));
|
xue@1
|
3531 }
|
xue@1
|
3532 delete cands[ind-1][0]->R; cands[ind-1][0]->R=0; psb[pin[i]]=1; pcs[ind]=1; ind++;
|
xue@1
|
3533 }
|
xue@1
|
3534 //harmonic atom grouping fails if anchors conflict
|
xue@1
|
3535 if (cands[ind-1][0]->R->N==0) {f0=0; goto cleanup;}
|
xue@1
|
3536
|
xue@1
|
3537 //user input partial: must have spectral peak
|
xue@1
|
3538 if (inputpartial)
|
xue@1
|
3539 {
|
xue@1
|
3540 //harmonic atom grouping fails if user partial is out of scope
|
xue@1
|
3541 if (pin0>numsam){f0=0; goto cleanup;}
|
xue@1
|
3542
|
xue@1
|
3543 TTempAtom* lcand=cands[ind-1][0];
|
xue@1
|
3544 //feasible frequency range for partial pin0
|
xue@1
|
3545 double f1, f2; ExFmStiff(f1, f2, pin0, lcand->R->N, lcand->R->X, lcand->R->Y);
|
xue@1
|
3546 f1-=delm, f2+=delm;
|
xue@1
|
3547 if (f1<0) f1=0; if (f1>N/2.1) f1=N/2.1; if (f2>N/2.1) f2=N/2.1;
|
xue@1
|
3548 //forcepin0 being true means this partial have to be the peak nearest to f0
|
xue@1
|
3549 bool inputfound=false;
|
xue@1
|
3550 if (forceinputlocalfr>=0)
|
xue@1
|
3551 {
|
xue@1
|
3552 int k1=floor(f0-epf0-1), k2=ceil(f0+epf0+1), k12=k2-k1+1, pk=-1;
|
xue@1
|
3553
|
xue@1
|
3554 cdouble *lx=x[forceinputlocalfr], *lr=new cdouble[k12];
|
xue@1
|
3555 for (int k=0; k<k12; k++) lr[k]=IPWindowC(k1+k, lx, N, M, c, iH2, k1+k-hB, k1+k+hB);
|
xue@1
|
3556 for (int k=1; k<k12-1; k++)
|
xue@1
|
3557 if (~lr[k]>~lr[k-1] && ~lr[k]>~lr[k+1])
|
xue@1
|
3558 {
|
xue@1
|
3559 if (pk==-1 || fabs(k1+pk-f0)>fabs(k1+k-f0)) pk=k;
|
xue@1
|
3560 }
|
xue@1
|
3561 if (pk>0)
|
xue@1
|
3562 {
|
xue@1
|
3563 double lf=k1+pk, la, lph, oldlf=lf;
|
xue@1
|
3564 LSESinusoid(lf, lf-1, lf+1, lx, N, hB, M, c, iH2, la, lph, settings->epf);
|
xue@1
|
3565 if (fabs(lf-oldlf)>0.6)
|
xue@1
|
3566 {
|
xue@1
|
3567 lf=oldlf;
|
xue@1
|
3568 cdouble r=IPWindowC(lf, lx, N, M, c, iH2, lf-hB, lf+hB);
|
xue@1
|
3569 la=abs(r); lph=arg(r);
|
xue@1
|
3570 }
|
xue@1
|
3571 if (lf>f1 && lf<f2)
|
xue@1
|
3572 {
|
xue@1
|
3573 void* dsparams;
|
xue@1
|
3574 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3575 else
|
xue@1
|
3576 {
|
xue@1
|
3577 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3578 dsparams=¶ms;
|
xue@1
|
3579 }
|
xue@1
|
3580 cands[ind][0]=new TTempAtom(lcand, pin0, lf, delm, la, computes(la, dsparams));
|
xue@1
|
3581 pcs[ind]=1;
|
xue@1
|
3582 inputfound=true;
|
xue@1
|
3583 }
|
xue@1
|
3584 }
|
xue@1
|
3585 }
|
xue@1
|
3586 if (!inputfound && settings->forcepin0)
|
xue@1
|
3587 { //find the nearest peak to f0
|
xue@1
|
3588 while (pm<pc-1 && fps[pm]<f0) pm++; while (pm>0 && fps[pm]>=f0) pm--;
|
xue@1
|
3589 if (pm<pc-1 && f0-fps[pm]>fps[pm+1]-f0) pm++;
|
xue@1
|
3590 if (fps[pm]>f1 && fps[pm]<f2)
|
xue@1
|
3591 {
|
xue@1
|
3592 void* dsparams;
|
xue@1
|
3593 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3594 else
|
xue@1
|
3595 {
|
xue@1
|
3596 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3597 dsparams=¶ms;
|
xue@1
|
3598 }
|
xue@1
|
3599 cands[ind][0]=new TTempAtom(lcand, pin0, fps[pm], delm, vps[pm], computes(vps[pm], dsparams));
|
xue@1
|
3600 pcs[ind]=1;
|
xue@1
|
3601 }
|
xue@1
|
3602 }
|
xue@1
|
3603 else if (!inputfound)
|
xue@1
|
3604 {
|
xue@1
|
3605 double epf0=settings->epf0;
|
xue@1
|
3606 //lpcs records number of candidates found for partial pin0
|
xue@1
|
3607 int lpcs=0;
|
xue@1
|
3608 //lcoate peaks with the feasible frequency range, specified by f0 and epf0
|
xue@1
|
3609 while (pm>0 && fps[pm]>=f0-epf0) pm--; while (pm<pc-1 && fps[pm]<f0-epf0) pm++;
|
xue@1
|
3610 while (pM<pc-1 && fps[pM]<=f0+epf0) pM++; while (pM>0 && fps[pM]>f0+epf0) pM--;
|
xue@1
|
3611 //add peaks as candidates
|
xue@1
|
3612 for (int j=pm; j<=pM; j++) if (fps[j]>f1 && fps[j]<f2)
|
xue@1
|
3613 {
|
xue@1
|
3614 void* dsparams;
|
xue@1
|
3615 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3616 else
|
xue@1
|
3617 {
|
xue@1
|
3618 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3619 dsparams=¶ms;
|
xue@1
|
3620 }
|
xue@1
|
3621 cands[ind][lpcs]=new TTempAtom(lcand, pin0, fps[j], delm, vps[j], computes(vps[j], dsparams));
|
xue@1
|
3622 lpcs++;
|
xue@1
|
3623 }
|
xue@1
|
3624 pcs[ind]=lpcs;
|
xue@1
|
3625 }
|
xue@1
|
3626 //harmonic atom grouping fails if user partial is not found
|
xue@1
|
3627 if (pcs[ind]==0){f0=0; goto cleanup;}
|
xue@1
|
3628 else {delete lcand->R; lcand->R=0;}
|
xue@1
|
3629 psb[pin0]=2; ind++;
|
xue@1
|
3630 }
|
xue@1
|
3631 //normal partials (non-anchor, non-user)
|
xue@1
|
3632 //p: partial index
|
xue@1
|
3633 {
|
xue@1
|
3634 int p=0;
|
xue@1
|
3635 while (ind<=numsam)
|
xue@1
|
3636 {
|
xue@1
|
3637 p++;
|
xue@1
|
3638 //skip anchor or user input partials
|
xue@1
|
3639 if (psb[p]) continue;
|
xue@1
|
3640 //loop over all candidates
|
xue@1
|
3641 for (int i=0; i<pcs[ind-1]; i++)
|
xue@1
|
3642 {
|
xue@1
|
3643 //the ith candidate of last partial
|
xue@1
|
3644 TTempAtom* lcand=cands[ind-1][i];
|
xue@1
|
3645 //lpcs records number of candidates found for partial p
|
xue@1
|
3646 int lpcs=0;
|
xue@1
|
3647 //the feasible frequency range for partial p
|
xue@1
|
3648 double f1, f2; ExFmStiff(f1, f2, p, lcand->R->N, lcand->R->X, lcand->R->Y); //calculate the frequency range to search for peak
|
xue@1
|
3649 f1-=delm, f2+=delm; //allow a frequency error for the new partial
|
xue@1
|
3650 if (f1<0) f1=0; if (f1>N/2.1) f1=N/2.1; if (f2>N/2.1) f2=N/2.1;
|
xue@1
|
3651 //locate peaks within this range
|
xue@1
|
3652 while (pm>0 && fps[pm]>=f1) pm--; while (pm<pc-1 && fps[pm]<f1) pm++;
|
xue@1
|
3653 while (pM<pc-1 && fps[pM]<=f2) pM++; while (pM>0 && fps[pM]>f2) pM--; //an index range for peaks
|
xue@1
|
3654 //add peaks as candidates
|
xue@1
|
3655 for (int j=pm; j<=pM; j++)
|
xue@1
|
3656 {
|
xue@1
|
3657 if (fps[j]>f1 && fps[j]<f2) //this peak frequency falls in the frequency range
|
xue@1
|
3658 {
|
xue@1
|
3659 void* dsparams;
|
xue@1
|
3660 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3661 else
|
xue@1
|
3662 {
|
xue@1
|
3663 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3664 dsparams=¶ms;
|
xue@1
|
3665 }
|
xue@1
|
3666 cands[ind][pcs[ind]+lpcs]=new TTempAtom(lcand, p, fps[j], delm, vps[j], computes(vps[j], dsparams));
|
xue@1
|
3667 lpcs++;
|
xue@1
|
3668 if (pcs[ind]+lpcs>=MAX_CAND) {int newpcs=DeleteByHalf(cands[ind], pcs[ind]); memcpy(&cands[ind][newpcs], &cands[ind][pcs[ind]], sizeof(TTempAtom)*lpcs); pcs[ind]=newpcs;}
|
xue@1
|
3669 }
|
xue@1
|
3670 }
|
xue@1
|
3671 //if there is no peak found for partial p
|
xue@1
|
3672 if (lpcs==0)
|
xue@1
|
3673 {
|
xue@1
|
3674 cands[ind][pcs[ind]+lpcs]=lcand; lpcs++;
|
xue@1
|
3675 cands[ind-1][i]=0;
|
xue@1
|
3676 if (pcs[ind]+lpcs>=MAX_CAND){int newpcs=DeleteByHalf(cands[ind], pcs[ind]); memcpy(&cands[ind][newpcs], &cands[ind][pcs[ind]], sizeof(TTempAtom*)*lpcs); pcs[ind]=newpcs;}
|
xue@1
|
3677 }
|
xue@1
|
3678 else{delete lcand->R; lcand->R=0;}
|
xue@1
|
3679
|
xue@1
|
3680 pcs[ind]+=lpcs;
|
xue@1
|
3681 }
|
xue@1
|
3682 ind++;
|
xue@1
|
3683 }
|
xue@1
|
3684
|
xue@1
|
3685 //select the candidate with maximal s
|
xue@1
|
3686 int maxs=0; double vmax=cands[ind-1][0]->s;
|
xue@1
|
3687 for (int i=1; i<pcs[ind-1]; i++) if (vmax<cands[ind-1][i]->s) maxs=i, vmax=cands[ind-1][i]->s;
|
xue@1
|
3688 TTempAtom* lcand=cands[ind-1][maxs];
|
xue@1
|
3689
|
xue@1
|
3690 //get results
|
xue@1
|
3691 //read frequencies of found partials
|
xue@1
|
3692 int P=0; int* ps=new int[maxp]; double* fs=new double[maxp]; //these are used for evaluating f0 and B
|
xue@1
|
3693 while (lcand){if (lcand->pind) {ps[P]=lcand->pind; fs[P]=lcand->f; P++;} lcand=lcand->Prev;}
|
xue@1
|
3694 //read R of candidate with maximal s as R0
|
xue@1
|
3695 TPolygon* R0=cands[ind-1][maxs]->R;
|
xue@1
|
3696
|
xue@1
|
3697 if (Fr==1) result=GetResultsSingleFr(f0, B, R, R0, P, ps, fs, 0, x[0], N, psb, numsam, settings, results);
|
xue@1
|
3698 else result=GetResultsMultiFr(f0, B, R, R0, P, ps, fs, 0, Fr, x, N, offst, psb, numsam, settings, results, forceinputlocalfr);
|
xue@1
|
3699
|
xue@1
|
3700 delete[] ps; delete[] fs;
|
xue@1
|
3701 }
|
xue@1
|
3702 cleanup:
|
xue@1
|
3703 for (int i=0; i<=numsam; i++)
|
xue@1
|
3704 for (int j=0; j<pcs[i]; j++)
|
xue@1
|
3705 delete cands[i][j];
|
xue@1
|
3706 DeAlloc2(cands);
|
xue@1
|
3707 delete[] psb;
|
xue@1
|
3708
|
xue@1
|
3709 return result;
|
xue@1
|
3710 }//NoteMatchStiff3
|
xue@1
|
3711
|
Chris@5
|
3712 /**
|
xue@1
|
3713 function NoteMatchStiff3: finds harmonic atom from spectrum if Fr=1, or constant-pitch harmonic
|
xue@1
|
3714 sinusoid from spectrogram if Fr>1. This version uses residue-sinusoid ratio ("rsr") that measures how
|
xue@1
|
3715 "good" a spectral peak is in terms of its shape. peaks with large rsr[] is likely to be contaminated
|
xue@1
|
3716 and their frequency estimates are regarded unreliable.
|
xue@1
|
3717
|
xue@1
|
3718 In: x[Fr][N/2+1]: spectrogram
|
xue@1
|
3719 N, offst: atom scale and hop size
|
xue@1
|
3720 fps[pc], vps[pc], rsr[pc]: primitive (rough) peak frequencies, amplitudes and shape factor
|
xue@1
|
3721 R: initial F-G polygon constraint, optional
|
xue@1
|
3722 settings: note match settings
|
xue@1
|
3723 computes: pointer to a function that computes HA score, must be ds0 or ds1
|
xue@1
|
3724 lastvfp[lastp]: amplitude of the previous harmonic atom
|
xue@1
|
3725 forceinputlocalfr: specifies if partial settings->pin0 is taken for granted ("pinned")
|
xue@1
|
3726 Out: results: note match results
|
xue@1
|
3727 f0, B: fundamental frequency and stiffness coefficient
|
xue@1
|
3728 R: F-G polygon of harmonic atom
|
xue@1
|
3729
|
xue@1
|
3730 Returns the total energy of HA or constant-pitch HS.
|
xue@1
|
3731 */
|
xue@1
|
3732 double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int pc, double* fps, double* vps,
|
xue@1
|
3733 double* rsr, int Fr, cdouble** x, int N, int offst, NMSettings* settings, NMResults* results,
|
xue@1
|
3734 int lastp, double* lastvfp, double (*computes)(double a, void* params), int forceinputlocalfr)
|
xue@1
|
3735 {
|
xue@1
|
3736 double result=0;
|
xue@1
|
3737
|
xue@1
|
3738 double maxB=settings->maxB, minf0=settings->minf0, maxf0=settings->maxf0,
|
xue@1
|
3739 delm=settings->delm, delp=settings->delp, *c=settings->c, iH2=settings->iH2,
|
xue@1
|
3740 *pinf=settings->pinf, hB=settings->hB, epf0=settings->epf0;// epf=settings->epf,
|
xue@1
|
3741 int maxp=settings->maxp, *pin=settings->pin, pin0=settings->pin0, *pinfr=settings->pinfr,
|
xue@1
|
3742 pcount=settings->pcount, M=settings->M;
|
xue@1
|
3743
|
xue@1
|
3744 // int *ptype=results->ptype;
|
xue@1
|
3745
|
xue@1
|
3746 //calculate the energy of the last frame (hp)
|
xue@1
|
3747 double lastene=0; for (int i=0; i<lastp; i++) lastene+=lastvfp[i]*lastvfp[i];
|
xue@1
|
3748 //fill frequency and amplitude buffers with 0
|
xue@1
|
3749 //now determine numsam (the maximal number of partials)
|
xue@1
|
3750 bool inputpartial=(f0>0 && settings->pin0>0);
|
xue@1
|
3751 if (!inputpartial)
|
xue@1
|
3752 {
|
xue@1
|
3753 if (pcount>0) f0=pinf[0], pin0=pin[0];
|
xue@1
|
3754 else f0=sqrt(R->X[0]), pin0=1;
|
xue@1
|
3755 }
|
xue@1
|
3756 int numsam=N*pin0/2.1/f0;
|
xue@1
|
3757 if (numsam>maxp) numsam=maxp;
|
xue@1
|
3758 //allocate buffer for candidate atoms
|
xue@1
|
3759 TTempAtom*** Allocate2(TTempAtom*, numsam+1, MAX_CAND, cands);
|
xue@1
|
3760 //pcs[p] records the number of candidates for partial index p
|
xue@1
|
3761 //psb[p] = 1: anchor, 2: user input, 0: normal
|
xue@1
|
3762 int *psb=new int[(numsam+1)*2], *pcs=&psb[numsam+1];
|
xue@1
|
3763 memset(psb, 0, sizeof(int)*(numsam+1)*2);
|
xue@1
|
3764 //if R is not specified, initialize a trivial candidate with maxB
|
xue@1
|
3765 if (R->N==0) cands[0][0]=new TTempAtom(1, (minf0+maxf0)*0.5, (maxf0-minf0)*0.5, maxB);
|
xue@1
|
3766 //if R is, initialize a trivial candidate by extending R by delp
|
xue@1
|
3767 else cands[0][0]=new TTempAtom(R, delp, delp, minf0);
|
xue@1
|
3768
|
xue@1
|
3769 int pm=0, pM=0;
|
xue@1
|
3770 int ind=1; pcs[0]=1;
|
xue@1
|
3771 //anchor partials: highest priority atoms, must have spectral peaks
|
xue@1
|
3772 for (int i=0; i<pcount; i++)
|
xue@1
|
3773 {
|
xue@1
|
3774 //skip out-of-scope atoms
|
xue@1
|
3775 if (pin[i]>=numsam) continue;
|
xue@1
|
3776 //skip user input atom
|
xue@1
|
3777 if (inputpartial && pin[i]==pin0) continue;
|
xue@1
|
3778
|
xue@1
|
3779 void* dsparams;
|
xue@1
|
3780 if (computes==ds0) dsparams=&cands[ind-1][0]->s;
|
xue@1
|
3781 else
|
xue@1
|
3782 {
|
xue@1
|
3783 dsparams1 params={cands[ind-1][0]->s, lastene, cands[ind-1][0]->acce, pin[i], lastp, lastvfp};
|
xue@1
|
3784 dsparams=¶ms;
|
xue@1
|
3785 }
|
xue@1
|
3786
|
xue@1
|
3787 if (pinfr[i]>0) //local anchor
|
xue@1
|
3788 {
|
xue@1
|
3789 double ls=0, lrsr=PeakShapeC(pinf[i], 1, N, &x[pinfr[i]], hB*2, M, c, iH2);
|
xue@1
|
3790 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
3791 {
|
xue@1
|
3792 cdouble r=IPWindowC(pinf[i], x[fr], N, M, c, iH2, pinf[i]-hB, pinf[i]+hB);
|
xue@1
|
3793 ls+=~r;
|
xue@1
|
3794 }
|
xue@1
|
3795 ls=sqrt(ls/Fr);
|
xue@1
|
3796 cands[ind][0]=new TTempAtom(cands[ind-1][0], pin[i], pinf[i], delm+lrsr, ls, computes(ls, dsparams)); cands[ind][0]->rsr=lrsr;
|
xue@1
|
3797 }
|
xue@1
|
3798 else
|
xue@1
|
3799 {
|
xue@1
|
3800 //find the nearest peak to pinf[i]
|
xue@1
|
3801 while (pm<pc-1 && fps[pm]<pinf[i]) pm++; while (pm>0 && fps[pm]>=pinf[i]) pm--;
|
xue@1
|
3802 if (pm<pc-1 && pinf[i]-fps[pm]>fps[pm+1]-pinf[i]) pm++;
|
xue@1
|
3803 cands[ind][0]=new TTempAtom(cands[ind-1][0], pin[i], fps[pm], delm+rsr[pm], vps[pm], computes(vps[pm], dsparams)); cands[ind][0]->rsr=rsr[pm];
|
xue@1
|
3804 }
|
xue@1
|
3805 delete cands[ind-1][0]->R; cands[ind-1][0]->R=0; psb[pin[i]]=1; pcs[ind]=1; ind++;
|
xue@1
|
3806 }
|
xue@1
|
3807 //harmonic atom grouping fails if anchors conflict
|
xue@1
|
3808 if (cands[ind-1][0]->R->N==0) {f0=0; goto cleanup;}
|
xue@1
|
3809
|
xue@1
|
3810 //user input partial: must have spectral peak
|
xue@1
|
3811 if (inputpartial)
|
xue@1
|
3812 {
|
xue@1
|
3813 //harmonic atom grouping fails if user partial is out of scope
|
xue@1
|
3814 if (pin0>numsam){f0=0; goto cleanup;}
|
xue@1
|
3815
|
xue@1
|
3816 TTempAtom* lcand=cands[ind-1][0];
|
xue@1
|
3817 //feasible frequency range for partial pin0
|
xue@1
|
3818 double f1, f2; ExFmStiff(f1, f2, pin0, lcand->R->N, lcand->R->X, lcand->R->Y);
|
xue@1
|
3819 f1-=delm, f2+=delm;
|
xue@1
|
3820 if (f1<0) f1=0; if (f1>N/2.1) f1=N/2.1; if (f2>N/2.1) f2=N/2.1;
|
xue@1
|
3821 bool inputfound=false;
|
xue@1
|
3822 if (forceinputlocalfr>=0)
|
xue@1
|
3823 {
|
xue@1
|
3824 int k1=floor(f0-epf0-1), k2=ceil(f0+epf0+1), k12=k2-k1+1, pk=-1;
|
xue@1
|
3825
|
xue@1
|
3826 cdouble *lx=x[forceinputlocalfr], *lr=new cdouble[k12];
|
xue@1
|
3827 for (int k=0; k<k12; k++) lr[k]=IPWindowC(k1+k, lx, N, M, c, iH2, k1+k-hB, k1+k+hB);
|
xue@1
|
3828 for (int k=1; k<k12-1; k++)
|
xue@1
|
3829 if (~lr[k]>~lr[k-1] && ~lr[k]>~lr[k+1])
|
xue@1
|
3830 {
|
xue@1
|
3831 if (pk==-1 || fabs(k1+pk-f0)>fabs(k1+k-f0)) pk=k;
|
xue@1
|
3832 }
|
xue@1
|
3833 if (pk>0)
|
xue@1
|
3834 {
|
xue@1
|
3835 double lf=k1+pk, la, lph, oldlf=lf;
|
xue@1
|
3836 LSESinusoid(lf, lf-1, lf+1, lx, N, hB, M, c, iH2, la, lph, settings->epf);
|
xue@1
|
3837 if (fabs(lf-oldlf)>0.6) //by which we judge that the LS result is biased by interference
|
xue@1
|
3838 {
|
xue@1
|
3839 lf=oldlf;
|
xue@1
|
3840 cdouble r=IPWindowC(lf, lx, N, M, c, iH2, lf-hB, lf+hB);
|
xue@1
|
3841 la=abs(r); lph=arg(r);
|
xue@1
|
3842 }
|
xue@1
|
3843 if (lf>f1 && lf<f2)
|
xue@1
|
3844 {
|
xue@1
|
3845 void* dsparams;
|
xue@1
|
3846 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3847 else
|
xue@1
|
3848 {
|
xue@1
|
3849 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3850 dsparams=¶ms;
|
xue@1
|
3851 }
|
xue@1
|
3852 double lrsr=PeakShapeC(lf, 1, N, &x[forceinputlocalfr], hB*2, M, c, iH2);
|
xue@1
|
3853 cands[ind][0]=new TTempAtom(lcand, pin0, lf, delm+lrsr, la, computes(la, dsparams)); cands[ind][0]->rsr=lrsr;
|
xue@1
|
3854 pcs[ind]=1;
|
xue@1
|
3855 inputfound=true;
|
xue@1
|
3856 }
|
xue@1
|
3857 }
|
xue@1
|
3858 }
|
xue@1
|
3859 //forcepin0 being true means this partial have to be the peak nearest to f0
|
xue@1
|
3860 if (!inputfound && settings->forcepin0)
|
xue@1
|
3861 { //find the nearest peak to f0
|
xue@1
|
3862 while (pm<pc-1 && fps[pm]<f0) pm++; while (pm>0 && fps[pm]>=f0) pm--;
|
xue@1
|
3863 if (pm<pc-1 && f0-fps[pm]>fps[pm+1]-f0) pm++;
|
xue@1
|
3864 if (fps[pm]>f1 && fps[pm]<f2)
|
xue@1
|
3865 {
|
xue@1
|
3866 void* dsparams;
|
xue@1
|
3867 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3868 else
|
xue@1
|
3869 {
|
xue@1
|
3870 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3871 dsparams=¶ms;
|
xue@1
|
3872 }
|
xue@1
|
3873 cands[ind][0]=new TTempAtom(lcand, pin0, fps[pm], delm+rsr[pm], vps[pm], computes(vps[pm], dsparams)); cands[ind][0]->rsr=rsr[pm];
|
xue@1
|
3874 pcs[ind]=1;
|
xue@1
|
3875 }
|
xue@1
|
3876 }
|
xue@1
|
3877 else if (!inputfound)
|
xue@1
|
3878 {
|
xue@1
|
3879 double epf0=settings->epf0;
|
xue@1
|
3880 //lpcs records number of candidates found for partial pin0
|
xue@1
|
3881 int lpcs=0;
|
xue@1
|
3882 //lcoate peaks with the feasible frequency range, specified by f0 and epf0
|
xue@1
|
3883 while (pm>0 && fps[pm]>=f0-epf0) pm--; while (pm<pc-1 && fps[pm]<f0-epf0) pm++;
|
xue@1
|
3884 while (pM<pc-1 && fps[pM]<=f0+epf0) pM++; while (pM>0 && fps[pM]>f0+epf0) pM--;
|
xue@1
|
3885 //add peaks as candidates
|
xue@1
|
3886 for (int j=pm; j<=pM; j++) if (fps[j]>f1 && fps[j]<f2)
|
xue@1
|
3887 {
|
xue@1
|
3888 void* dsparams;
|
xue@1
|
3889 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3890 else
|
xue@1
|
3891 {
|
xue@1
|
3892 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3893 dsparams=¶ms;
|
xue@1
|
3894 }
|
xue@1
|
3895 cands[ind][lpcs]=new TTempAtom(lcand, pin0, fps[j], delm+rsr[j], vps[j], computes(vps[j], dsparams)); cands[ind][lpcs]->rsr=rsr[j];
|
xue@1
|
3896 lpcs++;
|
xue@1
|
3897 }
|
xue@1
|
3898 pcs[ind]=lpcs;
|
xue@1
|
3899 }
|
xue@1
|
3900 //harmonic atom grouping fails if user partial is not found
|
xue@1
|
3901 if (pcs[ind]==0){f0=0; goto cleanup;}
|
xue@1
|
3902 else {delete lcand->R; lcand->R=0;}
|
xue@1
|
3903 psb[pin0]=2; ind++;
|
xue@1
|
3904 }
|
xue@1
|
3905 //normal partials (non-anchor, non-user)
|
xue@1
|
3906 //p: partial index
|
xue@1
|
3907 {
|
xue@1
|
3908 int p=0;
|
xue@1
|
3909 while (ind<=numsam)
|
xue@1
|
3910 {
|
xue@1
|
3911 p++;
|
xue@1
|
3912 //skip anchor or user input partials
|
xue@1
|
3913 if (psb[p]) continue;
|
xue@1
|
3914 //loop over all candidates
|
xue@1
|
3915 for (int i=0; i<pcs[ind-1]; i++)
|
xue@1
|
3916 {
|
xue@1
|
3917 int tightpks=0;
|
xue@1
|
3918 //the ith candidate of last partial
|
xue@1
|
3919 TTempAtom* lcand=cands[ind-1][i];
|
xue@1
|
3920 //lpcs records number of candidates found for partial p
|
xue@1
|
3921 int lpcs=0;
|
xue@1
|
3922 //the feasible frequency range for partial p
|
xue@1
|
3923 double tightf1, tightf2; ExFmStiff(tightf1, tightf2, p, lcand->R->N, lcand->R->X, lcand->R->Y); //calculate the frequency range to search for peak
|
xue@1
|
3924 double tightf=(tightf1+tightf2)*0.5, f1=tightf1-delm, f2=tightf2+delm; //allow a frequency error for the new partial
|
xue@1
|
3925 if (f1<0) f1=0; if (f1>N/2.1) f1=N/2.1; if (f2>N/2.1) f2=N/2.1;
|
xue@1
|
3926 //locate peaks within this range
|
xue@1
|
3927 while (pm>0 && fps[pm]>=f1) pm--; while (pm<pc-1 && fps[pm]<f1) pm++;
|
xue@1
|
3928 while (pM<pc-1 && fps[pM]<=f2) pM++; while (pM>0 && fps[pM]>f2) pM--; //an index range for peaks
|
xue@1
|
3929 //add peaks as candidates
|
xue@1
|
3930 for (int j=pm; j<=pM; j++)
|
xue@1
|
3931 {
|
xue@1
|
3932 if (fps[j]>f1 && fps[j]<f2) //this peak frequency falls in the frequency range
|
xue@1
|
3933 {
|
xue@1
|
3934 if ((fps[j]>tightf1 && fps[j]<tightf2) || fabs(fps[j]-tightf)<0.5) tightpks++; //indicates there are "tight" peaks found for this partial
|
xue@1
|
3935 void* dsparams;
|
xue@1
|
3936 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3937 else
|
xue@1
|
3938 {
|
xue@1
|
3939 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3940 dsparams=¶ms;
|
xue@1
|
3941 }
|
xue@1
|
3942 cands[ind][pcs[ind]+lpcs]=new TTempAtom(lcand, p, fps[j], delm+rsr[j], vps[j], computes(vps[j], dsparams)); cands[ind][pcs[ind]+lpcs]->rsr=rsr[j];
|
xue@1
|
3943 lpcs++;
|
xue@1
|
3944 if (pcs[ind]+lpcs>=MAX_CAND) {int newpcs=DeleteByHalf(cands[ind], pcs[ind]); memcpy(&cands[ind][newpcs], &cands[ind][pcs[ind]], sizeof(TTempAtom*)*lpcs); pcs[ind]=newpcs;}
|
xue@1
|
3945 }
|
xue@1
|
3946 }
|
xue@1
|
3947 //if there is no peak found for partial p.
|
xue@1
|
3948 if (!lpcs)
|
xue@1
|
3949 {
|
xue@1
|
3950 //use the lcand directly
|
xue@1
|
3951 //BUT UPDATE accumulative energy (acce) and s using induced partial
|
xue@1
|
3952 if (tightf<N/2-hB)
|
xue@1
|
3953 {
|
xue@1
|
3954 double la=0; for (int fr=0; fr<Fr; fr++) la+=~IPWindowC(tightf, x[fr], N, M, c, iH2, tightf-hB, tightf+hB); la=sqrt(la/Fr);
|
xue@1
|
3955 void* dsparams;
|
xue@1
|
3956 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3957 else
|
xue@1
|
3958 {
|
xue@1
|
3959 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3960 dsparams=¶ms;
|
xue@1
|
3961 }
|
xue@1
|
3962 double ls=computes(la, dsparams);
|
xue@1
|
3963
|
xue@1
|
3964 lcand->acce+=la*la;
|
xue@1
|
3965 lcand->s=ls;
|
xue@1
|
3966 }
|
xue@1
|
3967 cands[ind][pcs[ind]+lpcs]=lcand;
|
xue@1
|
3968 lpcs++;
|
xue@1
|
3969 cands[ind-1][i]=0;
|
xue@1
|
3970 if (pcs[ind]+lpcs>=MAX_CAND){int newpcs=DeleteByHalf(cands[ind], pcs[ind]); memcpy(&cands[ind][newpcs], &cands[ind][pcs[ind]], sizeof(TTempAtom*)*lpcs); pcs[ind]=newpcs;}
|
xue@1
|
3971 }
|
xue@1
|
3972 //if there are peaks but no tight peak found for partial p
|
xue@1
|
3973 else if (!tightpks)
|
xue@1
|
3974 {
|
xue@1
|
3975 if (tightf<N/2-hB)
|
xue@1
|
3976 {
|
xue@1
|
3977 double la=0; for (int fr=0; fr<Fr; fr++) la+=~IPWindowC(tightf, x[fr], N, M, c, iH2, tightf-hB, tightf+hB); la=sqrt(la/Fr);
|
xue@1
|
3978 void* dsparams;
|
xue@1
|
3979 if (computes==ds0) dsparams=&lcand->s;
|
xue@1
|
3980 else
|
xue@1
|
3981 {
|
xue@1
|
3982 dsparams1 params={lcand->s, lastene, lcand->acce, pin0, lastp, lastvfp};
|
xue@1
|
3983 dsparams=¶ms;
|
xue@1
|
3984 }
|
xue@1
|
3985 double ls=computes(la, dsparams);
|
xue@1
|
3986 TTempAtom* lnewcand=new TTempAtom(lcand, true);
|
xue@1
|
3987 lnewcand->f=0; lnewcand->acce+=la*la; lnewcand->s=ls;
|
xue@1
|
3988 cands[ind][pcs[ind]+lpcs]=lnewcand;
|
xue@1
|
3989 lpcs++;
|
xue@1
|
3990 if (pcs[ind]+lpcs>=MAX_CAND)
|
xue@1
|
3991 {int newpcs=DeleteByHalf(cands[ind], pcs[ind]); memcpy(&cands[ind][newpcs], &cands[ind][pcs[ind]], sizeof(TTempAtom*)*lpcs); pcs[ind]=newpcs;}
|
xue@1
|
3992 }
|
xue@1
|
3993 delete lcand->R; lcand->R=0;
|
xue@1
|
3994 }
|
xue@1
|
3995 else{delete lcand->R; lcand->R=0;}
|
xue@1
|
3996
|
xue@1
|
3997 pcs[ind]+=lpcs;
|
xue@1
|
3998 }
|
xue@1
|
3999 ind++;
|
xue@1
|
4000 }
|
xue@1
|
4001
|
xue@1
|
4002 //select the candidate with maximal s
|
xue@1
|
4003 int maxs=0; double vmax=cands[ind-1][0]->s;
|
xue@1
|
4004 for (int i=1; i<pcs[ind-1]; i++) if (vmax<cands[ind-1][i]->s) maxs=i, vmax=cands[ind-1][i]->s;
|
xue@1
|
4005 TTempAtom* lcand=cands[ind-1][maxs];
|
xue@1
|
4006
|
xue@1
|
4007 //get results
|
xue@1
|
4008 //read frequencies of found partials
|
xue@1
|
4009 int P=0; int* ps=new int[maxp]; double* fs=new double[maxp*2], *rsrs=&fs[maxp]; //these are used for evaluating f0 and B
|
xue@1
|
4010 while (lcand){if (lcand->pind && lcand->f) {ps[P]=lcand->pind; fs[P]=lcand->f; rsrs[P]=lcand->rsr; P++;} lcand=lcand->Prev;}
|
xue@1
|
4011 //read R of candidate with maximal s as R0
|
xue@1
|
4012 TPolygon* R0=cands[ind-1][maxs]->R;
|
xue@1
|
4013
|
xue@1
|
4014 if (Fr==1) result=GetResultsSingleFr(f0, B, R, R0, P, ps, fs, rsrs, x[0], N, psb, numsam, settings, results);
|
xue@1
|
4015 else result=GetResultsMultiFr(f0, B, R, R0, P, ps, fs, rsrs, Fr, x, N, offst, psb, numsam, settings, results, forceinputlocalfr);
|
xue@1
|
4016
|
xue@1
|
4017 delete[] ps; delete[] fs;
|
xue@1
|
4018 }
|
xue@1
|
4019 cleanup:
|
xue@1
|
4020 for (int i=0; i<=numsam; i++)
|
xue@1
|
4021 for (int j=0; j<pcs[i]; j++)
|
xue@1
|
4022 delete cands[i][j];
|
xue@1
|
4023 DeAlloc2(cands);
|
xue@1
|
4024 delete[] psb;
|
xue@1
|
4025
|
xue@1
|
4026 return result;
|
xue@1
|
4027 }//NoteMatchStiff3
|
xue@1
|
4028
|
Chris@5
|
4029 /**
|
xue@1
|
4030 function NoteMatchStiff3: wrapper function of the above that does peak picking and HA grouping (or
|
xue@1
|
4031 constant-pitch HS finding) in a single call.
|
xue@1
|
4032
|
xue@1
|
4033 In: x[Fr][N/2+1]: spectrogram
|
xue@1
|
4034 N, offst: atom scale and hop size
|
xue@1
|
4035 R: initial F-G polygon constraint, optional
|
xue@1
|
4036 startfr, validfrrange: centre and half width, in frames, of the interval used for peak picking if Fr>1
|
xue@1
|
4037 settings: note match settings
|
xue@1
|
4038 computes: pointer to a function that computes HA score, must be ds0 or ds1
|
xue@1
|
4039 lastvfp[lastp]: amplitude of the previous harmonic atom
|
xue@1
|
4040 forceinputlocalfr: specifies if partial settings->pin0 is taken for granted ("pinned")
|
xue@1
|
4041 Out: results: note match results
|
xue@1
|
4042 f0, B: fundamental frequency and stiffness coefficient
|
xue@1
|
4043 R: F-G polygon of harmonic atom
|
xue@1
|
4044
|
xue@1
|
4045 Returns the total energy of HA or constant-pitch HS.
|
xue@1
|
4046 */
|
xue@1
|
4047 double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int Fr, cdouble** x, int N, int offst, NMSettings* settings,
|
xue@1
|
4048 NMResults* results, int lastp, double* lastvfp, double (*computes)(double a, void* params),
|
xue@1
|
4049 bool forceinputlocalfr, int startfr, int validfrrange)
|
xue@1
|
4050 {
|
xue@1
|
4051 //find spectral peaks
|
xue@1
|
4052 double *fps=(double*)malloc8(sizeof(double)*N*2*Fr), *vps=&fps[N/2*Fr], *rsr=&fps[N*Fr];
|
xue@1
|
4053 int pc;
|
xue@1
|
4054 if (Fr>1) pc=QuickPeaks(fps, vps, Fr, N, x, startfr, validfrrange, settings->M, settings->c, settings->iH2, 0.0005, -1, -1, settings->hB*2, rsr);
|
xue@1
|
4055 else pc=QuickPeaks(fps, vps, N, x[0], settings->M, settings->c, settings->iH2, 0.0005, -1, -1, settings->hB*2, rsr);
|
xue@1
|
4056 //if no peaks are present, return 0, indicating empty hp
|
xue@1
|
4057 if (pc==0){free8(fps); return 0;}
|
xue@1
|
4058
|
xue@1
|
4059 double result=NoteMatchStiff3(R, f0, B, pc, fps, vps, rsr, Fr, x, N, offst, settings, results, lastp, lastvfp, computes, forceinputlocalfr?startfr:-1);
|
xue@1
|
4060 free8(fps);
|
xue@1
|
4061 return result;
|
xue@1
|
4062 }//NoteMatchStiff3
|
xue@1
|
4063
|
Chris@5
|
4064 /**
|
xue@1
|
4065 function NoteMatchStiff3: finds harmonic atom from spectrum given the pitch as a (partial index,
|
xue@1
|
4066 frequency) pair. This is used internally by NoteMatch3FB().
|
xue@1
|
4067
|
xue@1
|
4068 In: x[N/2+1]: spectrum
|
xue@1
|
4069 fps[pc], vps[pc]: primitive (rough) peak frequencies and amplitudes
|
xue@1
|
4070 R: initial F-G polygon constraint, optional
|
xue@1
|
4071 pin0: partial index in the pitch specifier pair
|
xue@1
|
4072 peak0: index to frequency in fps[] in the pitch specifier pair
|
xue@1
|
4073 settings: note match settings
|
xue@1
|
4074 Out: vfp[]: partial amplitudes
|
xue@1
|
4075 R: F-G polygon of harmonic atom
|
xue@1
|
4076
|
xue@1
|
4077 Returns the total energy of HA.
|
xue@1
|
4078 */
|
xue@1
|
4079 double NoteMatchStiff3(TPolygon* R, int peak0, int pin0, cdouble* x, int pc, double* fps, double* vps, int N,
|
xue@1
|
4080 NMSettings* settings, double* vfp, int** pitchind, int newpc)
|
xue@1
|
4081 {
|
xue@1
|
4082 double maxB=settings->maxB, minf0=settings->minf0, maxf0=settings->maxf0,
|
xue@1
|
4083 delm=settings->delm, delp=settings->delp, *c=settings->c, iH2=settings->iH2,
|
xue@1
|
4084 hB=settings->hB;
|
xue@1
|
4085 int maxp=settings->maxp, M=settings->M; // pcount=settings->pcount;
|
xue@1
|
4086
|
xue@1
|
4087 double f0=fps[peak0];
|
xue@1
|
4088
|
xue@1
|
4089 //determine numsam
|
xue@1
|
4090 int numsam=N*pin0/2.1/f0; if (numsam>maxp) numsam=maxp;
|
xue@1
|
4091 if (pin0>=numsam) return 0;
|
xue@1
|
4092 //pcs[p] contains the number of candidates for partial index p
|
xue@1
|
4093 TTempAtom*** Allocate2(TTempAtom*, numsam+1, MAX_CAND, cands);
|
xue@1
|
4094 int *pcs=new int[numsam+1]; memset(pcs, 0, sizeof(int)*(numsam+1));
|
xue@1
|
4095 if (R->N==0) cands[0][0]=new TTempAtom(1, (minf0+maxf0)*0.5, (maxf0-minf0)*0.5, maxB); //initialization: trivial candidate with maxB
|
xue@1
|
4096 else cands[0][0]=new TTempAtom(R, delp, delp, minf0); //initialization: trivial candidate by expanding R
|
xue@1
|
4097
|
xue@1
|
4098 cands[1][0]=new TTempAtom(cands[0][0], pin0, fps[peak0], delm, vps[peak0], vps[peak0]); cands[1][0]->tag[0]=peak0;
|
xue@1
|
4099 delete cands[0][0]->R; cands[0][0]->R=0;
|
xue@1
|
4100
|
xue@1
|
4101 int pm=0, pM=0, ind=2, p=0; pcs[0]=pcs[1]=1;
|
xue@1
|
4102
|
xue@1
|
4103 while (ind<=numsam)
|
xue@1
|
4104 {
|
xue@1
|
4105 p++;
|
xue@1
|
4106 if (p==pin0) continue;
|
xue@1
|
4107 for (int i=0; i<pcs[ind-1]; i++)
|
xue@1
|
4108 {
|
xue@1
|
4109 TTempAtom* lcand=cands[ind-1][i]; //the the ith candidate of last partial
|
xue@1
|
4110 int lpcs=0;
|
xue@1
|
4111 {
|
xue@1
|
4112 double f1, f2; ExFmStiff(f1, f2, p, lcand->R->N, lcand->R->X, lcand->R->Y); //calculate the frequency range to search for peak
|
xue@1
|
4113 f1-=delm, f2+=delm; //allow a frequency error for the new partial
|
xue@1
|
4114 if (f1<0) f1=0; if (f1>N/2.1) f1=N/2.1; if (f2>N/2.1) f2=N/2.1;
|
xue@1
|
4115 while (pm>0 && fps[pm]>=f1) pm--; while (pm<pc-1 && fps[pm]<f1) pm++;
|
xue@1
|
4116 while (pM<pc-1 && fps[pM]<=f2) pM++; while (pM>0 && fps[pM]>f2) pM--; //an index range for peaks
|
xue@1
|
4117 for (int j=pm; j<=pM; j++)
|
xue@1
|
4118 {
|
xue@1
|
4119 if (fps[j]>f1 && fps[j]<f2 && (p>pin0 || pitchind[j][p]<0))
|
xue@1
|
4120 {
|
xue@1
|
4121 //this peak frequency falls in the frequency range
|
xue@1
|
4122 cands[ind][pcs[ind]+lpcs]=new TTempAtom(lcand, p, fps[j], delm, vps[j], lcand->s+vps[j]); cands[ind][pcs[ind]+lpcs]->tag[0]=j; lpcs++;
|
xue@1
|
4123 if (pcs[ind]+lpcs>=MAX_CAND){int newpcs=DeleteByHalf(cands[ind], pcs[ind]); memcpy(&cands[ind][newpcs], &cands[ind][pcs[ind]], sizeof(TTempAtom)*lpcs); pcs[ind]=newpcs;}
|
xue@1
|
4124 }
|
xue@1
|
4125 }
|
xue@1
|
4126 if (lpcs==0) //there is no peak found for the partial i, the last level
|
xue@1
|
4127 {
|
xue@1
|
4128 cands[ind][pcs[ind]+lpcs]=lcand; lpcs++; //new TTempAtom(lcand, false);
|
xue@1
|
4129 cands[ind-1][i]=0;
|
xue@1
|
4130 if (pcs[ind]+lpcs>=MAX_CAND){int newpcs=DeleteByHalf(cands[ind], pcs[ind]); memcpy(&cands[ind][newpcs], &cands[ind][pcs[ind]], sizeof(TTempAtom*)*lpcs); pcs[ind]=newpcs;}
|
xue@1
|
4131 }
|
xue@1
|
4132 else
|
xue@1
|
4133 {
|
xue@1
|
4134 delete lcand->R; lcand->R=0;
|
xue@1
|
4135 }
|
xue@1
|
4136 }
|
xue@1
|
4137 pcs[ind]+=lpcs;
|
xue@1
|
4138 }
|
xue@1
|
4139 ind++;
|
xue@1
|
4140 }
|
xue@1
|
4141
|
xue@1
|
4142 //select the candidate with maximal s
|
xue@1
|
4143 int maxs=0; double vmax=cands[ind-1][0]->s;
|
xue@1
|
4144 for (int i=1; i<pcs[ind-1]; i++) if (vmax<cands[ind-1][i]->s) maxs=i, vmax=cands[ind-1][i]->s;
|
xue@1
|
4145 TTempAtom* lcand=cands[ind-1][maxs];
|
xue@1
|
4146
|
xue@1
|
4147 //get fp, vfp, pfp, ptype
|
xue@1
|
4148 memset(vfp, 0, sizeof(double)*maxp);
|
xue@1
|
4149
|
xue@1
|
4150 int P=0; int *ps=new int[maxp], *peaks=new int[maxp]; double* fs=new double[maxp]; //these are used for evaluating f0 and B
|
xue@1
|
4151
|
xue@1
|
4152 while (lcand){if (lcand->pind) {ps[P]=lcand->pind; fs[P]=lcand->f; peaks[P]=lcand->tag[0]; P++;} lcand=lcand->Prev;}
|
xue@1
|
4153 R->N=0;
|
xue@1
|
4154
|
xue@1
|
4155 if (P>0)
|
xue@1
|
4156 {
|
xue@1
|
4157 for (int i=P-1; i>=0; i--)
|
xue@1
|
4158 {
|
xue@1
|
4159 int lp=ps[i];
|
xue@1
|
4160 double lf=fs[i];
|
xue@1
|
4161 vfp[lp-1]=vps[peaks[i]];
|
xue@1
|
4162 if (R->N==0) InitializeR(R, lp, lf, delm, maxB);
|
xue@1
|
4163 else if (vfp[lp-1]>1) CutR(R, lp, lf, delm, true);
|
xue@1
|
4164 if (pitchind[peaks[i]][lp]>=0) {R->N=0; goto cleanup;}
|
xue@1
|
4165 else pitchind[peaks[i]][lp]=newpc;
|
xue@1
|
4166 }
|
xue@1
|
4167
|
xue@1
|
4168 //estimate f0 and B
|
xue@1
|
4169 double tmpa, cF, cG;
|
xue@1
|
4170 // double norm[1024]; for (int i=0; i<1024; i++) norm[i]=1;
|
xue@1
|
4171 areaandcentroid(tmpa, cF, cG, R->N, R->X, R->Y);
|
xue@1
|
4172 testnn(cF); f0=sqrt(cF); //B=cG/cF;
|
xue@1
|
4173
|
xue@1
|
4174
|
xue@1
|
4175 for (int i=0; i<numsam; i++)
|
xue@1
|
4176 {
|
xue@1
|
4177 if (vfp[i]==0) //no peak is found for this partial in lcand
|
xue@1
|
4178 {
|
xue@1
|
4179 int m=i+1;
|
xue@1
|
4180 double tmp=cF+(m*m-1)*cG; testnn(tmp);
|
xue@1
|
4181 double lf=m*sqrt(tmp);
|
xue@1
|
4182 if (lf<N/2.1)
|
xue@1
|
4183 {
|
xue@1
|
4184 cdouble r=IPWindowC(lf, x, N, M, c, iH2, lf-hB, lf+hB);
|
xue@1
|
4185 vfp[i]=-sqrt(r.x*r.x+r.y*r.y);
|
xue@1
|
4186 // vfp[i]=-IPWindowC(lf, xr, xi, N, M, c, iH2, lf-hB, lf+hB, 0);
|
xue@1
|
4187 }
|
xue@1
|
4188 }
|
xue@1
|
4189 }
|
xue@1
|
4190 }
|
xue@1
|
4191
|
xue@1
|
4192 cleanup:
|
xue@1
|
4193 delete[] ps; delete[] fs; delete[] peaks;
|
xue@1
|
4194 for (int i=0; i<=numsam; i++) for (int j=0; j<pcs[i]; j++) delete cands[i][j];
|
xue@1
|
4195 DeAlloc2(cands); delete[] pcs;
|
xue@1
|
4196
|
xue@1
|
4197 double result=0;
|
xue@1
|
4198 if (f0>0) for (int i=0; i<numsam; i++) result+=vfp[i]*vfp[i];
|
xue@1
|
4199 return result;
|
xue@1
|
4200 }//NoteMatchStiff3*/
|
xue@1
|
4201
|
Chris@5
|
4202 /**
|
xue@1
|
4203 function NoteMatchStiff3FB: does one dynamic programming step in forward-background pitch tracking of
|
xue@1
|
4204 harmonic sinusoids. This is used internally by FindNoteFB().
|
xue@1
|
4205
|
xue@1
|
4206 In: R[pitchcount]: initial F-G polygons associated with pitch candidates at last frame
|
xue@1
|
4207 vfp[pitchcount][maxp]: amplitude vectors associated with pitch candidates at last frame
|
xue@1
|
4208 sc[pitchcount]: accumulated scores associated with pitch candidates at last frame
|
xue@1
|
4209 fps[pc], vps[pc]: primitive (rough) peak frequencies and amplitudes at this frame
|
xue@1
|
4210 maxpitch: maximal number of pitch candidates
|
xue@1
|
4211 x[wid/2+1]: spectrum
|
xue@1
|
4212 settings: note match settings
|
xue@1
|
4213 Out: pitchcount: number of pitch candidiate at this frame
|
xue@1
|
4214 newpitches[pitchcount]: pitch candidates at this frame, whose lower word is peak index, higher word is partial index
|
xue@1
|
4215 prev[pitchcount]: indices to predecessors of the pitch candidates at this frame
|
xue@1
|
4216 R[pitchcount]: F-G polygons associated with pitch candidates at this frame
|
xue@1
|
4217 vfp[pitchcount][maxp]: amplitude vectors associated with pitch candidates at this frame
|
xue@1
|
4218 sc[pitchcount]: accumulated scores associated with pitch candidates at this frame
|
xue@1
|
4219
|
xue@1
|
4220 No return value.
|
xue@1
|
4221 */
|
xue@1
|
4222 void NoteMatchStiff3FB(int& pitchcount, TPolygon**& R, double**& vfp, double*& sc, int* newpitches, int* prev, int pc, double* fps, double* vps, cdouble* x, int wid, int maxpitch, NMSettings* settings)
|
xue@1
|
4223 {
|
xue@1
|
4224 int maxpin0=6; //this specifies the maximal value that a pitch candidate may have as partial index
|
xue@1
|
4225 double minf0=settings->minf0, delm=settings->delm, delp=settings->delp;
|
xue@1
|
4226 int maxp=settings->maxp;
|
xue@1
|
4227
|
xue@1
|
4228 //pc is the number of peaks at this frame, maxp is the maximal number of partials in the model
|
xue@1
|
4229 //pitchind is initialized to a sequence of -1
|
xue@1
|
4230 int** Allocate2(int, pc, maxp+1, pitchind); memset(pitchind[0], 0xff, sizeof(int)*pc*(maxp+1));
|
xue@1
|
4231
|
xue@1
|
4232 //extend F-G polygons to allow pitch variation
|
xue@1
|
4233 for (int i=0; i<pitchcount; i++) ExtendR(R[i], delp, delp, minf0);
|
xue@1
|
4234
|
xue@1
|
4235 double *f1=new double[pitchcount], *f2=new double[pitchcount];
|
xue@1
|
4236 int pm=0, newpc=0;
|
xue@1
|
4237 TPolygon** newR=new TPolygon*[maxpitch]; memset(newR, 0, sizeof(TPolygon*)*maxpitch);
|
xue@1
|
4238 double* newsc=new double[maxpitch]; memset(newsc, 0, sizeof(double)*maxpitch);
|
xue@1
|
4239 double** Allocate2(double, maxpitch, maxp, newvfp);
|
xue@1
|
4240
|
xue@1
|
4241 for (int pin0=1; pin0<=maxpin0; pin0++) //pin0: the partial index of a candidate pitch
|
xue@1
|
4242 {
|
xue@1
|
4243 //find out the range [pm, pM) of indices into fps[], so that for a * in this range (pin0, fps[*]) may fall
|
xue@1
|
4244 //in the feasible pitch range succeeding one of the candidate pitches of the previous frame
|
xue@1
|
4245 for (int i=0; i<pitchcount; i++) {ExFmStiff(f1[i], f2[i], pin0, R[i]->N, R[i]->X, R[i]->Y); f1[i]-=delm, f2[i]+=delm;}
|
xue@1
|
4246 double f1a=f1[0], f2a=f2[0]; for (int i=1; i<pitchcount; i++) {if (f1a>f1[i]) f1a=f1[i]; if (f2a<f2[i]) f2a=f2[i];}
|
xue@1
|
4247 while (pm<pc-1 && fps[pm]<f1a) pm++;
|
xue@1
|
4248 int pM=pm; while (pM<pc-1 && fps[pM]<f2a) pM++;
|
xue@1
|
4249
|
xue@1
|
4250 for (int p=pm; p<pM; p++) //loop through all peaks in this range
|
xue@1
|
4251 {
|
xue@1
|
4252 if (pitchind[p][pin0]>=0) continue; //skip this peak if it is already ...
|
xue@1
|
4253 int max; double maxs; TPolygon* lnewR=0;
|
xue@1
|
4254
|
xue@1
|
4255 for (int i=0; i<pitchcount; i++) //loop through candidate pitches of the previous frame
|
xue@1
|
4256 {
|
xue@1
|
4257 if (fps[p]>f1[i] && fps[p]<f2[i]) //so that this peak is a feasible successor of the i-th candidate pitch of the previous frame
|
xue@1
|
4258 {
|
xue@1
|
4259 if (pitchind[p][pin0]<0) //if this peak has not been registered as a candidate pitch with pin0 being the partial index
|
xue@1
|
4260 {
|
xue@1
|
4261 lnewR=new TPolygon(maxp*2+4, R[i]); //create a F-G polygon for (this peak, pin0) pair
|
xue@1
|
4262 if (newpc==maxpitch) //maximal number of candidate pitches is reached
|
xue@1
|
4263 {
|
xue@1
|
4264 //delete the candidate with the lowest score without checking if this lowest score is below the score
|
xue@1
|
4265 //of the current pitch candidate (which is not yet computed). of course there is a risk that the new
|
xue@1
|
4266 //score is even lower so that $maxpitch buffered scores may not be the highest $maxpitch scores, but
|
xue@1
|
4267 //the (maxpitch-1) highest of the $maxpitch buffered scores should be the highest (maxpitch01) scores.
|
xue@1
|
4268 int minsc=0; for (int j=0; j<maxpitch; j++) if (newsc[j]<newsc[minsc]) minsc=j;
|
xue@1
|
4269 delete newR[minsc];
|
xue@1
|
4270 if (minsc!=newpc-1) {newR[minsc]=newR[newpc-1]; memcpy(newvfp[minsc], newvfp[newpc-1], sizeof(double)*maxp); newsc[minsc]=newsc[newpc-1]; prev[minsc]=prev[newpc-1]; newpitches[minsc]=newpitches[newpc-1];}
|
xue@1
|
4271 }
|
xue@1
|
4272 else newpc++;
|
xue@1
|
4273 //try to find harmonic atom with this candidate pitch
|
xue@1
|
4274 if (NoteMatchStiff3(lnewR, p, pin0, x, pc, fps, vps, wid, settings, newvfp[newpc-1], pitchind, newpc-1)>0)
|
xue@1
|
4275 {//if successful, buffer its F-G polygon and save its score
|
xue@1
|
4276 newR[newpc-1]=lnewR;
|
xue@1
|
4277 max=i; maxs=sc[i]+conta(maxp, newvfp[newpc-1], vfp[i]);
|
xue@1
|
4278 }
|
xue@1
|
4279 else
|
xue@1
|
4280 {//if not, discard this candidate pitch
|
xue@1
|
4281 delete lnewR; lnewR=0; newpc--;
|
xue@1
|
4282 }
|
xue@1
|
4283 }
|
xue@1
|
4284 else //if this peak has already been registered as a candidate pitch with pin0 being the partial index
|
xue@1
|
4285 {
|
xue@1
|
4286 //compute it score as successor to the i-th candidate of the previous frame
|
xue@1
|
4287 double ls=sc[i]+conta(maxp, newvfp[newpc-1], vfp[i]);
|
xue@1
|
4288 //if the score is higher than mark the i-th candidate of previous frame as its predecessor
|
xue@1
|
4289 if (ls>maxs) maxs=ls, max=i;
|
xue@1
|
4290 }
|
xue@1
|
4291 }
|
xue@1
|
4292 }
|
xue@1
|
4293 if (lnewR) //i.e. a HA is found for this pitch candidate
|
xue@1
|
4294 {
|
xue@1
|
4295 ((__int16*)&newpitches[newpc-1])[0]=p; ((__int16*)&newpitches[newpc-1])[1]=pin0;
|
xue@1
|
4296 newsc[newpc-1]=maxs; //take note of its score
|
xue@1
|
4297 prev[newpc-1]=max; //take note of its predecessor
|
xue@1
|
4298 }
|
xue@1
|
4299 }
|
xue@1
|
4300 }
|
xue@1
|
4301 DeAlloc2(pitchind);
|
xue@1
|
4302 delete[] f1; delete[] f2;
|
xue@1
|
4303
|
xue@1
|
4304 for (int i=0; i<pitchcount; i++) delete R[i]; delete[] R; R=newR;
|
xue@1
|
4305 for (int i=0; i<newpc; i++) for (int j=0; j<maxp; j++) if (newvfp[i][j]<0) newvfp[i][j]=-newvfp[i][j];
|
xue@1
|
4306 DeAlloc2(vfp); vfp=newvfp;
|
xue@1
|
4307 delete[] sc; sc=newsc;
|
xue@1
|
4308 pitchcount=newpc;
|
xue@1
|
4309 }//NoteMatchStiff3FB
|
xue@1
|
4310
|
Chris@5
|
4311 /**
|
xue@1
|
4312 function PeakShapeC: residue-sinusoid-ratio for a given (hypothesis) sinusoid frequency
|
xue@1
|
4313
|
xue@1
|
4314 In: x[Fr][N/2+1]: spectrogram
|
xue@1
|
4315 M, c[], iH2: cosine-family window specifiers
|
xue@1
|
4316 f: reference frequency, in bins
|
xue@1
|
4317 B: spectral truncation width
|
xue@1
|
4318
|
xue@1
|
4319 Returns the residue-sinusoid-ratio.
|
xue@1
|
4320 */
|
xue@1
|
4321 double PeakShapeC(double f, int Fr, int N, cdouble** x, int B, int M, double* c, double iH2)
|
xue@1
|
4322 {
|
xue@1
|
4323 cdouble* w=new cdouble[B];
|
xue@1
|
4324 int fst=floor(f+1-B/2.0);
|
xue@1
|
4325 if (fst<0) fst=0;
|
xue@1
|
4326 if (fst+B>N/2) fst=N/2-B;
|
xue@1
|
4327 Window(w, f, N, M, c, fst, fst+B-1);
|
xue@1
|
4328 cdouble xx=0, ww=Inner(B, w, w);
|
xue@1
|
4329 double xw2=0;
|
xue@1
|
4330 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
4331 xw2+=~Inner(B, &x[fr][fst], w), xx+=Inner(B, &x[fr][fst], &x[fr][fst]);
|
xue@1
|
4332 delete[] w;
|
xue@1
|
4333 if (xx.x==0) return 1;
|
xue@1
|
4334 return 1-xw2/(xx.x*ww.x);
|
xue@1
|
4335 }//PeakShapeC
|
xue@1
|
4336 //version using cmplx<float> as spectrogram data type
|
xue@1
|
4337 double PeakShapeC(double f, int Fr, int N, cfloat** x, int B, int M, double* c, double iH2)
|
xue@1
|
4338 {
|
xue@1
|
4339 cdouble* w=new cdouble[B];
|
xue@1
|
4340 int fst=floor(f+1-B/2.0);
|
xue@1
|
4341 if (fst<0) fst=0;
|
xue@1
|
4342 if (fst+B>N/2) fst=N/2-B;
|
xue@1
|
4343 Window(w, f, N, M, c, fst, fst+B-1);
|
xue@1
|
4344 cdouble xx=0, ww=Inner(B, w, w);
|
xue@1
|
4345 double xw2=0;
|
xue@1
|
4346 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
4347 xw2+=~Inner(B, &x[fr][fst], w), xx+=Inner(B, &x[fr][fst], &x[fr][fst]);
|
xue@1
|
4348 delete[] w;
|
xue@1
|
4349 if (xx.x==0) return 1;
|
xue@1
|
4350 return 1-xw2/(xx.x*ww.x);
|
xue@1
|
4351 }//PeakShapeC
|
xue@1
|
4352
|
Chris@5
|
4353 /**
|
xue@1
|
4354 function QuickPeaks: finds rough peaks in the spectrum (peak picking)
|
xue@1
|
4355
|
xue@1
|
4356 In: x[N/2+1]: spectrum
|
xue@1
|
4357 M, c[], iH2: cosine-family window function specifiers
|
xue@1
|
4358 mina: minimal amplitude to spot a spectral peak
|
xue@1
|
4359 [binst, binen): frequency range, in bins, to look for peaks
|
xue@1
|
4360 B: spectral truncation width
|
xue@1
|
4361 Out; f[return value], a[return value]: frequencies (in bins) and amplitudes of found peaks
|
xue@1
|
4362 rsr[return value]: residue-sinusoid-ratio of found peaks, optional
|
xue@1
|
4363
|
xue@1
|
4364 Returns the number of peaks found. f[] and a[] must be allocated enough space before calling.
|
xue@1
|
4365 */
|
xue@1
|
4366 int QuickPeaks(double* f, double* a, int N, cdouble* x, int M, double* c, double iH2, double mina, int binst, int binen, int B, double* rsr)
|
xue@1
|
4367 {
|
xue@1
|
4368 double hB=B*0.5;
|
xue@1
|
4369 if (binst<2) binst=2;
|
xue@1
|
4370 if (binst<hB) binst=hB;
|
xue@1
|
4371 if (binen<0) binen=N/2-1;
|
xue@1
|
4372 if (binen<0 || binen+hB>N/2-1) binen=N/2-1-hB;
|
xue@1
|
4373 double a0=~x[binst-1], a1=~x[binst], a2;
|
xue@1
|
4374 double minA=mina*mina*2/iH2;
|
xue@1
|
4375 int p=0, n=binst;
|
xue@1
|
4376 cdouble* w=new cdouble[B];
|
xue@1
|
4377 while (n<binen)
|
xue@1
|
4378 {
|
xue@1
|
4379 a2=~x[n+1];
|
xue@1
|
4380 if (a1>0 && a1>=a0 && a1>=a2)
|
xue@1
|
4381 {
|
xue@1
|
4382 if (a1>minA)
|
xue@1
|
4383 {
|
xue@1
|
4384 double A0=sqrt(a0), A1=sqrt(a1), A2=sqrt(a2);
|
xue@1
|
4385 f[p]=n+(A0-A2)/2/(A0+A2-2*A1);
|
xue@1
|
4386 int fst=floor(f[p]+1-hB);
|
xue@1
|
4387 Window(w, f[p], N, M, c, fst, fst+B-1);
|
xue@1
|
4388 double xw2=~Inner(B, &x[fst], w);
|
xue@1
|
4389 a[p]=sqrt(xw2)*iH2;
|
xue@1
|
4390 if (rsr)
|
xue@1
|
4391 {
|
xue@1
|
4392 cdouble xx=Inner(B, &x[fst], &x[fst]);
|
xue@1
|
4393 if (xx.x==0) rsr[p]=1;
|
xue@1
|
4394 else rsr[p]=1-xw2/xx.x*iH2;
|
xue@1
|
4395 }
|
xue@1
|
4396 p++;
|
xue@1
|
4397 }
|
xue@1
|
4398 }
|
xue@1
|
4399 a0=a1;
|
xue@1
|
4400 a1=a2;
|
xue@1
|
4401 n++;
|
xue@1
|
4402 }
|
xue@1
|
4403 delete[] w;
|
xue@1
|
4404 return p;
|
xue@1
|
4405 }//QuickPeaks
|
xue@1
|
4406
|
Chris@5
|
4407 /**
|
xue@1
|
4408 function QuickPeaks: finds rough peaks in the spectrogram (peak picking) for constant-frequency
|
xue@1
|
4409 sinusoids
|
xue@1
|
4410
|
xue@1
|
4411 In: x[Fr][N/2+1]: spectrogram
|
xue@1
|
4412 fr0, r0: centre and half width of interval (in frames) to use for peak picking
|
xue@1
|
4413 M, c[], iH2: cosine-family window function specifiers
|
xue@1
|
4414 mina: minimal amplitude to spot a spectral peak
|
xue@1
|
4415 [binst, binen): frequency range, in bins, to look for peaks
|
xue@1
|
4416 B: spectral truncation width
|
xue@1
|
4417 Out; f[return value], a[return value]: frequencies (in bins) and summary amplitudes of found peaks
|
xue@1
|
4418 rsr[return value]: residue-sinusoid-ratio of found peaks, optional
|
xue@1
|
4419
|
xue@1
|
4420 Returns the number of peaks found. f[] and a[] must be allocated enough space before calling.
|
xue@1
|
4421 */
|
xue@1
|
4422 int QuickPeaks(double* f, double* a, int Fr, int N, cdouble** x, int fr0, int r0, int M, double* c, double iH2, double mina, int binst, int binen, int B, double* rsr)
|
xue@1
|
4423 {
|
xue@1
|
4424 double hB=B*0.5;
|
xue@1
|
4425 int hN=N/2;
|
xue@1
|
4426 if (binst<hB) binst=hB;
|
xue@1
|
4427 if (binen<0 || binen>hN-hB) binen=hN-hB;
|
xue@1
|
4428 double minA=mina*mina*2/iH2;
|
xue@1
|
4429
|
xue@1
|
4430 double *a0s=new double[hN*3*r0], *a1s=&a0s[hN*r0], *a2s=&a0s[hN*2*r0];
|
xue@1
|
4431 int *idx=new int[hN*r0], *frc=new int[hN*r0];
|
xue@1
|
4432 int** Allocate2(int, (hN*r0), (r0*2+1), frs);
|
xue@1
|
4433
|
xue@1
|
4434 int pc=0;
|
xue@1
|
4435
|
xue@1
|
4436 int lr=0;
|
xue@1
|
4437 while (lr<=r0)
|
xue@1
|
4438 {
|
xue@1
|
4439 int fr[2]; //indices to frames to process for this lr
|
xue@1
|
4440 if (lr==0) fr[0]=fr0, fr[1]=-1;
|
xue@1
|
4441 else
|
xue@1
|
4442 {
|
xue@1
|
4443 fr[0]=fr0-lr, fr[1]=fr0+lr;
|
xue@1
|
4444 if (fr[1]>=Fr) fr[1]=-1;
|
xue@1
|
4445 if (fr[0]<0) {fr[0]=fr[1]; fr[1]=-1;}
|
xue@1
|
4446 }
|
xue@1
|
4447 for (int i=0; i<2; i++)
|
xue@1
|
4448 {
|
xue@1
|
4449 if (fr[i]>=0)
|
xue@1
|
4450 {
|
xue@1
|
4451 cdouble* xfr=x[fr[i]];
|
xue@1
|
4452 for (int k=binst; k<binen; k++)
|
xue@1
|
4453 {
|
xue@1
|
4454 double a0=~xfr[k-1], a1=~xfr[k], a2=~xfr[k+1];
|
xue@1
|
4455 if (a1>=a0 && a1>=a2)
|
xue@1
|
4456 {
|
xue@1
|
4457 if (a1>minA)
|
xue@1
|
4458 {
|
xue@1
|
4459 double A1=sqrt(a1), A2=sqrt(a2), A0=sqrt(a0);
|
xue@1
|
4460 double lf=k+(A0-A2)/2/(A0+A2-2*A1);
|
xue@1
|
4461 if (lr==0) //starting frame
|
xue@1
|
4462 {
|
xue@1
|
4463 f[pc]=lf;
|
xue@1
|
4464 a0s[pc]=a0, a1s[pc]=a1, a2s[pc]=a2;
|
xue@1
|
4465 idx[pc]=pc; frs[pc][0]=fr[i]; frc[pc]=1;
|
xue@1
|
4466 pc++;
|
xue@1
|
4467 }
|
xue@1
|
4468 else
|
xue@1
|
4469 {
|
xue@1
|
4470 int closep, indexp=InsertInc(lf, f, pc, false); //find the closest peak ever found in previous (i.e. closer to fr0) frames
|
xue@1
|
4471 if (indexp==-1) indexp=pc, closep=pc-1;
|
xue@1
|
4472 else if (indexp-1>=0 && fabs(lf-f[indexp-1])<fabs(lf-f[indexp])) closep=indexp-1;
|
xue@1
|
4473 else closep=indexp;
|
xue@1
|
4474
|
xue@1
|
4475 if (fabs(lf-f[closep])<0.2) //i.e. lf is very close to previous peak at fs[closep]
|
xue@1
|
4476 {
|
xue@1
|
4477 int idxp=idx[closep];
|
xue@1
|
4478 a0s[idxp]+=a0, a1s[idxp]+=a1, a2s[idxp]+=a2;
|
xue@1
|
4479 frs[idxp][frc[idxp]]=fr[i]; frc[idxp]++;
|
xue@1
|
4480 double A0=sqrt(a0s[idxp]), A1=sqrt(a1s[idxp]), A2=sqrt(a2s[idxp]);
|
xue@1
|
4481 f[closep]=k+(A0-A2)/2/(A0+A2-2*A1);
|
xue@1
|
4482 }
|
xue@1
|
4483 else
|
xue@1
|
4484 {
|
xue@1
|
4485 memmove(&f[indexp+1], &f[indexp], sizeof(double)*(pc-indexp)); f[indexp]=lf;
|
xue@1
|
4486 memmove(&idx[indexp+1], &idx[indexp], sizeof(int)*(pc-indexp)); idx[indexp]=pc;
|
xue@1
|
4487 a0s[pc]=a0, a1s[pc]=a1, a2s[pc]=a2, frs[pc][0]=fr[i], frc[pc]=1;
|
xue@1
|
4488 pc++;
|
xue@1
|
4489 }
|
xue@1
|
4490 }
|
xue@1
|
4491 }
|
xue@1
|
4492 }
|
xue@1
|
4493 }
|
xue@1
|
4494 }
|
xue@1
|
4495 }
|
xue@1
|
4496 lr++;
|
xue@1
|
4497 }
|
xue@1
|
4498
|
xue@1
|
4499 cdouble* w=new cdouble[B];
|
xue@1
|
4500 int* frused=new int[Fr];
|
xue@1
|
4501 for (int p=0; p<pc; p++)
|
xue@1
|
4502 {
|
xue@1
|
4503 int fst=floor(f[p]+1-hB);
|
xue@1
|
4504 memset(frused, 0, sizeof(int)*Fr);
|
xue@1
|
4505 int idxp=idx[p];
|
xue@1
|
4506
|
xue@1
|
4507 Window(w, f[p], N, M, c, fst, fst+B-1);
|
xue@1
|
4508 double xw2=0, xw2r=0, xxr=0;
|
xue@1
|
4509
|
xue@1
|
4510 for (int ifr=0; ifr<frc[idxp]; ifr++)
|
xue@1
|
4511 {
|
xue@1
|
4512 int fr=frs[idxp][ifr];
|
xue@1
|
4513 frused[fr]=1;
|
xue@1
|
4514 xw2r+=~Inner(B, &x[fr][fst], w);
|
xue@1
|
4515 xxr+=Inner(B, &x[fr][fst], &x[fr][fst]).x;
|
xue@1
|
4516 }
|
xue@1
|
4517 xw2=xw2r;
|
xue@1
|
4518 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
4519 if (!frused[fr]) xw2+=~Inner(B, &x[fr][fst], w);
|
xue@1
|
4520 a[p]=sqrt(xw2/Fr)*iH2;
|
xue@1
|
4521 if (xxr==0) rsr[p]=1;
|
xue@1
|
4522 else rsr[p]=1-xw2r/xxr*iH2;
|
xue@1
|
4523 }
|
xue@1
|
4524 delete[] w;
|
xue@1
|
4525 delete[] frused;
|
xue@1
|
4526 delete[] a0s;
|
xue@1
|
4527 delete[] idx;
|
xue@1
|
4528 delete[] frc;
|
xue@1
|
4529 DeAlloc2(frs);
|
xue@1
|
4530 return pc;
|
xue@1
|
4531 }//QuickPeaks
|
xue@1
|
4532
|
Chris@5
|
4533 /**
|
xue@1
|
4534 function ReEstHS1: reestimates a harmonic sinusoid by one multiplicative reestimation using phasor
|
xue@1
|
4535 multiplier
|
xue@1
|
4536
|
xue@1
|
4537 In: partials[M][Fr]: HS partials
|
xue@1
|
4538 [frst, fren): frame (measurement point) range on which to do reestimation
|
xue@1
|
4539 Data16[]: waveform data
|
xue@1
|
4540 Out: partials[M][Fr]: updated HS partials
|
xue@1
|
4541
|
xue@1
|
4542 No return value.
|
xue@1
|
4543 */
|
xue@1
|
4544 void ReEstHS1(int M, int Fr, int frst, int fren, atom** partials, __int16* Data16)
|
xue@1
|
4545 {
|
xue@1
|
4546 double* fs=new double[Fr*3], *as=&fs[Fr], *phs=&fs[Fr*2];
|
xue@1
|
4547 int wid=partials[0][0].s, offst=partials[0][1].t-partials[0][0].t;
|
xue@1
|
4548 int ldatastart=partials[0][0].t-wid/2;
|
xue@1
|
4549 __int16* ldata16=&Data16[ldatastart];
|
xue@1
|
4550 for (int m=0; m<M; m++)
|
xue@1
|
4551 {
|
xue@1
|
4552 for (int fr=0; fr<Fr; fr++) {fs[fr]=partials[m][fr].f; if (fs[fr]<=0){delete[] fs; return;} as[fr]=partials[m][fr].a, phs[fr]=partials[m][fr].p;}
|
xue@1
|
4553 MultiplicativeUpdateF(fs, as, phs, ldata16, Fr, frst, fren, wid, offst);
|
xue@1
|
4554 for (int fr=0; fr<Fr; fr++) partials[m][fr].f=fs[fr], partials[m][fr].a=as[fr], partials[m][fr].p=phs[fr];
|
xue@1
|
4555 }
|
xue@1
|
4556 delete[] fs;
|
xue@1
|
4557 }//ReEstHS1
|
xue@1
|
4558
|
Chris@5
|
4559 /**
|
xue@1
|
4560 function ReEstHS1: wrapper function.
|
xue@1
|
4561
|
xue@1
|
4562 In: HS: a harmonic sinusoid
|
xue@1
|
4563 Data16: its waveform data
|
xue@1
|
4564 Out: HS: updated harmonic sinusoid
|
xue@1
|
4565
|
xue@1
|
4566 No return value.
|
xue@1
|
4567 */
|
xue@1
|
4568 void ReEstHS1(THS* HS, __int16* Data16)
|
xue@1
|
4569 {
|
xue@1
|
4570 ReEstHS1(HS->M, HS->Fr, 0, HS->Fr, HS->Partials, Data16);
|
xue@1
|
4571 }//ReEstHS1
|
xue@1
|
4572
|
Chris@5
|
4573 /**
|
xue@1
|
4574 function SortCandid: inserts a candid object into a listed of candid objects sorted first by f, then
|
xue@1
|
4575 (for identical f's) by df.
|
xue@1
|
4576
|
xue@1
|
4577 In: cand: the candid object to insert to the list
|
xue@1
|
4578 cands[newN]: the sorted list of candid objects
|
xue@1
|
4579 Out: cands[newN+1]: the sorted list after the insertion
|
xue@1
|
4580
|
xue@1
|
4581 Returns the index of $cand in the new list.
|
xue@1
|
4582 */
|
xue@1
|
4583 int SortCandid(candid cand, candid* cands, int newN)
|
xue@1
|
4584 {
|
xue@1
|
4585 int lnN=newN-1;
|
xue@1
|
4586 while (lnN>=0 && cands[lnN].f>cand.f) lnN--;
|
xue@1
|
4587 while (lnN>=0 && cands[lnN].f==cand.f && cands[lnN].df>cand.df) lnN--;
|
xue@1
|
4588 lnN++; //now insert cantmp as cands[lnN]
|
xue@1
|
4589 memmove(&cands[lnN+1], &cands[lnN], sizeof(candid)*(newN-lnN));
|
xue@1
|
4590 cands[lnN]=cand;
|
xue@1
|
4591 return lnN;
|
xue@1
|
4592 }//SortCandid
|
xue@1
|
4593
|
Chris@5
|
4594 /**
|
xue@1
|
4595 function SynthesisHS: synthesizes a harmonic sinusoid without aligning the phases
|
xue@1
|
4596
|
xue@1
|
4597 In: partials[M][Fr]: HS partials
|
xue@1
|
4598 terminatetag: external termination flag. Function SynthesisHS() polls *terminatetag and exits with
|
xue@1
|
4599 0 when it is set.
|
xue@1
|
4600 Out: [dst, den): time interval synthesized
|
xue@1
|
4601 xrec[den-dst]: resynthesized harmonic sinusoid
|
xue@1
|
4602
|
xue@1
|
4603 Returns pointer to xrec on normal finish, or 0 on external termination by setting $terminatetag. In
|
xue@1
|
4604 the first case xrec is created anew with malloc8() and must be freed by caller using free8().
|
xue@1
|
4605 */
|
xue@1
|
4606 double* SynthesisHS(int M, int Fr, atom** partials, int& dst, int& den, bool* terminatetag)
|
xue@1
|
4607 {
|
xue@1
|
4608 int wid=partials[0][0].s, hwid=wid/2;
|
xue@1
|
4609 double *as=(double*)malloc8(sizeof(double)*Fr*13);
|
xue@1
|
4610 double *fs=&as[Fr], *f3=&as[Fr*2], *f2=&as[Fr*3], *f1=&as[Fr*4], *f0=&as[Fr*5],
|
xue@1
|
4611 *a3=&as[Fr*6], *a2=&as[Fr*7], *a1=&as[Fr*8], *a0=&as[Fr*9], *xs=&as[Fr*11];
|
xue@1
|
4612 int* ixs=(int*)&as[Fr*12];
|
xue@1
|
4613
|
xue@1
|
4614 dst=partials[0][0].t-hwid, den=partials[0][Fr-1].t+hwid;
|
xue@1
|
4615 double* xrec=(double*)malloc8(sizeof(double)*(den-dst));
|
xue@1
|
4616 memset(xrec, 0, sizeof(double)*(den-dst));
|
xue@1
|
4617
|
xue@1
|
4618 for (int m=0; m<M; m++)
|
xue@1
|
4619 {
|
xue@1
|
4620 atom* part=partials[m]; bool fzero=false;
|
xue@1
|
4621 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
4622 {
|
xue@11
|
4623 if (terminatetag && *terminatetag) {free8(xrec); free8(as); return 0;}
|
xue@1
|
4624 if (part[fr].f<=0){fzero=true; break;}
|
xue@12
|
4625 if (part[fr].f>0.5){fzero=true; break;}
|
xue@1
|
4626 ixs[fr]=part[fr].t;
|
xue@1
|
4627 xs[fr]=part[fr].t;
|
xue@1
|
4628 as[fr]=part[fr].a*2;
|
xue@1
|
4629 fs[fr]=part[fr].f;
|
xue@1
|
4630 if (part[fr].type==atMuted) as[fr]=0;
|
xue@1
|
4631 }
|
xue@1
|
4632 if (fzero) break;
|
xue@1
|
4633
|
xue@1
|
4634 CubicSpline(Fr-1, f3, f2, f1, f0, xs, fs, 1, 1);
|
xue@1
|
4635 CubicSpline(Fr-1, a3, a2, a1, a0, xs, as, 1, 1);
|
xue@1
|
4636 double ph=0, ph0=0;
|
xue@1
|
4637 for (int fr=0; fr<Fr-1; fr++)
|
xue@1
|
4638 {
|
xue@11
|
4639 if (terminatetag && *terminatetag) {free8(xrec); free8(as); return 0;}
|
xue@1
|
4640 part[fr].p=ph;
|
xue@1
|
4641 ALIGN8(Sinusoid(&xrec[ixs[fr]-dst], 0, ixs[fr+1]-ixs[fr], a3[fr], a2[fr], a1[fr], a0[fr], f3[fr], f2[fr], f1[fr], f0[fr], ph, true);)
|
xue@1
|
4642 }
|
xue@11
|
4643 part[Fr-1].p=ph; ph=part[Fr-2].p;
|
xue@11
|
4644 ALIGN8(Sinusoid(&xrec[ixs[Fr-2]-dst], ixs[Fr-1]-ixs[Fr-2], den-ixs[Fr-2], a3[Fr-2], a2[Fr-2], a1[Fr-2], a0[Fr-2], f3[Fr-2], f2[Fr-2], f1[Fr-2], f0[Fr-2], ph, true);)
|
xue@11
|
4645 ALIGN8(Sinusoid(&xrec[ixs[0]-dst], dst-ixs[0], 0, a3[0], a2[0], a1[0], a0[0], f3[0], f2[0], f1[0], f0[0], ph0, true);)
|
xue@1
|
4646 }
|
xue@1
|
4647 free8(as);
|
xue@1
|
4648 return xrec;
|
xue@1
|
4649 }//SynthesisHS
|
xue@1
|
4650
|
xue@11
|
4651 double* SynthesisHS(THS* HS, int& dst, int& den, bool* terminatetag)
|
xue@11
|
4652 {
|
xue@11
|
4653 return SynthesisHS(HS->M, HS->Fr, HS->Partials, dst, den, terminatetag);
|
xue@11
|
4654 }//SynthesisHS
|
xue@11
|
4655
|
Chris@5
|
4656 /**
|
xue@10
|
4657 function SynthesisHS2: synthesizes a perfectly harmonic sinusoid without aligning the phases.
|
xue@1
|
4658 Frequencies of partials above the fundamental are not used in this synthesis process.
|
xue@1
|
4659
|
xue@1
|
4660 In: partials[M][Fr]: HS partials
|
xue@1
|
4661 terminatetag: external termination flag. This function polls *terminatetag and exits with 0 when
|
xue@1
|
4662 it is set.
|
xue@1
|
4663 Out: [dst, den) time interval synthesized
|
xue@1
|
4664 xrec[den-dst]: resynthesized harmonic sinusoid
|
xue@1
|
4665
|
xue@1
|
4666 Returns pointer to xrec on normal finish, or 0 on external termination by setting $terminatetag. In
|
xue@1
|
4667 the first case xrec is created anew with malloc8() and must be freed by caller using free8().
|
xue@1
|
4668 */
|
xue@1
|
4669 double* SynthesisHS2(int M, int Fr, atom** partials, int& dst, int& den, bool* terminatetag)
|
xue@1
|
4670 {
|
xue@1
|
4671 int wid=partials[0][0].s, hwid=wid/2;
|
xue@1
|
4672 double *as=(double*)malloc8(sizeof(double)*Fr*7); //*as=new double[Fr*8],
|
xue@1
|
4673 double *xs=&as[Fr], *f3=&as[Fr*2], *f2=&as[Fr*3], *f1=&as[Fr*4], *f0=&as[Fr*5];
|
xue@1
|
4674 int *ixs=(int*)&as[Fr*6];
|
xue@1
|
4675 double** a0=new double*[M*4], **a1=&a0[M], **a2=&a0[M*2], **a3=&a0[M*3];
|
xue@1
|
4676 a0[0]=(double*)malloc8(sizeof(double)*M*Fr*4); //a0[0]=new double[M*Fr*4];
|
xue@1
|
4677 for (int m=0; m<M; m++) a0[m]=&a0[0][m*Fr*4], a1[m]=&a0[m][Fr], a2[m]=&a0[m][Fr*2], a3[m]=&a0[m][Fr*3];
|
xue@1
|
4678
|
xue@1
|
4679 dst=partials[0][0].t-hwid, den=partials[0][Fr-1].t+hwid;
|
xue@1
|
4680 double* xrec=(double*)malloc8(sizeof(double)*(den-dst));
|
xue@1
|
4681 memset(xrec, 0, sizeof(double)*(den-dst));
|
xue@1
|
4682 atom* part=partials[0];
|
xue@1
|
4683
|
xue@1
|
4684 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
4685 {
|
xue@1
|
4686 xs[fr]=ixs[fr]=part[fr].t;
|
xue@1
|
4687 as[fr]=part[fr].f;
|
xue@1
|
4688 }
|
xue@1
|
4689 CubicSpline(Fr-1, f3, f2, f1, f0, xs, as, 1, 1);
|
xue@1
|
4690
|
xue@1
|
4691 for (int m=0; m<M; m++)
|
xue@1
|
4692 {
|
xue@1
|
4693 part=partials[m];
|
xue@1
|
4694 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
4695 {
|
xue@1
|
4696 if (part[fr].f<=0){M=m; break;}
|
xue@1
|
4697 as[fr]=part[fr].a*2;
|
xue@1
|
4698 }
|
xue@1
|
4699 if (terminatetag && *terminatetag) {free8(xrec); free8(as); free8(a0[0]); delete[] a0; return 0;}
|
xue@1
|
4700 if (m>=M) break;
|
xue@1
|
4701
|
xue@1
|
4702 CubicSpline(Fr-1, a3[m], a2[m], a1[m], a0[m], xs, as, 1, 1);
|
xue@1
|
4703 }
|
xue@1
|
4704
|
xue@1
|
4705 double *ph=(double*)malloc8(sizeof(double)*M*2), *ph0=&ph[M]; memset(ph, 0, sizeof(double)*M*2);
|
xue@1
|
4706 for (int fr=0; fr<Fr-1; fr++)
|
xue@1
|
4707 {
|
xue@1
|
4708 // double *la0=new double[M*4], *la1=&la0[M], *la2=&la0[M*2], *la3=&la0[M*3]; for (int m=0; m<M; m++) la0[m]=a0[m][fr], la1[m]=a1[m][fr], la2[m]=a2[m][fr], la3[m]=a3[m][fr], part[fr].p=ph[m]; Sinusoids(M, &xrec[ixs[fr]-dst], 0, ixs[fr+1]-ixs[fr], la3, la2, la1, la0, f3[fr], f2[fr], f1[fr], f0[fr], ph, true); delete[] la0;
|
xue@1
|
4709 for (int m=0; m<M; m++) ALIGN8(Sinusoid(&xrec[ixs[fr]-dst], 0, ixs[fr+1]-ixs[fr], a3[m][fr], a2[m][fr], a1[m][fr], a0[m][fr], (m+1)*f3[fr], (m+1)*f2[fr], (m+1)*f1[fr], (m+1)*f0[fr], ph[m], true);)
|
xue@1
|
4710 }
|
xue@1
|
4711 for (int m=0; m<M; m++)
|
xue@1
|
4712 {
|
xue@1
|
4713 part[Fr-1].p=ph[m];
|
xue@1
|
4714 ALIGN8(Sinusoid(&xrec[ixs[Fr-2]-dst], ixs[Fr-1]-ixs[Fr-2], den-ixs[Fr-2], a3[m][Fr-2], a2[m][Fr-2], a1[m][Fr-2], a0[m][Fr-2], (m+1)*f3[Fr-2], (m+1)*f2[Fr-2], (m+1)*f1[Fr-2], (m+1)*f0[Fr-2], ph[m], true);
|
xue@1
|
4715 Sinusoid(&xrec[ixs[0]-dst], dst-ixs[0], 0, a3[m][0], a2[m][0], a1[m][0], a0[m][0], (m+1)*f3[0], (m+1)*f2[0], (m+1)*f1[0], (m+1)*f0[0], ph0[m], true);)
|
xue@1
|
4716 if (terminatetag && *terminatetag) {free8(xrec); free8(as); free8(a0[0]); delete[] a0; free8(ph); return 0;}
|
xue@1
|
4717 }
|
xue@1
|
4718 free8(as); free8(ph); free8(a0[0]); delete[] a0;
|
xue@1
|
4719 return xrec;
|
xue@1
|
4720 }//SynthesisHS2
|
xue@1
|
4721
|
Chris@5
|
4722 /**
|
xue@1
|
4723 function SynthesisHSp: synthesizes a harmonic sinusoid with phase alignment
|
xue@1
|
4724
|
xue@1
|
4725 In: partials[pm][pfr]: HS partials
|
xue@1
|
4726 startamp[pm][st_count]: onset amplifiers, optional
|
xue@1
|
4727 st_start, st_offst: start of and interval between onset amplifying points, optional
|
xue@1
|
4728 Out: [dst, den): time interval synthesized
|
xue@1
|
4729 xrec[den-dst]: resynthesized harmonic sinusoid
|
xue@1
|
4730
|
xue@1
|
4731 Returns pointer to xrec. xrec is created anew with malloc8() and must be freed by caller with free8().
|
xue@1
|
4732 */
|
xue@1
|
4733 double* SynthesisHSp(int pm, int pfr, atom** partials, int& dst, int& den, double** startamp, int st_start, int st_offst, int st_count)
|
xue@1
|
4734 {
|
xue@1
|
4735 int wid=partials[0][0].s, hwid=wid/2, offst=partials[0][1].t-partials[0][0].t;
|
xue@1
|
4736 double *a1=new double[pfr*13];
|
xue@1
|
4737 double *f1=&a1[pfr], *fa=&a1[pfr*2], *fb=&a1[pfr*3], *fc=&a1[pfr*4], *fd=&a1[pfr*5],
|
xue@1
|
4738 *aa=&a1[pfr*6], *ab=&a1[pfr*7], *ac=&a1[pfr*8], *ad=&a1[pfr*9], *p1=&a1[pfr*10], *xs=&a1[pfr*11];
|
xue@1
|
4739 int* ixs=(int*)&a1[pfr*12];
|
xue@1
|
4740
|
xue@1
|
4741 dst=partials[0][0].t-hwid, den=partials[0][pfr-1].t+hwid;
|
xue@1
|
4742 double *xrec=(double*)malloc8(sizeof(double)*(den-dst)*2), *xrecm=&xrec[den-dst];
|
xue@1
|
4743 memset(xrec, 0, sizeof(double)*(den-dst));
|
xue@1
|
4744
|
xue@1
|
4745 for (int p=0; p<pm; p++)
|
xue@1
|
4746 {
|
xue@1
|
4747 atom* part=partials[p];
|
xue@1
|
4748 bool fzero=false;
|
xue@1
|
4749 for (int fr=0; fr<pfr; fr++)
|
xue@1
|
4750 {
|
xue@1
|
4751 if (part[fr].f<=0)
|
xue@1
|
4752 {
|
xue@1
|
4753 fzero=true;
|
xue@1
|
4754 break;
|
xue@1
|
4755 }
|
xue@1
|
4756 ixs[fr]=part[fr].t;
|
xue@1
|
4757 xs[fr]=part[fr].t;
|
xue@1
|
4758 a1[fr]=part[fr].a*2;
|
xue@1
|
4759 f1[fr]=part[fr].f;
|
xue@1
|
4760 p1[fr]=part[fr].p;
|
xue@1
|
4761 if (part[fr].type==atMuted) a1[fr]=0;
|
xue@1
|
4762 }
|
xue@1
|
4763 if (fzero) break;
|
xue@1
|
4764
|
xue@1
|
4765 CubicSpline(pfr-1, fa, fb, fc, fd, xs, f1, 1, 1);
|
xue@1
|
4766 CubicSpline(pfr-1, aa, ab, ac, ad, xs, a1, 1, 1);
|
xue@1
|
4767
|
xue@7
|
4768 for (int fr=0; fr<pfr-1; fr++) Sinusoid(offst, &xrecm[ixs[fr]-dst], aa[fr], ab[fr], ac[fr], ad[fr], fa[fr], fb[fr], fc[fr], fd[fr], p1[fr], p1[fr+1], false);
|
xue@1
|
4769 // Sinusoid(&xrecm[ixs[0]-dst], -hwid, 0, aa[0], ab[0], ac[0], ad[0], fa[0], fb[0], fc[0], fd[0], p1[0], p1[1], false);
|
xue@1
|
4770 // Sinusoid(&xrecm[ixs[pfr-2]-dst], offst, offst+hwid, aa[pfr-2], ab[pfr-2], ac[pfr-2], ad[pfr-2], fa[pfr-2], fb[pfr-2], fc[pfr-2], fd[pfr-2], p1[pfr-2], p1[pfr-1], false);
|
xue@7
|
4771 double tmpph=p1[0]; Sinusoid(&xrecm[ixs[0]-dst], -hwid, 0, 0, 0, 0, ad[0], fa[0], fb[0], fc[0], fd[0], tmpph, false);
|
xue@7
|
4772 ShiftTrinomial(offst, fa[pfr-1], fb[pfr-1], fc[pfr-1], fd[pfr-1], fa[pfr-2], fb[pfr-2], fc[pfr-2], fd[pfr-2]);
|
xue@7
|
4773 ShiftTrinomial(offst, aa[pfr-1], ab[pfr-1], ac[pfr-1], ad[pfr-1], aa[pfr-2], ab[pfr-2], ac[pfr-2], ad[pfr-2]);
|
xue@7
|
4774 tmpph=p1[pfr-1]; Sinusoid(&xrecm[ixs[pfr-2]-dst], offst, offst+hwid, 0, 0, 0, ad[pfr-1], fa[pfr-1], fb[pfr-1], fc[pfr-1], fd[pfr-1], tmpph, false);
|
xue@1
|
4775
|
xue@1
|
4776 if (st_count)
|
xue@1
|
4777 {
|
xue@1
|
4778 double* amp=startamp[p];
|
xue@1
|
4779 for (int c=0; c<st_count; c++)
|
xue@1
|
4780 {
|
xue@1
|
4781 double a1=amp[c], a2=(c+1<st_count)?amp[c+1]:1, da=(a2-a1)/st_offst;
|
xue@1
|
4782 int lst=ixs[0]-dst+st_start+c*st_offst;
|
xue@1
|
4783 double *lxrecm=&xrecm[lst];
|
xue@1
|
4784 if (lst>0) for (int i=0; i<st_offst; i++) lxrecm[i]*=(a1+da*i);
|
xue@1
|
4785 else for (int i=-lst; i<st_offst; i++) lxrecm[i]*=(a1+da*i);
|
xue@1
|
4786 }
|
xue@1
|
4787 for (int i=0; i<ixs[0]-dst+st_start; i++) xrecm[i]*=amp[0];
|
xue@1
|
4788 }
|
xue@1
|
4789 else
|
xue@1
|
4790 {
|
xue@1
|
4791 /*
|
xue@1
|
4792 for (int i=0; i<=hwid; i++)
|
xue@1
|
4793 {
|
xue@1
|
4794 double tmp=0.5+0.5*cos(M_PI*i/hwid);
|
xue@1
|
4795 xrecm[ixs[0]-dst-i]*=tmp;
|
xue@1
|
4796 xrecm[ixs[pfr-2]-dst+offst+i]*=tmp;
|
xue@1
|
4797 } */
|
xue@1
|
4798 }
|
xue@1
|
4799
|
xue@1
|
4800 for (int n=0; n<den-dst; n++) xrec[n]+=xrecm[n];
|
xue@1
|
4801 }
|
xue@1
|
4802
|
xue@1
|
4803 delete[] a1;
|
xue@1
|
4804 return xrec;
|
xue@1
|
4805 }//SynthesisHSp
|
xue@1
|
4806
|
Chris@5
|
4807 /**
|
xue@1
|
4808 function SynthesisHSp: wrapper function.
|
xue@1
|
4809
|
xue@1
|
4810 In: HS: a harmonic sinusoid.
|
xue@1
|
4811 Out: [dst, den): time interval synthesized
|
xue@1
|
4812 xrec[den-dst]: resynthesized harmonic sinusoid
|
xue@1
|
4813
|
xue@1
|
4814 Returns pointer to xrec, which is created anew with malloc8() and must be freed by caller using free8().
|
xue@1
|
4815 */
|
xue@1
|
4816 double* SynthesisHSp(THS* HS, int& dst, int& den)
|
xue@1
|
4817 {
|
xue@1
|
4818 return SynthesisHSp(HS->M, HS->Fr, HS->Partials, dst, den, HS->startamp, HS->st_start, HS->st_offst, HS->st_count);
|
xue@1
|
4819 }//SynthesisHSp
|
xue@1
|
4820
|