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