diff SFDemoUnit.cpp @ 0:a6a46af64546

first upload
author wenx <xue.wen@eecs.qmul.ac.uk>
date Wed, 10 Aug 2011 14:55:38 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SFDemoUnit.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,1474 @@
+/*
+    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 "SFDemoUnit.h"
+#include "Matrix.h"
+#include "Unit1.h"
+#include "splines.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+TSFDemoForm *SFDemoForm;
+//---------------------------------------------------------------------------
+const double log10e=Log10(exp(1));
+const Bdw=5, Bdwc=2; //border width of charts
+const ftrr=5; //filter control point radius
+
+
+__fastcall TSFDemoForm::TSFDemoForm(TComponent* Owner)
+	: TForm(Owner)
+{
+	ForceUpdate=false;
+
+	double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble();
+	dbrange=updb-downdb;
+
+	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;
+	WaveView2->LoopPlay=CheckBox1->Checked;		
+
+
+  HS=0;
+  cyclefrs=0;
+	cyclefs=0;
+
+	MethodListBox->ItemIndex=0;
+
+	analyze2=false;
+
+  AnsiString Path=ExtractFilePath(Application->ExeName)+"*.sf";
+  TSearchRec sr;
+  if (FindFirst(Path, faAnyFile, sr)==0)
+  {
+    do
+    {
+      TmplListBox->Items->Add(sr.Name);
+    }
+    while (FindNext(sr) == 0);
+    FindClose(sr);
+  }
+  Wave1=0;
+  CurrentP=-1;
+
+  memset(&SF, 0, sizeof(TSF));
+  memset(&SF0, 0, sizeof(TSF));
+
+  datain=0;
+}
+
+__fastcall TSFDemoForm::~TSFDemoForm()
+{
+	delete WaveAudio1;
+	delete WaveAudio2;
+  delete WaveView1;
+  delete WaveView2;
+  delete HS;
+  delete[] cyclefrs;
+	delete[] cyclefs;
+	for (int i=0; i<ThreadCaps; i++) if (ThreadList[i]) delete ThreadList[i];
+  delete[] Wave1;
+  delete[] datain;
+}
+//---------------------------------------------------------------------------
+
+void TSFDemoForm::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 TSFDemoForm::FindNote()
+{
+}
+
+void TSFDemoForm::Reset()
+{
+	if (!HS) return;
+	if (HS->M<=0 || HS->Fr<=0) return;
+
+	if (MethodListBox->ItemIndex<0) MethodListBox->ItemIndex=0;
+
+	double sps=WaveView1->SamplesPerSec;
+	double h=WaveView1->SpecOffst;
+	int FSMode=MethodListBox->ItemIndex;
+	double FSF=FEdit->Text.ToDouble();
+	int FSFScale=FScaleCombo->ItemIndex;
+	if (FSFScale==0) FSF/=sps;
+	else FSF/=Amel*log(1+sps/700);
+	double FStheta=ThetaEdit->Text.ToDouble();
+
+	AnalyzeSF_1(*HS, SF, sps, h);
+	AnalyzeSF_2(*HS, SF, cyclefrs, cyclefs, sps, &cyclefrcount, FSMode, FSF, FSFScale, FStheta);
+
+  SaveSF();
+  SaveSF0();
+
+  UpdateDisplay();
+}
+
+void TSFDemoForm::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 DrawsBarMap(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 frst, int fren, atom** Partials, bool MA, bool bars, double sps, int TextHeight=12)
+	{
+		double log10e=1.0/log(10);
+		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[(fren-frst)*4], *y=&x[fren-frst], *newa=&x[(fren-frst)*2], *neww=&x[(fren-frst)*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=frst; fr<fren; fr++)
+      {
+        if (Partialsm[fr].f>0 && Partialsm[fr].a>0)
+        {
+          x[Sc]=Partials[m][fr].f;
+					y[Sc]=20*(Log10(Partialsm[fr].a));
+          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=AnsiString().sprintf("%.2gkhz", sps*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
+		S=AnsiString().sprintf("%.2gkhz", sps*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
+		S=AnsiString().sprintf("%.2gkhz", sps*xen/1000); 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 frst, int fren, atom** Partials, double* logA0C, double* b, double F, int K, double* h, int FScaleMode, double Fs, int TextHeight=12)
+	{
+    Bitmap->Width=Rect.Width();
+    Bitmap->Height=Rect.Height();
+    TCanvas* Canvas=Bitmap->Canvas;
+		TFont* Ft=Canvas->Font; Ft->Color=clWhite; Ft->Height=TextHeight; Ft->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,
+           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=frst; fr<fren; fr++)
+      {
+        try{
+        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 logaf;
+							//calculate LogAF
+							if (FScaleMode) xx=log(1+xx*Fs/700)/log(1+Fs/700);
+							int k=floor(xx/F); double f_plus=xx/F-k;
+							if (k<K+1) logaf=h[k]*(1-f_plus)+h[k+1]*f_plus;
+							else logaf=h[K+1];
+
+						double yy=20*log10e*(logaf+b[m]+logA0C[fr]);
+            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);
+          }
+        }}catch(...)
+        {int k=0;}
+      }
+      if (!visible) break;
+    }
+    delete[] XRec;
+
+		AnsiString S=AnsiString().sprintf("%.2gkhz", Fs*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
+		S=AnsiString().sprintf("%.2gkhz", Fs*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
+		S=AnsiString().sprintf("%.2gkhz", Fs*xen/1000); 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 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)
+	{
+		double FShift=FShiftdB/(20.0*log10e); //allowing the filter to be drawn with a vertical shift, and source an opposite shift
+		Bitmap->Width=Rect.Width();
+		Bitmap->Height=Rect.Height();
+		TCanvas* Canvas=Bitmap->Canvas;
+		double *Sx=new double[M];
+		for (int i=0; i<M; i++) Sx[i]=20*log10e*(b[i]-FShift);
+
+		int result=0;
+		TFont* Ft=Canvas->Font; Ft->Color=clWhite; Ft->Height=TextHeight; Ft->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/(updb-downdb), xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange,
+			YY20log10eidbrange=YY*20*log10e*idbrange, BdwpYYpYYdbenidbrange=Bdw+YY+YY*downdb*idbrange,
+			Bdw_xstXXixrange=Bdw-xstXXixrange, YYidbrange=YY*idbrange;
+
+		double st=xst/F; int ist=ceil(st); if (ist<0) ist=0;
+		Canvas->Pen->Color=clWhite;
+		int X=Bdw+XX*(F*ist-xst)/xrange+0.5, Y=BdwpYYpYYdbenidbrange-YY20log10eidbrange*(h[ist]+FShift)+0.5;
+		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);}
+		Canvas->MoveTo(X, Y);
+		//draw filter contour
+		int LineCount=xrange/F;
+		if (LineCount<XX)
+		{
+			for (int i=ist+1; i<K+2; i++)
+			{
+				double xi=F*i;
+				if (FScaleMode)
+				{
+					double ximel=Amel*log(1+Fs/700)*xi;
+					double xihz=700*(exp(ximel/Amel)-1);
+					xi=xihz/Fs;
+				}
+				X=floor(Bdw_xstXXixrange+xi*XXixrange+0.5);
+				Y=floor(BdwpYYpYYdbenidbrange-YY20log10eidbrange*(h[i]+FShift)+0.5);
+				Canvas->LineTo(X, Y);
+				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);}
+			}
+		}
+		else
+		{
+			double di=xrange/(XX*F);
+			for (int x=0; x<XX; x++)
+			{
+				int i;
+				if (FScaleMode) i=log(1+(xst+xrange*x/XX)*Fs/700)/log(1+Fs/700)/F;
+				else i=st+x*di;
+				X=Bdw+x;
+				Y=floor(BdwpYYpYYdbenidbrange-YY20log10eidbrange*(h[i]+FShift)+0.5);
+				Canvas->LineTo(Bdw+x, Y);
+				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);}
+			}
+		}
+    //draw source lines
+    for (int i=0; i<M; 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=AnsiString().sprintf("%.2gkhz", Fs*xst/1000); Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
+		S=AnsiString().sprintf("%.2gkhz", Fs*(xst+xen)/2000); int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
+    S=AnsiString().sprintf("%.2gkhz", Fs*xen/1000); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S);
+    S.sprintf("%gdB", updb); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S);
+    S.sprintf("%gdB", (updb+downdb)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S);
+    S.sprintf("%gdB", downdb); 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 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)
+	{
+    if (f_ex==0) f_ex=0.01;
+		Canvas->Brush->Color=cl3DDkShadow; Canvas->FillRect(Rect);
+		int Width=Rect.Width(), Height=Rect.Height();
+		Bitmap->Width=Width; Bitmap->Height=Height;
+		TPen* Pn=Canvas->Pen;
+		TFont* F=Canvas->Font;
+
+		if (HLX1<HLX2)
+		{
+			Canvas->Brush->Color=clDkGray; Canvas->FillRect(TRect(HLX1, 0, HLX2, Height));
+			Canvas->Brush->Color=cl3DDkShadow;
+		}
+
+		int X, Y, Y1=0, Y2=Height, Y_;
+    AnsiString S, as;
+
+		Pn->Color=clBlack; Pn->Style=psDot; F->Color=clBlack; F->Height=12; F->Name="Ariel";
+		int lp0=ceil(lp[0]), lpp=ceil(lp[P-1]);
+    double f0max=-0.5, f0min=0.5; for (int fr=lp0; fr<lpp; fr++){if (f0max<F0[fr]) f0max=F0[fr]; if (f0min>F0[fr]) f0min=F0[fr];}
+    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);
+			
+      for (int pfr=0; pfr<P; pfr++)
+      {
+				int fr=floor(lp[pfr]); double frplus=lp[pfr]-fr;
+				X=Width*(Partials[1][fr].t*(1-frplus)+Partials[1][fr+1].t*frplus)/L;
+				Pn->Color=peakmarkcolor; Pn->Style=psDot; Canvas->MoveTo(X, Y1); Canvas->LineTo(X, Y2);
+				if (BX1) BX1[pfr]=X-1;
+				if (BX2) BX2[pfr]=X+1;
+			}
+    }
+
+		if (Captions) {Y_=Height*(0.5-(F0Overall-f_c)/f_ex); Pn->Color=clWhite; Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_);}
+
+    Pn->Style=psSolid; Pn->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)
+    {
+      Pn->Color=clRed;
+      for (int pfr=0; pfr<P-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)
+  {
+    if (f_ex==0) f_ex=f_c*0.005;
+    //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);
+  }
+
+  //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 TSFDemoForm::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=fmaxEdit->Text.ToDouble();
+	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)
+	{
+		int HLX1=0, HLX2=0;
+		if (CurrentP>=0) HLX1=BX1[CurrentP]+1, HLX2=BX1[CurrentP+1]+1;
+		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);
+	}
+	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, 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);
+  }
+  if (f0d)
+  {
+    //Draw the F0 modulator
+    DrawModulator();
+  }
+
+	if (sf)
+	{
+		int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]);
+		double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble();
+		dbrange=updb-downdb;
+		if (SFCheck->Checked)
+			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);
+		else
+			DrawAF(AImage1->Picture->Bitmap, AImage1->ClientRect, fst, fen, updb, downdb, SF.M, lp0, lpp, Partials, MACheck->Checked, false, WaveView1->SamplesPerSec);
+		dbrange=updb-downdb;
+		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());
+	}
+
+  ForceUpdate=false;
+}
+
+void __fastcall TSFDemoForm::WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode)
+{
+  if (Shift.Contains(ssShift)) OpMode=0; //drag mode
+  else OpMode=1; //select mode
+}
+
+int __fastcall TSFDemoForm::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 TSFDemoForm::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==Image0)
+	{
+		if (Shift.Contains(ssLeft))
+		{
+			if (CurrentB<0 || CurrentB>=SF.P) return;
+			if (X<0 || X>=Image->Width || CurrentB>0 && X<=BX2[CurrentB-1] || CurrentB<SF.P-1 && X>=BX1[CurrentB+1]){}
+			else
+			{
+				double dlp=1.0*(X-StartDragX)*SF.L/Image->Width;
+				SF.lp[CurrentB]+=dlp;
+				StartDragX=X;
+			}
+		}
+		else
+		{
+			CurrentB=-1;
+			for (int i=0; i<SF.P; i++) if (X>=BX1[i] && X<=BX2[i]) {CurrentB=i; break;}
+		}
+	}
+	else 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(SF.F0C, SF.L, cyclefrcount+1, cyclefs, cyclefrs);
+			SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
+			UpdateDisplay(true, true, true, false);
+
+				t=HS->Partials[0][0].t+SF.offst*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+SF.offst*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);
+
+
+	if (Sender==Image0)
+	{
+		int Wid=HS->Partials[0][1].s, hWid=Wid/2, Offst=HS->Partials[0][1].t-HS->Partials[0][0].t;
+		CurrentFr=(t-hWid)/Offst+0.5;
+		if (!Shift.Contains(ssLeft)) CurrentP=-1; while (CurrentP<SF.P-1 && CurrentFr>SF.lp[CurrentP+1]) CurrentP++; if (CurrentP>=SF.P-1) CurrentP=-1;
+
+		if (CurrentP>=0)
+    {
+      PageControl1->ActivePage=AmpCycleSheet;
+      SFCheck->Parent=Panel14;
+      MACheck->Parent=Panel14;
+    }
+		else
+    {
+      PageControl1->ActivePage=AmpOverSheet;
+      SFCheck->Parent=Panel12;
+      MACheck->Parent=Panel12;
+    }
+		UpdateDisplay(true, 0, CurrentP>=0, 0);
+
+			if (CurrentB>=0 && CurrentB<SF.P)
+			{
+				t=HS->Partials[0][0].t+SF.offst*SF.lp[CurrentB];
+				S.sprintf("%.3gs", t/sps);
+				F->Color=clYellow;
+				Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
+			}
+			else
+			{
+				S.sprintf("          ");
+				Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
+			}
+	}
+}
+//---------------------------------------------------------------------------
+
+void TSFDemoForm::DrawModulator()
+{
+	if (PageControl1->ActivePage==AmpCycleSheet && CurrentP>=0 && CurrentP<SF.P-1)
+	{
+			double fst=0, fen=fmaxEdit->Text.ToDouble();
+			int lp0=ceil(SF.lp[0]);
+			double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble();
+			dbrange=updb-downdb;
+			if (SFCheck->Checked)
+				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);
+			else
+				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);
+			dbrange=updb-downdb;
+			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());
+	}
+}
+
+
+void __fastcall TSFDemoForm::SFCheckClick(TObject *Sender)
+{
+  if (Sender==SFCheck)
+  {
+    MACheck->Visible=!SFCheck->Checked;
+  }
+  UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TSFDemoForm::ExternalInput()
+{
+  AnsiString FileName=ExtractFilePath(Application->ExeName)+"tsfin";
+	FILE* file;
+	if (file=fopen(FileName.c_str(), "rb"))
+  {
+    SF.LoadFromFileHandle(file);
+    fclose(file);
+    DeleteFile(FileName);
+		SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
+
+		SaveSF();
+    Synthesize();
+    UpdateDisplay();
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TSFDemoForm::SaveSF()
+{
+	FILE* file;
+	if (file=fopen((ExtractFilePath(Application->ExeName)+"tsfout").c_str(), "wb"))
+  {
+    SF.SaveToFileHandle(file);
+    fclose(file);
+  }
+}
+
+void __fastcall TSFDemoForm::SaveSF0()
+{
+  SF0.Duplicate(SF);
+}
+
+void __fastcall TSFDemoForm::SaveWave()
+{
+  THS* HS=Form1->HS; int dst, den;
+  double* xrec=SynthesisHSp(HS, dst, den);
+  delete[] Wave1; Wave1=new __int16[WaveView2->Length];
+  DoubleToInt(Wave1, 2, xrec, den-dst);
+  free8(xrec);
+}
+//---------------------------------------------------------------------------
+void __fastcall TSFDemoForm::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==AImage3->Parent) Event=AImage3MouseWheel, Sender=AImage3;
+	else if (ActiveControl==AImage1->Parent) Event=AImage3MouseWheel, Sender=AImage1;
+
+  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 TSFDemoForm::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<SF.L; l++) SF.F0C[l]*=rate, SF.F0D[l]*=rate; SF.F0Overall*=rate;
+  for (int fr=0; fr<cyclefrcount; fr++) cyclefs[fr]*=rate;
+
+	SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
+	SaveSF();
+	S_U();
+  Handled=true;
+}
+
+void __fastcall TSFDemoForm::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*SF.avgb[CurrentPartial];
+  if (WheelDelta<0) ddb=-ddb;
+
+  db+=ddb;
+  AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
+	Label7->Caption=S;
+	  ddb=ddb/(20*log10e);
+
+	int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]);
+	for (int l=0; l<lpp-lp0; l++) SF.b[l][CurrentPartial]+=ddb;
+	SF.avgb[CurrentPartial]+=ddb;
+
+	SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
+  SaveSF();
+  S_U(true);
+  Handled=true;
+}
+
+
+//---------------------------------------------------------------------------
+void __fastcall TSFDemoForm::AImage3MouseMove(TObject *Sender,
+			TShiftState Shift, int X, int Y)
+{
+	if (!HS) return;
+	TImage* Image=(TImage*)Sender;
+	int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]);
+
+	if (Shift.Contains(ssLeft))
+	{
+		if (CurrentFB<0 && CurrentPartial<0) return;
+		int fh=Image->Canvas->TextHeight("0");
+		int YY=Image->Height-Bdw-Bdwc-fh;
+		double dbperpixel=dbrange/YY;
+		int dY=Y-StartDrag;
+    if (dY==0) return;
+		StartDrag=Y;
+		double ddb=-dY*dbperpixel;
+
+		if (Sender==AImage3 && CurrentFB>=0)
+		{
+			double db=20*log10e*SF.avgh[CurrentPartial];
+			db+=ddb;
+			AnsiString S; S.sprintf("Filter control %d: %.2fdB", CurrentFB, db);
+			Label7->Caption=S;
+			ddb=ddb/(20*log10e);
+
+			for (int l=0; l<lpp-lp0; l++) SF.h[l][CurrentFB]+=ddb;
+			SF.avgh[CurrentFB]+=ddb;
+
+			if (Shift.Contains(ssShift))
+				for (int k=CurrentFB+1; k<=SF.K+1; k++) {for (int l=0; l<lpp-lp0; l++) SF.h[l][k]+=ddb; SF.avgh[k]+=ddb;}
+			if (Shift.Contains(ssCtrl)) {S_F_b(SF, HS->Partials); SaveSF0();}
+		}
+		else if (Sender==AImage1 || Sender==AImage3)
+		{
+			double db=20*log10e*SF.avgb[CurrentPartial];
+			db+=ddb;
+			AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
+			Label7->Caption=S;
+			ddb=ddb/(20*log10e);
+
+			for (int l=0; l<lpp-lp0; l++) SF.b[l][CurrentPartial]+=ddb;
+			SF.avgb[CurrentPartial]+=ddb;
+
+      int dm=0; for (int i=0x31; i<0x3a; i++) if (GetKeyState(i)<0) dm+=(i-0x30);
+      if (dm==0 && Shift.Contains(ssShift)) dm=CurrentPartial+1;
+      if (dm>0) for (int m=CurrentPartial+dm; m<SF.M; m+=dm){for (int l=0; l<lpp-lp0; l++) SF.b[l][m]+=ddb; SF.avgb[m]+=ddb;}
+		}
+		else if (Sender==AImage2 || Sender==AImage4)
+		{
+			if (CurrentFr>=lp0 && CurrentFr<lpp)
+			{
+				double db=20*log10e*SF.b[CurrentFr-lp0][CurrentPartial];
+				db+=ddb;
+				AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
+				Label8->Caption=S;
+				ddb=ddb/(20*log10e);
+
+				SF.b[CurrentFr-lp0][CurrentPartial]+=ddb;
+			}
+		}
+
+		SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
+		UpdateDisplay();
+	}
+	else
+	{
+		Image->Parent->SetFocus();
+
+		int lSXc, *lSX;
+		double* LogAS;
+		if (Sender==AImage1 || Sender==AImage3) lSXc=SXc, lSX=SX, LogAS=SF.avgb, X=Bdw+(X-Bdw)*AImage3->Width/((TImage*)Sender)->Width;
+		else if (Sender==AImage2 || Sender==AImage4)
+		{
+			if (CurrentFr<lp0 || CurrentFr>=lpp) return;
+			lSXc=SXcyclec, lSX=SXcycle, LogAS=SF.b[CurrentFr-lp0], 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--;
+		CurrentFB=-1; int lfb=0; while (lfb<=SF.K && X>FX[lfb]) lfb++;
+		if (Sender==AImage3)
+		{
+			if (X>=FX[lfb]-ftrr && X<=FX[lfb]+ftrr && Y>=FY[lfb]-ftrr && Y<=FY[lfb]+ftrr) CurrentFB=lfb;
+			if (X>=FX[lfb-1]-ftrr && X<=FX[lfb-1]+ftrr && Y>=FY[lfb-1]-ftrr && Y<=FY[lfb-1]+ftrr)
+			{
+				if (CurrentFB==-1) CurrentFB=lfb-1;
+				else if (abs(X-FX[lfb-1])<abs(X-FX[lfb])) CurrentFB=lfb-1;
+			}
+		}
+		
+		TLabel* Label; AnsiString S;
+		if (Sender==AImage1 || Sender==AImage3) Label=Label7;
+		else if (Sender==AImage2 || Sender==AImage4) Label=Label8;
+
+		if (CurrentFB>=0)
+		{
+			S.sprintf("Filter control %d: %.2fdB", CurrentFB, 20*log10e*SF.avgh[CurrentFB]);
+			Label->Font->Color=clWhite;
+		}
+		else
+		{
+			double dB=20*log10e*LogAS[CurrentPartial];
+			S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, dB);
+			Label->Font->Color=RotateColors[CurrentPartial%10];
+		}
+		Label->Caption=S;
+	}
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TSFDemoForm::AImage1MouseDown(TObject *Sender,
+			TMouseButton Button, TShiftState Shift, int X, int Y)
+{
+	FirstStartDrag=StartDrag=Y;
+	FirstStartDragX=StartDragX=X;
+	if (Sender==Image0 && Shift.Contains(ssShift))
+	{
+		if (CurrentB>=0) //delete current peakmark
+		{
+			for (int p=CurrentB; p<SF.P-1; p++) SF.lp[p]=SF.lp[p+1];
+			SF.P--;
+			CurrentB=-1;
+			UpdateDisplay(1, 0, 0, 0);
+			analyze2=true;
+		}
+		else
+		{
+			double newlpb=1.0*X/Image0->Width*SF.L, *newlp=new double[SF.P+3];
+			int newb=0; while (newb<SF.P && X>BX1[newb]) newb++;
+
+			if (newb>0) memcpy(newlp, SF.lp, sizeof(double)*newb);
+			if (newb<SF.P) memcpy(&newlp[newb+1], &SF.lp[newb], sizeof(double)*(SF.P-newb));
+			newlp[newb]=newlpb;
+			CurrentB=newb;
+			SF.P++;
+			delete[] SF.lp; SF.lp=newlp;
+			UpdateDisplay(1, 0, 0, 0);
+			analyze2=true;
+		}
+	}
+  if ((Sender==AImage2 || Sender==AImage4) && Shift.Contains(ssRight))
+    PageControl1->ActivePage=AmpOverSheet;
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::AImage1MouseUp(TObject *Sender,
+			TMouseButton Button, TShiftState Shift, int X, int Y)
+{
+	if (Sender==Image0 && (CurrentB>=0 && X!=FirstStartDragX || analyze2))
+	{
+    //do analysis using the new segmentation
+		double sps=WaveView1->SamplesPerSec;
+		double h=WaveView1->SpecOffst;
+		int FSMode=MethodListBox->ItemIndex;
+		double FSF=FEdit->Text.ToDouble();
+		int FSFScale=FScaleCombo->ItemIndex;
+		if (FSFScale==0) FSF/=sps;
+		else FSF/=Amel*log(1+sps/700);
+		double FStheta=ThetaEdit->Text.ToDouble();
+		AnalyzeSF_2(*HS, SF, cyclefrs, cyclefs, sps, &cyclefrcount, FSMode, FSF, FSFScale, FStheta);
+    SaveSF0();
+		SaveSF();
+		S_U(true);
+		UpdateDisplay();
+		analyze2=false;
+	}
+	else if (Y!=FirstStartDrag)
+	{
+		SaveSF();
+		S_U();
+		UpdateDisplay();
+	}
+}
+//---------------------------------------------------------------------------
+
+
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::PageControl1Change(TObject *Sender)
+{
+  if (PageControl1->ActivePage==AmpOverSheet)
+  {
+    SFCheck->Parent=Panel12;
+    MACheck->Parent=Panel12;
+  }
+  else
+  {
+    SFCheck->Parent=Panel14;
+    MACheck->Parent=Panel14;
+  }
+  UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::SaveButtonClick(TObject *Sender)
+{
+  int k=1; AnsiString FileName="1.sf";
+  while (TmplListBox->Items->IndexOf(FileName)>=0) {k++; FileName=AnsiString(k)+".sf";}
+  if (GetKeyState(VK_SHIFT)<0)
+  {
+    AnsiString oldpath=SaveDialog1->InitialDir;
+    SaveDialog1->InitialDir=ExtractFileDir(Application->ExeName);
+    if (SaveDialog1->Execute()) FileName=SaveDialog1->FileName;
+    SaveDialog1->InitialDir=oldpath;
+  }
+  else FileName=ExtractFilePath(Application->ExeName)+FileName;
+  SF.SaveToFile(FileName.c_str());
+  TmplListBox->Items->Add(ExtractFileName(FileName));
+}
+//---------------------------------------------------------------------------
+
+
+  //calculates increment dh on sf1.avgh so that it becomes sf2.avgh
+  // dh should have the same dimenstions as sf1.avgh
+  void* CompareFilters(double* dh, TSF& sf1, TSF& sf2)
+  {
+    int K1=sf1.K, FScale1=sf1.FScaleMode;
+    double F1=sf1.F, Fs=sf1.Fs;
+    for (int k=0; k<K1+2; k++)
+    {
+      double h1=sf1.avgh[k], f=F1*k;
+      if (FScale1)
+      {
+  			double fmel=Amel*log(1+Fs/700)*f;
+	  		double fhz=700*(exp(fmel/Amel)-1);
+		  	f=fhz/Fs;
+      }
+      double h2=sf2.LogAF(f);
+      dh[k]=h2-h1;
+    }
+  }
+  double* CompareFilters(TSF& sf1, TSF& sf2)
+  {
+    double* dh=new double[sf1.K+2];
+    CompareFilters(dh, sf1, sf2);
+    return dh;
+  }
+
+void __fastcall TSFDemoForm::UseButtonClick(TObject *Sender)
+{
+  if (TmplListBox->ItemIndex<0) return;
+	AnsiString FileName=ExtractFilePath(Application->ExeName)+TmplListBox->Items->Strings[TmplListBox->ItemIndex];
+  if (!FileExists(FileName)) return;
+  double dbamp=TrackBar1->Position/10.0;
+  double dbgain=TrackBar2->Position/5.0-10;
+
+  TSF* sf=new TSF;
+	FILE* file;
+	if (file=fopen(FileName.c_str(), "rb"))
+	{
+    sf->LoadFromFileHandle(file);
+    fclose(file);
+  }
+  if (dbgain!=0) sf->ShiftFilterByDB(dbgain);
+  int L=ceil(SF.lp[SF.P-1])-ceil(SF.lp[0]), K=SF.K, M=SF.M;
+  double avgbend=SF0.avgb[sf->M-1];
+  switch (ComboBox1->ItemIndex)
+  {
+		case 0: //use source
+    {
+      for (int l=0; l<L; l++) memcpy(SF.h[l], SF0.h[l], sizeof(double)*(K+2));
+      memcpy (SF.avgh, SF0.avgh, sizeof(double)*(K+2));
+      for (int m=0; m<M; m++)
+      {
+        double sfb=(m<sf->M)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]);
+        double db=(sfb-SF0.avgb[m])*dbamp;
+        for (int l=0; l<L; l++) SF.b[l][m]=SF0.b[l][m]+db;
+        SF.avgb[m]=SF0.avgb[m]+db;
+      }
+      break;
+    }
+    case 1: //use filter
+    {
+      for (int l=0; l<L; l++) memcpy(SF.b[l], SF0.b[l], sizeof(double)*M);
+      memcpy(SF.avgb, SF0.avgb, sizeof(double)*M); 
+      double* dh=CompareFilters(SF0, *sf);
+
+      for (int k=0; k<K+2; k++){double dhk=dh[k]*dbamp;
+        for (int l=0; l<L; l++) SF.h[l][k]=SF0.h[l][k]+dhk; SF.avgh[k]=SF0.avgh[k]+dhk;}
+      delete[] dh;
+      break;
+    }
+    case 2: //source and filter
+    {
+      for (int m=0; m<M; m++)
+      {
+        double sfb=(m<sf->M)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]);
+        double db=(sfb-SF0.avgb[m])*dbamp;
+        for (int l=0; l<L; l++) SF.b[l][m]=SF0.b[l][m]+db; SF.avgb[m]=SF0.avgb[m]+db;
+      }
+      double* dh=CompareFilters(SF0, *sf);
+
+      for (int k=0; k<K+2; k++){double dhk=dh[k]*dbamp;
+        for (int l=0; l<L; l++) SF.h[l][k]=SF0.h[l][k]+dhk; SF.avgh[k]=SF0.avgh[k]+dhk;}
+      delete[] dh;
+      break;
+    }
+    case 3: //towards
+    {
+      for (int m=0; m<M; m++)
+      {
+        double sfb=(m<sf->M)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]);
+        double db=(sfb-SF0.avgb[m])*dbamp, avgb=0;
+        for (int l=0; l<L; l++){SF.b[l][m]=SF0.b[l][m]+db*l/(L-1); avgb+=SF.b[l][m];}
+        SF.avgb[m]=avgb/L;
+      }
+      double *dh=CompareFilters(SF0, *sf);
+
+      for (int k=0; k<K+2; k++){double dhk=dh[k]*dbamp, avgh=0;
+        for (int l=0; l<L; l++){SF.h[l][k]=SF0.h[l][k]+dhk*l/(L-1); avgh+=SF.h[l][k];} SF.avgh[k]=avgh/L;}
+      delete[] dh;
+      break;
+    }
+    case 4: //towards and back
+    {
+      for (int m=0; m<M; m++)
+      {
+        double sfb=(m<sf->M)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]);
+        double db=(sfb-SF0.avgb[m])*dbamp, avgb=0;
+        for (int l=0; l<L; l++){SF.b[l][m]=SF0.b[l][m]+db*(1-fabs(l*2.0/(L-1)-1)); avgb+=SF.b[l][m];}
+        SF.avgb[m]=avgb/L;
+      }
+      double *dh=CompareFilters(SF0, *sf);
+
+      for (int k=0; k<K+2; k++){double dhk=dh[k]*dbamp, avgh=0;
+        for (int l=0; l<L; l++){SF.h[l][k]=SF0.h[l][k]+dhk*(1-fabs(l*2.0/(L-1)-1)); avgh+=SF.h[l][k];} SF.avgh[k]=avgh/L;}
+      delete[] dh;
+      break;
+    }
+      break;
+  }
+
+  delete sf;
+
+	SynthesizeSF(HS, &SF, WaveView1->SamplesPerSec);
+  SaveSF();
+  S_U(true);
+  UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+//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 TSFDemoForm::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 TSFDemoForm::SUTerminate(TObject* Sender)
+{
+	TSUThread* CurrentThread=(TSUThread*)Sender;
+  if (CurrentThread==SUThread)
+  {
+    double* xrec=CurrentThread->xrec;
+		if (xrec)
+		{
+			int dst=CurrentThread->dst, den=CurrentThread->den, bps=WaveAudio2->BitsPerSample;
+			if (dst<0) dst=0;
+			double max=1<<(bps-1); for (int i=dst; i<den; i++) if (xrec[i]>max) max=xrec[i]; else if (xrec[i]<-max) max=-xrec[i];
+			if (max>1<<(bps-1))
+			{
+				max=(1<<(bps-1))/max;
+				for (int i=dst; i<den; i++) xrec[i]*=max;
+			}
+			void* data=new char[(den-dst)*bps];
+			DoubleToInt(data, bps>>3, 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 TSFDemoForm::Panel4Resize(TObject *Sender)
+{
+	ForceUpdate=true;
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TSFDemoForm::Panel1Resize(TObject *Sender)
+{
+  Panel2->Height=(Panel1->Height-Splitter1->Height)/2;  
+}
+//---------------------------------------------------------------------------
+
+
+
+void __fastcall TSFDemoForm::AmpCycleSheetResize(TObject *Sender)
+{
+	UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TSFDemoForm::MethodListBoxClick(TObject *Sender)
+{
+	Reset();	
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::AmpOverSheetResize(TObject *Sender)
+{
+	UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::Splitter7Moved(TObject *Sender)
+{
+	if (Sender==Splitter7) AImage4->Parent->Parent->Height=AImage3->Parent->Parent->Height;
+	else if (Sender==Splitter8) AImage3->Parent->Parent->Height=AImage4->Parent->Parent->Height;
+	UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::AImage3DblClick(TObject *Sender)
+{
+	Graphics::TBitmap* bmp=new Graphics::TBitmap;
+	bmp->Width=800; bmp->Height=600; TRect Rect=TRect(0, 0, 800, 600);
+
+
+			double fst=0, fen=fmaxEdit->Text.ToDouble();
+
+			double updb=updbEdit->Text.ToDouble(), downdb=downdbEdit->Text.ToDouble(), dbshift=SFPicShift->Text.ToDouble();
+			dbrange=updb-downdb;
+
+			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());
+			else if (Sender==AImage1)
+			{
+				int lp0=ceil(SF.lp[0]), lpp=ceil(SF.lp[SF.P-1]);
+				if (!SFCheck->Checked)
+					DrawAF(bmp, Rect, fst, fen, updb, downdb, SF.M, lp0, lpp, HS->Partials, MACheck->Checked, false, WaveView1->SamplesPerSec, 36);
+				else
+					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);
+			}
+  Form1->SaveDialog1->FileName="waveview.waveview1.bmp";
+  Form1->SaveDialog1->FilterIndex=2;
+  if (Form1->SaveDialog1->Execute()) bmp->SaveToFile(Form1->SaveDialog1->FileName);
+	delete bmp;
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::Panel7Resize(TObject *Sender)
+{
+	UpdateDisplay(1, 0, 0, 0);
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::Panel8Resize(TObject *Sender)
+{
+	UpdateDisplay(0, 1, 0, 0);
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TSFDemoForm::CheckBox1Click(TObject *Sender)
+{
+	WaveView2->LoopPlay=CheckBox1->Checked;		
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::fmaxEditKeyPress(TObject *Sender, char &Key)
+{
+  if (Key==VK_RETURN) UpdateDisplay(0, 0, 0, 1);
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TSFDemoForm::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];
+    for (int n=0; n<N; n++) data[n]=data1[n]-datain[n]+data2[n];
+    Form1->PostWaveViewData(data, Channel, StartPos, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+    delete[] data;
+  }
+}
+//---------------------------------------------------------------------------
+
+
+
+