xue@0: /* xue@0: Harmonic Visualiser xue@0: xue@0: An audio file viewer and editor. xue@0: Centre for Digital Music, Queen Mary, University of London. xue@0: This file copyright 2011 Wen Xue. xue@0: xue@0: This program is free software; you can redistribute it and/or xue@0: modify it under the terms of the GNU General Public License as xue@0: published by the Free Software Foundation; either version 2 of the xue@0: License, or (at your option) any later version. xue@0: */ xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: #include xue@0: #pragma hdrstop xue@0: xue@0: #include xue@0: #include xue@0: #include "SFDemoUnit.h" xue@0: #include "Matrix.h" xue@0: #include "Unit1.h" xue@0: #include "splines.h" xue@0: //--------------------------------------------------------------------------- xue@0: #pragma package(smart_init) xue@0: #pragma resource "*.dfm" xue@0: TSFDemoForm *SFDemoForm; xue@0: //--------------------------------------------------------------------------- xue@0: const double log10e=Log10(exp(1)); xue@0: const Bdw=5, Bdwc=2; //border width of charts xue@0: const ftrr=5; //filter control point radius xue@0: xue@0: xue@0: __fastcall TSFDemoForm::TSFDemoForm(TComponent* Owner) xue@0: : TForm(Owner) xue@0: { xue@0: ForceUpdate=false; xue@0: xue@0: double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(); xue@0: dbrange=updb-downdb; xue@0: xue@0: SUThread=0; xue@0: pThread=0; xue@0: memset(ThreadList, 0, sizeof(TSUThread*)*ThreadCaps); xue@0: xue@0: WaveAudio1=new TWaveAudio(NULL); xue@0: WaveAudio1->UseMemoryStream=true; xue@0: WaveAudio1->Channels=1; xue@0: WaveView1=new TWaveView(NULL); xue@0: WaveView1->Parent=Panel2; xue@0: WaveView1->Align=alClient; xue@0: WaveView1->WaveAudio=WaveAudio1; xue@0: WaveView1->OnGetOpMode=WaveView1OpMode; xue@0: WaveView1->CreatePanes(1, 1); xue@0: WaveView1->SetContent(0, 0, 0, 1); xue@0: WaveView1->ClickFocus=true; xue@0: WaveView1->DefaultPopupMenu=false; xue@0: WaveView1->CustomInfo=WaveView1CustomInfo; xue@0: WaveView1->InfoLeft=5; WaveView1->InfoTop=5; xue@0: xue@0: WaveAudio2=new TWaveAudio(NULL); xue@0: WaveAudio2->UseMemoryStream=true; xue@0: WaveAudio2->Channels=1; xue@0: WaveView2=new TWaveView(NULL); xue@0: WaveView2->Parent=Panel3; xue@0: WaveView2->Align=alClient; xue@0: WaveView2->WaveAudio=WaveAudio2; xue@0: WaveView2->CreatePanes(1, 1); xue@0: WaveView2->SetContent(0, 0, 0, 1); xue@0: WaveView2->ClickFocus=true; xue@0: WaveView2->DefaultPopupMenu=false; xue@0: WaveView2->CustomInfo=WaveView1CustomInfo; xue@0: WaveView2->InfoLeft=5; WaveView2->InfoTop=5; xue@0: WaveView2->LoopPlay=CheckBox1->Checked; xue@0: xue@0: xue@0: HS=0; xue@0: cyclefrs=0; xue@0: cyclefs=0; xue@0: xue@0: MethodListBox->ItemIndex=0; xue@0: xue@0: analyze2=false; xue@0: xue@0: AnsiString Path=ExtractFilePath(Application->ExeName)+"*.sf"; xue@0: TSearchRec sr; xue@0: if (FindFirst(Path, faAnyFile, sr)==0) xue@0: { xue@0: do xue@0: { xue@0: TmplListBox->Items->Add(sr.Name); xue@0: } xue@0: while (FindNext(sr) == 0); xue@0: FindClose(sr); xue@0: } xue@0: Wave1=0; xue@0: CurrentP=-1; xue@0: xue@0: memset(&SF, 0, sizeof(TSF)); xue@0: memset(&SF0, 0, sizeof(TSF)); xue@0: xue@0: datain=0; xue@0: } xue@0: xue@0: __fastcall TSFDemoForm::~TSFDemoForm() xue@0: { xue@0: delete WaveAudio1; xue@0: delete WaveAudio2; xue@0: delete WaveView1; xue@0: delete WaveView2; xue@0: delete HS; xue@0: delete[] cyclefrs; xue@0: delete[] cyclefs; xue@0: for (int i=0; iM<=0 || HS->Fr<=0) return; xue@0: xue@0: if (MethodListBox->ItemIndex<0) MethodListBox->ItemIndex=0; xue@0: xue@0: double sps=WaveView1->SamplesPerSec; xue@0: double h=WaveView1->SpecOffst; xue@0: int FSMode=MethodListBox->ItemIndex; xue@0: double FSF=FEdit->Text.ToDouble(); xue@0: int FSFScale=FScaleCombo->ItemIndex; xue@0: if (FSFScale==0) FSF/=sps; xue@0: else FSF/=Amel*log(1+sps/700); xue@0: double FStheta=ThetaEdit->Text.ToDouble(); xue@0: xue@0: AnalyzeSF_1(*HS, SF, sps, h); xue@0: AnalyzeSF_2(*HS, SF, cyclefrs, cyclefs, sps, &cyclefrcount, FSMode, FSF, FSFScale, FStheta); xue@0: xue@0: SaveSF(); xue@0: SaveSF0(); xue@0: xue@0: UpdateDisplay(); xue@0: } xue@0: xue@0: void TSFDemoForm::Synthesize() xue@0: { xue@0: int dst, den; xue@0: double* xrec; xue@0: if (HS) xue@0: { xue@0: double t=GetTickCount(); xue@0: xrec=SynthesisHS(HS, dst, den); xue@0: t=GetTickCount()-t; xue@0: Label13->Caption=t; xue@0: } xue@0: int bips=WaveAudio1->BitsPerSample; xue@0: double max=(1<<(bips-1)); for (int i=dst; imax) max=xrec[i]; else if (xrec[i]<-max) max=-xrec[i]; xue@0: if (max>(1<<(bips-1))) xue@0: { xue@0: max=(1<<(bips-1))/max; xue@0: for (int i=dst; iClear(NULL); xue@0: WaveAudio2->GetWaveProperties(WaveAudio1); xue@0: if (HS) xue@0: { xue@0: if (dst<0) dst=0; xue@0: void* data=new char[(den-dst)*bps]; xue@0: DoubleToInt(data, bps, xrec, den-dst); xue@0: xue@0: WaveAudio2->Clear(NULL); xue@0: WaveAudio2->WriteSamples(data, den-dst); xue@0: free8(xrec); xue@0: delete[] data; xue@0: } xue@0: } xue@0: xue@0: //for frequency modulator shape xue@0: void DrawsBarMap(Graphics::TBitmap* Bitmap, TRect Rect, int Count, double* data, bool res, int* KX1=0, int* KX2=0) xue@0: { xue@0: TCanvas* Canvas=Bitmap->Canvas; xue@0: Bitmap->Width=Rect.Width(); xue@0: Bitmap->Height=Rect.Height(); xue@0: xue@0: TFont* F=Canvas->Font; F->Color=clWhite; F->Height=12; F->Name="Ariel"; xue@0: int fh=Canvas->TextHeight("0"); xue@0: int DrawCount=res?(Count+1):Count; xue@0: xue@0: double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh; xue@0: Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect); xue@0: Canvas->Brush->Color=clAqua; Canvas->Pen->Color=clAqua; Canvas->Brush->Style=bsSolid; xue@0: int empspace=XX/(DrawCount+1)/4; xue@0: double r=0; for (int i=0; i1)?0:sqrt(1-r); xue@0: for (int i=0; i=1) xue@0: { xue@0: Canvas->Brush->Style=bsSolid; Canvas->Brush->Color=TColor(0xFFFF00); xue@0: Canvas->Rectangle(X-empspace, Y, X+empspace, Bdw+YY); xue@0: if (KX1) KX1[i]=X-empspace, KX2[i]=X+empspace-1; xue@0: } xue@0: else xue@0: { xue@0: Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY); xue@0: if (KX1) KX1[i]=X-1, KX2[i]=X+1; xue@0: } xue@0: AnsiString S=i; if (i>=Count) S="R"; int fw=Canvas->TextWidth(S); xue@0: Canvas->Brush->Style=bsClear; xue@0: Canvas->TextOut(X-fw/2, Bdw+YY, S); xue@0: S.sprintf("%.3g", 100*ldata*ldata); if (S[1]=='0') S=S.SubString(2, S.Length()-1); fw=Canvas->TextWidth(S); xue@0: if (Y-Bdw>fh) Canvas->TextOut(X-fw/2, Y-fh, S); xue@0: else Canvas->TextOut(X+empspace+1, Y, S); xue@0: } xue@0: Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite; xue@0: Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY); xue@0: } xue@0: xue@0: TColor RotateColors[10]={clWhite, clAqua, clLime, clYellow, clRed, clTeal, clGray, clGreen, clFuchsia, clBlue}; xue@0: //draw A-F distribution xue@0: 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: { xue@0: double log10e=1.0/log(10); xue@0: Bitmap->Width=Rect.Width(); xue@0: Bitmap->Height=Rect.Height(); xue@0: TCanvas* Canvas=Bitmap->Canvas; xue@0: double idbrange=1.0/(dbst-dben); xue@0: TFont* F=Canvas->Font; F->Color=clWhite; F->Height=TextHeight; F->Name="Ariel"; xue@0: int fh=Canvas->TextHeight("0"); xue@0: xue@0: double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh; xue@0: Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect); xue@0: xue@0: Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5); xue@0: xue@0: double *x=new double[(fren-frst)*4], *y=&x[fren-frst], *newa=&x[(fren-frst)*2], *neww=&x[(fren-frst)*3]; xue@0: xue@0: for (int m=0; mPen->Color=RotateColors[m%10]; Canvas->Brush->Color=RotateColors[m%10]; xue@0: xue@0: int Sc=0; xue@0: bool visible=false; xue@0: atom* Partialsm=Partials[m]; xue@0: for (int fr=frst; fr0 && Partialsm[fr].a>0) xue@0: { xue@0: x[Sc]=Partials[m][fr].f; xue@0: y[Sc]=20*(Log10(Partialsm[fr].a)); xue@0: if (x[Sc]x[c]*0.05) fw=x[c]*0.05; xue@0: xue@0: for (int c1=0; c1xen) continue; xue@0: double ldata=(y[c]-dben)*idbrange; xue@0: int X=floor(Bdw+XX*(x[c]-xst)/(xen-xst)+0.5); xue@0: int Y=floor(Bdw+YY*(1-ldata)+0.5); xue@0: if (bars) {Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY);} xue@0: else {Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2);} xue@0: } xue@0: } xue@0: xue@0: AnsiString S=AnsiString().sprintf("%.2gkhz", sps*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S); xue@0: S=AnsiString().sprintf("%.2gkhz", sps*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S); xue@0: S=AnsiString().sprintf("%.2gkhz", sps*xen/1000); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S); xue@0: S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S); xue@0: S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S); xue@0: S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S); xue@0: xue@0: Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite; xue@0: Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY); xue@0: xue@0: delete[] x; xue@0: xue@0: } //*/ xue@0: //for source-filter results xue@0: 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: { xue@0: Bitmap->Width=Rect.Width(); xue@0: Bitmap->Height=Rect.Height(); xue@0: TCanvas* Canvas=Bitmap->Canvas; xue@0: TFont* Ft=Canvas->Font; Ft->Color=clWhite; Ft->Height=TextHeight; Ft->Name="Ariel"; xue@0: int fh=Canvas->TextHeight("0"); xue@0: xue@0: double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh; xue@0: Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect); xue@0: xue@0: Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5); xue@0: xue@0: double xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange, xue@0: xrangeiXX=xrange/XX, xue@0: YYidbrange=YY/(dbst-dben); xue@0: xue@0: int *XRec=new int[XX]; xue@0: for (int m=0; mBrush->Color=RotateColors[m%10]; Canvas->Pen->Color=RotateColors[m%10]; xue@0: memset(XRec, 0, sizeof(int)*XX); xue@0: xue@0: for (int fr=frst; fr0 && Partialsm[fr].a>0) xue@0: { xue@0: double xx=Partialsm[fr].f; xue@0: if (xxxen) continue; xue@0: int X=floor(XXixrange*xx-xstXXixrange+0.5); xue@0: if (X>=0 && XMoveTo(X-1, Y); Canvas->LineTo(X+2, Y); xue@0: Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2); xue@0: } xue@0: }}catch(...) xue@0: {int k=0;} xue@0: } xue@0: if (!visible) break; xue@0: } xue@0: delete[] XRec; xue@0: xue@0: AnsiString S=AnsiString().sprintf("%.2gkhz", Fs*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S); xue@0: S=AnsiString().sprintf("%.2gkhz", Fs*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S); xue@0: S=AnsiString().sprintf("%.2gkhz", Fs*xen/1000); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S); xue@0: S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S); xue@0: S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S); xue@0: S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S); xue@0: xue@0: Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite; xue@0: Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY); xue@0: } xue@0: xue@0: //*for source-filter model xue@0: 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: { xue@0: double FShift=FShiftdB/(20.0*log10e); //allowing the filter to be drawn with a vertical shift, and source an opposite shift xue@0: Bitmap->Width=Rect.Width(); xue@0: Bitmap->Height=Rect.Height(); xue@0: TCanvas* Canvas=Bitmap->Canvas; xue@0: double *Sx=new double[M]; xue@0: for (int i=0; iFont; Ft->Color=clWhite; Ft->Height=TextHeight; Ft->Name="Ariel"; xue@0: int fh=Canvas->TextHeight("0"); xue@0: xue@0: double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh; xue@0: Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect); xue@0: Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5); xue@0: xue@0: double idbrange=1.0/(updb-downdb), xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange, xue@0: YY20log10eidbrange=YY*20*log10e*idbrange, BdwpYYpYYdbenidbrange=Bdw+YY+YY*downdb*idbrange, xue@0: Bdw_xstXXixrange=Bdw-xstXXixrange, YYidbrange=YY*idbrange; xue@0: xue@0: double st=xst/F; int ist=ceil(st); if (ist<0) ist=0; xue@0: Canvas->Pen->Color=clWhite; xue@0: int X=Bdw+XX*(F*ist-xst)/xrange+0.5, Y=BdwpYYpYYdbenidbrange-YY20log10eidbrange*(h[ist]+FShift)+0.5; xue@0: 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: Canvas->MoveTo(X, Y); xue@0: //draw filter contour xue@0: int LineCount=xrange/F; xue@0: if (LineCountLineTo(X, Y); xue@0: 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: } xue@0: } xue@0: else xue@0: { xue@0: double di=xrange/(XX*F); xue@0: for (int x=0; xLineTo(Bdw+x, Y); xue@0: 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: } xue@0: } xue@0: //draw source lines xue@0: for (int i=0; ixen) continue; xue@0: int X=floor(Bdw_xstXXixrange+XXixrange*xi+0.5); xue@0: int Y=floor(BdwpYYpYYdbenidbrange-YYidbrange*Sx[i]+0.5); xue@0: if (Colors) Canvas->Pen->Color=Colors[i]; xue@0: else Canvas->Pen->Color=RotateColors[i%10]; xue@0: xue@0: Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY); xue@0: xue@0: if (SX) SX[i]=X, result++; xue@0: } xue@0: AnsiString S=AnsiString().sprintf("%.2gkhz", Fs*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S); xue@0: S=AnsiString().sprintf("%.2gkhz", Fs*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S); xue@0: S=AnsiString().sprintf("%.2gkhz", Fs*xen/1000); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S); xue@0: S.sprintf("%gdB", updb); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S); xue@0: S.sprintf("%gdB", (updb+downdb)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S); xue@0: S.sprintf("%gdB", downdb); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S); xue@0: xue@0: Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite; xue@0: Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY); xue@0: delete[] Sx; xue@0: return result; xue@0: } //*/ xue@0: xue@0: 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: { xue@0: if (f_ex==0) f_ex=0.01; xue@0: Canvas->Brush->Color=cl3DDkShadow; Canvas->FillRect(Rect); xue@0: int Width=Rect.Width(), Height=Rect.Height(); xue@0: Bitmap->Width=Width; Bitmap->Height=Height; xue@0: TPen* Pn=Canvas->Pen; xue@0: TFont* F=Canvas->Font; xue@0: xue@0: if (HLX1Brush->Color=clDkGray; Canvas->FillRect(TRect(HLX1, 0, HLX2, Height)); xue@0: Canvas->Brush->Color=cl3DDkShadow; xue@0: } xue@0: xue@0: int X, Y, Y1=0, Y2=Height, Y_; xue@0: AnsiString S, as; xue@0: xue@0: Pn->Color=clBlack; Pn->Style=psDot; F->Color=clBlack; F->Height=12; F->Name="Ariel"; xue@0: int lp0=ceil(lp[0]), lpp=ceil(lp[P-1]); xue@0: double f0max=-0.5, f0min=0.5; for (int fr=lp0; frF0[fr]) f0min=F0[fr];} xue@0: Y1=Height*(0.5-(f0max-f_c)/f_ex); Canvas->MoveTo(0, Y1); Canvas->LineTo(Width, Y1); xue@0: 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: Y2=Height*(0.5-(f0min-f_c)/f_ex); Canvas->MoveTo(0, Y2); Canvas->LineTo(Width, Y2); xue@0: 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: xue@0: if (peakmark) xue@0: { xue@0: int Y0=0.5*(Y1+Y2), Y0ex=0.5*(Y1-Y2); xue@0: xue@0: for (int pfr=0; pfrColor=peakmarkcolor; Pn->Style=psDot; Canvas->MoveTo(X, Y1); Canvas->LineTo(X, Y2); xue@0: if (BX1) BX1[pfr]=X-1; xue@0: if (BX2) BX2[pfr]=X+1; xue@0: } xue@0: } xue@0: xue@0: if (Captions) {Y_=Height*(0.5-(F0Overall-f_c)/f_ex); Pn->Color=clWhite; Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_);} xue@0: xue@0: Pn->Style=psSolid; Pn->Color=F0Color; xue@0: for (int fr=0; fr0) Canvas->MoveTo(X, Y); xue@0: X=Width*Partials[1][fr].t/L, Y=Height*(0.5-(F0[fr]-f_c)/f_ex); xue@0: if (fr>0) Canvas->LineTo(X, Y); xue@0: } xue@0: xue@0: if (frs) xue@0: { xue@0: Pn->Color=clRed; xue@0: for (int pfr=0; pfrMoveTo(X-4, Y); Canvas->LineTo(X+5, Y); xue@0: Canvas->MoveTo(X, Y-4); Canvas->LineTo(X, Y+5); xue@0: } xue@0: } xue@0: xue@0: if (Captions) xue@0: { xue@0: as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Overall*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Overall*sps, as.c_str()); xue@0: F->Color=clWhite; F->Style=F->Style<TextOut(Width-Canvas->TextWidth(S), Y_+1, S); F->Style=F->Style>>fsBold; xue@0: F->Color=clSilver; S="F0"; Canvas->TextOut(1, Height-Canvas->TextHeight(S), S); xue@0: 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: 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: } xue@0: } xue@0: xue@0: 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: { xue@0: if (f_ex==0) f_ex=f_c*0.005; xue@0: //Draw the F0 carrier xue@0: Canvas->Brush->Color=cl3DDkShadow; if (clearbackground) Canvas->FillRect(Rect); xue@0: int Width=Rect.Width(), Height=Rect.Height(); xue@0: Bitmap->Width=Width; Bitmap->Height=Height; xue@0: TPen* P=Canvas->Pen; xue@0: TFont* F=Canvas->Font; xue@0: xue@0: P->Color=clBlack; xue@0: F0Cmax=f_c-f_ex, F0Cmin=f_c+f_ex; xue@0: for (int fr=0; frF0C[fr]) F0Cmin=F0C[fr];} xue@0: P->Style=psDot; xue@0: int X, Y=Height*(0.5-(F0Cmax-f_c)/f_ex); xue@0: Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y); xue@0: AnsiString as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Cmax*sps)/C4)); AnsiString S; S.sprintf("%.4ghz (%s)", F0Cmax*sps, as.c_str()); xue@0: F->Color=clBlack; F->Height=12; F->Name="Ariel"; Canvas->TextOut(1, Y-Canvas->TextHeight(S)-1, S); xue@0: Y=Height*(0.5-(F0Cmin-f_c)/f_ex); xue@0: Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y); xue@0: as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Cmin*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Cmin*sps, as.c_str()); xue@0: Canvas->TextOut(1, Y+1, S); xue@0: P->Color=clWhite; xue@0: as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Overall*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Overall*sps, as.c_str()); xue@0: int Y_=Height*(0.5-(F0Overall-f_c)/f_ex); xue@0: Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_); xue@0: F->Color=clWhite; F->Style=F->Style<TextHeight(S)TextOut(Width-Canvas->TextWidth(S), Y_+1, S); xue@0: else Canvas->TextOut(Width-Canvas->TextWidth(S), Y+1, S); xue@0: F->Style=F->Style>>fsBold; xue@0: xue@0: P->Style=psSolid; P->Color=clLime; xue@0: for (int fr=0; fr0) Canvas->MoveTo(X, Y); xue@0: X=Width*Partials[1][fr].t/L, Y=Height*(0.5-(F0C[fr]-f_c)/f_ex); xue@0: if (fr>0) Canvas->LineTo(X, Y); xue@0: } xue@0: xue@0: if (frcount) xue@0: { xue@0: P->Color=clRed; xue@0: for (int p=0; pMoveTo(X-4, Y); Canvas->LineTo(X+5, Y); xue@0: Canvas->MoveTo(X, Y-4); Canvas->LineTo(X, Y+5); xue@0: if (CX1) CX1[p]=X-4; xue@0: if (CX2) CX2[p]=X+4; xue@0: if (CY1) CY1[p]=Y-4; xue@0: if (CY2) CY2[p]=Y+4; xue@0: } xue@0: } xue@0: xue@0: double f=(f_c+f_ex/2)*sps; xue@0: F->Color=clSilver; xue@0: as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str()); xue@0: Canvas->TextOut(Width-Canvas->TextWidth(S), 0, S); xue@0: 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: Canvas->TextOut(Width-Canvas->TextWidth(S), Height-Canvas->TextHeight(S), S); xue@0: F->Color=clSilver; S="F0 carrier"; xue@0: Canvas->TextOut(1, Height-Canvas->TextHeight(S), S); xue@0: } xue@0: xue@0: //y=ax+b xue@0: void linefit(int n, double* x, double* y, double* indi, double& a, double& b) xue@0: { xue@0: double sx=0, sy=0, sxy=0, sxx=0, m=0; xue@0: for (int i=0; i0) sx+=x[i], sy+=y[i], sxx+=x[i]*x[i], sxy+=x[i]*y[i], m++; xue@0: if (m<=0) {a=-1; b=-1; return;} xue@0: double id=1.0/(m*sxx-sx*sx); xue@0: a=(m*sxy-sx*sy)*id; xue@0: b=(sxx*sy-sx*sxy)*id; xue@0: } xue@0: xue@0: xue@0: xue@0: void TSFDemoForm::UpdateDisplay(bool f0, bool f0c, bool f0d, bool sf) xue@0: { xue@0: int Fr=HS->Fr; xue@0: atom** Partials=HS->Partials; xue@0: //find the highest point of the 2nd partial xue@0: double f2min=1, f2max=0, fst=0, fen=fmaxEdit->Text.ToDouble(); xue@0: for (int fr=0; frPartials[1][fr].f) f2min=Partials[1][fr].f; xue@0: } xue@0: f_c=(f2min+f2max)/4; f_ex=f2max-f2min; xue@0: xue@0: if (f0) xue@0: { xue@0: int HLX1=0, HLX2=0; xue@0: if (CurrentP>=0) HLX1=BX1[CurrentP]+1, HLX2=BX1[CurrentP+1]+1; xue@0: 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: } xue@0: if (f0c) xue@0: { xue@0: 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: 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: } xue@0: if (f0d) xue@0: { xue@0: //Draw the F0 modulator xue@0: DrawModulator(); xue@0: } xue@0: xue@0: if (sf) xue@0: { xue@0: int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]); xue@0: double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble(); xue@0: dbrange=updb-downdb; xue@0: if (SFCheck->Checked) xue@0: 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: else xue@0: DrawAF(AImage1->Picture->Bitmap, AImage1->ClientRect, fst, fen, updb, downdb, SF.M, lp0, lpp, Partials, MACheck->Checked, false, WaveView1->SamplesPerSec); xue@0: dbrange=updb-downdb; xue@0: 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: } xue@0: xue@0: ForceUpdate=false; xue@0: } xue@0: xue@0: void __fastcall TSFDemoForm::WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode) xue@0: { xue@0: if (Shift.Contains(ssShift)) OpMode=0; //drag mode xue@0: else OpMode=1; //select mode xue@0: } xue@0: xue@0: int __fastcall TSFDemoForm::WaveView1CustomInfo(TObject* Sender) xue@0: { xue@0: TWaveView* WV=(TWaveView*)Sender; xue@0: TStringList* List=new TStringList; xue@0: double fs=WV->StartPos*1.0/WV->SamplesPerSec, fe=WV->EndPos*1.0/WV->SamplesPerSec; xue@0: List->Add(AnsiString().sprintf(" Time (%.4gs): from %.4gs to %.4gs. ", fe-fs, fs, fe)); xue@0: List->Add(AnsiString().sprintf(" Frequency: from %.1fhz to %.1fhz. ", WV->StartDigiFreq*WV->SamplesPerSec, WV->EndDigiFreq*WV->SamplesPerSec)); xue@0: return int(List); xue@0: } xue@0: xue@0: void __fastcall TSFDemoForm::Image1MouseMove(TObject *Sender, xue@0: TShiftState Shift, int X, int Y) xue@0: { xue@0: if (!HS) return; xue@0: TImage* Image=(TImage*)Sender; xue@0: Image->Parent->SetFocus(); xue@0: xue@0: double t, sps=WaveView1->SamplesPerSec, f; AnsiString S, as; TFont* F=Image->Canvas->Font; xue@0: xue@0: if (Sender==Image0) xue@0: { xue@0: if (Shift.Contains(ssLeft)) xue@0: { xue@0: if (CurrentB<0 || CurrentB>=SF.P) return; xue@0: if (X<0 || X>=Image->Width || CurrentB>0 && X<=BX2[CurrentB-1] || CurrentB=BX1[CurrentB+1]){} xue@0: else xue@0: { xue@0: double dlp=1.0*(X-StartDragX)*SF.L/Image->Width; xue@0: SF.lp[CurrentB]+=dlp; xue@0: StartDragX=X; xue@0: } xue@0: } xue@0: else xue@0: { xue@0: CurrentB=-1; xue@0: for (int i=0; i=BX1[i] && X<=BX2[i]) {CurrentB=i; break;} xue@0: } xue@0: } xue@0: else if (Sender==Image1) xue@0: { xue@0: if (Shift.Contains(ssLeft)) xue@0: { xue@0: if (CurrentC<0 || CurrentC>=cyclefrcount) return; xue@0: double df=-(Y-StartDrag)*f_ex/Image->Height; xue@0: cyclefs[CurrentC]+=df; xue@0: StartDrag=Y; xue@0: Smooth_Interpolate(SF.F0C, SF.L, cyclefrcount+1, cyclefs, cyclefrs); xue@0: SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec); xue@0: UpdateDisplay(true, true, true, false); xue@0: xue@0: t=HS->Partials[0][0].t+SF.offst*cyclefrs[CurrentC]; xue@0: f=cyclefs[CurrentC]*sps; xue@0: as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); xue@0: S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str()); xue@0: F->Color=clRed; xue@0: Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S); xue@0: } xue@0: else xue@0: { xue@0: CurrentC=-1; xue@0: for (int i=0; i=CX1[i] && X<=CX2[i] && Y>=CY1[i] && Y<=CY2[i]) {CurrentC=i; break;} xue@0: } xue@0: if (CurrentC>=0 && CurrentCPartials[0][0].t+SF.offst*cyclefrs[CurrentC]; xue@0: f=cyclefs[CurrentC]*sps; xue@0: as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); xue@0: S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str()); xue@0: F->Color=clRed; xue@0: Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S); xue@0: } xue@0: else xue@0: { xue@0: S.sprintf(" ", t/sps, f, as.c_str()); xue@0: Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S); xue@0: } xue@0: } xue@0: xue@0: t=WaveView2->Length*1.0*(X+0.5)/Image->Width; xue@0: f=(f_c-(Y-0.5*Image->Height)*f_ex/Image->Height)*sps; xue@0: as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); xue@0: S.sprintf("%.3gs, %.4ghz (%s) ", t/sps, f, as.c_str()); xue@0: F->Color=clAqua; F->Height=12; F->Name="Ariel"; xue@0: Image->Canvas->TextOut(1, 0, S); xue@0: xue@0: xue@0: if (Sender==Image0) xue@0: { xue@0: int Wid=HS->Partials[0][1].s, hWid=Wid/2, Offst=HS->Partials[0][1].t-HS->Partials[0][0].t; xue@0: CurrentFr=(t-hWid)/Offst+0.5; xue@0: if (!Shift.Contains(ssLeft)) CurrentP=-1; while (CurrentPSF.lp[CurrentP+1]) CurrentP++; if (CurrentP>=SF.P-1) CurrentP=-1; xue@0: xue@0: if (CurrentP>=0) xue@0: { xue@0: PageControl1->ActivePage=AmpCycleSheet; xue@0: SFCheck->Parent=Panel14; xue@0: MACheck->Parent=Panel14; xue@0: } xue@0: else xue@0: { xue@0: PageControl1->ActivePage=AmpOverSheet; xue@0: SFCheck->Parent=Panel12; xue@0: MACheck->Parent=Panel12; xue@0: } xue@0: UpdateDisplay(true, 0, CurrentP>=0, 0); xue@0: xue@0: if (CurrentB>=0 && CurrentBPartials[0][0].t+SF.offst*SF.lp[CurrentB]; xue@0: S.sprintf("%.3gs", t/sps); xue@0: F->Color=clYellow; xue@0: Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S); xue@0: } xue@0: else xue@0: { xue@0: S.sprintf(" "); xue@0: Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S); xue@0: } xue@0: } xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void TSFDemoForm::DrawModulator() xue@0: { xue@0: if (PageControl1->ActivePage==AmpCycleSheet && CurrentP>=0 && CurrentPText.ToDouble(); xue@0: int lp0=ceil(SF.lp[0]); xue@0: double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble(); xue@0: dbrange=updb-downdb; xue@0: if (SFCheck->Checked) xue@0: 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: else xue@0: 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: dbrange=updb-downdb; xue@0: 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: } xue@0: } xue@0: xue@0: xue@0: void __fastcall TSFDemoForm::SFCheckClick(TObject *Sender) xue@0: { xue@0: if (Sender==SFCheck) xue@0: { xue@0: MACheck->Visible=!SFCheck->Checked; xue@0: } xue@0: UpdateDisplay(); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: void __fastcall TSFDemoForm::ExternalInput() xue@0: { xue@0: AnsiString FileName=ExtractFilePath(Application->ExeName)+"tsfin"; xue@0: FILE* file; xue@0: if (file=fopen(FileName.c_str(), "rb")) xue@0: { xue@0: SF.LoadFromFileHandle(file); xue@0: fclose(file); xue@0: DeleteFile(FileName); xue@0: SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec); xue@0: xue@0: SaveSF(); xue@0: Synthesize(); xue@0: UpdateDisplay(); xue@0: } xue@0: } xue@0: xue@0: //--------------------------------------------------------------------------- xue@0: void __fastcall TSFDemoForm::SaveSF() xue@0: { xue@0: FILE* file; xue@0: if (file=fopen((ExtractFilePath(Application->ExeName)+"tsfout").c_str(), "wb")) xue@0: { xue@0: SF.SaveToFileHandle(file); xue@0: fclose(file); xue@0: } xue@0: } xue@0: xue@0: void __fastcall TSFDemoForm::SaveSF0() xue@0: { xue@0: SF0.Duplicate(SF); xue@0: } xue@0: xue@0: void __fastcall TSFDemoForm::SaveWave() xue@0: { xue@0: THS* HS=Form1->HS; int dst, den; xue@0: double* xrec=SynthesisHSp(HS, dst, den); xue@0: delete[] Wave1; Wave1=new __int16[WaveView2->Length]; xue@0: DoubleToInt(Wave1, 2, xrec, den-dst); xue@0: free8(xrec); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: void __fastcall TSFDemoForm::MouseWheelHandler(TMessage& Msg) xue@0: { xue@0: TWMMouseWheel* WMsg=(TWMMouseWheel*)&Msg; xue@0: xue@0: bool Handled=false; xue@0: TMouseWheelEvent Event=NULL; xue@0: TControl* Sender; xue@0: TShiftState Shift; memcpy(&Shift, &WMsg->Keys, 1); xue@0: xue@0: if (ActiveControl==Image1->Parent) Event=Image1MouseWheel, Sender=Image1; xue@0: else if (ActiveControl==AImage3->Parent) Event=AImage3MouseWheel, Sender=AImage3; xue@0: else if (ActiveControl==AImage1->Parent) Event=AImage3MouseWheel, Sender=AImage1; xue@0: xue@0: if (Event) Event(Sender, Shift, WMsg->WheelDelta, Sender->ScreenToClient(TPoint(WMsg->Pos.x, WMsg->Pos.y)), Handled); xue@0: WMsg->Result=Handled; xue@0: xue@0: if (!Handled) TCustomForm::MouseWheelHandler(Msg); xue@0: } xue@0: xue@0: //--------------------------------------------------------------------------- xue@0: void __fastcall TSFDemoForm::Image1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) xue@0: { xue@0: double cent; xue@0: if (Shift.Contains(ssShift)) cent=1; xue@0: else if (Shift.Contains(ssCtrl)) cent=100; xue@0: else cent=10; xue@0: xue@0: if (WheelDelta<0) cent=-cent; xue@0: double rate=pow(2, cent/1200); xue@0: xue@0: for (int l=0; lSamplesPerSec); xue@0: SaveSF(); xue@0: S_U(); xue@0: Handled=true; xue@0: } xue@0: xue@0: void __fastcall TSFDemoForm::AImage3MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled) xue@0: { xue@0: double ddb; xue@0: if (Shift.Contains(ssShift)) ddb=0.2; xue@0: else if (Shift.Contains(ssCtrl)) ddb=5; xue@0: else ddb=1; xue@0: double db=20*log10e*SF.avgb[CurrentPartial]; xue@0: if (WheelDelta<0) ddb=-ddb; xue@0: xue@0: db+=ddb; xue@0: AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db); xue@0: Label7->Caption=S; xue@0: ddb=ddb/(20*log10e); xue@0: xue@0: int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]); xue@0: for (int l=0; lSamplesPerSec); xue@0: SaveSF(); xue@0: S_U(true); xue@0: Handled=true; xue@0: } xue@0: xue@0: xue@0: //--------------------------------------------------------------------------- xue@0: void __fastcall TSFDemoForm::AImage3MouseMove(TObject *Sender, xue@0: TShiftState Shift, int X, int Y) xue@0: { xue@0: if (!HS) return; xue@0: TImage* Image=(TImage*)Sender; xue@0: int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]); xue@0: xue@0: if (Shift.Contains(ssLeft)) xue@0: { xue@0: if (CurrentFB<0 && CurrentPartial<0) return; xue@0: int fh=Image->Canvas->TextHeight("0"); xue@0: int YY=Image->Height-Bdw-Bdwc-fh; xue@0: double dbperpixel=dbrange/YY; xue@0: int dY=Y-StartDrag; xue@0: if (dY==0) return; xue@0: StartDrag=Y; xue@0: double ddb=-dY*dbperpixel; xue@0: xue@0: if (Sender==AImage3 && CurrentFB>=0) xue@0: { xue@0: double db=20*log10e*SF.avgh[CurrentPartial]; xue@0: db+=ddb; xue@0: AnsiString S; S.sprintf("Filter control %d: %.2fdB", CurrentFB, db); xue@0: Label7->Caption=S; xue@0: ddb=ddb/(20*log10e); xue@0: xue@0: for (int l=0; lPartials); SaveSF0();} xue@0: } xue@0: else if (Sender==AImage1 || Sender==AImage3) xue@0: { xue@0: double db=20*log10e*SF.avgb[CurrentPartial]; xue@0: db+=ddb; xue@0: AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db); xue@0: Label7->Caption=S; xue@0: ddb=ddb/(20*log10e); xue@0: xue@0: for (int l=0; l0) for (int m=CurrentPartial+dm; m=lp0 && CurrentFrCaption=S; xue@0: ddb=ddb/(20*log10e); xue@0: xue@0: SF.b[CurrentFr-lp0][CurrentPartial]+=ddb; xue@0: } xue@0: } xue@0: xue@0: SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec); xue@0: UpdateDisplay(); xue@0: } xue@0: else xue@0: { xue@0: Image->Parent->SetFocus(); xue@0: xue@0: int lSXc, *lSX; xue@0: double* LogAS; xue@0: if (Sender==AImage1 || Sender==AImage3) lSXc=SXc, lSX=SX, LogAS=SF.avgb, X=Bdw+(X-Bdw)*AImage3->Width/((TImage*)Sender)->Width; xue@0: else if (Sender==AImage2 || Sender==AImage4) xue@0: { xue@0: if (CurrentFr=lpp) return; xue@0: lSXc=SXcyclec, lSX=SXcycle, LogAS=SF.b[CurrentFr-lp0], X=Bdw+(X-Bdw)*AImage4->Width/((TImage*)Sender)->Width; xue@0: } xue@0: xue@0: if (lSXc<=0) return; xue@0: xue@0: CurrentPartial=0; while (CurrentPartial=lSXc) CurrentPartial=lSXc-1; xue@0: if (CurrentPartial>=1 && X-lSX[CurrentPartial-1]FX[lfb]) lfb++; xue@0: if (Sender==AImage3) xue@0: { xue@0: if (X>=FX[lfb]-ftrr && X<=FX[lfb]+ftrr && Y>=FY[lfb]-ftrr && Y<=FY[lfb]+ftrr) CurrentFB=lfb; xue@0: if (X>=FX[lfb-1]-ftrr && X<=FX[lfb-1]+ftrr && Y>=FY[lfb-1]-ftrr && Y<=FY[lfb-1]+ftrr) xue@0: { xue@0: if (CurrentFB==-1) CurrentFB=lfb-1; xue@0: else if (abs(X-FX[lfb-1])=0) xue@0: { xue@0: S.sprintf("Filter control %d: %.2fdB", CurrentFB, 20*log10e*SF.avgh[CurrentFB]); xue@0: Label->Font->Color=clWhite; xue@0: } xue@0: else xue@0: { xue@0: double dB=20*log10e*LogAS[CurrentPartial]; xue@0: S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, dB); xue@0: Label->Font->Color=RotateColors[CurrentPartial%10]; xue@0: } xue@0: Label->Caption=S; xue@0: } xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: void __fastcall TSFDemoForm::AImage1MouseDown(TObject *Sender, xue@0: TMouseButton Button, TShiftState Shift, int X, int Y) xue@0: { xue@0: FirstStartDrag=StartDrag=Y; xue@0: FirstStartDragX=StartDragX=X; xue@0: if (Sender==Image0 && Shift.Contains(ssShift)) xue@0: { xue@0: if (CurrentB>=0) //delete current peakmark xue@0: { xue@0: for (int p=CurrentB; pWidth*SF.L, *newlp=new double[SF.P+3]; xue@0: int newb=0; while (newbBX1[newb]) newb++; xue@0: xue@0: if (newb>0) memcpy(newlp, SF.lp, sizeof(double)*newb); xue@0: if (newbActivePage=AmpOverSheet; xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::AImage1MouseUp(TObject *Sender, xue@0: TMouseButton Button, TShiftState Shift, int X, int Y) xue@0: { xue@0: if (Sender==Image0 && (CurrentB>=0 && X!=FirstStartDragX || analyze2)) xue@0: { xue@0: //do analysis using the new segmentation xue@0: double sps=WaveView1->SamplesPerSec; xue@0: double h=WaveView1->SpecOffst; xue@0: int FSMode=MethodListBox->ItemIndex; xue@0: double FSF=FEdit->Text.ToDouble(); xue@0: int FSFScale=FScaleCombo->ItemIndex; xue@0: if (FSFScale==0) FSF/=sps; xue@0: else FSF/=Amel*log(1+sps/700); xue@0: double FStheta=ThetaEdit->Text.ToDouble(); xue@0: AnalyzeSF_2(*HS, SF, cyclefrs, cyclefs, sps, &cyclefrcount, FSMode, FSF, FSFScale, FStheta); xue@0: SaveSF0(); xue@0: SaveSF(); xue@0: S_U(true); xue@0: UpdateDisplay(); xue@0: analyze2=false; xue@0: } xue@0: else if (Y!=FirstStartDrag) xue@0: { xue@0: SaveSF(); xue@0: S_U(); xue@0: UpdateDisplay(); xue@0: } xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::PageControl1Change(TObject *Sender) xue@0: { xue@0: if (PageControl1->ActivePage==AmpOverSheet) xue@0: { xue@0: SFCheck->Parent=Panel12; xue@0: MACheck->Parent=Panel12; xue@0: } xue@0: else xue@0: { xue@0: SFCheck->Parent=Panel14; xue@0: MACheck->Parent=Panel14; xue@0: } xue@0: UpdateDisplay(); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::SaveButtonClick(TObject *Sender) xue@0: { xue@0: int k=1; AnsiString FileName="1.sf"; xue@0: while (TmplListBox->Items->IndexOf(FileName)>=0) {k++; FileName=AnsiString(k)+".sf";} xue@0: if (GetKeyState(VK_SHIFT)<0) xue@0: { xue@0: AnsiString oldpath=SaveDialog1->InitialDir; xue@0: SaveDialog1->InitialDir=ExtractFileDir(Application->ExeName); xue@0: if (SaveDialog1->Execute()) FileName=SaveDialog1->FileName; xue@0: SaveDialog1->InitialDir=oldpath; xue@0: } xue@0: else FileName=ExtractFilePath(Application->ExeName)+FileName; xue@0: SF.SaveToFile(FileName.c_str()); xue@0: TmplListBox->Items->Add(ExtractFileName(FileName)); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: //calculates increment dh on sf1.avgh so that it becomes sf2.avgh xue@0: // dh should have the same dimenstions as sf1.avgh xue@0: void* CompareFilters(double* dh, TSF& sf1, TSF& sf2) xue@0: { xue@0: int K1=sf1.K, FScale1=sf1.FScaleMode; xue@0: double F1=sf1.F, Fs=sf1.Fs; xue@0: for (int k=0; kItemIndex<0) return; xue@0: AnsiString FileName=ExtractFilePath(Application->ExeName)+TmplListBox->Items->Strings[TmplListBox->ItemIndex]; xue@0: if (!FileExists(FileName)) return; xue@0: double dbamp=TrackBar1->Position/10.0; xue@0: double dbgain=TrackBar2->Position/5.0-10; xue@0: xue@0: TSF* sf=new TSF; xue@0: FILE* file; xue@0: if (file=fopen(FileName.c_str(), "rb")) xue@0: { xue@0: sf->LoadFromFileHandle(file); xue@0: fclose(file); xue@0: } xue@0: if (dbgain!=0) sf->ShiftFilterByDB(dbgain); xue@0: int L=ceil(SF.lp[SF.P-1])-ceil(SF.lp[0]), K=SF.K, M=SF.M; xue@0: double avgbend=SF0.avgb[sf->M-1]; xue@0: switch (ComboBox1->ItemIndex) xue@0: { xue@0: case 0: //use source xue@0: { xue@0: for (int l=0; lM)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]); xue@0: double db=(sfb-SF0.avgb[m])*dbamp; xue@0: for (int l=0; lM)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]); xue@0: double db=(sfb-SF0.avgb[m])*dbamp; xue@0: for (int l=0; lM)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]); xue@0: double db=(sfb-SF0.avgb[m])*dbamp, avgb=0; xue@0: for (int l=0; lM)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]); xue@0: double db=(sfb-SF0.avgb[m])*dbamp, avgb=0; xue@0: for (int l=0; lSamplesPerSec); xue@0: SaveSF(); xue@0: S_U(true); xue@0: UpdateDisplay(); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: //S_U implements delayed updating of lengthy synthesizing to speed up operation xue@0: // in case the HS is updated frequently, s.a. during mouse wheeling. xue@0: //This allows a later synthesis to start before an earlier synthesis finishes, xue@0: // at which the latter is terminated and its incomplete result is discarded. xue@0: void __fastcall TSFDemoForm::S_U(bool sf) xue@0: { xue@0: if (SUThread) xue@0: { xue@0: SUThread->Terminate(); xue@0: } xue@0: SUThread=new TSUThread(true); xue@0: SUThread->sf=sf; xue@0: SUThread->OnTerminate=SUTerminate; xue@0: SUThread->HS=new THS(HS); xue@0: ThreadList[pThread++]=SUThread; xue@0: if (pThread==ThreadCaps/2 && ThreadList[pThread]) xue@0: for (int i=pThread; iResume(); xue@0: } xue@0: xue@0: void __fastcall TSFDemoForm::SUTerminate(TObject* Sender) xue@0: { xue@0: TSUThread* CurrentThread=(TSUThread*)Sender; xue@0: if (CurrentThread==SUThread) xue@0: { xue@0: double* xrec=CurrentThread->xrec; xue@0: if (xrec) xue@0: { xue@0: int dst=CurrentThread->dst, den=CurrentThread->den, bps=WaveAudio2->BitsPerSample; xue@0: if (dst<0) dst=0; xue@0: double max=1<<(bps-1); for (int i=dst; imax) max=xrec[i]; else if (xrec[i]<-max) max=-xrec[i]; xue@0: if (max>1<<(bps-1)) xue@0: { xue@0: max=(1<<(bps-1))/max; xue@0: for (int i=dst; i>3, xrec, den-dst); xue@0: WaveAudio2->Clear(NULL); xue@0: WaveAudio2->WriteSamples(data, den-dst); xue@0: delete[] data; xue@0: UpdateDisplay(); xue@0: } xue@0: SUThread=0; xue@0: } xue@0: else xue@0: { xue@0: UpdateDisplay(true, true, true, CurrentThread->sf); xue@0: } xue@0: free8(CurrentThread->xrec); CurrentThread->xrec=0; xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::Panel4Resize(TObject *Sender) xue@0: { xue@0: ForceUpdate=true; xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: void __fastcall TSFDemoForm::Panel1Resize(TObject *Sender) xue@0: { xue@0: Panel2->Height=(Panel1->Height-Splitter1->Height)/2; xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: xue@0: void __fastcall TSFDemoForm::AmpCycleSheetResize(TObject *Sender) xue@0: { xue@0: UpdateDisplay(); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: void __fastcall TSFDemoForm::MethodListBoxClick(TObject *Sender) xue@0: { xue@0: Reset(); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::AmpOverSheetResize(TObject *Sender) xue@0: { xue@0: UpdateDisplay(); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::Splitter7Moved(TObject *Sender) xue@0: { xue@0: if (Sender==Splitter7) AImage4->Parent->Parent->Height=AImage3->Parent->Parent->Height; xue@0: else if (Sender==Splitter8) AImage3->Parent->Parent->Height=AImage4->Parent->Parent->Height; xue@0: UpdateDisplay(); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::AImage3DblClick(TObject *Sender) xue@0: { xue@0: Graphics::TBitmap* bmp=new Graphics::TBitmap; xue@0: bmp->Width=800; bmp->Height=600; TRect Rect=TRect(0, 0, 800, 600); xue@0: xue@0: xue@0: double fst=0, fen=fmaxEdit->Text.ToDouble(); xue@0: xue@0: double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble(); xue@0: dbrange=updb-downdb; xue@0: xue@0: 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: else if (Sender==AImage1) xue@0: { xue@0: int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]); xue@0: if (!SFCheck->Checked) xue@0: DrawAF(bmp, Rect, fst, fen, updb, downdb, SF.M, lp0, lpp, HS->Partials, MACheck->Checked, false, WaveView1->SamplesPerSec, 36); xue@0: else xue@0: 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: } xue@0: Form1->SaveDialog1->FileName="waveview.waveview1.bmp"; xue@0: Form1->SaveDialog1->FilterIndex=2; xue@0: if (Form1->SaveDialog1->Execute()) bmp->SaveToFile(Form1->SaveDialog1->FileName); xue@0: delete bmp; xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::Panel7Resize(TObject *Sender) xue@0: { xue@0: UpdateDisplay(1, 0, 0, 0); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::Panel8Resize(TObject *Sender) xue@0: { xue@0: UpdateDisplay(0, 1, 0, 0); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: void __fastcall TSFDemoForm::CheckBox1Click(TObject *Sender) xue@0: { xue@0: WaveView2->LoopPlay=CheckBox1->Checked; xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::fmaxEditKeyPress(TObject *Sender, char &Key) xue@0: { xue@0: if (Key==VK_RETURN) UpdateDisplay(0, 0, 0, 1); xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: void __fastcall TSFDemoForm::Button1Click(TObject *Sender) xue@0: { xue@0: int N=WaveView1->Length, Channel=Form1->HS->Channel; xue@0: xue@0: if (GetKeyState(VK_SHIFT)<0) xue@0: { xue@0: __int16* d2=WaveView2->Data16[0]; xue@0: Form1->PostWaveViewData(d2, Channel, StartPos, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt()); xue@0: } xue@0: else xue@0: { xue@0: __int16 *data=new __int16[N], *data1=WaveView1->Data16[0], *data2=WaveView2->Data16[0]; xue@0: for (int n=0; nPostWaveViewData(data, Channel, StartPos, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt()); xue@0: delete[] data; xue@0: } xue@0: } xue@0: //--------------------------------------------------------------------------- xue@0: xue@0: xue@0: xue@0: