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