Mercurial > hg > hv
view VibratoDemoUnit.cpp @ 0:a6a46af64546
first upload
author | wenx <xue.wen@eecs.qmul.ac.uk> |
---|---|
date | Wed, 10 Aug 2011 14:55:38 +0100 |
parents | |
children |
line wrap: on
line source
/* Harmonic Visualiser An audio file viewer and editor. Centre for Digital Music, Queen Mary, University of London. This file copyright 2011 Wen Xue. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include <Math.hpp> #include <math.h> #include "VibratoDemoUnit.h" #include "Matrix.h" #include "Unit1.h" #include "splines.h" #include "hssf.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TVibratoDemoForm *VibratoDemoForm; //--------------------------------------------------------------------------- const double updb=10, downdb=-80, dbrange=updb-downdb; const double log10e=Log10(exp(1)); const Bdw=5, Bdwc=2; __fastcall TVibratoDemoForm::TVibratoDemoForm(TComponent* Owner) : TForm(Owner) { ForceUpdate=false; SUThread=0; pThread=0; memset(ThreadList, 0, sizeof(TSUThread*)*ThreadCaps); WaveAudio1=new TWaveAudio(NULL); WaveAudio1->UseMemoryStream=true; WaveAudio1->Channels=1; WaveView1=new TWaveView(NULL); WaveView1->Parent=Panel2; WaveView1->Align=alClient; WaveView1->WaveAudio=WaveAudio1; WaveView1->OnGetOpMode=WaveView1OpMode; WaveView1->CreatePanes(1, 1); WaveView1->SetContent(0, 0, 0, 1); WaveView1->ClickFocus=true; WaveView1->DefaultPopupMenu=false; WaveView1->CustomInfo=WaveView1CustomInfo; WaveView1->InfoLeft=5; WaveView1->InfoTop=5; WaveAudio2=new TWaveAudio(NULL); WaveAudio2->UseMemoryStream=true; WaveAudio2->Channels=1; WaveView2=new TWaveView(NULL); WaveView2->Parent=Panel3; WaveView2->Align=alClient; WaveView2->WaveAudio=WaveAudio2; WaveView2->CreatePanes(1, 1); WaveView2->SetContent(0, 0, 0, 1); WaveView2->ClickFocus=true; WaveView2->DefaultPopupMenu=false; WaveView2->CustomInfo=WaveView1CustomInfo; WaveView2->InfoLeft=5; WaveView2->InfoTop=5; HS=0; CurrentModCycle=-1; peaky=0; cyclefrs=0; cyclefs=0; datain=0; } __fastcall TVibratoDemoForm::~TVibratoDemoForm() { delete WaveAudio1; delete WaveAudio2; delete WaveView1; delete WaveView2; delete HS; delete[] peaky; delete[] cyclefrs; delete[] cyclefs; for (int i=0; i<ThreadCaps; i++) if (ThreadList[i]) delete ThreadList[i]; delete[] datain; } //--------------------------------------------------------------------------- void TVibratoDemoForm::FindNote(){} void TVibratoDemoForm::Reset() { if (!HS) return; if (HS->M<=0 || HS->Fr<=0) return; if (ListBox1->ItemIndex<0) ListBox1->ItemIndex=0; double Fs=WaveView1->SamplesPerSec; int FSMode=ListBox1->ItemIndex; double FSF=FEdit->Text.ToDouble(); int FSFScale=FScaleCombo->ItemIndex; if (FSFScale==0) FSF/=Fs; else FSF/=Amel*log(1+Fs/700); double FStheta=ThetaEdit->Text.ToDouble(); double sps=WaveView1->SamplesPerSec; double h=WaveView1->SpecOffst; AnalyzeV(*HS, V, peaky, cyclefrs, cyclefs, sps, h, &cyclefrcount, FSMode, FSF, FSFScale, FStheta); SynthesizeV(HS, &V, WaveView1->SamplesPerSec); SaveV(); UpdateDisplay(); } void TVibratoDemoForm::Copydata() { int dst, den; double* xrec; if (HS) { xrec=SynthesisHSp(HS, dst, den); if (dst<0) dst=0; delete[] datain; datain=new __int16[den-dst]; DoubleToInt(datain, sizeof(__int16), xrec, den-dst); free8(xrec); } } void TVibratoDemoForm::Synthesize() { int dst, den; double* xrec; if (HS) { double t=GetTickCount(); xrec=SynthesisHS(HS, dst, den); t=GetTickCount()-t; Label13->Caption=t; } int bips=WaveAudio1->BitsPerSample; 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]; if (max>(1<<(bips-1))) { max=(1<<(bips-1))/max; for (int i=dst; i<den; i++) xrec[i]*=max; } int bps=bips/8; WaveAudio2->Clear(NULL); WaveAudio2->GetWaveProperties(WaveAudio1); if (HS) { if (dst<0) dst=0; void* data=new char[(den-dst)*bps]; DoubleToInt(data, bps, xrec, den-dst); WaveAudio2->Clear(NULL); WaveAudio2->WriteSamples(data, den-dst); free8(xrec); delete[] data; } } //for frequency modulator shape void DrawBarMap(Graphics::TBitmap* Bitmap, TRect Rect, int Count, double* data, bool res, int* KX1=0, int* KX2=0) { TCanvas* Canvas=Bitmap->Canvas; Bitmap->Width=Rect.Width(); Bitmap->Height=Rect.Height(); TFont* F=Canvas->Font; F->Color=clWhite; F->Height=12; F->Name="Ariel"; int fh=Canvas->TextHeight("0"); int DrawCount=res?(Count+1):Count; double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh; Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect); Canvas->Brush->Color=clAqua; Canvas->Pen->Color=clAqua; Canvas->Brush->Style=bsSolid; int empspace=XX/(DrawCount+1)/4; double r=0; for (int i=0; i<Count; i++) r+=data[i]*data[i]; double sqrtr=sqrt(r); double res_amp=(r>1)?0:sqrt(1-r); for (int i=0; i<DrawCount; i++) { double ldata; if (res) { if (i==0) ldata=data[i]; else if (i<Count) ldata=data[i]; else ldata=res_amp; } else ldata=data[i]/sqrtr; int X=floor(Bdw+XX*(i+1)/(DrawCount+1)+0.5); int Y=floor(Bdw+YY*(1-ldata)+0.5); if (empspace>=1) { Canvas->Brush->Style=bsSolid; Canvas->Brush->Color=TColor(0xFFFF00); Canvas->Rectangle(X-empspace, Y, X+empspace, Bdw+YY); if (KX1) KX1[i]=X-empspace, KX2[i]=X+empspace-1; } else { Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY); if (KX1) KX1[i]=X-1, KX2[i]=X+1; } AnsiString S=i; if (i>=Count) S="R"; int fw=Canvas->TextWidth(S); Canvas->Brush->Style=bsClear; Canvas->TextOut(X-fw/2, Bdw+YY, S); S.sprintf("%.3g", 100*ldata*ldata); if (S[1]=='0') S=S.SubString(2, S.Length()-1); fw=Canvas->TextWidth(S); if (Y-Bdw>fh) Canvas->TextOut(X-fw/2, Y-fh, S); else Canvas->TextOut(X+empspace+1, Y, S); } Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite; Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY); } TColor RotateColors[10]={clWhite, clAqua, clLime, clYellow, clRed, clTeal, clGray, clGreen, clFuchsia, clBlue}; //draw A-F distribution 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) { Bitmap->Width=Rect.Width(); Bitmap->Height=Rect.Height(); TCanvas* Canvas=Bitmap->Canvas; double idbrange=1.0/(dbst-dben); TFont* F=Canvas->Font; F->Color=clWhite; F->Height=TextHeight; F->Name="Ariel"; int fh=Canvas->TextHeight("0"); double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh; Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect); Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5); double *x=new double[(Fr-FrStart)*4], *y=&x[Fr-FrStart], *newa=&x[(Fr-FrStart)*2], *neww=&x[(Fr-FrStart)*3]; for (int m=0; m<M; m++) { Canvas->Pen->Color=RotateColors[m%10]; Canvas->Brush->Color=RotateColors[m%10]; int Sc=0; bool visible=false; atom* Partialsm=Partials[m]; for (int fr=FrStart; fr<Fr; fr++) { if (Partialsm[fr].f>0 && Partialsm[fr].a>0) { x[Sc]=Partials[m][fr].f; y[Sc]=20*Log10(Partialsm[fr].a/A0C[fr]); if (x[Sc]<xen) visible=true; Sc++; } } if (!visible) break; if (MA) { double fw; for (int c=0; c<Sc; c++) newa[c]=y[c], neww[c]=1; for (int c=0; c<Sc; c++) { fw=0.002; if (fw>x[c]*0.05) fw=x[c]*0.05; for (int c1=0; c1<c; c1++) { double df=fabs(x[c]-x[c1]); if (df<fw) { double w=0.5+0.5*cos(M_PI*df/fw); newa[c]+=y[c1]*w; neww[c]+=w; newa[c1]+=y[c]*w; neww[c1]+=w; } } } for (int c=0; c<Sc; c++) y[c]=newa[c]/neww[c]; } for (int c=0; c<Sc; c++) { if (x[c]<xst || x[c]>xen) continue; double ldata=(y[c]-dben)*idbrange; int X=floor(Bdw+XX*(x[c]-xst)/(xen-xst)+0.5); int Y=floor(Bdw+YY*(1-ldata)+0.5); if (bars) {Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY);} else {Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2);} } } AnsiString S="0hz"; Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S); S="5.5khz"; int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S); S="11khz"; fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S); S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S); S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S); S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S); Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite; Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY); delete[] x; } //*/ //for source-filter results 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) { Bitmap->Width=Rect.Width(); Bitmap->Height=Rect.Height(); TCanvas* Canvas=Bitmap->Canvas; TFont* F=Canvas->Font; F->Color=clWhite; F->Height=TextHeight; F->Name="Ariel"; int fh=Canvas->TextHeight("0"); double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh; Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect); Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5); double xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange, xrangeiXX=xrange/XX, xstafres=xst*afres, xrangeiXXafres=xrangeiXX*afres, YYidbrange=YY/(dbst-dben); int *XRec=new int[XX]; for (int m=0; m<M; m++) { bool visible=false; atom* Partialsm=Partials[m]; Canvas->Brush->Color=RotateColors[m%10]; Canvas->Pen->Color=RotateColors[m%10]; memset(XRec, 0, sizeof(int)*XX); for (int fr=0; fr<Fr; fr++) { if (Partialsm[fr].f>0 && Partialsm[fr].a>0) { double xx=Partialsm[fr].f; if (xx<xen) visible=true; if (xx<xst || xx>xen) continue; int X=floor(XXixrange*xx-xstXXixrange+0.5); if (X>=0 && X<XX && !XRec[X]) { XRec[X]=true; double yy=20*log10e*(LogAF[int(xstafres+X*xrangeiXXafres)]+LogAS[m]); int Y=Bdw+floor((YY-YYidbrange*(yy-dben))+0.5); X+=Bdw; Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2); } } } if (!visible) break; } delete[] XRec; AnsiString S="0hz"; Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S); S="5.5khz"; int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S); S="11khz"; fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S); S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S); S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S); S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S); Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite; Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY); } //*for source-filter model 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) { Bitmap->Width=Rect.Width(); Bitmap->Height=Rect.Height(); TCanvas* Canvas=Bitmap->Canvas; double *Sx=new double[SCount]; for (int i=0; i<SCount; i++) Sx[i]=20*log10e*LogAS[i]; int result=0; TFont* F=Canvas->Font; F->Color=clWhite; F->Height=TextHeight; F->Name="Ariel"; int fh=Canvas->TextHeight("0"); double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh; Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect); Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5); double idbrange=1.0/(dbst-dben), xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange, YY20log10eidbrange=YY*20*log10e*idbrange, BdwpYYpYYdbenidbrange=Bdw+YY+YY*dben*idbrange, Bdw_xstXXixrange=Bdw-xstXXixrange, YYidbrange=YY*idbrange; double st=xst/fc0; int ist=ceil(st); if (ist<0) ist=0; Canvas->Pen->Color=clWhite; Canvas->MoveTo(Bdw+XX*(fc0*ist-xst)/xrange+0.5, BdwpYYpYYdbenidbrange-YY20log10eidbrange*LogAF[ist]+0.5); //draw filter contour int LineCount=xrange/fc0; if (LineCount<XX) { for (int i=ist+1; i<FCount; i++) { double xi=fc0*i; if (xi>xen) break; int X=floor(Bdw_xstXXixrange+xi*XXixrange+0.5); int Y=floor(BdwpYYpYYdbenidbrange-YY20log10eidbrange*LogAF[i]+0.5); Canvas->LineTo(X, Y); } } else { double di=xrange/(XX*fc0); for (int x=0; x<XX; x++) { int i=st+x*di; int Y=floor(BdwpYYpYYdbenidbrange-YY20log10eidbrange*LogAF[i]+0.5); Canvas->LineTo(Bdw+x, Y); } } //draw source lines for (int i=0; i<SCount; i++) { double xi=f0*(i+1); if (xi<xst || xi>xen) continue; int X=floor(Bdw_xstXXixrange+XXixrange*xi+0.5); int Y=floor(BdwpYYpYYdbenidbrange-YYidbrange*Sx[i]+0.5); if (Colors) Canvas->Pen->Color=Colors[i]; else Canvas->Pen->Color=RotateColors[i%10]; Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY); if (SX) SX[i]=X, result++; } AnsiString S="0hz"; Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S); S="5.5khz"; int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S); S="11khz"; fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S); S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S); S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S); S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S); Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite; Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY); delete[] Sx; return result; } //*/ 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) { Canvas->Brush->Color=cl3DDkShadow; Canvas->FillRect(Rect); int Width=Rect.Width(), Height=Rect.Height(); Bitmap->Width=Width; Bitmap->Height=Height; TPen* P=Canvas->Pen; TFont* F=Canvas->Font; int X, Y, Y1=0, Y2=Height, Y_; AnsiString S, as; P->Color=clBlack; P->Style=psDot; F->Color=clBlack; F->Height=12; F->Name="Ariel"; 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];} Y1=Height*(0.5-(f0max-f_c)/f_ex); Canvas->MoveTo(0, Y1); Canvas->LineTo(Width, Y1); 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);} Y2=Height*(0.5-(f0min-f_c)/f_ex); Canvas->MoveTo(0, Y2); Canvas->LineTo(Width, Y2); 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);} if (peakmark) { int Y0=0.5*(Y1+Y2), Y0ex=0.5*(Y1-Y2); if (peaky) {P->Color=peakmarkcolor; P->Style=psDot; Canvas->MoveTo(0, Y0); Canvas->LineTo(Width, Y0);} for (int pfr=0; pfr<npfr; pfr++) { int fr=floor(lp[pfr]); X=Width*(Partials[1][fr].t*(fr+1-lp[pfr])+Partials[1][fr+1].t*(lp[pfr]-fr))/L; P->Color=peakmarkcolor; P->Style=psDot; Canvas->MoveTo(X, Y1); Canvas->LineTo(X, Y2); if (peaky) { Y=Y0ex*peaky[pfr]; P->Color=peakycolor; P->Style=psSolid; Canvas->MoveTo(X, Y0); Canvas->LineTo(X, Y0+Y); } } } if (Captions) {Y_=Height*(0.5-(F0Overall-f_c)/f_ex); P->Color=clWhite; Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_);} P->Style=psSolid; P->Color=F0Color; for (int fr=0; fr<Fr; fr++) { if (fr>0) Canvas->MoveTo(X, Y); X=Width*Partials[1][fr].t/L, Y=Height*(0.5-(F0[fr]-f_c)/f_ex); if (fr>0) Canvas->LineTo(X, Y); } if (frs) { P->Color=clRed; for (int pfr=0; pfr<npfr-1; pfr++) { int ifrs=frs[pfr]; double rfrs=frs[pfr]-ifrs; 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); Canvas->MoveTo(X-4, Y); Canvas->LineTo(X+5, Y); Canvas->MoveTo(X, Y-4); Canvas->LineTo(X, Y+5); } } if (Captions) { as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Overall*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Overall*sps, as.c_str()); F->Color=clWhite; F->Style=F->Style<<fsBold; Canvas->TextOut(Width-Canvas->TextWidth(S), Y_+1, S); F->Style=F->Style>>fsBold; F->Color=clSilver; S="F0"; Canvas->TextOut(1, Height-Canvas->TextHeight(S), S); 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); 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); } } 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) { //Draw the F0 carrier Canvas->Brush->Color=cl3DDkShadow; if (clearbackground) Canvas->FillRect(Rect); int Width=Rect.Width(), Height=Rect.Height(); Bitmap->Width=Width; Bitmap->Height=Height; TPen* P=Canvas->Pen; TFont* F=Canvas->Font; P->Color=clBlack; F0Cmax=f_c-f_ex, F0Cmin=f_c+f_ex; for (int fr=0; fr<Fr; fr++){if (F0Cmax<F0C[fr]) F0Cmax=F0C[fr]; if (F0Cmin>F0C[fr]) F0Cmin=F0C[fr];} P->Style=psDot; int X, Y=Height*(0.5-(F0Cmax-f_c)/f_ex); Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y); AnsiString as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Cmax*sps)/C4)); AnsiString S; S.sprintf("%.4ghz (%s)", F0Cmax*sps, as.c_str()); F->Color=clBlack; F->Height=12; F->Name="Ariel"; Canvas->TextOut(1, Y-Canvas->TextHeight(S)-1, S); Y=Height*(0.5-(F0Cmin-f_c)/f_ex); Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y); as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Cmin*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Cmin*sps, as.c_str()); Canvas->TextOut(1, Y+1, S); P->Color=clWhite; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Overall*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Overall*sps, as.c_str()); int Y_=Height*(0.5-(F0Overall-f_c)/f_ex); Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_); F->Color=clWhite; F->Style=F->Style<<fsBold; if (Y_+1+Canvas->TextHeight(S)<Y) Canvas->TextOut(Width-Canvas->TextWidth(S), Y_+1, S); else Canvas->TextOut(Width-Canvas->TextWidth(S), Y+1, S); F->Style=F->Style>>fsBold; P->Style=psSolid; P->Color=clLime; for (int fr=0; fr<Fr; fr++) { if (fr>0) Canvas->MoveTo(X, Y); X=Width*Partials[1][fr].t/L, Y=Height*(0.5-(F0C[fr]-f_c)/f_ex); if (fr>0) Canvas->LineTo(X, Y); } if (frcount) { P->Color=clRed; for (int p=0; p<frcount; p++) { int ifrs=frs[p]; double rfrs=frs[p]-ifrs; 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); Canvas->MoveTo(X-4, Y); Canvas->LineTo(X+5, Y); Canvas->MoveTo(X, Y-4); Canvas->LineTo(X, Y+5); if (CX1) CX1[p]=X-4; if (CX2) CX2[p]=X+4; if (CY1) CY1[p]=Y-4; if (CY2) CY2[p]=Y+4; } } double f=(f_c+f_ex/2)*sps; F->Color=clSilver; 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); 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); F->Color=clSilver; S="F0 carrier"; Canvas->TextOut(1, Height-Canvas->TextHeight(S), S); } 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) { int Width=Rect.Width(), Height=Rect.Height(); Bitmap->Width=Width; Bitmap->Height=Height; Canvas->Brush->Style=bsSolid; Canvas->Brush->Color=cl3DDkShadow; Canvas->FillRect(Rect); //this part draws the modulator itself F0Dmax=-f_ex, F0Dmin=f_ex; for (int fr=lp[0]; fr<lp[npfr-1]; fr++){if (F0Dmax<F0D[fr]) F0Dmax=F0D[fr]; if (F0Dmin>F0D[fr]) F0Dmin=F0D[fr];} TPen* P=Canvas->Pen; P->Color=clBlack; P->Style=psDot; int X, Y=Height*(0.5-F0Dmax/f_ex); Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y); AnsiString S; S.sprintf("%.4ghz (%.3g%%)", F0Dmax*sps, F0Dmax/F0Overall*100); TFont* F=Canvas->Font; F->Color=clBlack; F->Height=12; F->Name="Ariel"; Canvas->TextOut(1, Y-Canvas->TextHeight(S)-1, S); Y=Height*(0.5-F0Dmin/f_ex); Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y); S.sprintf("%.4ghz (%.3g%%)", F0Dmin*sps, F0Dmin/F0Overall*100); Canvas->TextOut(1, Y+1, S); P->Style=psSolid; P->Color=clSilver; Canvas->MoveTo(0, Height/2); Canvas->LineTo(Width, Height/2); Canvas->Pen->Color=clLime; for (int fr=0; fr<Fr; fr++) { if (fr>0) Canvas->MoveTo(X, Y); X=Width*Partials[1][fr].t/L, Y=Height*(0.5-F0D[fr]/f_ex); if (fr>0) Canvas->LineTo(X, Y); } P->Color=clBlue; for (int fr=0; fr<Fr; fr++) { X=Width*Partials[1][fr].t/L, Y=Height*(0.5-F0D[fr]/f_ex); Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2); } F->Color=clSilver; F->Height=12; F->Name="Ariel"; S.sprintf("%.4ghz (%.3g%%)", f_ex*sps/2, f_ex/2/F0Overall*100); Canvas->TextOut(Width-Canvas->TextWidth(S), 0, S); S.sprintf("%.4ghz (%.3g%%)", -f_ex*sps/2, -f_ex/2/F0Overall*100); Canvas->TextOut(Width-Canvas->TextWidth(S), Height-Canvas->TextHeight(S), S); F->Color=clSilver; S="F0 modulator"; Canvas->TextOut(1, Height-Canvas->TextHeight(S), S); } //y=ax+b void linefit(int n, double* x, double* y, double* indi, double& a, double& b) { double sx=0, sy=0, sxy=0, sxx=0, m=0; 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++; if (m<=0) {a=-1; b=-1; return;} double id=1.0/(m*sxx-sx*sx); a=(m*sxy-sx*sy)*id; b=(sxx*sy-sx*sxy)*id; } void TVibratoDemoForm::UpdateDisplay(bool f0, bool f0c, bool f0d, bool sf) { int Fr=HS->Fr; atom** Partials=HS->Partials; //find the highest point of the 2nd partial double f2min=1, f2max=0, fst=0, fen=0.25; for (int fr=0; fr<Fr; fr++) { if (f2max<Partials[1][fr].f) f2max=Partials[1][fr].f; if (f2min>Partials[1][fr].f) f2min=Partials[1][fr].f; } f_c=(f2min+f2max)/4; f_ex=f2max-f2min; 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); if (f0c) { memset(CX1, 0xFF, sizeof(int)*128); memset(CX2, 0xFF, sizeof(int)*128); memset(CY1, 0xFF, sizeof(int)*128); memset(CY1, 0xFF, sizeof(int)*128); 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); } if (f0d) { //Draw the F0 modulator DrawModulator(); // double sps=WaveView1->SamplesPerSec; DurationEdit->Text=AnsiString().sprintf("%.4gs", WaveView2->Length/sps); RegEdit->Text=AnsiString().sprintf("%.4g", V.regularity); RateEdit->Text=AnsiString().sprintf("%.4ghz", V.rate); 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]);} 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]);} DrawBarMap(MImage1->Picture->Bitmap, MImage1->ClientRect, V.K, FXX, ResidueCheck->Checked, KX1, KX2); } if (sf) { if (SFCheck->Checked) DrawSFr(AImage1->Picture->Bitmap, AImage1->ClientRect, fst, fen, updb, downdb, V.M, Fr, V.afres, Partials, V.LogAF, V.LogAS); else DrawAF(AImage1->Picture->Bitmap, AImage1->ClientRect, fst, fen, updb, downdb, V.M, Fr, Partials, V.A0C, MACheck->Checked, false); 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); } ForceUpdate=false; } void __fastcall TVibratoDemoForm::WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode) { if (Shift.Contains(ssShift)) OpMode=0; //drag mode else OpMode=1; //select mode } int __fastcall TVibratoDemoForm::WaveView1CustomInfo(TObject* Sender) { TWaveView* WV=(TWaveView*)Sender; TStringList* List=new TStringList; double fs=WV->StartPos*1.0/WV->SamplesPerSec, fe=WV->EndPos*1.0/WV->SamplesPerSec; List->Add(AnsiString().sprintf(" Time (%.4gs): from %.4gs to %.4gs. ", fe-fs, fs, fe)); List->Add(AnsiString().sprintf(" Frequency: from %.1fhz to %.1fhz. ", WV->StartDigiFreq*WV->SamplesPerSec, WV->EndDigiFreq*WV->SamplesPerSec)); return int(List); } void __fastcall TVibratoDemoForm::Image1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (!HS) return; TImage* Image=(TImage*)Sender; Image->Parent->SetFocus(); double t, sps=WaveView1->SamplesPerSec, f; AnsiString S, as; TFont* F=Image->Canvas->Font; if (Sender==Image1) { if (Shift.Contains(ssLeft)) { if (CurrentC<0 || CurrentC>=cyclefrcount) return; double df=-(Y-StartDrag)*f_ex/Image->Height; cyclefs[CurrentC]+=df; StartDrag=Y; Smooth_Interpolate(V.F0C, V.L, cyclefrcount+1, cyclefs, cyclefrs); SynthesizeV(HS, &V, WaveView1->SamplesPerSec); UpdateDisplay(true, true, true, false); t=HS->Partials[0][0].t+V.h*cyclefrs[CurrentC]; f=cyclefs[CurrentC]*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str()); F->Color=clRed; Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S); } else { CurrentC=-1; for (int i=0; i<cyclefrcount; i++) if (X>=CX1[i] && X<=CX2[i] && Y>=CY1[i] && Y<=CY2[i]) {CurrentC=i; break;} } if (CurrentC>=0 && CurrentC<cyclefrcount) { t=HS->Partials[0][0].t+V.h*cyclefrs[CurrentC]; f=cyclefs[CurrentC]*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str()); F->Color=clRed; Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S); } else { S.sprintf(" ", t/sps, f, as.c_str()); Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S); } } t=WaveView2->Length*1.0*(X+0.5)/Image->Width; f=(f_c-(Y-0.5*Image->Height)*f_ex/Image->Height)*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str()); F->Color=clAqua; F->Height=12; F->Name="Ariel"; Image->Canvas->TextOut(1, 0, S); } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Image2MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (!HS) return; if (Shift.Contains(ssLeft)) return; atom** Partials=HS->Partials; Image2->Parent->SetFocus(); double t=WaveView2->Length*1.0*(X+0.5)/Image2->Width, sps=WaveView1->SamplesPerSec; double f=-(Y-0.5*Image2->Height)*f_ex/Image2->Height; if (true || Shift.Contains(ssShift)) { int modcycle=0; 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; else while (t>Partials[0][0].t+V.lp[modcycle]*V.h) modcycle++; if (CurrentModCycle!=modcycle) { CurrentModCycle=modcycle; if (CurrentModCycle==-1) { if (PageControl1->ActivePage==ModCycleSheet) { PageControl1->ActivePage=ModOverSheet; ResidueCheck->Parent=ModOverSheet; } else if (PageControl1->ActivePage==AmpCycleSheet) { PageControl1->ActivePage=AmpOverSheet; SFCheck->Parent=AmpOverSheet; MACheck->Parent=AmpOverSheet; } } else { if (PageControl1->ActivePage==ModOverSheet) { PageControl1->ActivePage=ModCycleSheet; ResidueCheck->Parent=ModCycleSheet; } else if (PageControl1->ActivePage==AmpOverSheet) { PageControl1->ActivePage=AmpCycleSheet; SFCheck->Parent=AmpCycleSheet; MACheck->Parent=AmpCycleSheet; } ModCycleSheet->Caption="Modulator Cycle "+AnsiString(CurrentModCycle); AmpCycleSheet->Caption="Amplitudes Cycle "+AnsiString(CurrentModCycle); } DrawModulator(); } } AnsiString S; S.sprintf("%.3gs, %.4ghz (%.3g%%) ", t/sps, f*sps, f/V.F0Overall*100); TFont* F=Image2->Canvas->Font; F->Color=clAqua; F->Height=12; F->Name="Ariel"; Image2->Canvas->TextOut(1, 0, S); } //--------------------------------------------------------------------------- void TVibratoDemoForm::DrawModulator() { double fst=0, fen=0.25; Image2->Picture->Bitmap->Width=Image2->Width; Image2->Picture->Bitmap->Height=Image2->Height; int X, Y, L=WaveView2->Length, Fr=HS->Fr; double sps=WaveView2->SamplesPerSec; atom** Partials=HS->Partials; TCanvas* I2Canvas=Image2->Canvas; I2Canvas->Brush->Style=bsSolid; I2Canvas->Brush->Color=cl3DDkShadow; I2Canvas->FillRect(Image2->ClientRect); if (CurrentModCycle>=1 && CurrentModCycle<V.P) { CurrentModCycleStart=Partials[0][0].t+V.lp[CurrentModCycle-1]*WaveView1->SpecOffst; CurrentModCycleEnd=Partials[0][0].t+V.lp[CurrentModCycle]*WaveView1->SpecOffst; int X1=Image2->Width*CurrentModCycleStart/L; int X2=Image2->Width*CurrentModCycleEnd/L; I2Canvas->Brush->Color=clDkGray; I2Canvas->FillRect(TRect(X1, 0, X2, Image2->Height)); I2Canvas->Brush->Color=cl3DDkShadow; //this part update the tab sheet int frst=V.peakfr[CurrentModCycle-1], fren=V.peakfr[CurrentModCycle]; if (PageControl1->ActivePage==ModCycleSheet) { CycleDurationEdit->Text=AnsiString().sprintf("%.4gs (%.4gs~%.4gs)", (CurrentModCycleEnd-CurrentModCycleStart)/sps, CurrentModCycleStart/sps, CurrentModCycleEnd/sps); CycleRateEdit->Text=AnsiString().sprintf("%.4ghz", sps/(CurrentModCycleEnd-CurrentModCycleStart)); double af0c=(V.F0C[frst]+V.F0C[fren])*0.5, f0dmax=V.F0D[frst], f0dmin=V.F0D[frst]; double np=1, nn=0; double pdp=(V.F0D[frst]*V.F0D[frst]+V.F0D[fren]*V.F0D[fren])*0.5, pdn=0; for (int fr=frst+1; fr<fren; fr++) { af0c+=V.F0C[fr]; if (V.F0D[fr]>f0dmax) f0dmax=V.F0D[fr]; if (V.F0D[fr]<f0dmin) f0dmin=V.F0D[fr]; if (V.F0D[fr]>0) pdp+=V.F0D[fr]*V.F0D[fr], np+=1; else if (V.F0D[fr]<0) pdn+=V.F0D[fr]*V.F0D[fr], nn+=1; } af0c/=(fren-frst); pdp=(np>0)?sqrt(pdp/np):0, pdn=(nn>0)?sqrt(pdn/nn):0; AnsiString S=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(af0c*sps)/C4)); CyclePitchEdit->Text=AnsiString().sprintf("%.4ghz (%s)", af0c*sps, S.c_str()); CycleExtentEdit->Text=AnsiString().sprintf("%.3g%%~%.3g%%", f0dmin/af0c*100, f0dmax/af0c*100); CycleAvgPDEdit->Text=AnsiString().sprintf("-%.3g%%~%.3g%%", pdn/af0c*100, pdp/af0c*100); 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;} 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;} DrawBarMap(MImage2->Picture->Bitmap, MImage2->ClientRect, V.K, FXX, ResidueCheck->Checked, KX1, KX2); } else if (PageControl1->ActivePage==AmpCycleSheet) { if (SFCheck->Checked) DrawSFr(AImage2->Picture->Bitmap, AImage2->ClientRect, fst, fen, updb, downdb, V.M, Fr, V.afres, Partials, V.LogAF, V.LogASp[CurrentModCycle]); else 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]); double cf0=0; for (int i=frst; i<fren; i++) cf0+=V.F0C[i]; cf0/=(fren-frst); 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); } } else //CurrentCycle==-1 { } //this part draws the modulator itself V.F0Dmax=-f_ex, V.F0Dmin=f_ex; 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];} I2Canvas->Pen->Color=clBlack; I2Canvas->Pen->Style=psDot; Y=Image2->Height*(0.5-V.F0Dmax/f_ex); I2Canvas->MoveTo(0, Y); I2Canvas->LineTo(Image2->Width, Y); AnsiString S; S.sprintf("%.4ghz (%.3g%%)", V.F0Dmax*sps, V.F0Dmax/V.F0Overall*100); TFont* F=I2Canvas->Font; F->Color=clBlack; F->Height=12; F->Name="Ariel"; I2Canvas->TextOut(1, Y-I2Canvas->TextHeight(S)-1, S); Y=Image2->Height*(0.5-V.F0Dmin/f_ex); I2Canvas->MoveTo(0, Y); I2Canvas->LineTo(Image2->Width, Y); S.sprintf("%.4ghz (%.3g%%)", V.F0Dmin*sps, V.F0Dmin/V.F0Overall*100); I2Canvas->TextOut(1, Y+1, S); I2Canvas->Pen->Style=psSolid; I2Canvas->Pen->Color=clSilver; I2Canvas->MoveTo(0, Image2->Height/2); I2Canvas->LineTo(Image2->Width, Image2->Height/2); I2Canvas->Pen->Color=clBlue; for (int fr=0; fr<Fr; fr++) { if (fr>0) I2Canvas->MoveTo(X, Y); X=Image2->Width*Partials[1][fr].t/L, Y=Image2->Height*(0.5-V.F0D[fr]/f_ex); if (fr>0) I2Canvas->LineTo(X, Y); } I2Canvas->Pen->Color=clLime; for (int fr=0; fr<Fr; fr++) { X=Image2->Width*Partials[1][fr].t/L, Y=Image2->Height*(0.5-V.F0D[fr]/f_ex); I2Canvas->MoveTo(X-1, Y); I2Canvas->LineTo(X+2, Y); I2Canvas->MoveTo(X, Y-1); I2Canvas->LineTo(X, Y+2); } F->Color=clSilver; F->Height=12; F->Name="Ariel"; S.sprintf("%.4ghz (%.3g%%)", f_ex*sps/2, f_ex/2/V.F0Overall*100); I2Canvas->TextOut(Image2->Width-I2Canvas->TextWidth(S), 0, S); S.sprintf("%.4ghz (%.3g%%)", -f_ex*sps/2, -f_ex/2/V.F0Overall*100); I2Canvas->TextOut(Image2->Width-I2Canvas->TextWidth(S), Image2->Height-I2Canvas->TextHeight(S), S); F->Color=clSilver; S="F0 modulator"; I2Canvas->TextOut(1, Image2->Height-I2Canvas->TextHeight(S), S); } void __fastcall TVibratoDemoForm::SFCheckClick(TObject *Sender) { if (Sender==SFCheck) { MACheck->Visible=!SFCheck->Checked; } UpdateDisplay(); } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::RegButtonClick(TObject *Sender) { RegularizeV(*HS, V, WaveView1->SamplesPerSec, WaveView1->SpecOffst); AnalyzeV(*HS, V, peaky, cyclefrs, cyclefs, WaveView1->SamplesPerSec, WaveView1->SpecOffst, &cyclefrcount); SaveV(); Synthesize(); UpdateDisplay(); } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::ExternalInput() { AnsiString FileName=ExtractFilePath(Application->ExeName)+"tvoin"; FILE* file; if ((file=fopen(FileName.c_str(), "rb"))!=NULL) { V.LoadFromFileHandle(file); fclose(file); DeleteFile(FileName); SynthesizeV(HS, &V, WaveView1->SamplesPerSec); SaveV(); Synthesize(); UpdateDisplay(); } } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::SaveV() { FILE* file; if ((file=fopen((ExtractFilePath(Application->ExeName)+"tvoout").c_str(), "wb"))!=NULL) { V.SaveToFileHandle(file); fclose(file); } } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::MouseWheelHandler(TMessage& Msg) { TWMMouseWheel* WMsg=(TWMMouseWheel*)&Msg; bool Handled=false; TMouseWheelEvent Event=NULL; TControl* Sender; TShiftState Shift; memcpy(&Shift, &WMsg->Keys, 1); if (ActiveControl==Image1->Parent) Event=Image1MouseWheel, Sender=Image1; else if (ActiveControl==Image2->Parent) Event=Image2MouseWheel, Sender=Image2; else if (ActiveControl==AImage3->Parent) Event=AImage3MouseWheel, Sender=AImage3; else if (ActiveControl==AImage1->Parent) Event=AImage3MouseWheel, Sender=AImage1; else if (ActiveControl==AImage4->Parent) Event=AImage4MouseWheel, Sender=AImage4; else if (ActiveControl==AImage2->Parent) Event=AImage4MouseWheel, Sender=AImage2; else if (ActiveControl==MImage1->Parent) Event=MImage1MouseWheel, Sender=MImage1; else if (ActiveControl==MImage2->Parent) Event=MImage1MouseWheel, Sender=MImage2; else if (ActiveControl==RateEdit || ActiveControl==CycleRateEdit) Event=RateEditMouseWheel, Sender=ActiveControl; else if (ActiveControl==DurationEdit || ActiveControl==CycleDurationEdit) Event=DurationEditMouseWheel, Sender=ActiveControl; else if (ActiveControl==CyclePitchEdit) Event=PitchEditMouseWheel, Sender=ActiveControl; if (Event) Event(Sender, Shift, WMsg->WheelDelta, Sender->ScreenToClient(TPoint(WMsg->Pos.x, WMsg->Pos.y)), Handled); WMsg->Result=Handled; if (!Handled) TCustomForm::MouseWheelHandler(Msg); } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Image1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) { double cent; if (Shift.Contains(ssShift)) cent=1; else if (Shift.Contains(ssCtrl)) cent=100; else cent=10; if (WheelDelta<0) cent=-cent; double rate=pow(2, cent/1200); for (int l=0; l<V.L; l++) V.F0C[l]*=rate; V.F0Overall*=rate; for (int fr=0; fr<cyclefrcount; fr++) cyclefs[fr]*=rate; SynthesizeV(HS, &V, WaveView1->SamplesPerSec); SaveV(); S_U(); Handled=true; } void __fastcall TVibratoDemoForm::Image2MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) { double rate; if (Shift.Contains(ssShift)) rate=1.01; else if (Shift.Contains(ssCtrl)) rate=1.282432; else rate=1.05101; if (WheelDelta<0) rate=1.0/rate; if (CurrentModCycle>0) V.Dp[CurrentModCycle]=V.Dp[CurrentModCycle]*rate; else for (int p=1; p<V.P; p++) V.Dp[p]=V.Dp[p]*rate; SynthesizeV(HS, &V, WaveView1->SamplesPerSec); SaveV(); S_U(); Handled=true; } void __fastcall TVibratoDemoForm::AImage3MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) { double ddb; if (Shift.Contains(ssShift)) ddb=0.2; else if (Shift.Contains(ssCtrl)) ddb=5; else ddb=1; double db=20*log10e*V.LogAS[CurrentPartial]; if (WheelDelta<0) ddb=-ddb; db+=ddb; AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db); if (Sender==AImage3) Label7->Caption=S; else Label8->Caption=S; ddb=ddb/(20*log10e); for (int p=1; p<V.P; p++) V.LogASp[p][CurrentPartial]+=ddb; V.LogAS[CurrentPartial]+=ddb; SynthesizeV(HS, &V, WaveView1->SamplesPerSec); SaveV(); S_U(true); Handled=true; } void __fastcall TVibratoDemoForm::AImage4MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) { double ddb; if (Shift.Contains(ssShift)) ddb=0.2; else if (Shift.Contains(ssCtrl)) ddb=5; else ddb=1; double db=20*log10e*V.LogASp[CurrentModCycle][CurrentPartial]; if (WheelDelta<0) ddb=-ddb; db+=ddb; AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db); if (Sender==AImage4) Label9->Caption=S; else Label10->Caption=S; ddb=ddb/(20*log10e); V.LogASp[CurrentModCycle][CurrentPartial]+=ddb; SynthesizeV(HS, &V, WaveView1->SamplesPerSec); SaveV(); S_U(true); Handled=true; } void __fastcall TVibratoDemoForm::MImage1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) { double rate; if (Shift.Contains(ssShift)) rate=1.0192448764914566206520666016133; else if (Shift.Contains(ssCtrl)) rate=1.61051; else rate=1.1; if (WheelDelta<0) rate=1.0/rate; double* FXR; TLabel* Label; if (Sender==MImage1) FXR=V.FXR, Label=Label11; else if (ActiveControl==MImage2->Parent) FXR=V.fxr[CurrentModCycle], Label=Label12; if (CurrentK==0) { FXR[0]*=rate; if (Sender==MImage1) for (int p=1; p<V.P; p++) V.fxr[p][0]*=rate; } else { FXR[2*CurrentK-1]*=rate, FXR[2*CurrentK]*=rate; if (Sender==MImage1) for (int p=1; p<V.P; p++) V.fxr[p][2*CurrentK-1]*=rate, V.fxr[p][2*CurrentK]*=rate; } AnsiString S; if (CurrentK>0) S.sprintf("%d: %.3g", CurrentK, sqrt(FXR[CurrentK*2-1]*FXR[CurrentK*2-1]+FXR[CurrentK*2]*FXR[CurrentK*2])); else if (CurrentK==0) S.sprintf("%d: %.3g", CurrentK, fabs(FXR[0])); Label->Caption=S; Label->Left=ActiveControl->Left+0.5*(KX1[CurrentK]+KX2[CurrentK]-Label->Width); SynthesizeV(HS, &V, WaveView1->SamplesPerSec); SaveV(); S_U(); Handled=true; } void __fastcall TVibratoDemoForm::RateEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) { double rate, irate; if (Shift.Contains(ssShift)) rate=1.01; else if (Shift.Contains(ssCtrl)) rate=1.282432; else rate=1.05101; if (WheelDelta<0) {irate=rate; rate=1.0/rate;} else irate=1.0/rate; if (Sender==CycleRateEdit) { if (CurrentModCycle>0) { double dlp=(V.lp[CurrentModCycle]-V.lp[CurrentModCycle-1])*(irate-1); for (int p=CurrentModCycle; p<V.P; p++) { V.lp[p]+=dlp; if (V.lp[p]>V.L) {V.P=p; break;} } } } else if (Sender==RateEdit) { double newP=V.GetOldP()*rate; if (newP>2.5) { TVo* newV=InterpolateV(newP, rate, V); V.~TVo(); memcpy(&V, newV, sizeof(TVo)); memset(newV, 0, sizeof(TVo)); delete newV; } } SynthesizeV(HS, &V, WaveView1->SamplesPerSec); RateAndReg(V.rate, V.regularity, V.F0D, V.peakfr[0], V.peakfr[V.P-1], 8, WaveView1->SamplesPerSec, WaveView1->SpecOffst); SaveV(); S_U(); Handled=true; } void __fastcall TVibratoDemoForm::DurationEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) { double rate; if (Shift.Contains(ssShift)) rate=1.01; else if (Shift.Contains(ssCtrl)) rate=1.282432; else rate=1.05101; if (WheelDelta<0) rate=1.0/rate; if (Sender==CycleDurationEdit) { if (CurrentModCycle>0) { double dlp=(V.lp[CurrentModCycle]-V.lp[CurrentModCycle-1])*(rate-1); for (int p=CurrentModCycle; p<V.P; p++) { V.lp[p]+=dlp; } int oldL=V.L, newL=V.L+dlp+0.5; double *F0C=new double[V.L*2], *A0C=&F0C[V.L]; memcpy(F0C, V.F0C, sizeof(double)*oldL), memcpy(A0C, V.A0C, sizeof(double)*oldL); V.AllocateL(newL); for (int l=0; l<newL; l++) { double rl=1.0*l*oldL/newL; int il=floor(rl); rl-=il; if (fabs(rl)<1e-16) { V.F0C[l]=F0C[il]; V.A0C[l]=A0C[il]; } else if (il>=oldL-1) { V.F0C[l]=F0C[oldL-1]; V.A0C[l]=A0C[oldL-1]; } else { V.F0C[l]=F0C[il]*(1-rl)+F0C[il+1]*rl; V.A0C[l]=A0C[il]*(1-rl)+A0C[il+1]*rl; } } for (int c=0; c<cyclefrcount; c++) { cyclefrs[c]*=(1.0*newL/oldL); int ic=floor(cyclefrs[c]); if (ic<newL-1) cyclefs[c]=F0C[ic]*(ic+1-cyclefrs[c])+F0C[ic+1]*(cyclefrs[c]-ic); else cyclefs[c]=F0C[newL-1]; } delete[] F0C; } } else if (Sender==DurationEdit) { double newP=V.GetOldP()*rate; if (newP>2.5) { TVo* newV=InterpolateV(newP, 1, V); V.~TVo(); memcpy(&V, newV, sizeof(TVo)); memset(newV, 0, sizeof(TVo)); delete newV; for (int c=0; c<cyclefrcount; c++) { cyclefrs[c]*=rate; int ic=floor(cyclefrs[c]); if (ic<V.L-1) cyclefs[c]=V.F0C[ic]*(ic+1-cyclefrs[c])+V.F0C[ic+1]*(cyclefrs[c]-ic); else cyclefs[c]=V.F0C[V.L-1]; } } } SynthesizeV(HS, &V, WaveView1->SamplesPerSec); RateAndReg(V.rate, V.regularity, V.F0D, V.peakfr[0], V.peakfr[V.P-1], 8, WaveView1->SamplesPerSec, WaveView1->SpecOffst); SaveV(); S_U(); Handled=true; } void __fastcall TVibratoDemoForm::PitchEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) { if (CurrentModCycle<=0) return; double cent; if (Shift.Contains(ssShift)) cent=1; else if (Shift.Contains(ssCtrl)) cent=100; else cent=10; if (WheelDelta<0) cent=-cent; double rate_1=pow(2, cent/1200)-1; int frst=ceil(V.lp[CurrentModCycle-1]), freninc=floor(V.lp[CurrentModCycle]); 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])))); SynthesizeV(HS, &V, WaveView1->SamplesPerSec); SaveV(); S_U(); Handled=true; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::AImage3MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (!HS) return; TImage* Image=(TImage*)Sender; if (Shift.Contains(ssLeft)) { if (CurrentPartial<0) return; int fh=Image->Canvas->TextHeight("0"); int YY=Image->Height-Bdw-Bdwc-fh; double dbperpixel=dbrange/YY; int dY=Y-StartDrag; StartDrag=Y; double ddb=-dY*dbperpixel; if (Sender==AImage1 || Sender==AImage3) { double db=20*log10e*V.LogAS[CurrentPartial]; db+=ddb; AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db); if (Sender==AImage3) Label7->Caption=S; else Label8->Caption=S; ddb=ddb/(20*log10e); for (int p=1; p<V.P; p++) V.LogASp[p][CurrentPartial]+=ddb; V.LogAS[CurrentPartial]+=ddb; } else if (Sender==AImage2 || Sender==AImage4) { double db=20*log10e*V.LogASp[CurrentModCycle][CurrentPartial]; db+=ddb; AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db); if (Sender==AImage4) Label9->Caption=S; else Label10->Caption=S; ddb=ddb/(20*log10e); V.LogASp[CurrentModCycle][CurrentPartial]+=ddb; } SynthesizeV(HS, &V, WaveView1->SamplesPerSec); UpdateDisplay(); } else { Image->Parent->SetFocus(); int lSXc, *lSX; double* LogAS; if (Sender==AImage1 || Sender==AImage3) lSXc=SXc, lSX=SX, LogAS=V.LogAS, X=Bdw+(X-Bdw)*AImage3->Width/((TImage*)Sender)->Width; else if (Sender==AImage2 || Sender==AImage4) lSXc=SXcyclec, lSX=SXcycle, LogAS=V.LogASp[CurrentModCycle], X=Bdw+(X-Bdw)*AImage4->Width/((TImage*)Sender)->Width; if (lSXc<=0) return; CurrentPartial=0; while (CurrentPartial<lSXc && lSX[CurrentPartial]<X) CurrentPartial++; if (CurrentPartial>=lSXc) CurrentPartial=lSXc-1; if (CurrentPartial>=1 && X-lSX[CurrentPartial-1]<lSX[CurrentPartial]-X) CurrentPartial--; double dB=20*log10e*LogAS[CurrentPartial]; AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, dB); TLabel* Label; if (Sender==AImage1) Label=Label8; else if (Sender==AImage2) Label=Label10; else if (Sender==AImage4) Label=Label9; else Label=Label7; Label->Font->Color=RotateColors[CurrentPartial%10]; Label->Caption=S; } } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::MImage1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (!HS) return; if (Shift.Contains(ssLeft)) { if (CurrentK<0) return; } else { TImage* Image=(TImage*)Sender; Image->Parent->SetFocus(); CurrentK=-1; for (int i=0; i<V.K; i++) if (X>=KX1[i] && X<=KX2[i]) {CurrentK=i; break;} if (CurrentK<0) return; double* FXR; TLabel* Label; if (Sender==MImage1) FXR=V.FXR, Label=Label11; else if (Sender==MImage2) { if (CurrentModCycle<0) return; FXR=V.fxr[CurrentModCycle], Label=Label12; } AnsiString S; if (CurrentK>0) S.sprintf("%d: %.3g", CurrentK, sqrt(FXR[CurrentK*2-1]*FXR[CurrentK*2-1]+FXR[CurrentK*2]*FXR[CurrentK*2])); else if (CurrentK==0) S.sprintf("%d: %.3g", CurrentK, fabs(FXR[0])); Label->Caption=S; Label->Left=Image->Parent->Left+0.5*(KX1[CurrentK]+KX2[CurrentK]-Label->Width); } } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Image2DblClick(TObject *Sender) { TPoint P1; GetCursorPos(&P1); TPoint P2=MImage1->ClientToScreen(TPoint(0, MImage1->Height*0.3819)); SetCursorPos(P1.x, P2.y); } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::AImage1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { FirstStartDrag=StartDrag=Y; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::AImage1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (Y!=FirstStartDrag) { SaveV(); Synthesize(); UpdateDisplay(); } } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::CycleRateEditMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { TEdit* Edit=(TEdit*)Sender; Edit->SetFocus(); } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::PageControl1Change(TObject *Sender) { if (PageControl1->ActivePage==ModOverSheet || PageControl1->ActivePage==ModCycleSheet) ResidueCheck->Parent=PageControl1->ActivePage; else if (PageControl1->ActivePage==AmpOverSheet || PageControl1->ActivePage==AmpCycleSheet) {SFCheck->Parent=PageControl1->ActivePage; MACheck->Parent=PageControl1->ActivePage;} UpdateDisplay(); } //--------------------------------------------------------------------------- void SourceResponse(double* SV, TVo* V) { int N=V->afres/2; memset(SV, 0, sizeof(double)*N); for (int p=1; p<V->P; p++) { double F0p=0; int frst=V->lp[p-1], fren=V->lp[p]; for (int fr=frst; fr<fren; fr++) F0p+=V->F0C[fr]; F0p/=(fren-frst); F0p*=V->afres; int lastfp; double lastsv; for (int m=0; m<V->M; m++) { int fp=F0p*(m+1); double sv=V->LogASp[p][m]; if (m==0) for (int n=0; n<fp; n++) SV[n]+=sv; else for (int n=lastfp; n<fp; n++) SV[n]+=(sv*(n-lastfp)+lastsv*(fp-n))/(fp-lastfp); lastfp=fp, lastsv=sv; } for (int n=lastfp; n<N; n++) SV[n]+=lastsv; } for (int n=0; n<N; n++) SV[n]/=(V->P-1); } //S_U implements delayed updating of lengthy synthesizing to speed up operation // in case the HS is updated frequently, s.a. during mouse wheeling. //This allows a later synthesis to start before an earlier synthesis finishes, // at which the latter is terminated and its incomplete result is discarded. void __fastcall TVibratoDemoForm::S_U(bool sf) { if (SUThread) { SUThread->Terminate(); } SUThread=new TSUThread(true); SUThread->sf=sf; SUThread->OnTerminate=SUTerminate; SUThread->HS=new THS(HS); ThreadList[pThread++]=SUThread; if (pThread==ThreadCaps/2 && ThreadList[pThread]) for (int i=pThread; i<ThreadCaps; i++) {delete ThreadList[i]; ThreadList[i]=0;} else if (pThread==ThreadCaps) { for (int i=0; i<ThreadCaps/2; i++) {delete ThreadList[i]; ThreadList[i]=0;} pThread=0; } SUThread->Resume(); } void __fastcall TVibratoDemoForm::SUTerminate(TObject* Sender) { TSUThread* CurrentThread=(TSUThread*)Sender; if (CurrentThread==SUThread) { double* xrec=CurrentThread->xrec; if (xrec) { int dst=CurrentThread->dst, den=CurrentThread->den; if (dst<0) dst=0; __int16* data=new __int16[den]; memset(data, 0, sizeof(__int16)*dst); DoubleToInt(&data[dst], sizeof(__int16), xrec, den-dst); WaveAudio2->Clear(NULL); WaveAudio2->WriteSamples(data, den-dst); delete[] data; UpdateDisplay(); } SUThread=0; } else { UpdateDisplay(true, true, true, CurrentThread->sf); } free8(CurrentThread->xrec); CurrentThread->xrec=0; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Panel4Resize(TObject *Sender) { Panel10->Height=Panel4->Height/3; ForceUpdate=true; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Panel8Resize(TObject *Sender) { int H=(Panel8->Height-Splitter4->Height-Splitter5->Height)/3; Panel9->Height=H; Panel7->Height=H; ForceUpdate=true; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Panel1Resize(TObject *Sender) { Panel2->Height=(Panel1->Height-Splitter1->Height)/2; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::AmpOverSheetResize(TObject *Sender) { double W=(AmpOverSheet->Width-24)/20.0; AImage3->Parent->Width=W*9; Label7->Width=AImage3->Parent->Width; AImage1->Parent->Left=AImage3->Parent->Left+AImage3->Parent->Width+8; AImage1->Parent->Width=W*11; Label8->Left=AImage1->Parent->Left; Label8->Width=AImage1->Parent->Width; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::AmpCycleSheetResize(TObject *Sender) { double W=(AmpCycleSheet->Width-24)/20.0; AImage4->Parent->Width=W*9; Label9->Width=AImage4->Parent->Width; AImage2->Parent->Left=AImage4->Parent->Left+AImage4->Parent->Width+8; AImage2->Parent->Width=W*11; Label10->Left=AImage2->Parent->Left; Label10->Width=AImage2->Parent->Width; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::ListBox1Click(TObject *Sender) { if (ListBox1->ItemIndex==1) ThetaEdit->Enabled=true; else ThetaEdit->Enabled=false; Reset(); } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Button1Click(TObject *Sender) { int N=WaveView1->Length, Channel=Form1->HS->Channel; if (GetKeyState(VK_SHIFT)<0) { __int16* d2=WaveView2->Data16[0]; Form1->PostWaveViewData(d2, Channel, StartPos, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt()); } else { __int16 *data=new __int16[N], *data1=WaveView1->Data16[0], *data2=WaveView2->Data16[0]; int NN=N; if (NN>WaveView2->Length) NN=WaveView2->Length; for (int n=0; n<NN; n++) data[n]=data1[n]-datain[n]+data2[n]; for (int n=NN; n<N; n++) data[n]=data1[n]-datain[n]; Form1->PostWaveViewData(data, Channel, StartPos, StartPos+NN, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt()); if (NN!=N) Form1->PostWaveViewData(&data[NN], Channel, StartPos+NN, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt()); delete[] data; } } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Panel9Resize(TObject *Sender) { ForceUpdate=true; } //--------------------------------------------------------------------------- void __fastcall TVibratoDemoForm::Panel7Resize(TObject *Sender) { ForceUpdate=true; } //---------------------------------------------------------------------------