annotate SFDemoUnit.cpp @ 1:f3fd4e19cec0 tip

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