xue@0
|
1 /*
|
xue@0
|
2 Harmonic Visualiser
|
xue@0
|
3
|
xue@0
|
4 An audio file viewer and editor.
|
xue@0
|
5 Centre for Digital Music, Queen Mary, University of London.
|
xue@0
|
6 This file copyright 2011 Wen Xue.
|
xue@0
|
7
|
xue@0
|
8 This program is free software; you can redistribute it and/or
|
xue@0
|
9 modify it under the terms of the GNU General Public License as
|
xue@0
|
10 published by the Free Software Foundation; either version 2 of the
|
xue@0
|
11 License, or (at your option) any later version.
|
xue@0
|
12 */
|
xue@0
|
13 //---------------------------------------------------------------------------
|
xue@0
|
14
|
xue@0
|
15 #include <vcl.h>
|
xue@0
|
16 #pragma hdrstop
|
xue@0
|
17
|
xue@0
|
18 #include <Math.hpp>
|
xue@0
|
19 #include <math.h>
|
xue@0
|
20 #include "SFDemoUnit.h"
|
xue@0
|
21 #include "Matrix.h"
|
xue@0
|
22 #include "Unit1.h"
|
xue@0
|
23 #include "splines.h"
|
xue@0
|
24 //---------------------------------------------------------------------------
|
xue@0
|
25 #pragma package(smart_init)
|
xue@0
|
26 #pragma resource "*.dfm"
|
xue@0
|
27 TSFDemoForm *SFDemoForm;
|
xue@0
|
28 //---------------------------------------------------------------------------
|
xue@0
|
29 const double log10e=Log10(exp(1));
|
xue@0
|
30 const Bdw=5, Bdwc=2; //border width of charts
|
xue@0
|
31 const ftrr=5; //filter control point radius
|
xue@0
|
32
|
xue@0
|
33
|
xue@0
|
34 __fastcall TSFDemoForm::TSFDemoForm(TComponent* Owner)
|
xue@0
|
35 : TForm(Owner)
|
xue@0
|
36 {
|
xue@0
|
37 ForceUpdate=false;
|
xue@0
|
38
|
xue@0
|
39 double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble();
|
xue@0
|
40 dbrange=updb-downdb;
|
xue@0
|
41
|
xue@0
|
42 SUThread=0;
|
xue@0
|
43 pThread=0;
|
xue@0
|
44 memset(ThreadList, 0, sizeof(TSUThread*)*ThreadCaps);
|
xue@0
|
45
|
xue@0
|
46 WaveAudio1=new TWaveAudio(NULL);
|
xue@0
|
47 WaveAudio1->UseMemoryStream=true;
|
xue@0
|
48 WaveAudio1->Channels=1;
|
xue@0
|
49 WaveView1=new TWaveView(NULL);
|
xue@0
|
50 WaveView1->Parent=Panel2;
|
xue@0
|
51 WaveView1->Align=alClient;
|
xue@0
|
52 WaveView1->WaveAudio=WaveAudio1;
|
xue@0
|
53 WaveView1->OnGetOpMode=WaveView1OpMode;
|
xue@0
|
54 WaveView1->CreatePanes(1, 1);
|
xue@0
|
55 WaveView1->SetContent(0, 0, 0, 1);
|
xue@0
|
56 WaveView1->ClickFocus=true;
|
xue@0
|
57 WaveView1->DefaultPopupMenu=false;
|
xue@0
|
58 WaveView1->CustomInfo=WaveView1CustomInfo;
|
xue@0
|
59 WaveView1->InfoLeft=5; WaveView1->InfoTop=5;
|
xue@0
|
60
|
xue@0
|
61 WaveAudio2=new TWaveAudio(NULL);
|
xue@0
|
62 WaveAudio2->UseMemoryStream=true;
|
xue@0
|
63 WaveAudio2->Channels=1;
|
xue@0
|
64 WaveView2=new TWaveView(NULL);
|
xue@0
|
65 WaveView2->Parent=Panel3;
|
xue@0
|
66 WaveView2->Align=alClient;
|
xue@0
|
67 WaveView2->WaveAudio=WaveAudio2;
|
xue@0
|
68 WaveView2->CreatePanes(1, 1);
|
xue@0
|
69 WaveView2->SetContent(0, 0, 0, 1);
|
xue@0
|
70 WaveView2->ClickFocus=true;
|
xue@0
|
71 WaveView2->DefaultPopupMenu=false;
|
xue@0
|
72 WaveView2->CustomInfo=WaveView1CustomInfo;
|
xue@0
|
73 WaveView2->InfoLeft=5; WaveView2->InfoTop=5;
|
xue@0
|
74 WaveView2->LoopPlay=CheckBox1->Checked;
|
xue@0
|
75
|
xue@0
|
76
|
xue@0
|
77 HS=0;
|
xue@0
|
78 cyclefrs=0;
|
xue@0
|
79 cyclefs=0;
|
xue@0
|
80
|
xue@0
|
81 MethodListBox->ItemIndex=0;
|
xue@0
|
82
|
xue@0
|
83 analyze2=false;
|
xue@0
|
84
|
xue@0
|
85 AnsiString Path=ExtractFilePath(Application->ExeName)+"*.sf";
|
xue@0
|
86 TSearchRec sr;
|
xue@0
|
87 if (FindFirst(Path, faAnyFile, sr)==0)
|
xue@0
|
88 {
|
xue@0
|
89 do
|
xue@0
|
90 {
|
xue@0
|
91 TmplListBox->Items->Add(sr.Name);
|
xue@0
|
92 }
|
xue@0
|
93 while (FindNext(sr) == 0);
|
xue@0
|
94 FindClose(sr);
|
xue@0
|
95 }
|
xue@0
|
96 Wave1=0;
|
xue@0
|
97 CurrentP=-1;
|
xue@0
|
98
|
xue@0
|
99 memset(&SF, 0, sizeof(TSF));
|
xue@0
|
100 memset(&SF0, 0, sizeof(TSF));
|
xue@0
|
101
|
xue@0
|
102 datain=0;
|
xue@0
|
103 }
|
xue@0
|
104
|
xue@0
|
105 __fastcall TSFDemoForm::~TSFDemoForm()
|
xue@0
|
106 {
|
xue@0
|
107 delete WaveAudio1;
|
xue@0
|
108 delete WaveAudio2;
|
xue@0
|
109 delete WaveView1;
|
xue@0
|
110 delete WaveView2;
|
xue@0
|
111 delete HS;
|
xue@0
|
112 delete[] cyclefrs;
|
xue@0
|
113 delete[] cyclefs;
|
xue@0
|
114 for (int i=0; i<ThreadCaps; i++) if (ThreadList[i]) delete ThreadList[i];
|
xue@0
|
115 delete[] Wave1;
|
xue@0
|
116 delete[] datain;
|
xue@0
|
117 }
|
xue@0
|
118 //---------------------------------------------------------------------------
|
xue@0
|
119
|
xue@0
|
120 void TSFDemoForm::Copydata()
|
xue@0
|
121 {
|
xue@0
|
122 int dst, den;
|
xue@0
|
123 double* xrec;
|
xue@0
|
124 if (HS)
|
xue@0
|
125 {
|
xue@0
|
126 xrec=SynthesisHSp(HS, dst, den);
|
xue@0
|
127 if (dst<0) dst=0;
|
xue@0
|
128
|
xue@0
|
129 delete[] datain;
|
xue@0
|
130 datain=new __int16[den-dst];
|
xue@0
|
131
|
xue@0
|
132 DoubleToInt(datain, sizeof(__int16), xrec, den-dst);
|
xue@0
|
133
|
xue@0
|
134 free8(xrec);
|
xue@0
|
135 }
|
xue@0
|
136 }
|
xue@0
|
137
|
xue@0
|
138
|
xue@0
|
139 void TSFDemoForm::FindNote()
|
xue@0
|
140 {
|
xue@0
|
141 }
|
xue@0
|
142
|
xue@0
|
143 void TSFDemoForm::Reset()
|
xue@0
|
144 {
|
xue@0
|
145 if (!HS) return;
|
xue@0
|
146 if (HS->M<=0 || HS->Fr<=0) return;
|
xue@0
|
147
|
xue@0
|
148 if (MethodListBox->ItemIndex<0) MethodListBox->ItemIndex=0;
|
xue@0
|
149
|
xue@0
|
150 double sps=WaveView1->SamplesPerSec;
|
xue@0
|
151 double h=WaveView1->SpecOffst;
|
xue@0
|
152 int FSMode=MethodListBox->ItemIndex;
|
xue@0
|
153 double FSF=FEdit->Text.ToDouble();
|
xue@0
|
154 int FSFScale=FScaleCombo->ItemIndex;
|
xue@0
|
155 if (FSFScale==0) FSF/=sps;
|
xue@0
|
156 else FSF/=Amel*log(1+sps/700);
|
xue@0
|
157 double FStheta=ThetaEdit->Text.ToDouble();
|
xue@0
|
158
|
xue@0
|
159 AnalyzeSF_1(*HS, SF, sps, h);
|
xue@0
|
160 AnalyzeSF_2(*HS, SF, cyclefrs, cyclefs, sps, &cyclefrcount, FSMode, FSF, FSFScale, FStheta);
|
xue@0
|
161
|
xue@0
|
162 SaveSF();
|
xue@0
|
163 SaveSF0();
|
xue@0
|
164
|
xue@0
|
165 UpdateDisplay();
|
xue@0
|
166 }
|
xue@0
|
167
|
xue@0
|
168 void TSFDemoForm::Synthesize()
|
xue@0
|
169 {
|
xue@0
|
170 int dst, den;
|
xue@0
|
171 double* xrec;
|
xue@0
|
172 if (HS)
|
xue@0
|
173 {
|
xue@0
|
174 double t=GetTickCount();
|
xue@0
|
175 xrec=SynthesisHS(HS, dst, den);
|
xue@0
|
176 t=GetTickCount()-t;
|
xue@0
|
177 Label13->Caption=t;
|
xue@0
|
178 }
|
xue@0
|
179 int bips=WaveAudio1->BitsPerSample;
|
xue@0
|
180 double max=(1<<(bips-1)); for (int i=dst; i<den; i++) if (xrec[i]>max) max=xrec[i]; else if (xrec[i]<-max) max=-xrec[i];
|
xue@0
|
181 if (max>(1<<(bips-1)))
|
xue@0
|
182 {
|
xue@0
|
183 max=(1<<(bips-1))/max;
|
xue@0
|
184 for (int i=dst; i<den; i++) xrec[i]*=max;
|
xue@0
|
185 }
|
xue@0
|
186 int bps=bips/8;
|
xue@0
|
187 WaveAudio2->Clear(NULL);
|
xue@0
|
188 WaveAudio2->GetWaveProperties(WaveAudio1);
|
xue@0
|
189 if (HS)
|
xue@0
|
190 {
|
xue@0
|
191 if (dst<0) dst=0;
|
xue@0
|
192 void* data=new char[(den-dst)*bps];
|
xue@0
|
193 DoubleToInt(data, bps, xrec, den-dst);
|
xue@0
|
194
|
xue@0
|
195 WaveAudio2->Clear(NULL);
|
xue@0
|
196 WaveAudio2->WriteSamples(data, den-dst);
|
xue@0
|
197 free8(xrec);
|
xue@0
|
198 delete[] data;
|
xue@0
|
199 }
|
xue@0
|
200 }
|
xue@0
|
201
|
xue@0
|
202 //for frequency modulator shape
|
xue@0
|
203 void DrawsBarMap(Graphics::TBitmap* Bitmap, TRect Rect, int Count, double* data, bool res, int* KX1=0, int* KX2=0)
|
xue@0
|
204 {
|
xue@0
|
205 TCanvas* Canvas=Bitmap->Canvas;
|
xue@0
|
206 Bitmap->Width=Rect.Width();
|
xue@0
|
207 Bitmap->Height=Rect.Height();
|
xue@0
|
208
|
xue@0
|
209 TFont* F=Canvas->Font; F->Color=clWhite; F->Height=12; F->Name="Ariel";
|
xue@0
|
210 int fh=Canvas->TextHeight("0");
|
xue@0
|
211 int DrawCount=res?(Count+1):Count;
|
xue@0
|
212
|
xue@0
|
213 double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh;
|
xue@0
|
214 Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect);
|
xue@0
|
215 Canvas->Brush->Color=clAqua; Canvas->Pen->Color=clAqua; Canvas->Brush->Style=bsSolid;
|
xue@0
|
216 int empspace=XX/(DrawCount+1)/4;
|
xue@0
|
217 double r=0; for (int i=0; i<Count; i++) r+=data[i]*data[i];
|
xue@0
|
218
|
xue@0
|
219 double sqrtr=sqrt(r);
|
xue@0
|
220 double res_amp=(r>1)?0:sqrt(1-r);
|
xue@0
|
221 for (int i=0; i<DrawCount; i++)
|
xue@0
|
222 {
|
xue@0
|
223 double ldata;
|
xue@0
|
224 if (res)
|
xue@0
|
225 {
|
xue@0
|
226 if (i==0) ldata=data[i];
|
xue@0
|
227 else if (i<Count) ldata=data[i];
|
xue@0
|
228 else ldata=res_amp;
|
xue@0
|
229 }
|
xue@0
|
230 else ldata=data[i]/sqrtr;
|
xue@0
|
231 int X=floor(Bdw+XX*(i+1)/(DrawCount+1)+0.5);
|
xue@0
|
232 int Y=floor(Bdw+YY*(1-ldata)+0.5);
|
xue@0
|
233 if (empspace>=1)
|
xue@0
|
234 {
|
xue@0
|
235 Canvas->Brush->Style=bsSolid; Canvas->Brush->Color=TColor(0xFFFF00);
|
xue@0
|
236 Canvas->Rectangle(X-empspace, Y, X+empspace, Bdw+YY);
|
xue@0
|
237 if (KX1) KX1[i]=X-empspace, KX2[i]=X+empspace-1;
|
xue@0
|
238 }
|
xue@0
|
239 else
|
xue@0
|
240 {
|
xue@0
|
241 Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY);
|
xue@0
|
242 if (KX1) KX1[i]=X-1, KX2[i]=X+1;
|
xue@0
|
243 }
|
xue@0
|
244 AnsiString S=i; if (i>=Count) S="R"; int fw=Canvas->TextWidth(S);
|
xue@0
|
245 Canvas->Brush->Style=bsClear;
|
xue@0
|
246 Canvas->TextOut(X-fw/2, Bdw+YY, S);
|
xue@0
|
247 S.sprintf("%.3g", 100*ldata*ldata); if (S[1]=='0') S=S.SubString(2, S.Length()-1); fw=Canvas->TextWidth(S);
|
xue@0
|
248 if (Y-Bdw>fh) Canvas->TextOut(X-fw/2, Y-fh, S);
|
xue@0
|
249 else Canvas->TextOut(X+empspace+1, Y, S);
|
xue@0
|
250 }
|
xue@0
|
251 Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite;
|
xue@0
|
252 Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY);
|
xue@0
|
253 }
|
xue@0
|
254
|
xue@0
|
255 TColor RotateColors[10]={clWhite, clAqua, clLime, clYellow, clRed, clTeal, clGray, clGreen, clFuchsia, clBlue};
|
xue@0
|
256 //draw A-F distribution
|
xue@0
|
257 void DrawAF(Graphics::TBitmap* Bitmap, TRect Rect, double xst, double xen, double dbst, double dben, int M, int frst, int fren, atom** Partials, bool MA, bool bars, double sps, int TextHeight=12)
|
xue@0
|
258 {
|
xue@0
|
259 double log10e=1.0/log(10);
|
xue@0
|
260 Bitmap->Width=Rect.Width();
|
xue@0
|
261 Bitmap->Height=Rect.Height();
|
xue@0
|
262 TCanvas* Canvas=Bitmap->Canvas;
|
xue@0
|
263 double idbrange=1.0/(dbst-dben);
|
xue@0
|
264 TFont* F=Canvas->Font; F->Color=clWhite; F->Height=TextHeight; F->Name="Ariel";
|
xue@0
|
265 int fh=Canvas->TextHeight("0");
|
xue@0
|
266
|
xue@0
|
267 double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh;
|
xue@0
|
268 Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect);
|
xue@0
|
269
|
xue@0
|
270 Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5);
|
xue@0
|
271
|
xue@0
|
272 double *x=new double[(fren-frst)*4], *y=&x[fren-frst], *newa=&x[(fren-frst)*2], *neww=&x[(fren-frst)*3];
|
xue@0
|
273
|
xue@0
|
274 for (int m=0; m<M; m++)
|
xue@0
|
275 {
|
xue@0
|
276 Canvas->Pen->Color=RotateColors[m%10]; Canvas->Brush->Color=RotateColors[m%10];
|
xue@0
|
277
|
xue@0
|
278 int Sc=0;
|
xue@0
|
279 bool visible=false;
|
xue@0
|
280 atom* Partialsm=Partials[m];
|
xue@0
|
281 for (int fr=frst; fr<fren; fr++)
|
xue@0
|
282 {
|
xue@0
|
283 if (Partialsm[fr].f>0 && Partialsm[fr].a>0)
|
xue@0
|
284 {
|
xue@0
|
285 x[Sc]=Partials[m][fr].f;
|
xue@0
|
286 y[Sc]=20*(Log10(Partialsm[fr].a));
|
xue@0
|
287 if (x[Sc]<xen) visible=true;
|
xue@0
|
288 Sc++;
|
xue@0
|
289 }
|
xue@0
|
290 }
|
xue@0
|
291 if (!visible) break;
|
xue@0
|
292
|
xue@0
|
293 if (MA)
|
xue@0
|
294 {
|
xue@0
|
295 double fw;
|
xue@0
|
296 for (int c=0; c<Sc; c++) newa[c]=y[c], neww[c]=1;
|
xue@0
|
297 for (int c=0; c<Sc; c++)
|
xue@0
|
298 {
|
xue@0
|
299 fw=0.002; if (fw>x[c]*0.05) fw=x[c]*0.05;
|
xue@0
|
300
|
xue@0
|
301 for (int c1=0; c1<c; c1++)
|
xue@0
|
302 {
|
xue@0
|
303 double df=fabs(x[c]-x[c1]);
|
xue@0
|
304 if (df<fw)
|
xue@0
|
305 {
|
xue@0
|
306 double w=0.5+0.5*cos(M_PI*df/fw);
|
xue@0
|
307 newa[c]+=y[c1]*w; neww[c]+=w;
|
xue@0
|
308 newa[c1]+=y[c]*w; neww[c1]+=w;
|
xue@0
|
309 }
|
xue@0
|
310 }
|
xue@0
|
311 }
|
xue@0
|
312 for (int c=0; c<Sc; c++) y[c]=newa[c]/neww[c];
|
xue@0
|
313 }
|
xue@0
|
314
|
xue@0
|
315 for (int c=0; c<Sc; c++)
|
xue@0
|
316 {
|
xue@0
|
317 if (x[c]<xst || x[c]>xen) continue;
|
xue@0
|
318 double ldata=(y[c]-dben)*idbrange;
|
xue@0
|
319 int X=floor(Bdw+XX*(x[c]-xst)/(xen-xst)+0.5);
|
xue@0
|
320 int Y=floor(Bdw+YY*(1-ldata)+0.5);
|
xue@0
|
321 if (bars) {Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY);}
|
xue@0
|
322 else {Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2);}
|
xue@0
|
323 }
|
xue@0
|
324 }
|
xue@0
|
325
|
xue@0
|
326 AnsiString S=AnsiString().sprintf("%.2gkhz", sps*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
|
xue@0
|
327 S=AnsiString().sprintf("%.2gkhz", sps*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
|
xue@0
|
328 S=AnsiString().sprintf("%.2gkhz", sps*xen/1000); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S);
|
xue@0
|
329 S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S);
|
xue@0
|
330 S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S);
|
xue@0
|
331 S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S);
|
xue@0
|
332
|
xue@0
|
333 Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite;
|
xue@0
|
334 Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY);
|
xue@0
|
335
|
xue@0
|
336 delete[] x;
|
xue@0
|
337
|
xue@0
|
338 } //*/
|
xue@0
|
339 //for source-filter results
|
xue@0
|
340 void DrawSFr(Graphics::TBitmap* Bitmap, TRect Rect, double xst, double xen, double dbst, double dben, int M, int frst, int fren, atom** Partials, double* logA0C, double* b, double F, int K, double* h, int FScaleMode, double Fs, int TextHeight=12)
|
xue@0
|
341 {
|
xue@0
|
342 Bitmap->Width=Rect.Width();
|
xue@0
|
343 Bitmap->Height=Rect.Height();
|
xue@0
|
344 TCanvas* Canvas=Bitmap->Canvas;
|
xue@0
|
345 TFont* Ft=Canvas->Font; Ft->Color=clWhite; Ft->Height=TextHeight; Ft->Name="Ariel";
|
xue@0
|
346 int fh=Canvas->TextHeight("0");
|
xue@0
|
347
|
xue@0
|
348 double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh;
|
xue@0
|
349 Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect);
|
xue@0
|
350
|
xue@0
|
351 Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5);
|
xue@0
|
352
|
xue@0
|
353 double xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange,
|
xue@0
|
354 xrangeiXX=xrange/XX,
|
xue@0
|
355 YYidbrange=YY/(dbst-dben);
|
xue@0
|
356
|
xue@0
|
357 int *XRec=new int[XX];
|
xue@0
|
358 for (int m=0; m<M; m++)
|
xue@0
|
359 {
|
xue@0
|
360 bool visible=false;
|
xue@0
|
361 atom* Partialsm=Partials[m];
|
xue@0
|
362 Canvas->Brush->Color=RotateColors[m%10]; Canvas->Pen->Color=RotateColors[m%10];
|
xue@0
|
363 memset(XRec, 0, sizeof(int)*XX);
|
xue@0
|
364
|
xue@0
|
365 for (int fr=frst; fr<fren; fr++)
|
xue@0
|
366 {
|
xue@0
|
367 try{
|
xue@0
|
368 if (Partialsm[fr].f>0 && Partialsm[fr].a>0)
|
xue@0
|
369 {
|
xue@0
|
370 double xx=Partialsm[fr].f;
|
xue@0
|
371 if (xx<xen) visible=true;
|
xue@0
|
372 if (xx<xst || xx>xen) continue;
|
xue@0
|
373 int X=floor(XXixrange*xx-xstXXixrange+0.5);
|
xue@0
|
374 if (X>=0 && X<XX && !XRec[X])
|
xue@0
|
375 {
|
xue@0
|
376 XRec[X]=true;
|
xue@0
|
377 double logaf;
|
xue@0
|
378 //calculate LogAF
|
xue@0
|
379 if (FScaleMode) xx=log(1+xx*Fs/700)/log(1+Fs/700);
|
xue@0
|
380 int k=floor(xx/F); double f_plus=xx/F-k;
|
xue@0
|
381 if (k<K+1) logaf=h[k]*(1-f_plus)+h[k+1]*f_plus;
|
xue@0
|
382 else logaf=h[K+1];
|
xue@0
|
383
|
xue@0
|
384 double yy=20*log10e*(logaf+b[m]+logA0C[fr]);
|
xue@0
|
385 int Y=Bdw+floor((YY-YYidbrange*(yy-dben))+0.5);
|
xue@0
|
386 X+=Bdw;
|
xue@0
|
387 Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y);
|
xue@0
|
388 Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2);
|
xue@0
|
389 }
|
xue@0
|
390 }}catch(...)
|
xue@0
|
391 {int k=0;}
|
xue@0
|
392 }
|
xue@0
|
393 if (!visible) break;
|
xue@0
|
394 }
|
xue@0
|
395 delete[] XRec;
|
xue@0
|
396
|
xue@0
|
397 AnsiString S=AnsiString().sprintf("%.2gkhz", Fs*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
|
xue@0
|
398 S=AnsiString().sprintf("%.2gkhz", Fs*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
|
xue@0
|
399 S=AnsiString().sprintf("%.2gkhz", Fs*xen/1000); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S);
|
xue@0
|
400 S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S);
|
xue@0
|
401 S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S);
|
xue@0
|
402 S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S);
|
xue@0
|
403
|
xue@0
|
404 Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite;
|
xue@0
|
405 Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY);
|
xue@0
|
406 }
|
xue@0
|
407
|
xue@0
|
408 //*for source-filter model
|
xue@0
|
409 int DrawSF(Graphics::TBitmap* Bitmap, TRect Rect, double xst, double xen, double updb, double downdb, double f0, int M, double* b, double F, int K, double* h, int FScaleMode, double Fs=44100, int* SX=0, int* FX=0, int* FY=0, TColor* Colors=0, int TextHeight=12, int FShiftdB=0)
|
xue@0
|
410 {
|
xue@0
|
411 double FShift=FShiftdB/(20.0*log10e); //allowing the filter to be drawn with a vertical shift, and source an opposite shift
|
xue@0
|
412 Bitmap->Width=Rect.Width();
|
xue@0
|
413 Bitmap->Height=Rect.Height();
|
xue@0
|
414 TCanvas* Canvas=Bitmap->Canvas;
|
xue@0
|
415 double *Sx=new double[M];
|
xue@0
|
416 for (int i=0; i<M; i++) Sx[i]=20*log10e*(b[i]-FShift);
|
xue@0
|
417
|
xue@0
|
418 int result=0;
|
xue@0
|
419 TFont* Ft=Canvas->Font; Ft->Color=clWhite; Ft->Height=TextHeight; Ft->Name="Ariel";
|
xue@0
|
420 int fh=Canvas->TextHeight("0");
|
xue@0
|
421
|
xue@0
|
422 double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh;
|
xue@0
|
423 Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect);
|
xue@0
|
424 Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5);
|
xue@0
|
425
|
xue@0
|
426 double idbrange=1.0/(updb-downdb), xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange,
|
xue@0
|
427 YY20log10eidbrange=YY*20*log10e*idbrange, BdwpYYpYYdbenidbrange=Bdw+YY+YY*downdb*idbrange,
|
xue@0
|
428 Bdw_xstXXixrange=Bdw-xstXXixrange, YYidbrange=YY*idbrange;
|
xue@0
|
429
|
xue@0
|
430 double st=xst/F; int ist=ceil(st); if (ist<0) ist=0;
|
xue@0
|
431 Canvas->Pen->Color=clWhite;
|
xue@0
|
432 int X=Bdw+XX*(F*ist-xst)/xrange+0.5, Y=BdwpYYpYYdbenidbrange-YY20log10eidbrange*(h[ist]+FShift)+0.5;
|
xue@0
|
433 if (FX){FX[ist]=X, FY[ist]=Y; Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2);}
|
xue@0
|
434 Canvas->MoveTo(X, Y);
|
xue@0
|
435 //draw filter contour
|
xue@0
|
436 int LineCount=xrange/F;
|
xue@0
|
437 if (LineCount<XX)
|
xue@0
|
438 {
|
xue@0
|
439 for (int i=ist+1; i<K+2; i++)
|
xue@0
|
440 {
|
xue@0
|
441 double xi=F*i;
|
xue@0
|
442 if (FScaleMode)
|
xue@0
|
443 {
|
xue@0
|
444 double ximel=Amel*log(1+Fs/700)*xi;
|
xue@0
|
445 double xihz=700*(exp(ximel/Amel)-1);
|
xue@0
|
446 xi=xihz/Fs;
|
xue@0
|
447 }
|
xue@0
|
448 X=floor(Bdw_xstXXixrange+xi*XXixrange+0.5);
|
xue@0
|
449 Y=floor(BdwpYYpYYdbenidbrange-YY20log10eidbrange*(h[i]+FShift)+0.5);
|
xue@0
|
450 Canvas->LineTo(X, Y);
|
xue@0
|
451 if (FX){FX[i]=X, FY[i]=Y; Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2); Canvas->MoveTo(X, Y);}
|
xue@0
|
452 }
|
xue@0
|
453 }
|
xue@0
|
454 else
|
xue@0
|
455 {
|
xue@0
|
456 double di=xrange/(XX*F);
|
xue@0
|
457 for (int x=0; x<XX; x++)
|
xue@0
|
458 {
|
xue@0
|
459 int i;
|
xue@0
|
460 if (FScaleMode) i=log(1+(xst+xrange*x/XX)*Fs/700)/log(1+Fs/700)/F;
|
xue@0
|
461 else i=st+x*di;
|
xue@0
|
462 X=Bdw+x;
|
xue@0
|
463 Y=floor(BdwpYYpYYdbenidbrange-YY20log10eidbrange*(h[i]+FShift)+0.5);
|
xue@0
|
464 Canvas->LineTo(Bdw+x, Y);
|
xue@0
|
465 if (FX){FX[i]=X, FY[i]=Y; Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2); Canvas->MoveTo(X, Y);}
|
xue@0
|
466 }
|
xue@0
|
467 }
|
xue@0
|
468 //draw source lines
|
xue@0
|
469 for (int i=0; i<M; i++)
|
xue@0
|
470 {
|
xue@0
|
471 double xi=f0*(i+1);
|
xue@0
|
472 if (xi<xst || xi>xen) continue;
|
xue@0
|
473 int X=floor(Bdw_xstXXixrange+XXixrange*xi+0.5);
|
xue@0
|
474 int Y=floor(BdwpYYpYYdbenidbrange-YYidbrange*Sx[i]+0.5);
|
xue@0
|
475 if (Colors) Canvas->Pen->Color=Colors[i];
|
xue@0
|
476 else Canvas->Pen->Color=RotateColors[i%10];
|
xue@0
|
477
|
xue@0
|
478 Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY);
|
xue@0
|
479
|
xue@0
|
480 if (SX) SX[i]=X, result++;
|
xue@0
|
481 }
|
xue@0
|
482 AnsiString S=AnsiString().sprintf("%.2gkhz", Fs*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
|
xue@0
|
483 S=AnsiString().sprintf("%.2gkhz", Fs*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
|
xue@0
|
484 S=AnsiString().sprintf("%.2gkhz", Fs*xen/1000); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S);
|
xue@0
|
485 S.sprintf("%gdB", updb); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S);
|
xue@0
|
486 S.sprintf("%gdB", (updb+downdb)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S);
|
xue@0
|
487 S.sprintf("%gdB", downdb); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S);
|
xue@0
|
488
|
xue@0
|
489 Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite;
|
xue@0
|
490 Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY);
|
xue@0
|
491 delete[] Sx;
|
xue@0
|
492 return result;
|
xue@0
|
493 } //*/
|
xue@0
|
494
|
xue@0
|
495 void DrawF0(Graphics::TBitmap* Bitmap, TCanvas* Canvas, TRect Rect, double* lp, int P, double* F0, double f_c, double f_ex, double sps, double F0Overall, int Fr, atom** Partials, double L, bool Captions=true, TColor F0Color=clLime, bool peakmark=false, TColor peakmarkcolor=clYellow, double* frs=0, double* fs=0, int* BX1=0, int* BX2=0, int HLX1=0, int HLX2=0)
|
xue@0
|
496 {
|
xue@0
|
497 if (f_ex==0) f_ex=0.01;
|
xue@0
|
498 Canvas->Brush->Color=cl3DDkShadow; Canvas->FillRect(Rect);
|
xue@0
|
499 int Width=Rect.Width(), Height=Rect.Height();
|
xue@0
|
500 Bitmap->Width=Width; Bitmap->Height=Height;
|
xue@0
|
501 TPen* Pn=Canvas->Pen;
|
xue@0
|
502 TFont* F=Canvas->Font;
|
xue@0
|
503
|
xue@0
|
504 if (HLX1<HLX2)
|
xue@0
|
505 {
|
xue@0
|
506 Canvas->Brush->Color=clDkGray; Canvas->FillRect(TRect(HLX1, 0, HLX2, Height));
|
xue@0
|
507 Canvas->Brush->Color=cl3DDkShadow;
|
xue@0
|
508 }
|
xue@0
|
509
|
xue@0
|
510 int X, Y, Y1=0, Y2=Height, Y_;
|
xue@0
|
511 AnsiString S, as;
|
xue@0
|
512
|
xue@0
|
513 Pn->Color=clBlack; Pn->Style=psDot; F->Color=clBlack; F->Height=12; F->Name="Ariel";
|
xue@0
|
514 int lp0=ceil(lp[0]), lpp=ceil(lp[P-1]);
|
xue@0
|
515 double f0max=-0.5, f0min=0.5; for (int fr=lp0; fr<lpp; fr++){if (f0max<F0[fr]) f0max=F0[fr]; if (f0min>F0[fr]) f0min=F0[fr];}
|
xue@0
|
516 Y1=Height*(0.5-(f0max-f_c)/f_ex); Canvas->MoveTo(0, Y1); Canvas->LineTo(Width, Y1);
|
xue@0
|
517 if (Captions){as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f0max*sps)/C4)); S.sprintf("%.4ghz (%s)", f0max*sps, as.c_str()); Canvas->TextOut(1, Y1-Canvas->TextHeight(S)-1, S);}
|
xue@0
|
518 Y2=Height*(0.5-(f0min-f_c)/f_ex); Canvas->MoveTo(0, Y2); Canvas->LineTo(Width, Y2);
|
xue@0
|
519 if (Captions){as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f0min*sps)/C4)); S.sprintf("%.4ghz (%s)", f0min*sps, as.c_str()); Canvas->TextOut(1, Y2+1, S);}
|
xue@0
|
520
|
xue@0
|
521 if (peakmark)
|
xue@0
|
522 {
|
xue@0
|
523 int Y0=0.5*(Y1+Y2), Y0ex=0.5*(Y1-Y2);
|
xue@0
|
524
|
xue@0
|
525 for (int pfr=0; pfr<P; pfr++)
|
xue@0
|
526 {
|
xue@0
|
527 int fr=floor(lp[pfr]); double frplus=lp[pfr]-fr;
|
xue@0
|
528 X=Width*(Partials[1][fr].t*(1-frplus)+Partials[1][fr+1].t*frplus)/L;
|
xue@0
|
529 Pn->Color=peakmarkcolor; Pn->Style=psDot; Canvas->MoveTo(X, Y1); Canvas->LineTo(X, Y2);
|
xue@0
|
530 if (BX1) BX1[pfr]=X-1;
|
xue@0
|
531 if (BX2) BX2[pfr]=X+1;
|
xue@0
|
532 }
|
xue@0
|
533 }
|
xue@0
|
534
|
xue@0
|
535 if (Captions) {Y_=Height*(0.5-(F0Overall-f_c)/f_ex); Pn->Color=clWhite; Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_);}
|
xue@0
|
536
|
xue@0
|
537 Pn->Style=psSolid; Pn->Color=F0Color;
|
xue@0
|
538 for (int fr=0; fr<Fr; fr++)
|
xue@0
|
539 {
|
xue@0
|
540 if (fr>0) Canvas->MoveTo(X, Y);
|
xue@0
|
541 X=Width*Partials[1][fr].t/L, Y=Height*(0.5-(F0[fr]-f_c)/f_ex);
|
xue@0
|
542 if (fr>0) Canvas->LineTo(X, Y);
|
xue@0
|
543 }
|
xue@0
|
544
|
xue@0
|
545 if (frs)
|
xue@0
|
546 {
|
xue@0
|
547 Pn->Color=clRed;
|
xue@0
|
548 for (int pfr=0; pfr<P-1; pfr++)
|
xue@0
|
549 {
|
xue@0
|
550 int ifrs=frs[pfr]; double rfrs=frs[pfr]-ifrs;
|
xue@0
|
551 X=(Width*Partials[1][ifrs].t*(1-rfrs)+Width*Partials[1][ifrs+1].t*rfrs)/L, Y=Height*(0.5-(fs[pfr]-f_c)/f_ex);
|
xue@0
|
552 Canvas->MoveTo(X-4, Y); Canvas->LineTo(X+5, Y);
|
xue@0
|
553 Canvas->MoveTo(X, Y-4); Canvas->LineTo(X, Y+5);
|
xue@0
|
554 }
|
xue@0
|
555 }
|
xue@0
|
556
|
xue@0
|
557 if (Captions)
|
xue@0
|
558 {
|
xue@0
|
559 as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Overall*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Overall*sps, as.c_str());
|
xue@0
|
560 F->Color=clWhite; F->Style=F->Style<<fsBold; Canvas->TextOut(Width-Canvas->TextWidth(S), Y_+1, S); F->Style=F->Style>>fsBold;
|
xue@0
|
561 F->Color=clSilver; S="F0"; Canvas->TextOut(1, Height-Canvas->TextHeight(S), S);
|
xue@0
|
562 double f=(f_c+f_ex/2)*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str()); Canvas->TextOut(Width-Canvas->TextWidth(S), 0, S);
|
xue@0
|
563 f=(f_c-f_ex/2)*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str()); Canvas->TextOut(Width-Canvas->TextWidth(S), Height-Canvas->TextHeight(S), S);
|
xue@0
|
564 }
|
xue@0
|
565 }
|
xue@0
|
566
|
xue@0
|
567 void DrawF0C(Graphics::TBitmap* Bitmap, TCanvas* Canvas, TRect Rect, double* F0C, double& F0Cmax, double& F0Cmin, double f_c, double f_ex, double sps, double F0Overall, int Fr, atom** Partials, double L, bool clearbackground=true, int frcount=0, double* frs=0, double* fs=0, int* CX1=0, int* CX2=0, int* CY1=0, int* CY2=0)
|
xue@0
|
568 {
|
xue@0
|
569 if (f_ex==0) f_ex=f_c*0.005;
|
xue@0
|
570 //Draw the F0 carrier
|
xue@0
|
571 Canvas->Brush->Color=cl3DDkShadow; if (clearbackground) Canvas->FillRect(Rect);
|
xue@0
|
572 int Width=Rect.Width(), Height=Rect.Height();
|
xue@0
|
573 Bitmap->Width=Width; Bitmap->Height=Height;
|
xue@0
|
574 TPen* P=Canvas->Pen;
|
xue@0
|
575 TFont* F=Canvas->Font;
|
xue@0
|
576
|
xue@0
|
577 P->Color=clBlack;
|
xue@0
|
578 F0Cmax=f_c-f_ex, F0Cmin=f_c+f_ex;
|
xue@0
|
579 for (int fr=0; fr<Fr; fr++){if (F0Cmax<F0C[fr]) F0Cmax=F0C[fr]; if (F0Cmin>F0C[fr]) F0Cmin=F0C[fr];}
|
xue@0
|
580 P->Style=psDot;
|
xue@0
|
581 int X, Y=Height*(0.5-(F0Cmax-f_c)/f_ex);
|
xue@0
|
582 Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y);
|
xue@0
|
583 AnsiString as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Cmax*sps)/C4)); AnsiString S; S.sprintf("%.4ghz (%s)", F0Cmax*sps, as.c_str());
|
xue@0
|
584 F->Color=clBlack; F->Height=12; F->Name="Ariel"; Canvas->TextOut(1, Y-Canvas->TextHeight(S)-1, S);
|
xue@0
|
585 Y=Height*(0.5-(F0Cmin-f_c)/f_ex);
|
xue@0
|
586 Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y);
|
xue@0
|
587 as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Cmin*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Cmin*sps, as.c_str());
|
xue@0
|
588 Canvas->TextOut(1, Y+1, S);
|
xue@0
|
589 P->Color=clWhite;
|
xue@0
|
590 as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Overall*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Overall*sps, as.c_str());
|
xue@0
|
591 int Y_=Height*(0.5-(F0Overall-f_c)/f_ex);
|
xue@0
|
592 Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_);
|
xue@0
|
593 F->Color=clWhite; F->Style=F->Style<<fsBold;
|
xue@0
|
594 if (Y_+1+Canvas->TextHeight(S)<Y) Canvas->TextOut(Width-Canvas->TextWidth(S), Y_+1, S);
|
xue@0
|
595 else Canvas->TextOut(Width-Canvas->TextWidth(S), Y+1, S);
|
xue@0
|
596 F->Style=F->Style>>fsBold;
|
xue@0
|
597
|
xue@0
|
598 P->Style=psSolid; P->Color=clLime;
|
xue@0
|
599 for (int fr=0; fr<Fr; fr++)
|
xue@0
|
600 {
|
xue@0
|
601 if (fr>0) Canvas->MoveTo(X, Y);
|
xue@0
|
602 X=Width*Partials[1][fr].t/L, Y=Height*(0.5-(F0C[fr]-f_c)/f_ex);
|
xue@0
|
603 if (fr>0) Canvas->LineTo(X, Y);
|
xue@0
|
604 }
|
xue@0
|
605
|
xue@0
|
606 if (frcount)
|
xue@0
|
607 {
|
xue@0
|
608 P->Color=clRed;
|
xue@0
|
609 for (int p=0; p<frcount; p++)
|
xue@0
|
610 {
|
xue@0
|
611 int ifrs=frs[p]; double rfrs=frs[p]-ifrs;
|
xue@0
|
612 X=(Width*Partials[1][ifrs].t*(1-rfrs)+Width*Partials[1][ifrs+1].t*rfrs)/L, Y=Height*(0.5-(fs[p]-f_c)/f_ex);
|
xue@0
|
613 Canvas->MoveTo(X-4, Y); Canvas->LineTo(X+5, Y);
|
xue@0
|
614 Canvas->MoveTo(X, Y-4); Canvas->LineTo(X, Y+5);
|
xue@0
|
615 if (CX1) CX1[p]=X-4;
|
xue@0
|
616 if (CX2) CX2[p]=X+4;
|
xue@0
|
617 if (CY1) CY1[p]=Y-4;
|
xue@0
|
618 if (CY2) CY2[p]=Y+4;
|
xue@0
|
619 }
|
xue@0
|
620 }
|
xue@0
|
621
|
xue@0
|
622 double f=(f_c+f_ex/2)*sps;
|
xue@0
|
623 F->Color=clSilver;
|
xue@0
|
624 as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str());
|
xue@0
|
625 Canvas->TextOut(Width-Canvas->TextWidth(S), 0, S);
|
xue@0
|
626 f=(f_c-f_ex/2)*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str());
|
xue@0
|
627 Canvas->TextOut(Width-Canvas->TextWidth(S), Height-Canvas->TextHeight(S), S);
|
xue@0
|
628 F->Color=clSilver; S="F0 carrier";
|
xue@0
|
629 Canvas->TextOut(1, Height-Canvas->TextHeight(S), S);
|
xue@0
|
630 }
|
xue@0
|
631
|
xue@0
|
632 //y=ax+b
|
xue@0
|
633 void linefit(int n, double* x, double* y, double* indi, double& a, double& b)
|
xue@0
|
634 {
|
xue@0
|
635 double sx=0, sy=0, sxy=0, sxx=0, m=0;
|
xue@0
|
636 for (int i=0; i<n; i++) if (indi[i]>0) sx+=x[i], sy+=y[i], sxx+=x[i]*x[i], sxy+=x[i]*y[i], m++;
|
xue@0
|
637 if (m<=0) {a=-1; b=-1; return;}
|
xue@0
|
638 double id=1.0/(m*sxx-sx*sx);
|
xue@0
|
639 a=(m*sxy-sx*sy)*id;
|
xue@0
|
640 b=(sxx*sy-sx*sxy)*id;
|
xue@0
|
641 }
|
xue@0
|
642
|
xue@0
|
643
|
xue@0
|
644
|
xue@0
|
645 void TSFDemoForm::UpdateDisplay(bool f0, bool f0c, bool f0d, bool sf)
|
xue@0
|
646 {
|
xue@0
|
647 int Fr=HS->Fr;
|
xue@0
|
648 atom** Partials=HS->Partials;
|
xue@0
|
649 //find the highest point of the 2nd partial
|
xue@0
|
650 double f2min=1, f2max=0, fst=0, fen=fmaxEdit->Text.ToDouble();
|
xue@0
|
651 for (int fr=0; fr<Fr; fr++)
|
xue@0
|
652 {
|
xue@0
|
653 if (f2max<Partials[1][fr].f) f2max=Partials[1][fr].f;
|
xue@0
|
654 if (f2min>Partials[1][fr].f) f2min=Partials[1][fr].f;
|
xue@0
|
655 }
|
xue@0
|
656 f_c=(f2min+f2max)/4; f_ex=f2max-f2min;
|
xue@0
|
657
|
xue@0
|
658 if (f0)
|
xue@0
|
659 {
|
xue@0
|
660 int HLX1=0, HLX2=0;
|
xue@0
|
661 if (CurrentP>=0) HLX1=BX1[CurrentP]+1, HLX2=BX1[CurrentP+1]+1;
|
xue@0
|
662 DrawF0(Image0->Picture->Bitmap, Image0->Canvas, Image0->ClientRect, SF.lp, SF.P, SF.F0, f_c, f_ex, WaveView1->SamplesPerSec, SF.F0Overall, Fr, Partials, WaveView2->Length, true, clLime, true, clYellow, 0, cyclefs, BX1, BX2, HLX1, HLX2);
|
xue@0
|
663 }
|
xue@0
|
664 if (f0c)
|
xue@0
|
665 {
|
xue@0
|
666 memset(CX1, 0xFF, sizeof(int)*128); memset(CX2, 0xFF, sizeof(int)*128); memset(CY1, 0xFF, sizeof(int)*128); memset(CY1, 0xFF, sizeof(int)*128);
|
xue@0
|
667 DrawF0C(Image1->Picture->Bitmap, Image1->Canvas, Image1->ClientRect, SF.F0C, SF.F0Cmax, SF.F0Cmin, f_c, f_ex, WaveView1->SamplesPerSec, SF.F0Overall, Fr, Partials, WaveView2->Length, true, cyclefrcount, cyclefrs, cyclefs, CX1, CX2, CY1, CY2);
|
xue@0
|
668 }
|
xue@0
|
669 if (f0d)
|
xue@0
|
670 {
|
xue@0
|
671 //Draw the F0 modulator
|
xue@0
|
672 DrawModulator();
|
xue@0
|
673 }
|
xue@0
|
674
|
xue@0
|
675 if (sf)
|
xue@0
|
676 {
|
xue@0
|
677 int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]);
|
xue@0
|
678 double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble();
|
xue@0
|
679 dbrange=updb-downdb;
|
xue@0
|
680 if (SFCheck->Checked)
|
xue@0
|
681 DrawSFr(AImage1->Picture->Bitmap, AImage1->ClientRect, fst, fen, updb, downdb, SF.M, lp0, lpp, Partials, useA0?SF.logA0:SF.logA0C, SF.avgb, SF.F, SF.K, SF.avgh, SF.FScaleMode, SF.Fs);
|
xue@0
|
682 else
|
xue@0
|
683 DrawAF(AImage1->Picture->Bitmap, AImage1->ClientRect, fst, fen, updb, downdb, SF.M, lp0, lpp, Partials, MACheck->Checked, false, WaveView1->SamplesPerSec);
|
xue@0
|
684 dbrange=updb-downdb;
|
xue@0
|
685 SXc=DrawSF(AImage3->Picture->Bitmap, AImage3->ClientRect, fst, fen, updb+dbshift, downdb+dbshift, SF.F0Overall, SF.M, SF.avgb, SF.F, SF.K, SF.avgh, SF.FScaleMode, 44100, SX, FX, FY, 0, 12, FShiftdBEdit->Text.ToInt());
|
xue@0
|
686 }
|
xue@0
|
687
|
xue@0
|
688 ForceUpdate=false;
|
xue@0
|
689 }
|
xue@0
|
690
|
xue@0
|
691 void __fastcall TSFDemoForm::WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode)
|
xue@0
|
692 {
|
xue@0
|
693 if (Shift.Contains(ssShift)) OpMode=0; //drag mode
|
xue@0
|
694 else OpMode=1; //select mode
|
xue@0
|
695 }
|
xue@0
|
696
|
xue@0
|
697 int __fastcall TSFDemoForm::WaveView1CustomInfo(TObject* Sender)
|
xue@0
|
698 {
|
xue@0
|
699 TWaveView* WV=(TWaveView*)Sender;
|
xue@0
|
700 TStringList* List=new TStringList;
|
xue@0
|
701 double fs=WV->StartPos*1.0/WV->SamplesPerSec, fe=WV->EndPos*1.0/WV->SamplesPerSec;
|
xue@0
|
702 List->Add(AnsiString().sprintf(" Time (%.4gs): from %.4gs to %.4gs. ", fe-fs, fs, fe));
|
xue@0
|
703 List->Add(AnsiString().sprintf(" Frequency: from %.1fhz to %.1fhz. ", WV->StartDigiFreq*WV->SamplesPerSec, WV->EndDigiFreq*WV->SamplesPerSec));
|
xue@0
|
704 return int(List);
|
xue@0
|
705 }
|
xue@0
|
706
|
xue@0
|
707 void __fastcall TSFDemoForm::Image1MouseMove(TObject *Sender,
|
xue@0
|
708 TShiftState Shift, int X, int Y)
|
xue@0
|
709 {
|
xue@0
|
710 if (!HS) return;
|
xue@0
|
711 TImage* Image=(TImage*)Sender;
|
xue@0
|
712 Image->Parent->SetFocus();
|
xue@0
|
713
|
xue@0
|
714 double t, sps=WaveView1->SamplesPerSec, f; AnsiString S, as; TFont* F=Image->Canvas->Font;
|
xue@0
|
715
|
xue@0
|
716 if (Sender==Image0)
|
xue@0
|
717 {
|
xue@0
|
718 if (Shift.Contains(ssLeft))
|
xue@0
|
719 {
|
xue@0
|
720 if (CurrentB<0 || CurrentB>=SF.P) return;
|
xue@0
|
721 if (X<0 || X>=Image->Width || CurrentB>0 && X<=BX2[CurrentB-1] || CurrentB<SF.P-1 && X>=BX1[CurrentB+1]){}
|
xue@0
|
722 else
|
xue@0
|
723 {
|
xue@0
|
724 double dlp=1.0*(X-StartDragX)*SF.L/Image->Width;
|
xue@0
|
725 SF.lp[CurrentB]+=dlp;
|
xue@0
|
726 StartDragX=X;
|
xue@0
|
727 }
|
xue@0
|
728 }
|
xue@0
|
729 else
|
xue@0
|
730 {
|
xue@0
|
731 CurrentB=-1;
|
xue@0
|
732 for (int i=0; i<SF.P; i++) if (X>=BX1[i] && X<=BX2[i]) {CurrentB=i; break;}
|
xue@0
|
733 }
|
xue@0
|
734 }
|
xue@0
|
735 else if (Sender==Image1)
|
xue@0
|
736 {
|
xue@0
|
737 if (Shift.Contains(ssLeft))
|
xue@0
|
738 {
|
xue@0
|
739 if (CurrentC<0 || CurrentC>=cyclefrcount) return;
|
xue@0
|
740 double df=-(Y-StartDrag)*f_ex/Image->Height;
|
xue@0
|
741 cyclefs[CurrentC]+=df;
|
xue@0
|
742 StartDrag=Y;
|
xue@0
|
743 Smooth_Interpolate(SF.F0C, SF.L, cyclefrcount+1, cyclefs, cyclefrs);
|
xue@0
|
744 SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
|
xue@0
|
745 UpdateDisplay(true, true, true, false);
|
xue@0
|
746
|
xue@0
|
747 t=HS->Partials[0][0].t+SF.offst*cyclefrs[CurrentC];
|
xue@0
|
748 f=cyclefs[CurrentC]*sps;
|
xue@0
|
749 as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4));
|
xue@0
|
750 S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str());
|
xue@0
|
751 F->Color=clRed;
|
xue@0
|
752 Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
|
xue@0
|
753 }
|
xue@0
|
754 else
|
xue@0
|
755 {
|
xue@0
|
756 CurrentC=-1;
|
xue@0
|
757 for (int i=0; i<cyclefrcount; i++)
|
xue@0
|
758 if (X>=CX1[i] && X<=CX2[i] && Y>=CY1[i] && Y<=CY2[i]) {CurrentC=i; break;}
|
xue@0
|
759 }
|
xue@0
|
760 if (CurrentC>=0 && CurrentC<cyclefrcount)
|
xue@0
|
761 {
|
xue@0
|
762 t=HS->Partials[0][0].t+SF.offst*cyclefrs[CurrentC];
|
xue@0
|
763 f=cyclefs[CurrentC]*sps;
|
xue@0
|
764 as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4));
|
xue@0
|
765 S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str());
|
xue@0
|
766 F->Color=clRed;
|
xue@0
|
767 Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
|
xue@0
|
768 }
|
xue@0
|
769 else
|
xue@0
|
770 {
|
xue@0
|
771 S.sprintf(" ", t/sps, f, as.c_str());
|
xue@0
|
772 Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
|
xue@0
|
773 }
|
xue@0
|
774 }
|
xue@0
|
775
|
xue@0
|
776 t=WaveView2->Length*1.0*(X+0.5)/Image->Width;
|
xue@0
|
777 f=(f_c-(Y-0.5*Image->Height)*f_ex/Image->Height)*sps;
|
xue@0
|
778 as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4));
|
xue@0
|
779 S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str());
|
xue@0
|
780 F->Color=clAqua; F->Height=12; F->Name="Ariel";
|
xue@0
|
781 Image->Canvas->TextOut(1, 0, S);
|
xue@0
|
782
|
xue@0
|
783
|
xue@0
|
784 if (Sender==Image0)
|
xue@0
|
785 {
|
xue@0
|
786 int Wid=HS->Partials[0][1].s, hWid=Wid/2, Offst=HS->Partials[0][1].t-HS->Partials[0][0].t;
|
xue@0
|
787 CurrentFr=(t-hWid)/Offst+0.5;
|
xue@0
|
788 if (!Shift.Contains(ssLeft)) CurrentP=-1; while (CurrentP<SF.P-1 && CurrentFr>SF.lp[CurrentP+1]) CurrentP++; if (CurrentP>=SF.P-1) CurrentP=-1;
|
xue@0
|
789
|
xue@0
|
790 if (CurrentP>=0)
|
xue@0
|
791 {
|
xue@0
|
792 PageControl1->ActivePage=AmpCycleSheet;
|
xue@0
|
793 SFCheck->Parent=Panel14;
|
xue@0
|
794 MACheck->Parent=Panel14;
|
xue@0
|
795 }
|
xue@0
|
796 else
|
xue@0
|
797 {
|
xue@0
|
798 PageControl1->ActivePage=AmpOverSheet;
|
xue@0
|
799 SFCheck->Parent=Panel12;
|
xue@0
|
800 MACheck->Parent=Panel12;
|
xue@0
|
801 }
|
xue@0
|
802 UpdateDisplay(true, 0, CurrentP>=0, 0);
|
xue@0
|
803
|
xue@0
|
804 if (CurrentB>=0 && CurrentB<SF.P)
|
xue@0
|
805 {
|
xue@0
|
806 t=HS->Partials[0][0].t+SF.offst*SF.lp[CurrentB];
|
xue@0
|
807 S.sprintf("%.3gs", t/sps);
|
xue@0
|
808 F->Color=clYellow;
|
xue@0
|
809 Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
|
xue@0
|
810 }
|
xue@0
|
811 else
|
xue@0
|
812 {
|
xue@0
|
813 S.sprintf(" ");
|
xue@0
|
814 Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
|
xue@0
|
815 }
|
xue@0
|
816 }
|
xue@0
|
817 }
|
xue@0
|
818 //---------------------------------------------------------------------------
|
xue@0
|
819
|
xue@0
|
820 void TSFDemoForm::DrawModulator()
|
xue@0
|
821 {
|
xue@0
|
822 if (PageControl1->ActivePage==AmpCycleSheet && CurrentP>=0 && CurrentP<SF.P-1)
|
xue@0
|
823 {
|
xue@0
|
824 double fst=0, fen=fmaxEdit->Text.ToDouble();
|
xue@0
|
825 int lp0=ceil(SF.lp[0]);
|
xue@0
|
826 double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble();
|
xue@0
|
827 dbrange=updb-downdb;
|
xue@0
|
828 if (SFCheck->Checked)
|
xue@0
|
829 DrawSFr(AImage2->Picture->Bitmap, AImage2->ClientRect, fst, fen, updb, downdb, SF.M, ceil(SF.lp[CurrentP]), ceil(SF.lp[CurrentP+1]), HS->Partials, useA0?SF.logA0:SF.logA0C, SF.b[CurrentFr-lp0], SF.F, SF.K, SF.h[CurrentFr-lp0], SF.FScaleMode, SF.Fs);
|
xue@0
|
830 else
|
xue@0
|
831 DrawAF(AImage2->Picture->Bitmap, AImage2->ClientRect, fst, fen, updb, downdb, SF.M, ceil(SF.lp[CurrentP]), ceil(SF.lp[CurrentP+1]), HS->Partials, MACheck->Checked, false, WaveView1->SamplesPerSec);
|
xue@0
|
832 dbrange=updb-downdb;
|
xue@0
|
833 SXcyclec=DrawSF(AImage4->Picture->Bitmap, AImage4->ClientRect, fst, fen, updb+dbshift, downdb+dbshift, SF.F0[CurrentFr], SF.M, SF.b[CurrentFr-lp0], SF.F, SF.K, SF.h[CurrentFr-lp0], SF.FScaleMode, SF.Fs, SXcycle, 0, 0, 0, 12, FShiftdBEdit->Text.ToInt());
|
xue@0
|
834 }
|
xue@0
|
835 }
|
xue@0
|
836
|
xue@0
|
837
|
xue@0
|
838 void __fastcall TSFDemoForm::SFCheckClick(TObject *Sender)
|
xue@0
|
839 {
|
xue@0
|
840 if (Sender==SFCheck)
|
xue@0
|
841 {
|
xue@0
|
842 MACheck->Visible=!SFCheck->Checked;
|
xue@0
|
843 }
|
xue@0
|
844 UpdateDisplay();
|
xue@0
|
845 }
|
xue@0
|
846 //---------------------------------------------------------------------------
|
xue@0
|
847
|
xue@0
|
848
|
xue@0
|
849 void __fastcall TSFDemoForm::ExternalInput()
|
xue@0
|
850 {
|
xue@0
|
851 AnsiString FileName=ExtractFilePath(Application->ExeName)+"tsfin";
|
xue@0
|
852 FILE* file;
|
xue@0
|
853 if (file=fopen(FileName.c_str(), "rb"))
|
xue@0
|
854 {
|
xue@0
|
855 SF.LoadFromFileHandle(file);
|
xue@0
|
856 fclose(file);
|
xue@0
|
857 DeleteFile(FileName);
|
xue@0
|
858 SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
|
xue@0
|
859
|
xue@0
|
860 SaveSF();
|
xue@0
|
861 Synthesize();
|
xue@0
|
862 UpdateDisplay();
|
xue@0
|
863 }
|
xue@0
|
864 }
|
xue@0
|
865
|
xue@0
|
866 //---------------------------------------------------------------------------
|
xue@0
|
867 void __fastcall TSFDemoForm::SaveSF()
|
xue@0
|
868 {
|
xue@0
|
869 FILE* file;
|
xue@0
|
870 if (file=fopen((ExtractFilePath(Application->ExeName)+"tsfout").c_str(), "wb"))
|
xue@0
|
871 {
|
xue@0
|
872 SF.SaveToFileHandle(file);
|
xue@0
|
873 fclose(file);
|
xue@0
|
874 }
|
xue@0
|
875 }
|
xue@0
|
876
|
xue@0
|
877 void __fastcall TSFDemoForm::SaveSF0()
|
xue@0
|
878 {
|
xue@0
|
879 SF0.Duplicate(SF);
|
xue@0
|
880 }
|
xue@0
|
881
|
xue@0
|
882 void __fastcall TSFDemoForm::SaveWave()
|
xue@0
|
883 {
|
xue@0
|
884 THS* HS=Form1->HS; int dst, den;
|
xue@0
|
885 double* xrec=SynthesisHSp(HS, dst, den);
|
xue@0
|
886 delete[] Wave1; Wave1=new __int16[WaveView2->Length];
|
xue@0
|
887 DoubleToInt(Wave1, 2, xrec, den-dst);
|
xue@0
|
888 free8(xrec);
|
xue@0
|
889 }
|
xue@0
|
890 //---------------------------------------------------------------------------
|
xue@0
|
891 void __fastcall TSFDemoForm::MouseWheelHandler(TMessage& Msg)
|
xue@0
|
892 {
|
xue@0
|
893 TWMMouseWheel* WMsg=(TWMMouseWheel*)&Msg;
|
xue@0
|
894
|
xue@0
|
895 bool Handled=false;
|
xue@0
|
896 TMouseWheelEvent Event=NULL;
|
xue@0
|
897 TControl* Sender;
|
xue@0
|
898 TShiftState Shift; memcpy(&Shift, &WMsg->Keys, 1);
|
xue@0
|
899
|
xue@0
|
900 if (ActiveControl==Image1->Parent) Event=Image1MouseWheel, Sender=Image1;
|
xue@0
|
901 else if (ActiveControl==AImage3->Parent) Event=AImage3MouseWheel, Sender=AImage3;
|
xue@0
|
902 else if (ActiveControl==AImage1->Parent) Event=AImage3MouseWheel, Sender=AImage1;
|
xue@0
|
903
|
xue@0
|
904 if (Event) Event(Sender, Shift, WMsg->WheelDelta, Sender->ScreenToClient(TPoint(WMsg->Pos.x, WMsg->Pos.y)), Handled);
|
xue@0
|
905 WMsg->Result=Handled;
|
xue@0
|
906
|
xue@0
|
907 if (!Handled) TCustomForm::MouseWheelHandler(Msg);
|
xue@0
|
908 }
|
xue@0
|
909
|
xue@0
|
910 //---------------------------------------------------------------------------
|
xue@0
|
911 void __fastcall TSFDemoForm::Image1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
|
xue@0
|
912 {
|
xue@0
|
913 double cent;
|
xue@0
|
914 if (Shift.Contains(ssShift)) cent=1;
|
xue@0
|
915 else if (Shift.Contains(ssCtrl)) cent=100;
|
xue@0
|
916 else cent=10;
|
xue@0
|
917
|
xue@0
|
918 if (WheelDelta<0) cent=-cent;
|
xue@0
|
919 double rate=pow(2, cent/1200);
|
xue@0
|
920
|
xue@0
|
921 for (int l=0; l<SF.L; l++) SF.F0C[l]*=rate, SF.F0D[l]*=rate; SF.F0Overall*=rate;
|
xue@0
|
922 for (int fr=0; fr<cyclefrcount; fr++) cyclefs[fr]*=rate;
|
xue@0
|
923
|
xue@0
|
924 SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
|
xue@0
|
925 SaveSF();
|
xue@0
|
926 S_U();
|
xue@0
|
927 Handled=true;
|
xue@0
|
928 }
|
xue@0
|
929
|
xue@0
|
930 void __fastcall TSFDemoForm::AImage3MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
|
xue@0
|
931 {
|
xue@0
|
932 double ddb;
|
xue@0
|
933 if (Shift.Contains(ssShift)) ddb=0.2;
|
xue@0
|
934 else if (Shift.Contains(ssCtrl)) ddb=5;
|
xue@0
|
935 else ddb=1;
|
xue@0
|
936 double db=20*log10e*SF.avgb[CurrentPartial];
|
xue@0
|
937 if (WheelDelta<0) ddb=-ddb;
|
xue@0
|
938
|
xue@0
|
939 db+=ddb;
|
xue@0
|
940 AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
|
xue@0
|
941 Label7->Caption=S;
|
xue@0
|
942 ddb=ddb/(20*log10e);
|
xue@0
|
943
|
xue@0
|
944 int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]);
|
xue@0
|
945 for (int l=0; l<lpp-lp0; l++) SF.b[l][CurrentPartial]+=ddb;
|
xue@0
|
946 SF.avgb[CurrentPartial]+=ddb;
|
xue@0
|
947
|
xue@0
|
948 SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
|
xue@0
|
949 SaveSF();
|
xue@0
|
950 S_U(true);
|
xue@0
|
951 Handled=true;
|
xue@0
|
952 }
|
xue@0
|
953
|
xue@0
|
954
|
xue@0
|
955 //---------------------------------------------------------------------------
|
xue@0
|
956 void __fastcall TSFDemoForm::AImage3MouseMove(TObject *Sender,
|
xue@0
|
957 TShiftState Shift, int X, int Y)
|
xue@0
|
958 {
|
xue@0
|
959 if (!HS) return;
|
xue@0
|
960 TImage* Image=(TImage*)Sender;
|
xue@0
|
961 int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]);
|
xue@0
|
962
|
xue@0
|
963 if (Shift.Contains(ssLeft))
|
xue@0
|
964 {
|
xue@0
|
965 if (CurrentFB<0 && CurrentPartial<0) return;
|
xue@0
|
966 int fh=Image->Canvas->TextHeight("0");
|
xue@0
|
967 int YY=Image->Height-Bdw-Bdwc-fh;
|
xue@0
|
968 double dbperpixel=dbrange/YY;
|
xue@0
|
969 int dY=Y-StartDrag;
|
xue@0
|
970 if (dY==0) return;
|
xue@0
|
971 StartDrag=Y;
|
xue@0
|
972 double ddb=-dY*dbperpixel;
|
xue@0
|
973
|
xue@0
|
974 if (Sender==AImage3 && CurrentFB>=0)
|
xue@0
|
975 {
|
xue@0
|
976 double db=20*log10e*SF.avgh[CurrentPartial];
|
xue@0
|
977 db+=ddb;
|
xue@0
|
978 AnsiString S; S.sprintf("Filter control %d: %.2fdB", CurrentFB, db);
|
xue@0
|
979 Label7->Caption=S;
|
xue@0
|
980 ddb=ddb/(20*log10e);
|
xue@0
|
981
|
xue@0
|
982 for (int l=0; l<lpp-lp0; l++) SF.h[l][CurrentFB]+=ddb;
|
xue@0
|
983 SF.avgh[CurrentFB]+=ddb;
|
xue@0
|
984
|
xue@0
|
985 if (Shift.Contains(ssShift))
|
xue@0
|
986 for (int k=CurrentFB+1; k<=SF.K+1; k++) {for (int l=0; l<lpp-lp0; l++) SF.h[l][k]+=ddb; SF.avgh[k]+=ddb;}
|
xue@0
|
987 if (Shift.Contains(ssCtrl)) {S_F_b(SF, HS->Partials); SaveSF0();}
|
xue@0
|
988 }
|
xue@0
|
989 else if (Sender==AImage1 || Sender==AImage3)
|
xue@0
|
990 {
|
xue@0
|
991 double db=20*log10e*SF.avgb[CurrentPartial];
|
xue@0
|
992 db+=ddb;
|
xue@0
|
993 AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
|
xue@0
|
994 Label7->Caption=S;
|
xue@0
|
995 ddb=ddb/(20*log10e);
|
xue@0
|
996
|
xue@0
|
997 for (int l=0; l<lpp-lp0; l++) SF.b[l][CurrentPartial]+=ddb;
|
xue@0
|
998 SF.avgb[CurrentPartial]+=ddb;
|
xue@0
|
999
|
xue@0
|
1000 int dm=0; for (int i=0x31; i<0x3a; i++) if (GetKeyState(i)<0) dm+=(i-0x30);
|
xue@0
|
1001 if (dm==0 && Shift.Contains(ssShift)) dm=CurrentPartial+1;
|
xue@0
|
1002 if (dm>0) for (int m=CurrentPartial+dm; m<SF.M; m+=dm){for (int l=0; l<lpp-lp0; l++) SF.b[l][m]+=ddb; SF.avgb[m]+=ddb;}
|
xue@0
|
1003 }
|
xue@0
|
1004 else if (Sender==AImage2 || Sender==AImage4)
|
xue@0
|
1005 {
|
xue@0
|
1006 if (CurrentFr>=lp0 && CurrentFr<lpp)
|
xue@0
|
1007 {
|
xue@0
|
1008 double db=20*log10e*SF.b[CurrentFr-lp0][CurrentPartial];
|
xue@0
|
1009 db+=ddb;
|
xue@0
|
1010 AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
|
xue@0
|
1011 Label8->Caption=S;
|
xue@0
|
1012 ddb=ddb/(20*log10e);
|
xue@0
|
1013
|
xue@0
|
1014 SF.b[CurrentFr-lp0][CurrentPartial]+=ddb;
|
xue@0
|
1015 }
|
xue@0
|
1016 }
|
xue@0
|
1017
|
xue@0
|
1018 SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
|
xue@0
|
1019 UpdateDisplay();
|
xue@0
|
1020 }
|
xue@0
|
1021 else
|
xue@0
|
1022 {
|
xue@0
|
1023 Image->Parent->SetFocus();
|
xue@0
|
1024
|
xue@0
|
1025 int lSXc, *lSX;
|
xue@0
|
1026 double* LogAS;
|
xue@0
|
1027 if (Sender==AImage1 || Sender==AImage3) lSXc=SXc, lSX=SX, LogAS=SF.avgb, X=Bdw+(X-Bdw)*AImage3->Width/((TImage*)Sender)->Width;
|
xue@0
|
1028 else if (Sender==AImage2 || Sender==AImage4)
|
xue@0
|
1029 {
|
xue@0
|
1030 if (CurrentFr<lp0 || CurrentFr>=lpp) return;
|
xue@0
|
1031 lSXc=SXcyclec, lSX=SXcycle, LogAS=SF.b[CurrentFr-lp0], X=Bdw+(X-Bdw)*AImage4->Width/((TImage*)Sender)->Width;
|
xue@0
|
1032 }
|
xue@0
|
1033
|
xue@0
|
1034 if (lSXc<=0) return;
|
xue@0
|
1035
|
xue@0
|
1036 CurrentPartial=0; while (CurrentPartial<lSXc && lSX[CurrentPartial]<X) CurrentPartial++;
|
xue@0
|
1037 if (CurrentPartial>=lSXc) CurrentPartial=lSXc-1;
|
xue@0
|
1038 if (CurrentPartial>=1 && X-lSX[CurrentPartial-1]<lSX[CurrentPartial]-X) CurrentPartial--;
|
xue@0
|
1039 CurrentFB=-1; int lfb=0; while (lfb<=SF.K && X>FX[lfb]) lfb++;
|
xue@0
|
1040 if (Sender==AImage3)
|
xue@0
|
1041 {
|
xue@0
|
1042 if (X>=FX[lfb]-ftrr && X<=FX[lfb]+ftrr && Y>=FY[lfb]-ftrr && Y<=FY[lfb]+ftrr) CurrentFB=lfb;
|
xue@0
|
1043 if (X>=FX[lfb-1]-ftrr && X<=FX[lfb-1]+ftrr && Y>=FY[lfb-1]-ftrr && Y<=FY[lfb-1]+ftrr)
|
xue@0
|
1044 {
|
xue@0
|
1045 if (CurrentFB==-1) CurrentFB=lfb-1;
|
xue@0
|
1046 else if (abs(X-FX[lfb-1])<abs(X-FX[lfb])) CurrentFB=lfb-1;
|
xue@0
|
1047 }
|
xue@0
|
1048 }
|
xue@0
|
1049
|
xue@0
|
1050 TLabel* Label; AnsiString S;
|
xue@0
|
1051 if (Sender==AImage1 || Sender==AImage3) Label=Label7;
|
xue@0
|
1052 else if (Sender==AImage2 || Sender==AImage4) Label=Label8;
|
xue@0
|
1053
|
xue@0
|
1054 if (CurrentFB>=0)
|
xue@0
|
1055 {
|
xue@0
|
1056 S.sprintf("Filter control %d: %.2fdB", CurrentFB, 20*log10e*SF.avgh[CurrentFB]);
|
xue@0
|
1057 Label->Font->Color=clWhite;
|
xue@0
|
1058 }
|
xue@0
|
1059 else
|
xue@0
|
1060 {
|
xue@0
|
1061 double dB=20*log10e*LogAS[CurrentPartial];
|
xue@0
|
1062 S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, dB);
|
xue@0
|
1063 Label->Font->Color=RotateColors[CurrentPartial%10];
|
xue@0
|
1064 }
|
xue@0
|
1065 Label->Caption=S;
|
xue@0
|
1066 }
|
xue@0
|
1067 }
|
xue@0
|
1068 //---------------------------------------------------------------------------
|
xue@0
|
1069
|
xue@0
|
1070
|
xue@0
|
1071 void __fastcall TSFDemoForm::AImage1MouseDown(TObject *Sender,
|
xue@0
|
1072 TMouseButton Button, TShiftState Shift, int X, int Y)
|
xue@0
|
1073 {
|
xue@0
|
1074 FirstStartDrag=StartDrag=Y;
|
xue@0
|
1075 FirstStartDragX=StartDragX=X;
|
xue@0
|
1076 if (Sender==Image0 && Shift.Contains(ssShift))
|
xue@0
|
1077 {
|
xue@0
|
1078 if (CurrentB>=0) //delete current peakmark
|
xue@0
|
1079 {
|
xue@0
|
1080 for (int p=CurrentB; p<SF.P-1; p++) SF.lp[p]=SF.lp[p+1];
|
xue@0
|
1081 SF.P--;
|
xue@0
|
1082 CurrentB=-1;
|
xue@0
|
1083 UpdateDisplay(1, 0, 0, 0);
|
xue@0
|
1084 analyze2=true;
|
xue@0
|
1085 }
|
xue@0
|
1086 else
|
xue@0
|
1087 {
|
xue@0
|
1088 double newlpb=1.0*X/Image0->Width*SF.L, *newlp=new double[SF.P+3];
|
xue@0
|
1089 int newb=0; while (newb<SF.P && X>BX1[newb]) newb++;
|
xue@0
|
1090
|
xue@0
|
1091 if (newb>0) memcpy(newlp, SF.lp, sizeof(double)*newb);
|
xue@0
|
1092 if (newb<SF.P) memcpy(&newlp[newb+1], &SF.lp[newb], sizeof(double)*(SF.P-newb));
|
xue@0
|
1093 newlp[newb]=newlpb;
|
xue@0
|
1094 CurrentB=newb;
|
xue@0
|
1095 SF.P++;
|
xue@0
|
1096 delete[] SF.lp; SF.lp=newlp;
|
xue@0
|
1097 UpdateDisplay(1, 0, 0, 0);
|
xue@0
|
1098 analyze2=true;
|
xue@0
|
1099 }
|
xue@0
|
1100 }
|
xue@0
|
1101 if ((Sender==AImage2 || Sender==AImage4) && Shift.Contains(ssRight))
|
xue@0
|
1102 PageControl1->ActivePage=AmpOverSheet;
|
xue@0
|
1103 }
|
xue@0
|
1104 //---------------------------------------------------------------------------
|
xue@0
|
1105
|
xue@0
|
1106 void __fastcall TSFDemoForm::AImage1MouseUp(TObject *Sender,
|
xue@0
|
1107 TMouseButton Button, TShiftState Shift, int X, int Y)
|
xue@0
|
1108 {
|
xue@0
|
1109 if (Sender==Image0 && (CurrentB>=0 && X!=FirstStartDragX || analyze2))
|
xue@0
|
1110 {
|
xue@0
|
1111 //do analysis using the new segmentation
|
xue@0
|
1112 double sps=WaveView1->SamplesPerSec;
|
xue@0
|
1113 double h=WaveView1->SpecOffst;
|
xue@0
|
1114 int FSMode=MethodListBox->ItemIndex;
|
xue@0
|
1115 double FSF=FEdit->Text.ToDouble();
|
xue@0
|
1116 int FSFScale=FScaleCombo->ItemIndex;
|
xue@0
|
1117 if (FSFScale==0) FSF/=sps;
|
xue@0
|
1118 else FSF/=Amel*log(1+sps/700);
|
xue@0
|
1119 double FStheta=ThetaEdit->Text.ToDouble();
|
xue@0
|
1120 AnalyzeSF_2(*HS, SF, cyclefrs, cyclefs, sps, &cyclefrcount, FSMode, FSF, FSFScale, FStheta);
|
xue@0
|
1121 SaveSF0();
|
xue@0
|
1122 SaveSF();
|
xue@0
|
1123 S_U(true);
|
xue@0
|
1124 UpdateDisplay();
|
xue@0
|
1125 analyze2=false;
|
xue@0
|
1126 }
|
xue@0
|
1127 else if (Y!=FirstStartDrag)
|
xue@0
|
1128 {
|
xue@0
|
1129 SaveSF();
|
xue@0
|
1130 S_U();
|
xue@0
|
1131 UpdateDisplay();
|
xue@0
|
1132 }
|
xue@0
|
1133 }
|
xue@0
|
1134 //---------------------------------------------------------------------------
|
xue@0
|
1135
|
xue@0
|
1136
|
xue@0
|
1137 //---------------------------------------------------------------------------
|
xue@0
|
1138
|
xue@0
|
1139 void __fastcall TSFDemoForm::PageControl1Change(TObject *Sender)
|
xue@0
|
1140 {
|
xue@0
|
1141 if (PageControl1->ActivePage==AmpOverSheet)
|
xue@0
|
1142 {
|
xue@0
|
1143 SFCheck->Parent=Panel12;
|
xue@0
|
1144 MACheck->Parent=Panel12;
|
xue@0
|
1145 }
|
xue@0
|
1146 else
|
xue@0
|
1147 {
|
xue@0
|
1148 SFCheck->Parent=Panel14;
|
xue@0
|
1149 MACheck->Parent=Panel14;
|
xue@0
|
1150 }
|
xue@0
|
1151 UpdateDisplay();
|
xue@0
|
1152 }
|
xue@0
|
1153 //---------------------------------------------------------------------------
|
xue@0
|
1154
|
xue@0
|
1155 void __fastcall TSFDemoForm::SaveButtonClick(TObject *Sender)
|
xue@0
|
1156 {
|
xue@0
|
1157 int k=1; AnsiString FileName="1.sf";
|
xue@0
|
1158 while (TmplListBox->Items->IndexOf(FileName)>=0) {k++; FileName=AnsiString(k)+".sf";}
|
xue@0
|
1159 if (GetKeyState(VK_SHIFT)<0)
|
xue@0
|
1160 {
|
xue@0
|
1161 AnsiString oldpath=SaveDialog1->InitialDir;
|
xue@0
|
1162 SaveDialog1->InitialDir=ExtractFileDir(Application->ExeName);
|
xue@0
|
1163 if (SaveDialog1->Execute()) FileName=SaveDialog1->FileName;
|
xue@0
|
1164 SaveDialog1->InitialDir=oldpath;
|
xue@0
|
1165 }
|
xue@0
|
1166 else FileName=ExtractFilePath(Application->ExeName)+FileName;
|
xue@0
|
1167 SF.SaveToFile(FileName.c_str());
|
xue@0
|
1168 TmplListBox->Items->Add(ExtractFileName(FileName));
|
xue@0
|
1169 }
|
xue@0
|
1170 //---------------------------------------------------------------------------
|
xue@0
|
1171
|
xue@0
|
1172
|
xue@0
|
1173 //calculates increment dh on sf1.avgh so that it becomes sf2.avgh
|
xue@0
|
1174 // dh should have the same dimenstions as sf1.avgh
|
xue@0
|
1175 void* CompareFilters(double* dh, TSF& sf1, TSF& sf2)
|
xue@0
|
1176 {
|
xue@0
|
1177 int K1=sf1.K, FScale1=sf1.FScaleMode;
|
xue@0
|
1178 double F1=sf1.F, Fs=sf1.Fs;
|
xue@0
|
1179 for (int k=0; k<K1+2; k++)
|
xue@0
|
1180 {
|
xue@0
|
1181 double h1=sf1.avgh[k], f=F1*k;
|
xue@0
|
1182 if (FScale1)
|
xue@0
|
1183 {
|
xue@0
|
1184 double fmel=Amel*log(1+Fs/700)*f;
|
xue@0
|
1185 double fhz=700*(exp(fmel/Amel)-1);
|
xue@0
|
1186 f=fhz/Fs;
|
xue@0
|
1187 }
|
xue@0
|
1188 double h2=sf2.LogAF(f);
|
xue@0
|
1189 dh[k]=h2-h1;
|
xue@0
|
1190 }
|
xue@0
|
1191 }
|
xue@0
|
1192 double* CompareFilters(TSF& sf1, TSF& sf2)
|
xue@0
|
1193 {
|
xue@0
|
1194 double* dh=new double[sf1.K+2];
|
xue@0
|
1195 CompareFilters(dh, sf1, sf2);
|
xue@0
|
1196 return dh;
|
xue@0
|
1197 }
|
xue@0
|
1198
|
xue@0
|
1199 void __fastcall TSFDemoForm::UseButtonClick(TObject *Sender)
|
xue@0
|
1200 {
|
xue@0
|
1201 if (TmplListBox->ItemIndex<0) return;
|
xue@0
|
1202 AnsiString FileName=ExtractFilePath(Application->ExeName)+TmplListBox->Items->Strings[TmplListBox->ItemIndex];
|
xue@0
|
1203 if (!FileExists(FileName)) return;
|
xue@0
|
1204 double dbamp=TrackBar1->Position/10.0;
|
xue@0
|
1205 double dbgain=TrackBar2->Position/5.0-10;
|
xue@0
|
1206
|
xue@0
|
1207 TSF* sf=new TSF;
|
xue@0
|
1208 FILE* file;
|
xue@0
|
1209 if (file=fopen(FileName.c_str(), "rb"))
|
xue@0
|
1210 {
|
xue@0
|
1211 sf->LoadFromFileHandle(file);
|
xue@0
|
1212 fclose(file);
|
xue@0
|
1213 }
|
xue@0
|
1214 if (dbgain!=0) sf->ShiftFilterByDB(dbgain);
|
xue@0
|
1215 int L=ceil(SF.lp[SF.P-1])-ceil(SF.lp[0]), K=SF.K, M=SF.M;
|
xue@0
|
1216 double avgbend=SF0.avgb[sf->M-1];
|
xue@0
|
1217 switch (ComboBox1->ItemIndex)
|
xue@0
|
1218 {
|
xue@0
|
1219 case 0: //use source
|
xue@0
|
1220 {
|
xue@0
|
1221 for (int l=0; l<L; l++) memcpy(SF.h[l], SF0.h[l], sizeof(double)*(K+2));
|
xue@0
|
1222 memcpy (SF.avgh, SF0.avgh, sizeof(double)*(K+2));
|
xue@0
|
1223 for (int m=0; m<M; m++)
|
xue@0
|
1224 {
|
xue@0
|
1225 double sfb=(m<sf->M)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]);
|
xue@0
|
1226 double db=(sfb-SF0.avgb[m])*dbamp;
|
xue@0
|
1227 for (int l=0; l<L; l++) SF.b[l][m]=SF0.b[l][m]+db;
|
xue@0
|
1228 SF.avgb[m]=SF0.avgb[m]+db;
|
xue@0
|
1229 }
|
xue@0
|
1230 break;
|
xue@0
|
1231 }
|
xue@0
|
1232 case 1: //use filter
|
xue@0
|
1233 {
|
xue@0
|
1234 for (int l=0; l<L; l++) memcpy(SF.b[l], SF0.b[l], sizeof(double)*M);
|
xue@0
|
1235 memcpy(SF.avgb, SF0.avgb, sizeof(double)*M);
|
xue@0
|
1236 double* dh=CompareFilters(SF0, *sf);
|
xue@0
|
1237
|
xue@0
|
1238 for (int k=0; k<K+2; k++){double dhk=dh[k]*dbamp;
|
xue@0
|
1239 for (int l=0; l<L; l++) SF.h[l][k]=SF0.h[l][k]+dhk; SF.avgh[k]=SF0.avgh[k]+dhk;}
|
xue@0
|
1240 delete[] dh;
|
xue@0
|
1241 break;
|
xue@0
|
1242 }
|
xue@0
|
1243 case 2: //source and filter
|
xue@0
|
1244 {
|
xue@0
|
1245 for (int m=0; m<M; m++)
|
xue@0
|
1246 {
|
xue@0
|
1247 double sfb=(m<sf->M)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]);
|
xue@0
|
1248 double db=(sfb-SF0.avgb[m])*dbamp;
|
xue@0
|
1249 for (int l=0; l<L; l++) SF.b[l][m]=SF0.b[l][m]+db; SF.avgb[m]=SF0.avgb[m]+db;
|
xue@0
|
1250 }
|
xue@0
|
1251 double* dh=CompareFilters(SF0, *sf);
|
xue@0
|
1252
|
xue@0
|
1253 for (int k=0; k<K+2; k++){double dhk=dh[k]*dbamp;
|
xue@0
|
1254 for (int l=0; l<L; l++) SF.h[l][k]=SF0.h[l][k]+dhk; SF.avgh[k]=SF0.avgh[k]+dhk;}
|
xue@0
|
1255 delete[] dh;
|
xue@0
|
1256 break;
|
xue@0
|
1257 }
|
xue@0
|
1258 case 3: //towards
|
xue@0
|
1259 {
|
xue@0
|
1260 for (int m=0; m<M; m++)
|
xue@0
|
1261 {
|
xue@0
|
1262 double sfb=(m<sf->M)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]);
|
xue@0
|
1263 double db=(sfb-SF0.avgb[m])*dbamp, avgb=0;
|
xue@0
|
1264 for (int l=0; l<L; l++){SF.b[l][m]=SF0.b[l][m]+db*l/(L-1); avgb+=SF.b[l][m];}
|
xue@0
|
1265 SF.avgb[m]=avgb/L;
|
xue@0
|
1266 }
|
xue@0
|
1267 double *dh=CompareFilters(SF0, *sf);
|
xue@0
|
1268
|
xue@0
|
1269 for (int k=0; k<K+2; k++){double dhk=dh[k]*dbamp, avgh=0;
|
xue@0
|
1270 for (int l=0; l<L; l++){SF.h[l][k]=SF0.h[l][k]+dhk*l/(L-1); avgh+=SF.h[l][k];} SF.avgh[k]=avgh/L;}
|
xue@0
|
1271 delete[] dh;
|
xue@0
|
1272 break;
|
xue@0
|
1273 }
|
xue@0
|
1274 case 4: //towards and back
|
xue@0
|
1275 {
|
xue@0
|
1276 for (int m=0; m<M; m++)
|
xue@0
|
1277 {
|
xue@0
|
1278 double sfb=(m<sf->M)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]);
|
xue@0
|
1279 double db=(sfb-SF0.avgb[m])*dbamp, avgb=0;
|
xue@0
|
1280 for (int l=0; l<L; l++){SF.b[l][m]=SF0.b[l][m]+db*(1-fabs(l*2.0/(L-1)-1)); avgb+=SF.b[l][m];}
|
xue@0
|
1281 SF.avgb[m]=avgb/L;
|
xue@0
|
1282 }
|
xue@0
|
1283 double *dh=CompareFilters(SF0, *sf);
|
xue@0
|
1284
|
xue@0
|
1285 for (int k=0; k<K+2; k++){double dhk=dh[k]*dbamp, avgh=0;
|
xue@0
|
1286 for (int l=0; l<L; l++){SF.h[l][k]=SF0.h[l][k]+dhk*(1-fabs(l*2.0/(L-1)-1)); avgh+=SF.h[l][k];} SF.avgh[k]=avgh/L;}
|
xue@0
|
1287 delete[] dh;
|
xue@0
|
1288 break;
|
xue@0
|
1289 }
|
xue@0
|
1290 break;
|
xue@0
|
1291 }
|
xue@0
|
1292
|
xue@0
|
1293 delete sf;
|
xue@0
|
1294
|
xue@0
|
1295 SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
|
xue@0
|
1296 SaveSF();
|
xue@0
|
1297 S_U(true);
|
xue@0
|
1298 UpdateDisplay();
|
xue@0
|
1299 }
|
xue@0
|
1300 //---------------------------------------------------------------------------
|
xue@0
|
1301 //S_U implements delayed updating of lengthy synthesizing to speed up operation
|
xue@0
|
1302 // in case the HS is updated frequently, s.a. during mouse wheeling.
|
xue@0
|
1303 //This allows a later synthesis to start before an earlier synthesis finishes,
|
xue@0
|
1304 // at which the latter is terminated and its incomplete result is discarded.
|
xue@0
|
1305 void __fastcall TSFDemoForm::S_U(bool sf)
|
xue@0
|
1306 {
|
xue@0
|
1307 if (SUThread)
|
xue@0
|
1308 {
|
xue@0
|
1309 SUThread->Terminate();
|
xue@0
|
1310 }
|
xue@0
|
1311 SUThread=new TSUThread(true);
|
xue@0
|
1312 SUThread->sf=sf;
|
xue@0
|
1313 SUThread->OnTerminate=SUTerminate;
|
xue@0
|
1314 SUThread->HS=new THS(HS);
|
xue@0
|
1315 ThreadList[pThread++]=SUThread;
|
xue@0
|
1316 if (pThread==ThreadCaps/2 && ThreadList[pThread])
|
xue@0
|
1317 for (int i=pThread; i<ThreadCaps; i++) {delete ThreadList[i]; ThreadList[i]=0;}
|
xue@0
|
1318 else if (pThread==ThreadCaps)
|
xue@0
|
1319 {
|
xue@0
|
1320 for (int i=0; i<ThreadCaps/2; i++) {delete ThreadList[i]; ThreadList[i]=0;}
|
xue@0
|
1321 pThread=0;
|
xue@0
|
1322 }
|
xue@0
|
1323 SUThread->Resume();
|
xue@0
|
1324 }
|
xue@0
|
1325
|
xue@0
|
1326 void __fastcall TSFDemoForm::SUTerminate(TObject* Sender)
|
xue@0
|
1327 {
|
xue@0
|
1328 TSUThread* CurrentThread=(TSUThread*)Sender;
|
xue@0
|
1329 if (CurrentThread==SUThread)
|
xue@0
|
1330 {
|
xue@0
|
1331 double* xrec=CurrentThread->xrec;
|
xue@0
|
1332 if (xrec)
|
xue@0
|
1333 {
|
xue@0
|
1334 int dst=CurrentThread->dst, den=CurrentThread->den, bps=WaveAudio2->BitsPerSample;
|
xue@0
|
1335 if (dst<0) dst=0;
|
xue@0
|
1336 double max=1<<(bps-1); for (int i=dst; i<den; i++) if (xrec[i]>max) max=xrec[i]; else if (xrec[i]<-max) max=-xrec[i];
|
xue@0
|
1337 if (max>1<<(bps-1))
|
xue@0
|
1338 {
|
xue@0
|
1339 max=(1<<(bps-1))/max;
|
xue@0
|
1340 for (int i=dst; i<den; i++) xrec[i]*=max;
|
xue@0
|
1341 }
|
xue@0
|
1342 void* data=new char[(den-dst)*bps];
|
xue@0
|
1343 DoubleToInt(data, bps>>3, xrec, den-dst);
|
xue@0
|
1344 WaveAudio2->Clear(NULL);
|
xue@0
|
1345 WaveAudio2->WriteSamples(data, den-dst);
|
xue@0
|
1346 delete[] data;
|
xue@0
|
1347 UpdateDisplay();
|
xue@0
|
1348 }
|
xue@0
|
1349 SUThread=0;
|
xue@0
|
1350 }
|
xue@0
|
1351 else
|
xue@0
|
1352 {
|
xue@0
|
1353 UpdateDisplay(true, true, true, CurrentThread->sf);
|
xue@0
|
1354 }
|
xue@0
|
1355 free8(CurrentThread->xrec); CurrentThread->xrec=0;
|
xue@0
|
1356 }
|
xue@0
|
1357 //---------------------------------------------------------------------------
|
xue@0
|
1358
|
xue@0
|
1359 void __fastcall TSFDemoForm::Panel4Resize(TObject *Sender)
|
xue@0
|
1360 {
|
xue@0
|
1361 ForceUpdate=true;
|
xue@0
|
1362 }
|
xue@0
|
1363 //---------------------------------------------------------------------------
|
xue@0
|
1364
|
xue@0
|
1365
|
xue@0
|
1366 void __fastcall TSFDemoForm::Panel1Resize(TObject *Sender)
|
xue@0
|
1367 {
|
xue@0
|
1368 Panel2->Height=(Panel1->Height-Splitter1->Height)/2;
|
xue@0
|
1369 }
|
xue@0
|
1370 //---------------------------------------------------------------------------
|
xue@0
|
1371
|
xue@0
|
1372
|
xue@0
|
1373
|
xue@0
|
1374 void __fastcall TSFDemoForm::AmpCycleSheetResize(TObject *Sender)
|
xue@0
|
1375 {
|
xue@0
|
1376 UpdateDisplay();
|
xue@0
|
1377 }
|
xue@0
|
1378 //---------------------------------------------------------------------------
|
xue@0
|
1379
|
xue@0
|
1380
|
xue@0
|
1381 void __fastcall TSFDemoForm::MethodListBoxClick(TObject *Sender)
|
xue@0
|
1382 {
|
xue@0
|
1383 Reset();
|
xue@0
|
1384 }
|
xue@0
|
1385 //---------------------------------------------------------------------------
|
xue@0
|
1386
|
xue@0
|
1387 void __fastcall TSFDemoForm::AmpOverSheetResize(TObject *Sender)
|
xue@0
|
1388 {
|
xue@0
|
1389 UpdateDisplay();
|
xue@0
|
1390 }
|
xue@0
|
1391 //---------------------------------------------------------------------------
|
xue@0
|
1392
|
xue@0
|
1393 void __fastcall TSFDemoForm::Splitter7Moved(TObject *Sender)
|
xue@0
|
1394 {
|
xue@0
|
1395 if (Sender==Splitter7) AImage4->Parent->Parent->Height=AImage3->Parent->Parent->Height;
|
xue@0
|
1396 else if (Sender==Splitter8) AImage3->Parent->Parent->Height=AImage4->Parent->Parent->Height;
|
xue@0
|
1397 UpdateDisplay();
|
xue@0
|
1398 }
|
xue@0
|
1399 //---------------------------------------------------------------------------
|
xue@0
|
1400
|
xue@0
|
1401 void __fastcall TSFDemoForm::AImage3DblClick(TObject *Sender)
|
xue@0
|
1402 {
|
xue@0
|
1403 Graphics::TBitmap* bmp=new Graphics::TBitmap;
|
xue@0
|
1404 bmp->Width=800; bmp->Height=600; TRect Rect=TRect(0, 0, 800, 600);
|
xue@0
|
1405
|
xue@0
|
1406
|
xue@0
|
1407 double fst=0, fen=fmaxEdit->Text.ToDouble();
|
xue@0
|
1408
|
xue@0
|
1409 double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble();
|
xue@0
|
1410 dbrange=updb-downdb;
|
xue@0
|
1411
|
xue@0
|
1412 if (Sender==AImage3) DrawSF(bmp, Rect, fst, fen, updb+dbshift, downdb=dbshift, SF.F0Overall, SF.M, SF.avgb, SF.F, SF.K, SF.avgh, SF.FScaleMode, 44100, SX, 0, 0, 0, 36, FShiftdBEdit->Text.ToInt());
|
xue@0
|
1413 else if (Sender==AImage1)
|
xue@0
|
1414 {
|
xue@0
|
1415 int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]);
|
xue@0
|
1416 if (!SFCheck->Checked)
|
xue@0
|
1417 DrawAF(bmp, Rect, fst, fen, updb, downdb, SF.M, lp0, lpp, HS->Partials, MACheck->Checked, false, WaveView1->SamplesPerSec, 36);
|
xue@0
|
1418 else
|
xue@0
|
1419 DrawSFr(bmp, Rect, fst, fen, updb, downdb, SF.M, lp0, lpp, HS->Partials, useA0?SF.logA0:SF.logA0C, SF.avgb, SF.F, SF.K, SF.avgh, SF.FScaleMode, SF.Fs, 36);
|
xue@0
|
1420 }
|
xue@0
|
1421 Form1->SaveDialog1->FileName="waveview.waveview1.bmp";
|
xue@0
|
1422 Form1->SaveDialog1->FilterIndex=2;
|
xue@0
|
1423 if (Form1->SaveDialog1->Execute()) bmp->SaveToFile(Form1->SaveDialog1->FileName);
|
xue@0
|
1424 delete bmp;
|
xue@0
|
1425 }
|
xue@0
|
1426 //---------------------------------------------------------------------------
|
xue@0
|
1427
|
xue@0
|
1428 void __fastcall TSFDemoForm::Panel7Resize(TObject *Sender)
|
xue@0
|
1429 {
|
xue@0
|
1430 UpdateDisplay(1, 0, 0, 0);
|
xue@0
|
1431 }
|
xue@0
|
1432 //---------------------------------------------------------------------------
|
xue@0
|
1433
|
xue@0
|
1434 void __fastcall TSFDemoForm::Panel8Resize(TObject *Sender)
|
xue@0
|
1435 {
|
xue@0
|
1436 UpdateDisplay(0, 1, 0, 0);
|
xue@0
|
1437 }
|
xue@0
|
1438 //---------------------------------------------------------------------------
|
xue@0
|
1439
|
xue@0
|
1440
|
xue@0
|
1441 void __fastcall TSFDemoForm::CheckBox1Click(TObject *Sender)
|
xue@0
|
1442 {
|
xue@0
|
1443 WaveView2->LoopPlay=CheckBox1->Checked;
|
xue@0
|
1444 }
|
xue@0
|
1445 //---------------------------------------------------------------------------
|
xue@0
|
1446
|
xue@0
|
1447 void __fastcall TSFDemoForm::fmaxEditKeyPress(TObject *Sender, char &Key)
|
xue@0
|
1448 {
|
xue@0
|
1449 if (Key==VK_RETURN) UpdateDisplay(0, 0, 0, 1);
|
xue@0
|
1450 }
|
xue@0
|
1451 //---------------------------------------------------------------------------
|
xue@0
|
1452
|
xue@0
|
1453 void __fastcall TSFDemoForm::Button1Click(TObject *Sender)
|
xue@0
|
1454 {
|
xue@0
|
1455 int N=WaveView1->Length, Channel=Form1->HS->Channel;
|
xue@0
|
1456
|
xue@0
|
1457 if (GetKeyState(VK_SHIFT)<0)
|
xue@0
|
1458 {
|
xue@0
|
1459 __int16* d2=WaveView2->Data16[0];
|
xue@0
|
1460 Form1->PostWaveViewData(d2, Channel, StartPos, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
|
xue@0
|
1461 }
|
xue@0
|
1462 else
|
xue@0
|
1463 {
|
xue@0
|
1464 __int16 *data=new __int16[N], *data1=WaveView1->Data16[0], *data2=WaveView2->Data16[0];
|
xue@0
|
1465 for (int n=0; n<N; n++) data[n]=data1[n]-datain[n]+data2[n];
|
xue@0
|
1466 Form1->PostWaveViewData(data, Channel, StartPos, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
|
xue@0
|
1467 delete[] data;
|
xue@0
|
1468 }
|
xue@0
|
1469 }
|
xue@0
|
1470 //---------------------------------------------------------------------------
|
xue@0
|
1471
|
xue@0
|
1472
|
xue@0
|
1473
|
xue@0
|
1474
|