xue@1
|
1 #ifndef hsH
|
xue@1
|
2 #define hsH
|
xue@1
|
3
|
Chris@5
|
4 /**
|
Chris@5
|
5 \file hs.h - harmonic sinusoid model
|
xue@1
|
6
|
xue@1
|
7 Further reading: Wen X. and M. Sandler, "Sinusoid modeling in a harmonic context," in Proc. DAFx'07, Bordeaux, 2007.
|
xue@1
|
8 */
|
xue@1
|
9
|
xue@1
|
10 //---------------------------------------------------------------------------
|
Chris@2
|
11 #include <string.h>
|
xue@1
|
12 #include "arrayalloc.h"
|
xue@1
|
13 #include "align8.h"
|
xue@1
|
14 #include "fft.h"
|
Chris@2
|
15 #include "quickspec.h"
|
Chris@2
|
16 #include "tstream.h"
|
xue@1
|
17
|
xue@1
|
18 #define ATOM_LOCALANCHOR 1
|
xue@1
|
19 #define HS_CONSTF 1
|
xue@1
|
20 #define MAX_CAND 64
|
xue@1
|
21 #define STIFF_B_MAX 0.01
|
xue@1
|
22
|
xue@1
|
23 enum atomtype //type flags of an HS atom
|
xue@1
|
24 {
|
xue@1
|
25 atAnchor, //"anchor" is an atom whose validity is taken for granted, e.g. user input
|
xue@1
|
26 atPeak, //an atom whose frequency is an actual spectral peak
|
xue@1
|
27 atInfered, //an atom which has no spectral peak and whose frequency is inferred from other atoms
|
xue@1
|
28 atMuted, //an atom which is being muted
|
xue@1
|
29 atBuried //an atom which is buried in background noise
|
xue@1
|
30 };
|
xue@1
|
31
|
xue@1
|
32 struct atom //an atom of a harmonic sinusoid
|
xue@1
|
33 {
|
xue@1
|
34 double t; //time
|
xue@1
|
35 double s; //scale
|
xue@1
|
36 double f; //digital frequency
|
xue@1
|
37 double a; //amplitude
|
xue@1
|
38 double p; //phase angle
|
xue@1
|
39 int pin; //partial index
|
xue@1
|
40 atomtype type; //atom type
|
xue@1
|
41 int tags; //additional info on atom type
|
xue@1
|
42 float r1;
|
xue@1
|
43 };
|
xue@1
|
44
|
xue@1
|
45 struct candid //candidate atom
|
xue@1
|
46 {
|
xue@1
|
47 int p; //partial index
|
xue@1
|
48 double f; //frequency
|
xue@1
|
49 double df; //delta freqdel folk
|
xue@1
|
50 double s; //score in partial-sum
|
xue@1
|
51 int prev; //index of last partial f-df
|
xue@1
|
52 int type; //0: f0, 1: local maximum, 2: not a maxixum
|
xue@1
|
53 double ms;
|
xue@1
|
54 };
|
xue@1
|
55
|
xue@1
|
56 struct dsparams1 //argument structure for calling ds1()
|
xue@1
|
57 {
|
xue@1
|
58 double s; //score
|
xue@1
|
59 double lastene; //energy of last frame
|
xue@1
|
60 double currentacce; //energy of this frame, currently accumulated
|
xue@1
|
61 int p; //partial index
|
xue@1
|
62 int lastP; //number of efficient partials in last frame
|
xue@1
|
63 double* lastvfp; //amplitude estimates of partials at last frame
|
xue@1
|
64 };
|
xue@1
|
65
|
xue@1
|
66 struct NMResults //note match output structure
|
xue@1
|
67 {
|
xue@1
|
68 double* fp; //frequencies, in bins
|
xue@1
|
69 double* vfp; //amplitudes
|
xue@1
|
70 double* pfp; //phase angles
|
xue@1
|
71 atomtype* ptype; //atom types
|
xue@1
|
72 };
|
xue@1
|
73
|
xue@1
|
74 struct NMSettings //note match algorithm settings
|
xue@1
|
75 {
|
xue@1
|
76 double c[4]; //cosine-family window specifiers
|
xue@1
|
77 int M; //ditto
|
xue@1
|
78 double iH2; //ditto
|
xue@1
|
79 double hB; //spectral truncation half width
|
xue@1
|
80 int maxp; //maximal number of partials
|
xue@1
|
81 double maxB; //stiffness coefficient upper bound
|
xue@1
|
82 double epf; //frequency estimation error tolerance for LSE estimation
|
xue@1
|
83 double epf0; //input frequency error bound for harmonic grouping
|
xue@1
|
84 double delm; //frequency error bound for harmonic grouping
|
xue@1
|
85 double delp; //pitch jump upper bound
|
xue@1
|
86 double minf0; //minimal fundamental frequency
|
xue@1
|
87 double maxf0; //maximal fundamental frequency
|
xue@1
|
88 int pin0; //input partial index
|
xue@1
|
89 bool forcepin0; //force the peak nearest to input frequency as an atom
|
xue@1
|
90 bool pin0asanchor; //mark atom found near the input frequency as anchor
|
xue@1
|
91 int pcount; //number of "pinned" (anchor) partials
|
xue@1
|
92 int* pin; //partial indices of pinned partials
|
xue@1
|
93 double* pinf; //frequencies of pinned partials
|
xue@1
|
94 int* pinfr; //frame indices of pinned partials, used in multi-frame constant-pitch note match
|
xue@1
|
95 };
|
xue@1
|
96
|
xue@1
|
97
|
Chris@5
|
98 /**
|
xue@1
|
99 stiffcandid is the harmonic atom class used internally by harmonic grouping and tracking routines. Literally
|
xue@1
|
100 it means "candidate harmonic atoms on a stiff string model". The stiff string is the main harmonic model used
|
xue@1
|
101 by me for describing frequency relations between partials of a harmonic sound.
|
xue@1
|
102
|
xue@1
|
103 stiffcandid is superceded by TTempAtom class.
|
xue@1
|
104 */
|
xue@1
|
105
|
xue@1
|
106 class stiffcandid
|
xue@1
|
107 {
|
xue@1
|
108 public:
|
xue@1
|
109 int P; //number of partial estimates located
|
xue@1
|
110 int* p; //partial indices of located partials, sizeof(int)*P
|
xue@1
|
111 double* f; //frequencies of located partials, sizeof(double)*P
|
xue@1
|
112 double s; //score in partial-sum
|
xue@1
|
113 //{N; F, G}: the feasible polygonal area of (F, G) given the P partials, where F=F0*F0, G=F0*B
|
xue@1
|
114 int N;
|
xue@1
|
115 double* F; //sizeof(double)*N
|
xue@1
|
116 double* G; //sizeof(double)*N
|
xue@1
|
117
|
xue@1
|
118 stiffcandid(int Wid); //create empty with minimal info
|
xue@1
|
119 stiffcandid(int Wid, int ap, double af, double errf); //create empty with pitch range
|
xue@1
|
120 stiffcandid(int Wid, int ap, double af, double errf, double ds); //create with 1 atom
|
xue@1
|
121 stiffcandid(stiffcandid* prev, int ap, double af, double errf, double ds); //create by updating with new atom
|
xue@1
|
122 ~stiffcandid();
|
xue@1
|
123 };
|
xue@1
|
124
|
xue@1
|
125
|
Chris@5
|
126 /**
|
xue@1
|
127 THS is the data structure hosting a harmonic sinusoid representation. Its key members include the number
|
xue@1
|
128 of partials, number of frames, and all its atoms (sinusoid parameters of all partials at measurement points).
|
xue@1
|
129 */
|
xue@1
|
130
|
xue@1
|
131 class THS
|
xue@1
|
132 {
|
xue@1
|
133 public:
|
xue@1
|
134 int Channel; //channel id: THS describes a harmonic sinusoid in single channel
|
xue@1
|
135 int M; //number of partials
|
xue@1
|
136 int Fr; //number of frames
|
xue@1
|
137 atom** Partials; //atoms, [M][Fr]
|
xue@1
|
138
|
xue@1
|
139 int* BufM[128]; //a buffer for algorithmic use
|
xue@1
|
140
|
xue@1
|
141 int isconstf; //constant frequencies flag
|
xue@1
|
142
|
xue@1
|
143 double** startamp;//onset amplifiers, optional
|
xue@1
|
144 int st_start; //position of the first onset amplifying point
|
xue@1
|
145 int st_offst; //interval of onset amplifying points
|
xue@1
|
146 int st_count; //number of onset amplifying points
|
xue@1
|
147
|
xue@1
|
148 //constructors and destructor
|
xue@1
|
149 THS();
|
xue@1
|
150 THS(int aM, int aFr);
|
xue@1
|
151 THS(THS* HS);
|
xue@1
|
152 THS(THS* HS, double start, double end);
|
xue@1
|
153 ~THS();
|
xue@1
|
154
|
xue@1
|
155 int StartPos(); //start position
|
xue@1
|
156 int EndPos(); //end position
|
xue@1
|
157 int EndPosEx(); //extended end position
|
xue@1
|
158 int StdOffst(); //hop size
|
xue@1
|
159
|
xue@1
|
160 void ClearBufM(); //free buffers registered in BufM[]
|
xue@1
|
161 void Resize(int aM, int aFr, bool copydata=false, bool forcealloc=false); //change size (M or Fr)
|
xue@1
|
162
|
xue@1
|
163 //I/O routines
|
xue@1
|
164 int WriteHdrToStream(TStream* Stream);
|
xue@1
|
165 int ReadHdrFromStream(TStream* Stream);
|
xue@1
|
166 int WriteAtomToStream(TStream* Stream, atom* atm);
|
xue@1
|
167 int ReadAtomFromStream(TStream* Stream, atom* atm);
|
xue@1
|
168 int WriteToStream(TStream* Stream);
|
xue@1
|
169 int ReadFromStream(TStream* Stream);
|
xue@1
|
170 };
|
xue@1
|
171
|
xue@1
|
172
|
Chris@5
|
173 /**
|
xue@1
|
174 TPolygon is a polygon class. This class itself does not enforce convexness. However, when used for solving
|
xue@1
|
175 the stiff string model, all polygons are convex, as they are the results of current a first convex polygon
|
xue@1
|
176 by straight lines.
|
xue@1
|
177
|
xue@1
|
178 For the convenience of computation, the sequence of vertices are arranged so that they come in clockwise
|
xue@1
|
179 order starting from the leftmost (smallest x coordinate) vertex; in case two vertices are both leftmost
|
xue@1
|
180 the upper (larger y coordinate) one is placed at the start and the lower one is placed at the end.
|
xue@1
|
181 */
|
xue@1
|
182
|
xue@1
|
183 class TPolygon
|
xue@1
|
184 {
|
xue@1
|
185 public:
|
xue@1
|
186 int N; //number of vertices (equals number of edges)
|
xue@1
|
187 double* X; //x-coordinates of vertices
|
xue@1
|
188 double* Y; //y-coordinates of vertices
|
xue@1
|
189 TPolygon(int cap);
|
xue@1
|
190 TPolygon(int cap, TPolygon* R);
|
xue@1
|
191 ~TPolygon();
|
xue@1
|
192 };
|
xue@1
|
193
|
xue@1
|
194
|
Chris@5
|
195 /**
|
xue@1
|
196 TTempAtom is an atom class within the stiff-stirng harmonic atom context used internally by harmonic
|
xue@1
|
197 grouping and tracking routines. Literally it means "a temporary atom", and truly it hosts most info
|
xue@1
|
198 one expects of a potential atom. TTempAtom replaces stiffcandid class in harmonic sinusoid group and
|
xue@1
|
199 tracking algorithms, due to the advanges that it carries atom information (frequency, amplitude, etc.)
|
xue@1
|
200 as well as harmonic atom information (link to other atom, the F-G polygon), and is therefore both an
|
xue@1
|
201 individual atom and a harmonic atom containing all atoms tracked down through the linked list Prev.
|
xue@1
|
202 */
|
xue@1
|
203
|
xue@1
|
204 class TTempAtom
|
xue@1
|
205 {
|
xue@1
|
206 public:
|
xue@1
|
207 int pind; //partial index
|
xue@1
|
208 double f; //frequency
|
xue@1
|
209 double a; //amplitude
|
xue@1
|
210 double s; //scale
|
xue@1
|
211 double rsr; //residue-sinusoid ratio
|
xue@1
|
212 TTempAtom* Prev; //previous atom
|
xue@1
|
213 TPolygon *R; //F-G polygon for harmonic group
|
xue@1
|
214 union {double acce; int tag[2];};
|
xue@1
|
215
|
xue@1
|
216 TTempAtom(double af, double ef, double maxB); //create empty with frequency range
|
xue@1
|
217 TTempAtom(int apin, double af, double ef, double maxB); //create empty with frequency range
|
xue@1
|
218 TTempAtom(TPolygon* AR, double delf1, double delf2, double minf); //create empty with extended R
|
xue@1
|
219 TTempAtom(int apind, double af, double ef, double aa, double as, double maxB); //create with one partial
|
xue@1
|
220 TTempAtom(TTempAtom* APrev, bool DupR); //create duplicate
|
xue@1
|
221 TTempAtom(TTempAtom* APrev, int apind, double af, double ef, double aa, double as, bool updateR=true); //duplicate and add one partial
|
xue@1
|
222 ~TTempAtom();
|
xue@1
|
223 };
|
xue@1
|
224
|
xue@1
|
225 //--internal function--------------------------------------------------------
|
xue@1
|
226 double ds0(double, void*); //a score function, internal use only
|
xue@1
|
227
|
xue@1
|
228 //--general polygon routines-------------------------------------------------
|
xue@1
|
229 void areaandcentroid(double& A, double& cx, double& cy, int N, double* x, double* y); //compute area and centroid
|
xue@1
|
230 void cutcvpoly(int& N, double* x, double* y, double A, double B, double C, bool protect=false); //sever polygon by line
|
xue@1
|
231 double maximalminimum(double& x, double& y, int N, double* sx, double* sy); //maximum inscribed circle
|
xue@1
|
232
|
xue@1
|
233 //--F-G polygon routines-----------------------------------------------------
|
xue@1
|
234 void CutR(TPolygon* R, int apind, double af, double ef, bool protect=false);
|
xue@1
|
235 void ExBStiff(double& Bmin, double& Bmax, int N, double* F, double* G);
|
xue@1
|
236 void ExFmStiff(double& Fmin, double& Fmax, int m, int N, double* F, double* G);
|
xue@1
|
237 void ExtendR(TPolygon* R, double delf1, double delf2, double minf);
|
xue@1
|
238 void InitializeR(TPolygon* R, double af, double ef, double maxB);
|
xue@1
|
239 void InitializeR(TPolygon* R, int apind, double af, double ef, double maxB);
|
xue@1
|
240
|
xue@1
|
241 //--internal structure conversion routines-----------------------------------
|
xue@1
|
242 int NMResultToAtoms(int M, atom* HP, int t, int wid, NMResults results);
|
xue@1
|
243 int NMResultToPartials(int M, int fr, atom** Partials, int t, int wid, NMResults results);
|
xue@1
|
244
|
xue@1
|
245 //--batch sinusoid estimation routines---------------------------------------
|
xue@1
|
246 double PeakShapeC(double f, int Fr, int N, cdouble** x, int B, int M, double* c, double iH2);
|
xue@1
|
247 double PeakShapeC(double f, int Fr, int N, cfloat** x, int B, int M, double* c, double iH2);
|
xue@1
|
248 int QuickPeaks(double* f, double* a, int N, cdouble* x, int M, double* c, double iH2, double mina, int binst=-1, int binen=-1, int B=5, double* rsr=0);
|
xue@1
|
249 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=-1, int binen=-1, int B=5, double* rsr=0);
|
xue@1
|
250
|
xue@1
|
251 //--harmonic atom detection (harmonic grouping) routines---------------------
|
xue@1
|
252 double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int pc, double* fps, double* vps, int Fr, cdouble** x, int N, int offst, NMSettings* settings, NMResults* results, int lastp, double* lastvfp, double (*computes)(double a, void* params)=ds0, int forceinputlocalfr=-1); //basic grouping without rsr
|
xue@1
|
253 double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int pc, double* fps, double* vps, double* rsr, int Fr, cdouble** x, int N, int offst, NMSettings* settings, NMResults* results, int lastp, double* lastvfp, double (*computes)(double a, void* params)=ds0, int forceinputlocalfr=-1); //basic grouping with rsr
|
xue@1
|
254 double NoteMatchStiff3(TPolygon* R, double &f0, double& B, int Fr, cdouble** x, int N, int offst, NMSettings* settings, NMResults* results, int lastp, double* lastvfp, double (*deltas)(double a, void* params)=ds0, bool forceinputlocalfr=false, int startfr=-1, int validfrrange=0); //basic grouping with rsr - wrapper
|
xue@1
|
255 double NoteMatchStiff3(TPolygon* R, int peak0, int pin0, cdouble* x, int pc, double* fps, double* vps, int N, NMSettings* settings, double* vfp, int** pitchind, int newpc); //grouping with given pitch, single-frame
|
xue@1
|
256
|
xue@1
|
257 //--harmonic sinusoid tracking routines--------------------------------------
|
xue@1
|
258 int FindNote(int _t, double _f, int& M, int& Fr, atom**& partials, int frst, int fren, int wid, int offst, TQuickSpectrogram* Spec, NMSettings settings); //harmonic sinusoid tracking (forward and backward tracking)
|
xue@1
|
259 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); //constant-pitch harmonic sinusoid tracking
|
xue@1
|
260 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); //forward harmonic sinusoid tracking
|
xue@1
|
261 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); //forward-backward harmonic sinusoid tracking
|
xue@1
|
262 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); //single DP step of FindNoteFB()
|
xue@1
|
263
|
xue@1
|
264 //--harmonic sinusoid synthesis routines-------------------------------------
|
xue@1
|
265 double* SynthesisHS(int pm, int pfr, atom** partials, int& dst, int& den, bool* terminatetag=0);
|
xue@1
|
266 double* SynthesisHS2(int M, int Fr, atom** partials, int& dst, int& den, bool* terminatetag=0);
|
xue@1
|
267 double* SynthesisHSp(int pm, int pfr, atom** partials, int& dst, int& den, double** startamp=0, int st_start=0, int st_offst=0, int st_count=0);
|
xue@1
|
268 double* SynthesisHSp(THS* HS, int& dst, int& den);
|
xue@1
|
269
|
xue@1
|
270 //--other functions----------------------------------------------------------
|
xue@1
|
271 void ReEstHS1(THS* HS, __int16* Data16); //reestimation of HS
|
xue@1
|
272
|
xue@1
|
273 #endif
|