annotate hs.cpp @ 10:c6528c38b23c

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