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