view Unit1.cpp @ 0:a6a46af64546

first upload
author wenx <xue.wen@eecs.qmul.ac.uk>
date Wed, 10 Aug 2011 14:55:38 +0100
parents
children
line wrap: on
line source
/*
    Harmonic Visualiser

    An audio file viewer and editor.
    Centre for Digital Music, Queen Mary, University of London.
    This file copyright 2011 Wen Xue.

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version. 
*/
//---------------------------------------------------------------------------

#pragma hdrstop

#include <vcl.h>                
#include <inifiles.hpp>
#include "Unit1.h"
#include "BackUpTool.h"
#include <math.h>
#include <Math.hpp>
#include "UnitRangeEdit.h"
#include "EditorPanelUnit.h"
#include "VibratoDemoUnit.h"
#include "RecordingUnit.h"
#include "opt.h"
#include "Matrix.h"
#include "SFDemoUnit.h"
#include "SinEst.h"
#include "splines.h"
#include "SinSyn.h"
#include "hsedit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
extern timestamp1;
//---------------------------------------------------------------------------
char ReturnKey=VK_RETURN;
int BAR=2;
#define ASMALLNEGATIVEVALUE -1.1e-24

__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  Application->HintPause=0.1;

  WaveAudio1=new TWaveAudio(NULL);
  WaveAudio1->AutoUseMemoryStream=true;
	WaveAudio1->OnLoad=WaveAudio1Load;
  WaveView1=new TWaveView(NULL, true, false);
  WaveView1->Parent=PanelWaveView;
  WaveView1->Align=alClient;
  WaveView1->ScrollBar=ScrollBar1;
  WaveView1->WaveAudio=WaveAudio1;
	WaveView1->ClickFocus=true;
	WaveView1->WaveBackColor=clWhite;
	WaveView1->WaveColor=clBlack;
  WaveView1->AxisColor=clGray;
	WaveView1->CustomInfo=WaveView1CustomInfo;
	WaveView1->CustomPaneInfo=WaveView1CustomPaneInfo;
  WaveView1->OnGetOpMode=WaveView1OpMode;
  WaveView1->OnGetPlaybackStartAndEndPos=WaveView1PlaybackStartAndEndPos;
  WaveView1->OnInfoDblClick=WaveView1InfoDblClick;
  WaveView1->OnPaint=WaveView1AfterPaint;
  WaveView1->OnPlaybackStart=WaveView1PlaybackStart;
  WaveView1->OnPlaybackDone=WaveView1PlaybackDone;
  WaveView1->OnKeyPress=WaveView1KeyPress;
	WaveView1->OnMouseDown=WaveView1MouseDown;
	WaveView1->OnMouseMove=WaveView1MouseMove;
  WaveView1->OnMousePointer=WaveView1MousePointer;
	WaveView1->OnMouseUp=WaveView1MouseUp;
  WaveView1->OnMouseWheel=WaveView1MouseWheel;
  WaveView1->SelectedFrameColorX=clGreen;
  WaveView1->SelectedAreaColorX=clGreen;
  WaveView1->BeforePlayback=WaveView1BeforePlayback;
  WaveView1->Hint=""; WaveView1->ShowHint=true;
  WaveView1->DefaultPopupMenu=false; WaveView1->PopupMenu=WaveView1PopupMenu;
  WaveView1->Tools<<wvtPlayNote;
  WaveView1->PlayNoteInSemitone=true;

	WaveAudio2=0;

  TWaveViewObject Obj; memset(&Obj, 0, sizeof(TWaveViewObject));
  Obj.DrawObject=WaveView1DrawObject; Obj.OnClick=WaveView1ObjectClick;
  for (int i=0; i<6; i++){Obj.Id=i; WaveView1->FObjects.Add(Obj);}
  WaveView1->FObjects.Items[5].OnClick=0; WaveView1->FObjects.Items[5].OnDblClick=WaveView1ObjectDblClick;
  WaveView1->FObjects.Items[5].OnMouseWheel=WaveView1ObjectMouseWheel;

  Navigator1=new TNavigator(NULL);
  Navigator1->Parent=PanelNavigator;
  Navigator1->Align=alClient;
  Navigator1->AreaColorX=clYellow;
  Navigator1->OnAreaChange=Navigator1AreaChange;
  Navigator1->OnBackground=Navigator1Background;
  NavButton=new TSpeedButton(this); NavButton->Parent=Navigator1; NavButton->Left=0; NavButton->Top=0; NavButton->Width=24; NavButton->Height=16;
  NavButton->Transparent=true; NavButton->Font->Name="Ariel"; NavButton->Font->Height=12; NavButton->Font->Color=clBlack; NavButton->Caption="W/S";
  NavButton->Flat=true; NavButton->OnClick=NavButtonClick;

	Initialize();
	SetWaveViewContents();

  BitmapPlay=new Graphics::TBitmap; BitmapPlay->LoadFromResourceID((int)HInstance, 100);
  BitmapStop=new Graphics::TBitmap; BitmapStop->LoadFromResourceID((int)HInstance, 101);
	SpeedButtonPlay->Glyph=BitmapPlay;
	BitmapSpectrogram=new Graphics::TBitmap; BitmapSpectrogram->LoadFromResourceID((int)HInstance, 102);
	BitmapWaveform=new Graphics::TBitmap; BitmapWaveform->LoadFromResourceID((int)HInstance, 103);
	SpeedButtonS->Glyph=BitmapSpectrogram;
	BitmapRecord=new Graphics::TBitmap; BitmapRecord->LoadFromResourceID((int)HInstance, 104);
  BitmapRecording=new Graphics::TBitmap; BitmapRecording->LoadFromResourceID((int)HInstance, 105);
	SpeedButtonRecord->Glyph=BitmapRecord;
  BitmapTimeSelect=new Graphics::TBitmap; BitmapTimeSelect->LoadFromResourceID((int)HInstance, 106);
  SpeedButtonT->Glyph=BitmapTimeSelect;
  BitmapFreqSelect=new Graphics::TBitmap; BitmapFreqSelect->LoadFromResourceID((int)HInstance, 107);
  SpeedButtonF->Glyph=BitmapFreqSelect;
  BitmapMultiSelect=new Graphics::TBitmap; BitmapMultiSelect->LoadFromResourceID((int)HInstance, 108);
  SpeedButtonM->Glyph=BitmapMultiSelect;
  BitmapHSSelect=new Graphics::TBitmap; BitmapHSSelect->LoadFromResourceID((int)HInstance, 109);
  SpeedButtonSelect->Glyph=BitmapHSSelect;
  BitmapCursorText=new Graphics::TBitmap; BitmapCursorText->LoadFromResourceID((int)HInstance, 110);
  SpeedButtonCursorText->Glyph=BitmapCursorText;
  BitmapPaneInfo=new Graphics::TBitmap; BitmapPaneInfo->LoadFromResourceID((int)HInstance, 111);
  SpeedButtonPaneInfo->Glyph=BitmapPaneInfo;

  SpectrogramView=false;
  HS=0;
  PartialSelectCombo->ItemIndex=0;
  ancps=0;
  ancfrs=0;
  ancfs=0;
	ancts=0;
  onset.f0s=0;
  onset.pitches=0;
  onset.xfr=0;

	Application->OnIdle=ApplicationIdle;

	for (int i=0; i<MaxRecents; i++)
	{
		int ind=File1->IndexOf(Recent00);
		TMenuItem* Item=new TMenuItem(this);
		Item->Tag=i;
    Item->Caption=i+1;
    Item->OnClick=Recent11Click;
    File1->Insert(ind, Item);
    Recents[i]=Item;
  }


	ExePath=ExtractFilePath(Application->ExeName);
	TmpInFileName=ExePath+"tvoin";
	TmpOutFileName=ExePath+"tvoout";
	IniFileName=ChangeFileExt(Application->ExeName, ".ini");
	
	RecentFile("");

}

__fastcall TForm1::~TForm1()
{
	TIniFile* Ini=0;
  try{
  Ini=new TIniFile(ChangeFileExt(Application->ExeName, ".ini"));
  Ini->WriteString("CurrentFile", "FileName", WaveAudio1->FileName);
  Ini->WriteInteger("CurrentView", "Start", WaveView1->StartPos);
  Ini->WriteInteger("CurrentView", "End", WaveView1->EndPos);
  Ini->WriteFloat("CurrentView", "StartF", WaveView1->StartDigiFreq);
  Ini->WriteFloat("CurrentView", "EndF", WaveView1->EndDigiFreq);
  Ini->WriteInteger("CurrentView", "SpecRes", WindowSizeCombo->ItemIndex);
  Ini->WriteInteger("CurrentView", "WindowType", WindowTypeCombo->ItemIndex);
  Ini->WriteString("HS", "delp", HSDelpEdit1->Text);
  Ini->WriteString("HS", "delm", HSDelmEdit1->Text);
  Ini->WriteInteger("Settings", "MouseWheelZoom", MouseWheelZoom->Checked);
  Ini->WriteInteger("Settings", "Mixer", false);
  } catch(...) {}
  delete Ini;

  delete WaveAudio1;
  delete WaveView1;
	delete Navigator1;
	delete BitmapPlay;
  delete BitmapStop;
  delete BitmapSpectrogram;
	delete BitmapWaveform;
	delete BitmapRecord;
	delete BitmapRecording;
  delete BitmapTimeSelect;
  delete BitmapFreqSelect;
  delete BitmapMultiSelect;
  delete BitmapHSSelect;
  delete BitmapCursorText;
  delete BitmapPaneInfo;

  free(ancps);
  free(ancfrs);
  free(ancfs);
  free(ancts);
  DeAlloc2(onset.f0s);
  DeAlloc2(onset.pitches);
  delete[] onset.xfr;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ApplicationIdle(TObject* Sender, bool& Done)
{
	if (FileExists(TmpInFileName)) VibratoDemoForm->ExternalInput();
  if (VibratoDemoForm->ForceUpdate) VibratoDemoForm->UpdateDisplay();

	Done=true;
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Backup1Click(TObject *Sender)
{
  BackupForm1->ShowModal();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Exit1Click(TObject *Sender)
{
  Close();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ZoomToSelection1Click(TObject *Sender)
{
  WaveView1->DoExtract(Sender);
  if (GetKeyState(VK_SHIFT)>=0) WaveView1->RemoveSelection(-1);
}
//---------------------------------------------------------------------------
void TForm1::Initialize()
{
  TIniFile* Ini=new TIniFile(ChangeFileExt(Application->ExeName, ".ini"));
  AnsiString FileName=Ini->ReadString("CurrentFile", "FileName", "");
  if (FileExists(FileName))
  {
    WaveAudio1->LoadFromFile(FileName);
    int Start=Ini->ReadInteger("CurrentView", "Start", 0);
    int End=Ini->ReadInteger("CurrentView", "End", WaveAudio1->Length);
    double StartDF=Ini->ReadFloat("CurrentView", "StartF", 0);
    double EndDF=Ini->ReadFloat("CurrentView", "EndF", 0.5);
    WaveView1->SetArea(Start, End, StartDF, EndDF);
    WindowTypeCombo->ItemIndex=Ini->ReadInteger("CurrentView", "WindowType", 2); WindowTypeComboChange(NULL);
    WindowSizeCombo->ItemIndex=Ini->ReadInteger("CurrentView", "SpecRes", 5); WindowSizeComboChange(NULL);
    HSDelpEdit1->Text=Ini->ReadString("HS", "delp", "1.0");
    HSDelmEdit1->Text=Ini->ReadString("HS", "delm", "1.0");
    MouseWheelZoom->Checked=Ini->ReadInteger("Settings", "MouseWheelZoom", true);
    WaveView1->DisableMouseWheelZoom=!MouseWheelZoom->Checked;
  }
  delete Ini;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LogFreqCheckClick(TObject *Sender)
{
  SetWaveViewContents();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::NavButtonClick(TObject*)
{
  NavButton->Font->Color=(NavButton->Font->Color==clBlack)?clYellow:clBlack;
  Navigator1->Resize();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Navigator1AreaChange(TObject*)
{
  WaveView1->SetArea(WaveView1->Length*Navigator1->x1, WaveView1->Length*Navigator1->x2,
    (1-Navigator1->y2)*0.5, (1-Navigator1->y1)*0.5);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Navigator1Background(TObject*)
{
  if (WaveAudio1->Length<=0)
    Navigator1->BkgBmp->Canvas->FillRect(Navigator1->ClientRect);
  else if (NavButton->Font->Color==clYellow)
  {
    TWaveViewSelection Sel={0, WaveView1->Length, 0, 0.5};
    WaveView1->DrawSpectrogramX(0, Sel, 0, Navigator1->BkgBmp->Canvas, Navigator1->ClientRect, 10, false, false, 1);
  }
  else WaveView1->DrawWaveForm(0, Navigator1->BkgBmp->Canvas, Navigator1->ClientRect, 0, WaveView1->Length);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Open1Click(TObject *Sender)
{
	OpenDialog1->FilterIndex=1;
	if (OpenDialog1->Execute())
	{
		if (WaveAudio1->FileName!=OpenDialog1->FileName) RecentFile(WaveAudio1->FileName);
		WaveAudio1->LoadFromFile(OpenDialog1->FileName);
	}
}

//---------------------------------------------------------------------------
void __fastcall TForm1::PanelRightButtonMouseUp(TObject *Sender,
			TMouseButton Button, TShiftState Shift, int X, int Y)
{
  TShape* Shape=(TShape*)Sender;
  if (Button==mbLeft && X>=0 && Y>=0 && X<Shape->Width && Y<Shape->Height)
	{
    TPanel* APanel; TSplitter* ASplitter;
    if (Shape==PanelRightButton) APanel=PanelRight, ASplitter=Splitter1;
    else if (Shape==PanelRightButton2) APanel=PanelGrid, ASplitter=Splitter3;
    ShowPanel(APanel, APanel->Visible);
    ASplitter->Visible=!ASplitter->Visible;
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Play1Click(TObject *Sender)
{
  WaveView1->StartPlayback(Sender);  
}
//---------------------------------------------------------------------------
void TForm1::PrepareNMSettings(NMSettings* settings)
{
  memset(settings, 0, sizeof(NMSettings));
  int wid=WaveView1->SpecRes, sps=WaveView1->SamplesPerSec;
  windowspec(WaveView1->SpecWindowType, wid, &settings->M, settings->c, &settings->iH2);
	settings->hB=3;
  settings->maxp=HSMaxpEdit1->Text.ToInt();
  settings->maxB=HSMaxBEdit1->Text.ToDouble();
  settings->epf=2.0e-4;
  settings->epf0=2;
  settings->delm=HSDelmEdit1->Text.ToDouble();
  settings->delp=HSDelpEdit1->Text.ToDouble();
  settings->minf0=HSMinF0Edit1->Text.ToDouble()/sps*wid;
  settings->maxf0=HSMaxF0Edit1->Text.ToDouble()/sps*wid;
  settings->pin0=PartialSelectCombo->ItemIndex+1;
  settings->pcount=0;
}

//---------------------------------------------------------------------------
void TForm1::RecentFile(AnsiString FileName)
{
  TIniFile* Ini=0;
  try{
  Ini=new TIniFile(IniFileName);

  int newi=0, start[MaxRecents+1], end[MaxRecents+1];
  double fstart[MaxRecents+1], fend[MaxRecents+1];
	AnsiString Names[MaxRecents+1];
  if (FileExists(FileName))
	{
    Names[0]=FileName;
    start[0]=WaveView1->StartPos, end[0]=WaveView1->EndPos;
    fstart[0]=WaveView1->StartDigiFreq, fend[0]=WaveView1->EndDigiFreq;
    newi=1;
  }

  AnsiString S0="RecentFile";
	for (int i=1; i<=MaxRecents; i++)
	{
		AnsiString S=S0+i;
    if (!Ini->SectionExists(S)) continue;
    AnsiString LName=Ini->ReadString(S, "FileName", "");
    if (FileExists(LName) && LName!=FileName)
    {
      Names[newi]=LName;
      start[newi]=Ini->ReadInteger(S, "Start", 0);
      end[newi]=Ini->ReadInteger(S, "End", -1);
      fstart[newi]=Ini->ReadFloat(S, "StartF", 0);
      fend[newi]=Ini->ReadFloat(S, "EndF", 0.5);
      newi++;
    }
		Ini->EraseSection(S);
	}

  if (newi>MaxRecents) newi=MaxRecents;
  for (int i=0; i<newi; i++)
  {
    AnsiString S="RecentFile"; S=S+(i+1);
    Ini->WriteString(S, "FileName", Names[i]);
    Ini->WriteInteger(S, "Start", start[i]);
    Ini->WriteInteger(S, "End", end[i]);
    Ini->WriteFloat(S, "StartF", fstart[i]);
    Ini->WriteFloat(S, "EndF", fend[i]);
  }

  for (int i=0; i<newi; i++)
  {
    Recents[i]->Caption=AnsiString(i+1)+". "+Names[i];
    Recents[i]->Visible=true;
  }
  for (int i=newi; i<MaxRecents; i++) Recents[i]->Visible=false;
  Recent00->Visible=(newi>0);
  }catch(...){}
  delete Ini;
}

//---------------------------------------------------------------------------

void TForm1::SetGridContents()
{
  if (!PanelGrid->Visible) return;
  if (WaveView1->CurrentPane<0) return;
  GridSourcePane=WaveView1->CurrentPane;
  int Wid=WaveView1->SpecRes, hWid=Wid/2, Offst=WaveView1->SpecOffst;
  double t=WaveView1->CurrentTime, f=WaveView1->CurrentDigiFreq, amp=sqrt(1.0/Wid), prange=100, i2pi=0.5*prange/M_PI;
  int Channel=WaveView1->FPanes.Channel[GridSourcePane];
  if (WaveView1->FPanes.HasFreqAxis[GridSourcePane] && (AmpTab->Visible || ArcTab->Visible))
  {
    TStringGrid* Grid;
    if (AmpTab->Visible) Grid=AmpGrid;
    else if (ArcTab->Visible) Grid=PhaseGrid;
    Grid->RowCount=Grid->Height/(Grid->DefaultRowHeight+1);
    Grid->ColCount=Grid->Width/(Grid->DefaultColWidth+1);
    int maxfr=(WaveView1->Length-Wid)/Offst+1;
    if (Grid->ColCount>maxfr+1) Grid->ColCount=maxfr+1;
    if (Grid->RowCount>hWid+1) Grid->ColCount=hWid+1;

    int CurrentBin=floor(f*Wid+0.5), CurrentFr=floor((t-hWid)*1.0/Offst+0.5);
    if (CurrentFr<0) CurrentFr=0; else if (CurrentFr>maxfr-1) CurrentFr=maxfr-1;
    if (CurrentBin<0) CurrentBin=0; if (CurrentBin>hWid-1) CurrentBin=hWid-1;
    int frst=CurrentFr-Grid->ColCount/2; if (frst<0) frst=0;
    int fren=frst+Grid->ColCount-1; if (fren>maxfr) fren=maxfr, frst=maxfr-Grid->ColCount+1;
    int binst=CurrentBin-Grid->RowCount/2; if (binst<0) binst=0;
    int binen=binst+Grid->RowCount-1; if (binen>hWid) binen=hWid, binst=hWid-Grid->RowCount+1;

    char format[128];
    memcpy(format, FormatEdit->Text.c_str(), FormatEdit->Text.Length()+1);

    double *dw=0, *tw=0;
    cdouble *W, *X=0;

    for (int fr=frst; fr<fren; fr++)
    {
      if (AmpTab->Visible)
      {
        QSPEC_FORMAT* data=WaveView1->A[Channel][fr];
        for (int bin=binst; bin<binen; bin++)
          Grid->Cells[fr-frst+1][binen-bin]=AnsiString().sprintf(format, data[bin]*amp);
      }
      else if (ArcTab->Visible)
      {
        cmplx<QSPEC_FORMAT>* data=WaveView1->Spec[Channel][fr];
        for (int bin=binst; bin<binen; bin++)
        {
          double pvalue=arg(data[bin])*i2pi;
          if (bin%2) pvalue+=prange/2;
          if (pvalue>prange/2) pvalue-=prange;
          Grid->Cells[fr-frst+1][binen-bin]=AnsiString().sprintf(format, pvalue);
        }
      }

      Grid->Cells[fr-frst+1][0]=fr;
        for (int bin=binst; bin<binen; bin++) Grid->Cells[0][binen-bin]=bin;
    }

    Grid->Row=binen-CurrentBin;
    Grid->Col=CurrentFr-frst+1;

    delete[] dw;
    delete[] tw;
    delete[] X;
  }
  else if (WaveView1->FPanes.HasFreqAxis[GridSourcePane] && QPkTab->Visible)
  {
    TStringGrid* Grid=QPkGrid;
    Grid->RowCount=Grid->Height/(Grid->DefaultRowHeight+1);
    int maxfr=(WaveView1->Length-Wid)/Offst+1;
    if (Grid->RowCount>hWid+1) Grid->ColCount=hWid+1;
    TStringList* List=new TStringList;
    for (int c=0; c<Grid->ColCount; c++)
      for (int r=0; r<Grid->RowCount; r++) Grid->Cells[c][r]="";
    delete List;

    int CurrentBin=floor(f*Wid+0.5), CurrentFr=floor((t-hWid)*1.0/Offst+0.5);
    if (CurrentFr<0) CurrentFr=0; else if (CurrentFr>maxfr-1) CurrentFr=maxfr-1;
    if (CurrentBin<0) CurrentBin=0; if (CurrentBin>hWid-1) CurrentBin=hWid-1;
    int binst=CurrentBin-Grid->RowCount/2; if (binst<0) binst=0;
    int binen=binst+Grid->RowCount-1; if (binen>hWid) binen=hWid, binst=hWid-Grid->RowCount+1;


    int frst=CurrentFr-Grid->ColCount/2; if (frst<0) frst=0;
    int fren=frst+Grid->ColCount-1; if (fren>maxfr) fren=maxfr, frst=maxfr-Grid->ColCount+1;

    char format[128];
    memcpy(format, FormatEdit->Text.c_str(), FormatEdit->Text.Length()+1);

    Grid->Cells[0][0]=AnsiString().sprintf("fr.%d", CurrentFr);
    for (int bin=binst; bin<binen; bin++) Grid->Cells[0][binen-bin]=bin;
    Grid->Cells[1][0]="f"; Grid->Cells[2][0]="a";

    double *f=new double[(binen-binst)*3], *a=&f[binen-binst];
    cmplx<QSPEC_FORMAT>* spec=WaveView1->Spec[Channel][CurrentFr];
    cdouble *x=new cdouble[Wid/2+1]; memset(x, 0, sizeof(cdouble)*(Wid/2+1));
    int bnst=binst-2, bnen=binen+2; if (bnst<0) bnst=0; if (bnen>Wid/2) bnen=Wid/2;
    for (int i=bnst; i<bnen; i++) x[i]=spec[i];
    int M; double c[6], iH2;
    windowspec(WaveView1->SpecWindowType, Wid, &M, c, &iH2);
    int p=QuickPeaks(f, a, Wid, x, M, c, iH2, 0.0005, binst, binen);

    MList* mlist=0;
    int M_, I, p0, q0, *p0s;
    double **h, *s;
    cdouble **u, **du;
    if (p>0)
    {
      mlist=new MList;
      s=new double[Wid]; mlist->Add(s, 1);
      __int16* data=&WaveView1->Data16[Channel][Offst*CurrentFr];
      for (int n=0; n<Wid; n++) s[n]=data[n];
    }


    for (int ip=0; ip<p; ip++)
    {
      int bin=floor(f[ip]+0.5);
      Grid->Cells[1][binen-bin]=AnsiString().sprintf(format, f[ip]);
      Grid->Cells[2][binen-bin]=AnsiString().sprintf(format, a[ip]);
    }

    delete mlist;

    delete[] x;
    delete[] f;

    Grid->Row=binen-CurrentBin;
  }
}
//---------------------------------------------------------------------------
void TForm1::SetWaveViewContents()
{
  int rulers=(WaveView1->FPanes.Count>0)?WaveView1->FPanes.Rulers[0]:7;
  if (WaveView1->ShowInfo) WaveView1->FPanes.MarginOut=TRect(5, WaveView1->DefaultInfoFont->Height, 5, WaveView1->DefaultInfoFont->Height);
  else WaveView1->FPanes.MarginOut=TRect(5, 5, 5, WaveView1->DefaultInfoFont->Height);
  if (WaveView1->Channels>=2 && DisplayChannelRadio->ItemIndex==0)
  {
    int Columns=PanesRadio->ItemIndex+1;
    WaveView1->CreatePanes(Columns, 2);
    int type=SpectrogramView?(FreqLineCheck->Checked?2:1):0;
    WaveView1->SetContent(0, 0, 0, type);
    WaveView1->SetContent(0, 1, 1, type);
    if (Columns>1)
    {
      type=SpectrogramView?0:(FreqLineCheck->Checked?2:1);
      WaveView1->SetContent(1, 0, 0, type);
      WaveView1->SetContent(1, 1, 1, type);
    }
  }
  else
  {
    int Rows=PanesRadio->ItemIndex+1;
    WaveView1->CreatePanes(1, Rows);
    int type=SpectrogramView?(FreqLineCheck->Checked?2:1):0;
    int channel=(WaveView1->Channels>=2 && DisplayChannelRadio->ItemIndex==2)?1:0;
    WaveView1->SetContent(0, 0, channel, type);
    if (Rows>1)
    {
      type=SpectrogramView?0:(FreqLineCheck->Checked?2:1);
      WaveView1->SetContent(0, 1, channel, type);
    }
  }

  int yscale=LogFreqCheck->Checked?1:0;
  for (int i=0; i<4; i++) WaveView1->SetYScale(i, yscale), WaveView1->SetRulers(i, rulers);

  WaveView1->ShowCursorText=SpeedButtonCursorText->Down;
  WaveView1->ShowPaneInfo=SpeedButtonPaneInfo->Down;
}
//---------------------------------------------------------------------------
void TForm1::ShowPanel(TPanel* APanel, bool Hide)
{
  APanel->Visible=!Hide;
  if (APanel==PanelRight) PanelRightButton->Brush->Color=Hide?clTeal:clSilver;
  else if (APanel==PanelGrid) PanelRightButton2->Brush->Color=Hide?clTeal:clSilver;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SpectrogramBrightness1Click(TObject *Sender)
{
  WaveView1->SpecAmp=1;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::SpeedButtonFClick(TObject *Sender)
{
  if (SpeedButtonF->Down)
  {
    WaveView1->SelectMode=WaveView1->SelectMode|WV2_VSELECT;
    if (GetKeyState(VK_SHIFT)>=0 && SpeedButtonT->Down)
    {
      SpeedButtonT->Down=false;
      WaveView1->SelectMode=WaveView1->SelectMode&(~WV2_HSELECT);

    }
  }
  else WaveView1->SelectMode=WaveView1->SelectMode&(~WV2_VSELECT);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButtonMClick(TObject *Sender)
{
  WaveView1->MultiSelect=(SpeedButtonM->Down);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SpeedButtonTClick(TObject *Sender)
{
  if (SpeedButtonT->Down)
  {
    WaveView1->SelectMode=WaveView1->SelectMode|WV2_HSELECT;
    if (GetKeyState(VK_SHIFT)>=0 && SpeedButtonF->Down)
    {
      SpeedButtonF->Down=false;
      WaveView1->SelectMode=WaveView1->SelectMode&(~WV2_VSELECT);
    }
  }
  else WaveView1->SelectMode=WaveView1->SelectMode&(~WV2_HSELECT);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::UndoZoom1Click(TObject *Sender)
{
  WaveView1->UndoExtract(Sender);
}
//---------------------------------------------------------------------------
  void ClearObjectByShortTag0(TWaveView* WV, int tag0)
  {
    if (WV->ObjectAtPointer && WV->ObjectAtPointer->ShortTag[0]==tag0) WV->ObjectAtPointer=0;
    int ind=0; for (int i=0; i<WV->FObjects.Count; i++) if (WV->FObjects.Items[i].ShortTag[0]!=tag0) WV->FObjects.Items[ind++]=WV->FObjects.Items[i]; WV->FObjects.Count=ind;
  }

void __fastcall TForm1::WaveAudio1Load(TObject*)
{
  DisplayChannelRadio->Enabled=(WaveAudio1->Channels>1);
  PlayChannelRadio->Enabled=(WaveAudio1->Channels>1);
  ClearObjectByShortTag0(WaveView1, stAtom);
  ClearObjectByShortTag0(WaveView1, stOnset);
  SetWaveViewContents();
  Caption="hv - "+WaveAudio1->FileName;
  if (EventBox) {EventBox->Load(NULL);}
  Navigator1->SetArea(0, 1, 1-WaveView1->EndDigiFreq*2, 1-WaveView1->StartDigiFreq*2);
  Navigator1->Resize();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1AfterPaint(TObject*)
{
  Navigator1->SetArea(WaveView1->StartPos*1.0/WaveView1->Length, WaveView1->EndPos*1.0/WaveView1->Length, 1-WaveView1->EndDigiFreq*2, 1-WaveView1->StartDigiFreq*2);
  fcalculatespcount=WaveView1->TimeStamp1;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1BeforePlayback(TObject*)
{
  if (WaveView1->Selections->Count)
    WaveView1->PlaybackFilter=(TWaveViewPlaybackFilter)PlayFilterCombo->ItemIndex;
  else
    WaveView1->PlaybackFilter=wvfNone;
  WaveView1->StereoMode=(TWaveViewStereoMode)PlayChannelRadio->ItemIndex;
}
//---------------------------------------------------------------------------
int __fastcall TForm1::WaveView1CustomInfo(TObject* Sender)
{
  TStringList* List=new TStringList;
  List->Add(AnsiString().sprintf(" %d-channel, %dhz, %dbit. ", WaveView1->Channels, WaveView1->SamplesPerSec, WaveView1->BytesPerSample*8));
  if (WaveView1->RulerUnitTime==0)
    List->Add(AnsiString().sprintf(" Time(%d): from %d to %d. ", WaveView1->EndPos-WaveView1->StartPos, WaveView1->StartPos, WaveView1->EndPos));
  else
  {
    double fs=WaveView1->StartPos*1.0/WaveView1->SamplesPerSec, fe=WaveView1->EndPos*1.0/WaveView1->SamplesPerSec;
    List->Add(AnsiString().sprintf(" Time(%.4gs): from %.4gs to %.4gs. ", fe-fs, fs, fe));
  }
  if (WaveView1->RulerUnitFreq==0)
  {
    double fs=WaveView1->StartDigiFreq*WaveView1->SamplesPerSec, fe=WaveView1->EndDigiFreq*WaveView1->SamplesPerSec;
    AnsiString as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(fs)/C4)), ae=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(fe)/C4));
    List->Add(AnsiString().sprintf(" Frequency: from %.1fhz(%s) to %.1fhz(%s). ", fs, as.c_str(), fe, ae.c_str()));
  }
  else
    List->Add(AnsiString().sprintf(" Frequency: from %.4gbin to %.4gbin. ", WaveView1->StartDigiFreq*WaveView1->SpecRes, WaveView1->EndDigiFreq*WaveView1->SpecRes));
  return (int)List;
}

int __fastcall TForm1::WaveView1CustomPaneInfo(TObject* Sender)
{
	TStringList* List=new TStringList;

  if (WaveView1->Channels>1) List->Add(WaveView1->FPanes.Channel[WaveView1->CurrentPane]==0?"Channel: left":"Channel: right");
    if (WaveView1->Selections->Count>0 && WaveView1->Selections->Focus>=0)
    {
      List->Add("Current Selection");
        int st=WaveView1->Selections->StartPos, en=WaveView1->Selections->EndPos;
      List->Add(AnsiString().sprintf("Time(%d): from %d to %d", en-st, st, en));
//      List->Add(AnsiString().sprintf("Frequency: from %.1fhz to %.1fhz", WaveView1->Selections->StartDigiFreq*WaveView1->SamplesPerSec, WaveView1->Selections->EndDigiFreq*WaveView1->SamplesPerSec));
    }
  if (WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom)
  {
    atom* part=(atom*)WaveView1->ObjectAtPointer->Buffer;
    List->Add("Current Atom");
    List->Add(AnsiString().sprintf("Partial %d", WaveView1->ObjectAtPointer->ShortTag[2]));
    List->Add(AnsiString().sprintf("Frame %d", WaveView1->ObjectAtPointer->Tag[2]));
    if (WaveView1->RulerUnitTime==0) List->Add(AnsiString().sprintf("Time %d", int(part->t)));
    else List->Add(AnsiString().sprintf("Time %.4fs", part->t/WaveView1->SamplesPerSec));
    if (WaveView1->RulerUnitFreq==0) List->Add(AnsiString().sprintf("Freq %.2fhz", part->f*WaveView1->SamplesPerSec));
    else List->Add(AnsiString().sprintf("Freq %.2fbin", part->f*WaveView1->SpecRes));
    List->Add(AnsiString().sprintf("Phase%% %.2f", part->p*50/M_PI));
    List->Add(AnsiString().sprintf("Amplitude %.4g", part->a));
    List->Add(AnsiString().sprintf("Scale %d", int(part->s)));
  }

  return (int)List;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1DrawFreqLimiter(TObject* Sender, TWaveViewObject& Obj)
{
  TCanvas* Canv=WaveView1->Canvas; Canv->Pen->Color=clGreen; Canv->Pen->Mode=pmCopy; Canv->Pen->Style=psDot;
  int X=Obj.Tag[1], Y=WaveView1->FromDigiFreqToPixel(WaveView1->StartPane, f1/WaveView1->SpecRes);
  Canv->MoveTo(X-10, Y); Canv->LineTo(X+10, Y);
  Y=WaveView1->FromDigiFreqToPixel(WaveView1->StartPane, f2/WaveView1->SpecRes);
  Canv->MoveTo(X-10, Y); Canv->LineTo(X+10, Y);
  Canv->Pen->Style=psSolid;
  double delm=HSDelmEdit1->Text.ToDouble();
  Y=WaveView1->FromDigiFreqToPixel(WaveView1->StartPane, (f1-delm)/WaveView1->SpecRes);
  Canv->MoveTo(X-10, Y); Canv->LineTo(X+10, Y);
  Y=WaveView1->FromDigiFreqToPixel(WaveView1->StartPane, (f2+delm)/WaveView1->SpecRes);
  Canv->MoveTo(X-10, Y); Canv->LineTo(X+10, Y);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1DrawObject(TObject* Sender, TWaveViewObject& Obj)
{
  TCanvas* Canv=WaveView1->Canvas;
  int Y=WaveView1->Height;

  if (Obj.Id>=0)
  {
    if (WaveView1->ObjectAtPointer==&Obj)
    {
      Canv->Brush->Color=clRed; Canv->Brush->Style=bsSolid;
      Canv->Font=WaveView1->DefaultInfoFont; Canv->Font->Color=clWhite;
    }
    else
    {
      Canv->Brush->Color=clBlack; Canv->Brush->Style=bsSolid;
      Canv->Font=WaveView1->DefaultInfoFont; Canv->Font->Color=clWhite;
    }
    AnsiString text; int left, top;
    if (Obj.Id==0)
    {
      text=(WaveView1->RulerUnitTime==1)?AnsiString(" [seconds] "):AnsiString(" [samples] ");
      left=WaveView1->FPanes.MarginOut.left, top=Y-WaveView1->FPanes.MarginOut.bottom;
    }
    else if (Obj.Id==1)
    {
      if (WaveView1->RulerUnitFreq==1)
      {
        if (LogFreqCheck->Checked) text=" [pitch] ";
        else text= " [bin] ";
      }
      else text=" [hz] ";
      left=WaveView1->FObjects.Items[0].Rect.right, top=WaveView1->FObjects.Items[0].Rect.top;
    }
    else if (Obj.Id==2)
    {
      text=(WaveView1->RulerUnitAmp==1)?AnsiString(" [abs. amp] "):AnsiString(" [rel. amp] ");
      left=WaveView1->FObjects.Items[1].Rect.right, top=WaveView1->FObjects.Items[0].Rect.top;
    }
    else if (Obj.Id==3)
    {
      if (WaveView1->FPanes.Rulers[0] & WV2_HSELECT) text=(WaveView1->RulerAlignX==alTop)?AnsiString(" [X axis: top] "):AnsiString(" [X axis: bottom] ");
      else text=" [X axis: off] ";
      left=WaveView1->FObjects.Items[2].Rect.right, top=WaveView1->FObjects.Items[0].Rect.top;
    }
    else if (Obj.Id==4)
    {
      if (WaveView1->FPanes.Rulers[0] & WV2_VSELECT) text=(WaveView1->RulerAlignY==alLeft)?AnsiString(" [Y axis: left] "):AnsiString(" [Y axis: right] ");
      else text=" [Y axis: off] ";
      left=WaveView1->FObjects.Items[3].Rect.right, top=WaveView1->FObjects.Items[0].Rect.top;
    }
    else if (Obj.Id==5)
    {
      if (WaveView1->AutoSpecAmp) text=AnsiString().sprintf(" [spec. amp (auto): %.3g] ", log(WaveView1->SpecAmp)/log(2.0));
      else text=AnsiString().sprintf(" [spec. amp: %.3g] ", log(WaveView1->SpecAmp)/log(2.0));
      left=WaveView1->FObjects.Items[4].Rect.right, top=WaveView1->FObjects.Items[0].Rect.top;
    }
    Canv->TextOut(left, top, text);
    Obj.Rect.left=left, Obj.Rect.top=top, Obj.Rect.right=left+Canv->TextWidth(text), Obj.Rect.bottom=top+Canv->TextHeight(text);
  }
}

//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1DrawAtom(TObject* Sender, TWaveViewObject& Obj)
{
  int pane=0;
  while (pane<WaveView1->FPanes.Count && (!WaveView1->FPanes.HasFreqAxis[pane]
    ||WaveView1->FPanes.Channel[pane]!=Obj.ShortTag[1])) pane++;
  if (pane>=WaveView1->FPanes.Count)
    {Obj.Rect.left=0, Obj.Rect.right=-1, Obj.Rect.top=0, Obj.Rect.bottom=-1; return;}

    atom* par=(atom*)Obj.Buffer;
    if (par->t<WaveView1->StartPos || par->t>=WaveView1->EndPos || par->f<WaveView1->StartDigiFreq || par->f>WaveView1->EndDigiFreq || par->f<=0)
      {Obj.Rect.left=0, Obj.Rect.right=-1, Obj.Rect.top=0, Obj.Rect.bottom=-1; return;}

    TCanvas* Canv=WaveView1->Canvas;
    TRect Rect=WaveView1->FPanes.Rect[pane];
    HRGN Rgn=CreateRectRgn(Rect.left, Rect.top, Rect.right, Rect.bottom);
    SelectClipRgn(Canv->Handle, Rgn);

    int Wid=WaveView1->SpecRes, HOffst=WaveView1->SpecOffst/2; double df=1.0/Wid;
    int X=WaveView1->FromSampleToPixel(pane, par->t), X1=WaveView1->FromSampleToPixel(pane, par->t-HOffst), X2=WaveView1->FromSampleToPixel(pane, par->t+HOffst);
    int Y=WaveView1->FromDigiFreqToPixel(pane, par->f), Y1=WaveView1->FromDigiFreqToPixel(pane, par->f+df), Y2=WaveView1->FromDigiFreqToPixel(pane, par->f-df);
    if (X1>X-1) X1=X-1; if (X2<X+2) X2=X+2;
    if (Y1>Y-1) Y1=Y-1; if (Y2<Y+2) Y2=Y+2;
    Canv->Pen->Mode=pmCopy; Canv->Pen->Style=psSolid;
		bool shiftdown=(GetKeyState(VK_SHIFT)<0), ctrldown=(GetKeyState(VK_CONTROL)<0), onobj=(WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom);
    if (!shiftdown && !ctrldown && onobj
        || !shiftdown && ctrldown && onobj && Obj.ShortTag[2]==WaveView1->ObjectAtPointer->ShortTag[2]
        || shiftdown && !ctrldown && onobj && Obj.Tag[2]==WaveView1->ObjectAtPointer->Tag[2])
    {
      switch (par->type)
      {
        case atAnchor: case atPeak: Canv->Pen->Color=clWhite; break;
        case atInfered: Canv->Pen->Color=clLime; break;
        case atMuted: 
        case atBuried: Canv->Pen->Color=clRed; break;
      }
    }
    else
    {
      switch (par->type)
      {
        case atAnchor: case atPeak: Canv->Pen->Color=clGray; break;
        case atInfered: Canv->Pen->Color=clGreen; break;
        case atMuted:
        case atBuried: Canv->Pen->Color=TColor(RGB(128, 0, 0)); break;
      }
    }
    Canv->MoveTo(X-1, Y); Canv->LineTo(X+2, Y); Canv->MoveTo(X, Y-1); Canv->LineTo(X, Y+2);
    if (par->type==atAnchor) {Canv->MoveTo(X, Y+3); Canv->LineTo(X-3, Y); Canv->LineTo(X, Y-3); Canv->LineTo(X+3, Y); Canv->LineTo(X, Y+3);}
    if (WaveView1->ObjectAtPointer==&Obj)
    {
      if (par->type==atAnchor) {Canv->MoveTo(X, Y+4); Canv->LineTo(X-4, Y); Canv->LineTo(X, Y-4); Canv->LineTo(X+4, Y); Canv->LineTo(X, Y+4);}
      else {Canv->Brush->Style=bsClear; Canv->Rectangle(X1, Y1, X2, Y2);}
    }
    Obj.Rect.left=X1, Obj.Rect.right=X2;
    Obj.Rect.top=(Y1<Y-5)?(Y-5):Y1, Obj.Rect.bottom=(Y2>Y+6)?(Y+6):Y2;
		SelectClipRgn(Canv->Handle, NULL);
		DeleteObject(Rgn);
}

//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1InfoDblClick(TObject* Sender)
{
  if (WaveView1->InfoRectAtPointer==1) //time range
  {
    bool timeunit=(WaveView1->RulerUnitTime==0);
    RangeEdit->Caption="Edit time range";
    if (timeunit){RangeEdit->Edit1->Text=WaveView1->StartPos; RangeEdit->Edit2->Text=WaveView1->EndPos;}
    else {RangeEdit->Edit1->Text=WaveView1->StartPos*1.0/WaveView1->SamplesPerSec; RangeEdit->Edit2->Text=WaveView1->EndPos*1.0/WaveView1->SamplesPerSec;}
    if (RangeEdit->ShowModal())
    {
      int NewStartPos, NewEndPos;
      if (timeunit) NewStartPos=RangeEdit->Edit1->Text.ToInt(), NewEndPos=RangeEdit->Edit2->Text.ToInt();
      else NewStartPos=RangeEdit->Edit1->Text.ToDouble()*WaveView1->SamplesPerSec, NewEndPos=RangeEdit->Edit2->Text.ToDouble()*WaveView1->SamplesPerSec;
      if (NewStartPos>NewEndPos) {int tmp=NewStartPos; NewStartPos=NewEndPos; NewEndPos=tmp;}
      if (NewStartPos<0) NewStartPos=0; if (NewEndPos>WaveView1->Length) NewEndPos=WaveView1->Length;
      WaveView1->SetStartAndEndPos(NewStartPos, NewEndPos);
    }
  }
  else if (WaveView1->InfoRectAtPointer==2)
  {
    bool frequnit=(WaveView1->RulerUnitFreq==0);
    RangeEdit->Caption="Edit frequency range";
    if (frequnit){RangeEdit->Edit1->Text=WaveView1->StartDigiFreq*WaveView1->SamplesPerSec; RangeEdit->Edit2->Text=WaveView1->EndDigiFreq*WaveView1->SamplesPerSec;}
    else {RangeEdit->Edit1->Text=WaveView1->StartDigiFreq*WaveView1->SpecRes; RangeEdit->Edit2->Text=WaveView1->EndDigiFreq*WaveView1->SpecRes;}
    if (RangeEdit->ShowModal())
    {
      double NewStartDigiFreq, NewEndDigiFreq;
      if (frequnit) NewStartDigiFreq=RangeEdit->Edit1->Text.ToDouble()/WaveView1->SamplesPerSec, NewEndDigiFreq=RangeEdit->Edit2->Text.ToDouble()/WaveView1->SamplesPerSec;
      else NewStartDigiFreq=RangeEdit->Edit1->Text.ToDouble()/WaveView1->SpecRes, NewEndDigiFreq=RangeEdit->Edit2->Text.ToDouble()/WaveView1->SpecRes;
      if (NewStartDigiFreq>NewEndDigiFreq) {double tmp=NewStartDigiFreq; NewStartDigiFreq=NewEndDigiFreq; NewEndDigiFreq=tmp;}
      if (NewStartDigiFreq<0) NewStartDigiFreq=0; if (NewEndDigiFreq>0.5) NewEndDigiFreq=0.5;
      WaveView1->SetStartAndEndDigiFreq(NewStartDigiFreq, NewEndDigiFreq);
    }
  }
}

//---------------------------------------------------------------------------

void __fastcall TForm1::WaveView1KeyPress(TObject* Sender, char &Key)
{
  if (Key=='a')
  {
    if (PanelGrid->Visible)
    {
      PageControl2->SelectNextPage(true, true);
    }
  }
  else if (Key=='A')
  {
    if (PanelGrid->Visible)
    {
      PageControl2->SelectNextPage(false, true);
    }
  }
  else if (Key=='E')
  {
  if (GetKeyState(VK_SHIFT)<0)
  {
    if (EventBox->HSCount<1) return;
    int idx=-1;
    double delf;
    double f=WaveView1->CurrentDigiFreq;
    int t=WaveView1->CurrentTime, ch=WaveView1->FPanes.Channel[WaveView1->CurrentPane];
    for (int ev=0; ev<EventBox->HSCount; ev++)
    {
      THS* hs=EventBox->HS[ev];
      if (t<hs->StartPos() || t>hs->EndPos()) continue;
      int offst=hs->StdOffst();
      int fr=(t-hs->StartPos())/offst;
      int m=f/hs->Partials[0][fr].f-1;
      if (m<0) m=0;
      if (m>hs->M-1) m=hs->M-1;
      double ldelf=fabs(f-hs->Partials[m][fr].f);
      while (m>0 && ldelf>fabs(f-hs->Partials[m-1][fr].f))
      {
        ldelf=ldelf>fabs(f-hs->Partials[m-1][fr].f);
        m--;
      }
      while (m<hs->M-1 && ldelf>fabs(f-hs->Partials[m+1][fr].f))
      {
        ldelf=fabs(f-hs->Partials[m+1][fr].f);
        m++;
      }
      if (idx==-1 || delf>ldelf)
      {
        delf=ldelf;
        idx=ev;
      }
    }
    if (idx>=0) EventBox->SetItemIndex(idx);
  }}
}


  void __fastcall TForm1::AddHSObject(THS* aHS)
  {
    for (int m=0; m<aHS->M; m++) for (int fr=0; fr<aHS->Fr; fr++)
    {
      if (aHS->Partials[m][fr].f>0)
      {
        TWaveViewObject Obj; memset(&Obj, 0, sizeof(TWaveViewObject));
        Obj.ShortTag[0]=stAtom; Obj.ShortTag[1]=aHS->Channel; Obj.ShortTag[2]=m+1; Obj.ShortTag[3]=0;
        Obj.Tag[2]=fr;
        Obj.DrawObject=WaveView1DrawAtom; Obj.Buffer=&aHS->Partials[m][fr]; Obj.OnKeyDown=WaveView1ParKeyDown;
        Obj.OnMouseDown=WaveView1ParMouseDown; Obj.OnMouseMove=WaveView1ParMouseMove; Obj.OnMouseUp=WaveView1ParMouseUp;
        Obj.OnMouseWheel=WaveView1ParMouseWheel;
        WaveView1->FObjects.Add(Obj);
      }
    }
  }

void __fastcall TForm1::WaveView1MouseDown(TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
  if (WaveView1->OpMode!=wopCrop) WaveView1PopupMenu->AutoPopup=true;
  else WaveView1PopupMenu->AutoPopup=false;
  if (WaveView1->Playing && Shift.Contains(ssCtrl) && Button==mbRight) {WaveView1->PBPR=WaveView1->CurrentTime, WaveView1->ForceOLA=true; WaveView1PopupMenu->AutoPopup=false; return;}

  if (WaveView1->OpMode==wopHS && WaveView1->FPanes.HasFreqAxis[WaveView1->CurrentPane] && Shift.Contains(ssLeft))
  {
    if (WaveView1->CurrentPane<0) return;
    if (WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom) PartialSelectCombo->ItemIndex=WaveView1->ObjectAtPointer->ShortTag[2]-1;

    if (Shift.Contains(ssShift) || !(WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom))
    {
      double _f=WaveView1->CurrentDigiFreq;
      int _t=WaveView1->CurrentTime, SpecRes=WaveView1->SpecRes, SpecOffst=WaveView1->SpecOffst;

      int frst=(WaveView1->StartPos-SpecRes/2)/SpecOffst, fren=(WaveView1->EndPos-SpecRes/2)/SpecOffst;
      if (frst<0) frst=0;

      int M, Fr; atom** Partials;
      int Channel=WaveView1->FPanes.Channel[WaveView1->CurrentPane];
      NMSettings settings; PrepareNMSettings(&settings);
      int tag=FindNote(_t, _f, M, Fr, Partials, frst, fren, SpecRes, SpecOffst, WaveView1->Spectrogram[Channel], settings);

      if (M>0)
      {
        if (!HS) HS=EventBox->NewHS(0, 0);
        else
        {
          ClearObjectByShortTag0(WaveView1, stAtom);
          if (HS->Partials) DeAlloc2(HS->Partials);
          if (HS->startamp) {DeAlloc2(HS->startamp); HS->st_count=0;}
        }
        HS->M=M, HS->Fr=Fr; HS->Partials=Partials;
        HS->Channel=Channel;

        AddHSObject(HS);
        if (tag) HS->isconstf=1;

        EventBox->ListBox1->Items->Strings[EventBox->ListBox1->ItemIndex]
          =((HS->Channel==0)?"left: ":"right: ")
           +AnsiString().sprintf("%.2fs, ", HS->Partials[0][0].t*1.0/WaveView1->SamplesPerSec)
           +SemitoneToPitch(Log2(HS->Partials[0][0].f*WaveView1->SamplesPerSec/C4)*12);
				if (!EventBox->Visible)
				{
					EventBox->Left=Left+Width;
          EventBox->Top=Top;
          EventBox->Height=Height;
					EventBox->Show();
				}
      }
    }
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1MouseMove(TObject* Sender, TShiftState Shift, int X, int Y)
{
  if (Shift.Contains(ssRight) && (X!=WaveView1->StartSelX || Y!=WaveView1->StartSelY))
  if (WaveView1PopupMenu->AutoPopup) WaveView1PopupMenu->AutoPopup=false;
  if (PanelGrid->Visible && (!MBCheck->Checked || Shift.Contains(ssShift))) SetGridContents();
  if (Shift.Contains(ssLeft) && WaveView1->OpMode==wopSample)
  {
    int channel=WaveView1->FPanes.Channel[WaveView1->StartPane],
        t=WaveView1->StartSel;
    WaveView1->Data16[channel][t]=WaveView1->FromPixelToAmplitude(WaveView1->StartPane, Y);
    WaveView1->ExtDataChange(Sender, channel, t, t);
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1MousePointer(TObject* Sender, int Pane, int t, double f)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1MouseUp(TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
}

//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint& MousePos, bool& Handled)
{
  if (Shift.Contains(ssRight))
  {
    if (WaveView1PopupMenu->AutoPopup) WaveView1PopupMenu->AutoPopup=false;
    if (WaveView1->OpMode==wopDrag) WaveView1->StartDrag(WaveView1->LastX, WaveView1->LastY); //dragmode=false;
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1ObjectClick(TObject*)
{
  if (WaveView1->ObjectAtPointer->Id==0) WaveView1->RulerUnitTime=1-WaveView1->RulerUnitTime;
  else if (WaveView1->ObjectAtPointer->Id==1) WaveView1->RulerUnitFreq=1-WaveView1->RulerUnitFreq;
  else if (WaveView1->ObjectAtPointer->Id==2) WaveView1->RulerUnitAmp=1-WaveView1->RulerUnitAmp;
  else if (WaveView1->ObjectAtPointer->Id==3){
		if (WaveView1->FPanes.Rulers[0] & WV2_HSELECT){if (WaveView1->RulerAlignX==alTop) WaveView1->RulerAlignX=alBottom; else {int rulers=WaveView1->FPanes.Rulers[0] & ~WV2_HSELECT; for (int i=0; i<WaveView1->FPanes.Count; i++) WaveView1->FPanes.Rulers[i]=rulers; WaveView1->InvalidateBasic(-1, 0); WaveView1->RulerAlignX=alTop;}}
		else {int rulers=WaveView1->FPanes.Rulers[0] | WV2_HSELECT; for (int i=0; i<WaveView1->FPanes.Count; i++) WaveView1->FPanes.Rulers[i]=rulers; WaveView1->InvalidateBasic(-1, 0); WaveView1->RulerAlignX=alTop;}}
  else if (WaveView1->ObjectAtPointer->Id==4){
    if (WaveView1->FPanes.Rulers[0] & (WV2_VSELECT|WV2_AMP)){if (WaveView1->RulerAlignY==alLeft) WaveView1->RulerAlignY=alRight; else {int rulers=WaveView1->FPanes.Rulers[0] & ~WV2_VSELECT & ~WV2_AMP; for (int i=0; i<WaveView1->FPanes.Count; i++) WaveView1->FPanes.Rulers[i]=rulers; WaveView1->InvalidateBasic(-1, 0); WaveView1->RulerAlignY=alLeft;}}
    else {int rulers=WaveView1->FPanes.Rulers[0] | WV2_VSELECT | WV2_AMP; for (int i=0; i<WaveView1->FPanes.Count; i++) WaveView1->FPanes.Rulers[i]=rulers; WaveView1->InvalidateBasic(-1, 0); WaveView1->RulerAlignY=alLeft;}}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1ObjectDblClick(TObject*)
{
  if (WaveView1->ObjectAtPointer->Id==5)
  {
    if (GetKeyState(VK_CONTROL)<0) WaveView1->AutoSpecAmp=!WaveView1->AutoSpecAmp;
    else WaveView1->SpecAmp=1;
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1ObjectMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint& MousePos, bool& Handled)
{
  if (WaveView1->ObjectAtPointer->Id==5)
  {
    double amp=(WheelDelta>0)?sqrt(2.0):sqrt(0.5);
    if (WaveView1->AutoSpecAmp) WaveView1->maxv_specamp*=amp;
    WaveView1->SpecAmp*=amp;
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode)
{
  AnsiString S="";
  if (WaveView1->Length<=0) OpMode=wopIdle;
  else if (GetKeyState('X')<0) {OpMode=wopCrop; S="Crop"; WaveView1PopupMenu->AutoPopup=false;} //crop mode
  else if ((SpeedButtonSelect->Down || GetKeyState('S')<0) && !EditorPanel->Visible) {OpMode=wopHS; WaveView1->Cursor=crArrow, S="Sinusoid";  WaveView1PopupMenu->AutoPopup=false;}//special select mode
  else if (WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom) {OpMode=wopEdit; WaveView1->Cursor=crHandPoint; S="Edit";} //Edit mode
  else if (Shift.Contains(ssCtrl)) OpMode=wopReselect, S="Reselect"; //re-select mode
  else if (Shift.Contains(ssRight)) OpMode=wopDrag, S="Drag"; //drag mode
  else if (WaveView1->CurrentPane>=0
    && WaveView1->FPanes.Type[WaveView1->CurrentPane]==0
    && (WaveView1->EndPos-WaveView1->StartPos)*10<WaveView1->FPanes.Rect[WaveView1->CurrentPane].Width()
    && abs(WaveView1->CurrentSampleInPixel-WaveView1->CurrentY)<5)
  {
    OpMode=wopSample, S="Edit";
    if (WaveView1->Cursor!=crHandPoint){WaveView1->Cursor=crHandPoint; ::SetCursor(Screen->Cursors[crHandPoint]);}
  }
  else OpMode=wopSelect, S="Select"; //select mode
  StatusBar1->Panels->Items[0]->Text=S;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CropEventStart(TObject*, TShiftState Shift)
{
  int dfr=WaveView1->ObjectAtPointer->Tag[2];
  if (Shift.Contains(ssShift))
  {
    int dm=WaveView1->ObjectAtPointer->ShortTag[2];
    for (int i=0; i<WaveView1->FObjects.Count; i++)
    {
      TWaveViewObject Obj=WaveView1->FObjects.Items[i];
      if (Obj.ShortTag[0]==stAtom && Obj.ShortTag[2]==dm && Obj.Tag[2]<dfr) ((atom*)Obj.Buffer)->type=atMuted;
    }
  }
  else
  {
    for (int m=0; m<HS->M; m++) for (int fr=0; fr<HS->Fr-dfr; fr++)
      HS->Partials[m][fr]=HS->Partials[m][fr+dfr];
    HS->Fr-=dfr;
    int ind=0;
    for (int i=0; i<WaveView1->FObjects.Count; i++)
    {
      TWaveViewObject Obj=WaveView1->FObjects.Items[i];
      if (Obj.ShortTag[0]==stAtom)
      {
        {
          if (Obj.Tag[2]>=dfr)
          {
            Obj.Tag[2]-=dfr;
            Obj.Buffer=&HS->Partials[Obj.ShortTag[2]-1][Obj.Tag[2]];
            if (WaveView1->ObjectAtPointer==&WaveView1->FObjects.Items[i]) WaveView1->ObjectAtPointer=&WaveView1->FObjects.Items[ind];
            if (WaveView1->StartObject==&WaveView1->FObjects.Items[i]) WaveView1->StartObject=&WaveView1->FObjects.Items[ind];
            WaveView1->FObjects.Items[ind++]=Obj;
          }
          else {}
        }
      }
      else WaveView1->FObjects.Items[ind++]=Obj;
    }
    WaveView1->FObjects.Count=ind;
    int EBLI=EventBox->ListBox1->ItemIndex;
    if (HS==EventBox->HS[EBLI])
    {
      EventBox->ListBox1->Items->Strings[EBLI]=(HS->Channel==0?"left: ":"right: ")
        +AnsiString().sprintf("%.2fs, ", HS->Partials[0][0].t*1.0/WaveView1->SamplesPerSec)
        +SemitoneToPitch(Log2(HS->Partials[0][0].f*WaveView1->SamplesPerSec/C4)*12);
    }
  }
}
void __fastcall TForm1::CropEventEnd(TObject*, TShiftState Shift)
{
  int dfr=WaveView1->ObjectAtPointer->Tag[2];
  if (Shift.Contains(ssShift))
  {
    int dm=WaveView1->ObjectAtPointer->ShortTag[2];
    for (int i=0; i<WaveView1->FObjects.Count; i++)
    {
      TWaveViewObject Obj=WaveView1->FObjects.Items[i];
      if (Obj.ShortTag[0]==stAtom && Obj.ShortTag[2]==dm && Obj.Tag[2]>dfr) ((atom*)Obj.Buffer)->type=atMuted;
    }
    return;
  }
  HS->Fr=dfr+1;
  int ind=0;
  for (int i=0; i<WaveView1->FObjects.Count; i++)
  {
    TWaveViewObject Obj=WaveView1->FObjects.Items[i];
    if (Obj.ShortTag[0]==stAtom && Obj.Tag[2]>dfr) {}
    else
    {
      if (WaveView1->ObjectAtPointer==&WaveView1->FObjects.Items[i]) WaveView1->ObjectAtPointer=&WaveView1->FObjects.Items[ind];
      if (WaveView1->StartObject==&WaveView1->FObjects.Items[i]) WaveView1->StartObject=&WaveView1->FObjects.Items[ind];
      WaveView1->FObjects.Items[ind++]=Obj;
    }
  }
  WaveView1->FObjects.Count=ind;
}
void __fastcall TForm1::WaveView1ParKeyDown(TObject*, Word& Key, TShiftState Shift)
{
  if ((WaveView1->OpMode==wopHS || WaveView1->OpMode==wopEdit) && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom)
  {
    if (Key==VK_DELETE)
    {
      atom* par=(atom*)WaveView1->ObjectAtPointer->Buffer;
      if (par->type==atAnchor)
      {
        if (Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
        {
          atom** Partials=HS->Partials;
          for (int m=0; m<HS->M; m++) for (int fr=0; fr<HS->Fr; fr++) if (Partials[m][fr].type==atAnchor) Partials[m][fr].type=atPeak;
        }
        else if (Shift.Contains(ssShift))
        {
          atom** Partials=HS->Partials; int fr=WaveView1->ObjectAtPointer->Tag[2];
          for (int m=0; m<HS->M; m++) if (Partials[m][fr].type==atAnchor) Partials[m][fr].type=atPeak;
        }
        else {par->type=atPeak;}
        WaveView1->Invalidate();
      }
    }
  }
}
//---------------------------------------------------------------------------
#define ExFpStiff ExFmStiff
void __fastcall TForm1::WaveView1ParMouseDown(TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
  if (WaveView1->OpMode==wopHS && Shift.Contains(ssShift)) return;
  if (WaveView1->ObjectAtPointer->ShortTag[0]!=stAtom) return;
  if (WaveView1->OpMode==wopHS)
  {
    if (!Shift.Contains(ssLeft)) return;
    edfr=WaveView1->ObjectAtPointer->Tag[2]; int M=HS->M, Fr=HS->Fr, p=WaveView1->ObjectAtPointer->ShortTag[2];
    anccount=0;
    ancps=(int*)realloc(ancps, sizeof(int)*M); ancfs=(double*)realloc(ancfs, sizeof(double)*M);
    ancfrs=(int*)realloc(ancfrs, sizeof(int)*M); 
    atom** Partials=HS->Partials;

    int frst=edfr, fren=edfr+1;
    if (HS->isconstf) frst=0, fren=HS->Fr;

    int N=WaveView1->SpecRes;
    for (int m=0; m<M; m++)
    {
      for (int fr=frst; fr<fren; fr++)
      {
        if (m+1==p) continue;
        double f=Partials[m][fr].f;
        if (f>0 && HS->Partials[m][fr].type==atAnchor)
        {
          ancps[anccount]=m+1, ancfs[anccount]=f*N;
          ancfrs[anccount]=(HS->Partials[m][fr].tags&ATOM_LOCALANCHOR)?fr:(-1);   //fr>=0: local anchor, used in constant-f tracking
          anccount++;
          break;
        }
      }
    }
    if (anccount>0)
    {
      double delm=HSDelmEdit1->Text.ToDouble(), maxB=HSMaxBEdit1->Text.ToDouble();
      TPolygon* R=new TPolygon(4+anccount*2);
      InitializeR(R, ancps[0], ancfs[0], delm, maxB);
      for (int i=1; i<anccount; i++) CutR(R, ancps[i], ancfs[i], delm);
      ExFpStiff(f1, f2, p, R->N, R->X, R->Y);

      TWaveViewObject Obj; memset(&Obj, 0, sizeof(TWaveViewObject));
      Obj.ShortTag[0]=stFreqDelimiter; Obj.Tag[1]=WaveView1->FromSampleToPixel(WaveView1->StartPane, Partials[p-1][edfr].t); Obj.DrawObject=WaveView1DrawFreqLimiter;
      WaveView1->FObjects.Add(Obj);
      delete R;
    }
  }
  else if (WaveView1->OpMode==wopCrop)
  {
    bool refresh=false;
    if (Button==mbLeft) CropEventStart(0, Shift), refresh=true;
    else if (Button==mbRight) CropEventEnd(0, Shift), refresh=true;
    if (refresh) WaveView1->Invalidate();
  }
}

void __fastcall TForm1::WaveView1ParMouseMove(TObject* Sender, TShiftState Shift, int X, int Y)
{
  if (Shift.Contains(ssLeft))
  {
    WaveView1->ObjectAtPointer=WaveView1->StartObject;
    if (Y==WaveView1->LastY) return;
    if (WaveView1->OpMode==wopHS) //harmonic sinusoid estimation mode
    {  //*
      if (!WaveView1->StartObject) return;
      atom* par=(atom*)WaveView1->StartObject->Buffer;
      int t=par->t, wid=WaveView1->SpecRes, offst=WaveView1->SpecOffst;
      int hwid=wid/2, fr=(t-hwid)/offst;
      double f0=WaveView1->CurrentDigiFreq*wid, B;

      int Channel=WaveView1->StartObject->ShortTag[1];

      cdouble *x=new cdouble[hwid+1];
      cmplx<QSPEC_FORMAT>* spec=WaveView1->Spec[Channel][fr];
      for (int i=0; i<=hwid; i++) x[i]=spec[i];
      TPolygon* R=new TPolygon(1024); R->N=0;

      NMSettings settings; PrepareNMSettings(&settings);
      settings.pcount=anccount; settings.pin=ancps; settings.pinf=ancfs; settings.pin0asanchor=true;
      settings.pinfr=ancfrs;

      if (!HS->isconstf)
      {
        double fpp[1024], *vfpp=&fpp[256], *pfpp=&fpp[512]; atomtype *ptype=(atomtype*)&fpp[768];
        memset(fpp, 0, sizeof(double)*1024);
        NMResults results={fpp, vfpp, pfpp, ptype};

  			NoteMatchStiff3(R, f0, B, 1, &x, wid, 0, &settings, &results, 0, 0, ds0);
        atom part; part.t=par->t; part.s=par->s;
        if (f0>0)
        {
          int Fr=WaveView1->StartObject->Tag[2];
          for (int i=0; i<settings.maxp; i++)
          {
            if (fpp[i]>0)
            {
              if (i<HS->M)
              {
                part.f=fpp[i]/wid;
                part.a=vfpp[i];
                part.p=pfpp[i];
                part.pin=i+1;
                part.type=ptype[i];
                HS->Partials[i][Fr]=part;
              }
            }
            else
            {
              for (int j=i; j<HS->M; j++) HS->Partials[j][Fr].f=0;
              break;
            }
          }
        }
      }
      else //HS->isconstf==true
      {
        int Fr=HS->Fr, maxp=settings.maxp;
        Alloc2(Fr*3, maxp+2, fpp); double **vfpp=&fpp[Fr], **pfpp=&fpp[Fr*2];
        atomtype** Allocate2(atomtype, Fr, maxp+2, ptype);
        NMResults* results=new NMResults[Fr];
        for (int fr=0; fr<Fr; fr++) results[fr].fp=fpp[fr], results[fr].vfp=vfpp[fr], results[fr].pfp=pfpp[fr], results[fr].ptype=ptype[fr];
        cdouble** Allocate2(cdouble, Fr, hwid+1, xx);
        int frst=(HS->Partials[0][0].t-hwid)/offst;
        for (int fr=0; fr<Fr; fr++)
        {
          cmplx<QSPEC_FORMAT>* spec=WaveView1->Spec[Channel][frst+fr];
          for (int i=0; i<=hwid; i++) xx[fr][i]=spec[i];
        }

        if (Shift.Contains(ssCtrl)) NoteMatchStiff3(R, f0, B, Fr, xx, wid, offst, &settings, results, 0, 0, ds0, true, WaveView1->StartObject->Tag[2], 3);
        else NoteMatchStiff3(R, f0, B, Fr, xx, wid, offst, &settings, results, 0, 0, ds0, false, WaveView1->StartObject->Tag[2], 3);
        if (f0>0)
        {
          for (int fr=0; fr<Fr; fr++)
          {
            double *fppfr=fpp[fr], *vfppfr=vfpp[fr], *pfppfr=pfpp[fr];
            atomtype *ptypefr=ptype[fr];
            for (int i=0; i<HS->M; i++)
            {
              atom* part=&HS->Partials[i][fr];
              if (fppfr[i]>0)
              {
                if (i<HS->M)
                {
                  part->f=fppfr[i]/wid;
                  part->a=vfppfr[i];
                  part->p=pfppfr[i];
                  part->pin=i+1;
                  if (ptypefr[i]) part->type=ptypefr[i];
                  else if (i==settings.pin0-1) part->type=atPeak;
                }
              }
              else
              {
                for (int j=i; j<HS->M; j++) HS->Partials[j][fr].f=0;
                break;
              }
            }
          }
          atom* atm=&HS->Partials[settings.pin0-1][WaveView1->StartObject->Tag[2]];
          atm->type=atAnchor;
          if (Shift.Contains(ssCtrl)) atm->tags=atm->tags|ATOM_LOCALANCHOR;
          else atm->tags=atm->tags&~ATOM_LOCALANCHOR;
        }
        DeAlloc2(xx); delete[] results; DeAlloc2(fpp); DeAlloc2(ptype);
      }
      delete R;
      delete[] x;
    }
    else if (WaveView1->OpMode==wopCrop) //crop mode
    {
    }
    else if (WaveView1->OpMode==wopEdit) //HS edit mode
    {
      if (GetKeyState('F')<0)
      {
        Amplify1Click(FM1);
      }
      else
      {
        Amplify1Click(Pitchshifting1);
        double f1=WaveView1->FromPixelToDigiFreq(WaveView1->StartPane, WaveView1->StartSelY),
               f2=WaveView1->FromPixelToDigiFreq(WaveView1->StartPane, Y);
        double dp=12*Log2(f2/f1);
        EditorPanel->PitchEdit1->Text=dp;
        EditorPanel->AmpEdit1KeyPress(EditorPanel->PitchEdit1, ReturnKey);
      }
    }
  }
}

  TPolygon* RFromAtoms(int& startp, double* vfped, double starts, int M, int fr, atom** Partials, int wid, double delm, double maxB)
  {
    TPolygon* R=new TPolygon(M*2+4); R->N=0;
    memset(vfped, 0, sizeof(double)*M);
    startp=M;
    for (int m=0; m<M; m++)
    {
      double lf=Partials[m][fr].f*wid, la=Partials[m][fr].a;
      if (lf>0)
      {
        if (Partials[m][fr].type<=1)
        {
          if (R->N==0) InitializeR(R, m+1, lf, delm, maxB);
          else if (la>1) CutR(R, m+1, lf, delm, true);
        }
        vfped[m]=la; starts+=la*la;
      }
      else {startp=m; break;}
    }
    return R;
  }

void __fastcall TForm1::WaveView1ParMouseUp(TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
  if (Button==mbRight) return;

  if (WaveView1->OpMode==wopHS)
  {
    if (!WaveView1->StartObject) return;
    ClearObjectByShortTag0(WaveView1, stFreqDelimiter); //erase the delimiter

    int M=HS->M, Fr=HS->Fr; atom** Partials=HS->Partials;
    //*
    edfr=WaveView1->StartObject->Tag[2];
    int channel=WaveView1->StartObject->ShortTag[1];
    int wid=WaveView1->SpecRes, offst=WaveView1->SpecOffst, hwid=wid/2;
    NMSettings settings; PrepareNMSettings(&settings);
    int maxp=settings.maxp;

    if (HS->isconstf)
    {
      double brake=0.1;
      if (edfr==0 || edfr==Fr-1)
      {
        int frst, fren, edt=HS->Partials[0][edfr].t, startfr=(edt-hwid)/offst;
        atom* part;
        if (edfr==0)
        {
          frst=ceil((WaveView1->StartPos-hwid)*1.0/offst); if (frst<0) frst=0;
          part=new atom[M*(Fr+startfr-frst+1)];
        }
        else //edfr==Fr-1
        {
          fren=floor((WaveView1->EndPos-hwid)*1.0/offst);
          part=new atom[M*(Fr+fren-startfr+1)];
        }
        int k=0; for (int fr=0; fr<Fr; fr++) for (int m=0; m<M; m++) if (Partials[m][fr].f>0) part[k++]=Partials[m][fr];

        double ene0=0;
        for (int m=0; m<HS->M; m++)
        {
          if (HS->Partials[m][edfr].f>0)
          {
            double tmp=HS->Partials[m][edfr].a;
            ene0+=tmp*tmp;
          }
          else break;
        }

        int t=edt, dt=(edfr==0)?(-offst):offst;
        int channel=WaveView1->StartObject->ShortTag[1];
        cdouble* x=new cdouble[hwid+1];
        if (edfr==0)
        {
          for (int fr=startfr-1; fr>=frst; fr--)
          {
            t+=dt;
            cmplx<QSPEC_FORMAT>* spec=WaveView1->Spec[channel][fr];
            for (int i=0; i<=hwid; i++) x[i]=spec[i];
            double ene=0;
            for (int m=0; m<HS->M; m++)
            {

              double f=HS->Partials[m][edfr].f*wid;
              cdouble r=IPWindowC(f, x, wid, settings.M, settings.c, settings.iH2, ceil(f-settings.hB), floor(f+settings.hB));
              double la=abs(r); atomtype ltype=HS->Partials[m][edfr].type; if (!ltype) ltype=atPeak;
              atom lpart={t, wid, f/wid, la, arg(r), m+1, ltype};
              part[k++]=lpart;
              ene+=la*la;
            }
            if (ene<ene0*brake) break;
            if (ene>ene0) ene0=ene;
          }
        }
        else //edfr==Fr-1
        {
          for (int fr=startfr+1; fr<=fren; fr++)
          {
            t+=dt;
            cmplx<QSPEC_FORMAT>* spec=WaveView1->Spec[channel][fr];
            for (int i=0; i<=hwid; i++) x[i]=spec[i];
            double ene=0;
            for (int m=0; m<HS->M; m++)
            {

              double f=HS->Partials[m][edfr].f*wid;
              cdouble r=IPWindowC(f, x, wid, settings.M, settings.c, settings.iH2, ceil(f-settings.hB), floor(f+settings.hB));
              double la=abs(r); atomtype ltype=HS->Partials[m][edfr].type; if (!ltype) ltype=atPeak;
              atom lpart={t, wid, f/wid, la, arg(r), m+1, ltype};
              part[k++]=lpart;
              ene+=la*la;
            }
            if (ene<ene0*brake) break;
            if (ene>ene0) ene0=ene;
          }
        }
        delete[] x;

        DeAlloc2(HS->Partials); AtomsToPartials(k, part, HS->M, HS->Fr, HS->Partials, offst);
        ClearObjectByShortTag0(WaveView1, stAtom); AddHSObject(HS);
        delete[] part;

        if (edfr==0)
        {
          int EBLI=EventBox->ListBox1->ItemIndex;
          if (HS==EventBox->HS[EBLI])
          {
            EventBox->ListBox1->Items->Strings[EBLI]=(HS->Channel==0?"left: ":"right: ")
              +AnsiString().sprintf("%.2fs, ", HS->Partials[0][0].t*1.0/WaveView1->SamplesPerSec)
              +SemitoneToPitch(Log2(HS->Partials[0][0].f*WaveView1->SamplesPerSec/C4)*12);
          }
        }
      }
      return;
    }


    double delm=settings.delm, maxB=settings.maxB;

    double *vfped=new double[M], starts=0;

    int startp;

    TPolygon* R=RFromAtoms(startp, vfped, starts, M, edfr, Partials, wid, delm, maxB);
    int fr1=edfr-1; while (fr1>=0){int m; for (m=0; m<M; m++) if (Partials[m][fr1].f>0 && Partials[m][fr1].type==atAnchor) break; if (m<M) break; fr1--;}
    int fr2=edfr+1; while (fr2<Fr){int m; for (m=0; m<M; m++) if (Partials[m][fr2].f>0 && Partials[m][fr2].type==atAnchor) break; if (m<M) break; fr2++;}

    int fred=(Partials[0][edfr].t-wid/2)/offst, frst=(WaveView1->StartPos-wid/2)/offst, fren=(WaveView1->EndPos-wid/2)/offst;

    if (fr1>=0)
    {
      int startpst; double startsst, *vfpst=new double[M];
      TPolygon* Rst=RFromAtoms(startpst, vfpst, startsst, M, fr1, Partials, wid, delm, maxB);
      FindNoteFB(fr1, Rst, vfpst, edfr, R, vfped, M, Partials, wid, offst, WaveView1->Spectrogram[channel], settings);
      delete Rst; delete[] vfpst;
      if (fr2<Fr)
      {
        int startpen; double startsen, *vfpen=new double[M];
        TPolygon* Ren=RFromAtoms(startpen, vfpen, startsen, M, fr2, Partials, wid, delm, maxB);
        FindNoteFB(edfr, R, vfped, fr2, Ren, vfpen, M, Partials, wid, offst, WaveView1->Spectrogram[channel], settings);
        delete Ren; delete[] vfpen;
      }
      else
      {
        atom* part=new atom[M*Fr+maxp*(fren-frst)];
        int k=0; for (int fr=0; fr<=edfr; fr++) for (int m=0; m<M; m++) if (Partials[m][fr].f>0) part[k++]=Partials[m][fr];
        k+=FindNoteF(&part[k], starts, R, startp, vfped, fred, fren, wid, offst, WaveView1->Spectrogram[channel], settings, 0.02);
        DeAlloc2(HS->Partials); AtomsToPartials(k, part, HS->M, HS->Fr, HS->Partials, offst);
        ClearObjectByShortTag0(WaveView1, stAtom); AddHSObject(HS);
        delete[] part;
      }
    }
    else //fr1<0
    {
      if (fr2<Fr)
      {
        int startpen; double startsen, *vfpen=new double[M];
          TPolygon* Ren=RFromAtoms(startpen, vfpen, startsen, M, fr2, Partials, wid, delm, maxB);
        FindNoteFB(edfr, R, vfped, fr2, Ren, vfpen, M, Partials, wid, offst, WaveView1->Spectrogram[channel], settings);
        delete Ren; delete[] vfpen;
      }
      atom* part=new atom[M*Fr+maxp*(fren-frst)];
      int k=0, keepst=edfr, keepen=(fr2>=Fr)?edfr:(Fr-1);
      for (int fr=keepst; fr<=keepen; fr++) for (int m=0; m<M; m++) if (Partials[m][fr].f>0) part[k++]=Partials[m][fr];
      k+=FindNoteF(&part[k], starts, R, startp, vfped, fred, (frst>=0)?(frst-1):-1, wid, offst, WaveView1->Spectrogram[channel], settings, 0.02);
      if (fr2>=Fr) k+=FindNoteF(&part[k], starts, R, startp, vfped, fred, fren, wid, offst, WaveView1->Spectrogram[channel], settings, 0.02);
      DeAlloc2(HS->Partials); AtomsToPartials(k, part, HS->M, HS->Fr, HS->Partials, offst);
      ClearObjectByShortTag0(WaveView1, stAtom); AddHSObject(HS);
      delete[] part;
    }
    delete R;
    delete[] vfped;
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1ParMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint& MousePos, bool& Handled)
{
  if (WaveView1->OpMode==wopEdit)
  {
    if (GetKeyState('A')<0)
    {
      Amplify1Click(AM1);
      EditorPanel->AMAEdit1MouseWheel(WheelDelta);
    }
    else if (GetKeyState('D')<0)
    {
      Amplify1Click(DeFM1);
      EditorPanel->DeFMEdit1MouseWheel(WheelDelta);
    }
    else if (GetKeyState('F')<0)
    {
      Amplify1Click(FM1);
      EditorPanel->FMAEdit1MouseWheel(WheelDelta);
    }
    else
    {
      Amplify1Click(Amplify1);
      EditorPanel->AmpEdit1MouseWheel(WheelDelta);
    }

  }
}


//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1PlaybackDone(TObject*)
{
  SpeedButtonPlay->Glyph=BitmapPlay;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1PlaybackStart(TObject*)
{
  SpeedButtonPlay->Glyph=BitmapStop;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1PopupMenuPopup(TObject *Sender)
{
  ZoomToSelection1->Visible=(WaveView1->Selections->Count>0 && WaveView1->Selections->Focus>=0);
  UndoZoom1->Visible=(WaveView1->UndoExtractSelection.EndPos>=0);
  TimeZoom1->Visible=(WaveView1->StartPos!=0 || WaveView1->EndPos!=WaveView1->Length);
  FrequencyZoom1->Visible=(WaveView1->StartDigiFreq!=0 || WaveView1->EndDigiFreq!=0.5);
  AmplitudeZoom1->Visible=(WaveView1->YZoomRate!=1);
  SpectrogramBrightness1->Visible=(WaveView1->SpecAmp!=1);
  Restore1->Visible=TimeZoom1->Visible || FrequencyZoom1->Visible || AmplitudeZoom1->Visible || SpectrogramBrightness1->Visible;

  Play1->Visible=(WaveView1->Length>0);
  Play1->Caption=WaveView1->Playing?"Stop":"Play";

  Cut1->Visible=(WaveView1->OpMode<=2 && WaveView1->Selections->Count>0 &&
                 WaveView1->FPanes.HasFreqAxis[WaveView1->CurrentPane]) ||
                (WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom);
  Extract1->Visible=Cut1->Visible;
  Editorpanel1->Visible=(WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WindowSizeComboChange(TObject *Sender)
{
  WaveView1->SpecRes=WindowSizeCombo->Text.ToInt();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WindowTypeComboChange(TObject *Sender)
{
  WindowType types[]={wtRectangle, wtHamming, wtHann, wtBlackman, wtGaussian};
  WaveView1->SpecWindowType=types[WindowTypeCombo->ItemIndex];
}

//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButtonSClick(TObject *Sender)
{
  SpectrogramView=!SpectrogramView;
  SpeedButtonS->Glyph=SpectrogramView?BitmapWaveform:BitmapSpectrogram;
  Spectrogram2->Caption=SpectrogramView?"Waveform":"Spectrogram";
  SetWaveViewContents();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::AmplitudeZoom1Click(TObject *Sender)
{
  WaveView1->YZoomRate=1;
}
//---------------------------------------------------------------------------





void __fastcall TForm1::Extract1Click(TObject *Sender)
{
	if (WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom
		|| Sender==EventBox->Extract1 && HS)
	{
		int dst, den;
		double* xrec=SynthesisHSp(HS, dst, den);
		memset(&WaveView1->Data8[HS->Channel][WaveView1->BytesPerSample*WaveView1->StartPos], 0, WaveView1->BytesPerSample*(WaveView1->EndPos-WaveView1->StartPos));
		WaveView1->ExtDataChange(NULL, HS->Channel, WaveView1->StartPos, WaveView1->EndPos);
		PostWaveViewData(xrec, HS->Channel, dst, den, FadeInCheck->Checked, FadeInCombo->Text.ToInt());
		free8(xrec);
	}
  else if (WaveView1->OpMode<=2 && WaveView1->Selections->Count>0 && WaveView1->Selections->Focus>=0)
  {
    WaveView1->TFFilter(WaveView1->CurrentChannel, true);
    WaveView1->ExtDataChange(Sender, WaveView1->CurrentChannel, WaveView1->StartPos-WaveView1->SpecRes, WaveView1->EndPos+WaveView1->SpecRes);
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PostWaveViewData(double* data, int Channel, int StartPos, int EndPos, bool fadein, int W)
{
	int bps=WaveView1->BytesPerSample, L=EndPos-StartPos;
  if (fadein)
  {
    int hW=W/2;
		double* leadin=new double[hW*2]; double* leadout=&leadin[hW];
    IntToDouble(leadin, &WaveView1->Data8[Channel][StartPos*bps], bps, hW);
    IntToDouble(leadout, &WaveView1->Data8[Channel][(EndPos-hW)*bps], bps, hW);
    for (int i=0; i<hW; i++)
    {
			double w=0.5+0.5*cos(M_PI*i/hW);
      leadin[i]=leadin[i]*w+data[i]*(1-w);
      leadout[i]=leadout[i]*(1-w)+data[L-hW+i]*w;
    }
    if (L>hW*2)
    {
      DoubleToInt(&WaveView1->Data8[Channel][StartPos*bps], bps, leadin, hW);
      DoubleToInt(&WaveView1->Data8[Channel][(StartPos+hW)*bps], bps, &data[hW], L-hW*2);
      DoubleToInt(&WaveView1->Data8[Channel][(EndPos-hW)*bps], bps, leadout, hW);
    }
    else
    {
      DoubleToInt(&WaveView1->Data8[Channel][StartPos*bps], bps, leadin, L/2);
      DoubleToInt(&WaveView1->Data8[Channel][(StartPos+L/2)*bps], bps, &leadout[hW-L/2], L-L/2);
    }
    delete[] leadin;
  }
  else
    DoubleToInt(&WaveView1->Data8[Channel][StartPos*bps], bps, data, L);
  WaveView1->ExtDataChange(this, Channel, StartPos, EndPos);
}

void __fastcall TForm1::PostWaveViewData(__int16* data, int Channel, int StartPos, int EndPos, bool fadein, int W)
{
	int bps=WaveView1->BytesPerSample, L=EndPos-StartPos;
  if (fadein)
  {
    int hW=W/2;
		double* leadin=new double[hW*2]; double* leadout=&leadin[hW];
    IntToDouble(leadin, &WaveView1->Data8[Channel][StartPos*bps], bps, hW);
    IntToDouble(leadout, &WaveView1->Data8[Channel][(EndPos-hW)*bps], bps, hW);
    for (int i=0; i<hW; i++)
    {
			double w=0.5+0.5*cos(M_PI*i/hW);
      leadin[i]=leadin[i]*w+data[i]*(1-w);
      leadout[i]=leadout[i]*(1-w)+data[L-hW+i]*w;
    }
    if (L>hW*2)
    {
      DoubleToInt(&WaveView1->Data8[Channel][StartPos*bps], bps, leadin, hW);
      memcpy(&WaveView1->Data8[Channel][(StartPos+hW)*bps], &data[hW], 2*(L-hW*2));
      DoubleToInt(&WaveView1->Data8[Channel][(EndPos-hW)*bps], bps, leadout, hW);
    }
    else
    {
      DoubleToInt(&WaveView1->Data8[Channel][StartPos*bps], bps, leadin, L/2);
      DoubleToInt(&WaveView1->Data8[Channel][(StartPos+L/2)*bps], bps, &leadout[hW-L/2], L-L/2);
    }
    delete[] leadin;
  }
  else
    memcpy(&WaveView1->Data8[Channel][StartPos*bps],data, 2*L);
  WaveView1->ExtDataChange(this, Channel, StartPos, EndPos);
}

void __fastcall TForm1::PostWaveViewData(__int16* data, int Channel, int StartPos, int EndPos)
{
  memcpy(&WaveView1->Data16[Channel][StartPos], data, 2*(EndPos-StartPos));
  WaveView1->ExtDataChange(this, Channel, StartPos, EndPos);
}


void __fastcall TForm1::FadeInCheckClick(TObject *Sender)
{
  FadeInLabel->Enabled=FadeInCheck->Checked;
  FadeInCombo->Enabled=FadeInCheck->Checked;
}
//---------------------------------------------------------------------------

  void FadeInOut(double* x, int N, int hWid)
  {
    x[0]=0; double iPI=M_PI/hWid;
    for (int n=1; n<hWid; n++)
    {
      double tmp=0.5-0.5*cos(n*iPI);
      x[n]*=tmp;
      x[N-n]*=tmp;
    }
  }

void __fastcall TForm1::Cut1Click(TObject *Sender)
{
	if (WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom
    || Sender==EventBox->Cut1 && HS)
  {
    int s=HS->Partials[0][0].s, hs=s/2, dst=HS->Partials[0][0].t-hs,
        den=HS->Partials[0][HS->Fr-1].t+hs, bps=WaveView1->BytesPerSample;

    double* data=new double[den-dst];
    IntToDouble(data, &WaveView1->Data8[HS->Channel][dst*bps], bps, den-dst);

    if (GetKeyState(VK_SHIFT)<0)
    {
      int st_wid=s/2, st_offst=st_wid/2, st_len=s;
      int st_count=(st_len-st_wid)/st_offst+1;
      int st_start=st_len-st_offst*st_count-hs, Fr=HS->Fr;
      HS->st_start=st_start, HS->st_offst=st_offst, HS->st_count=st_count;
      DeAlloc2(HS->startamp); Allocate2(double, HS->M, st_count, HS->startamp); memset(HS->startamp[0], 0, sizeof(double)*st_count*HS->M);
      double *f1=new double[Fr*15], *fa=&f1[Fr], *fb=&fa[Fr], *fc=&fb[Fr], *fd=&fc[Fr], *xs=&fd[Fr], *p1=&xs[Fr], *a1=&p1[Fr],
        *aa=&a1[Fr], *ab=&aa[Fr], *ac=&ab[Fr], *ad=&ac[Fr];
      int *ixs=(int*)&f1[Fr*14];
      double* xrec=new double[st_len];
      for (int m=0; m<HS->M; m++)
      {
        atom* part=HS->Partials[m];
        bool fzero=false;
        for (int fr=0; fr<Fr; fr++)
        {
          if (part[fr].f<=0){fzero=true; break;}
          ixs[fr]=part[fr].t;
          xs[fr]=part[fr].t;
          f1[fr]=part[fr].f;
          p1[fr]=part[fr].p;
          a1[fr]=part[fr].a*2;
        }
        if (fzero) break;

    		CubicSpline(Fr-1, fa, fb, fc, fd, xs, f1, 1, 1);
    		CubicSpline(Fr-1, aa, ab, ac, ad, xs, a1, 1, 1);
        for (int l=0; l<Fr && ixs[l]-dst<st_len; l++)
        {
          int llen=(ixs[l+1]-dst<st_len)?(ixs[l+1]-ixs[l]):(st_len+dst-ixs[l]);
          Sinusoid(llen, &xrec[ixs[l]-dst], aa[l], ab[l], ac[l], ad[l], fa[l], fb[l], fc[l], fd[l], p1[l], p1[l+1], false);
        }
        double tmpph=p1[0]; Sinusoid(&xrec[ixs[0]-dst], -hs, 0, aa[0], ab[0], ac[0], ad[0], fa[0], fb[0], fc[0], fd[0], tmpph, false);

        for (int l=0; l<st_count; l++)
        {
          double *ldata=&data[st_offst*l], *lxrec=&xrec[st_offst*l];
          double tmp=0, tmp2=0; for (int n=0; n<st_wid; n++) tmp+=ldata[n]*lxrec[n], tmp2+=lxrec[n]*lxrec[n];
          HS->startamp[m][l]=tmp/tmp2;
        }
      }
      delete[] xrec;
      delete[] f1;
    }

		double* xrec=SynthesisHSp(HS, dst, den);
    FadeInOut(xrec, den-dst, s/2);

    for (int i=0; i<den-dst; i++) data[i]-=xrec[i];
    PostWaveViewData(data, HS->Channel, dst, den, false&&FadeInCheck->Checked, FadeInCombo->Text.ToInt());
		free8(xrec);
		delete[] data;
  }
  else if (WaveView1->OpMode<=2 && WaveView1->Selections->Count>0 && WaveView1->Selections->Focus>=0)
  {
      WaveView1->TFFilter(WaveView1->CurrentChannel, false);
      WaveView1->ExtDataChange(Sender, WaveView1->CurrentChannel, WaveView1->StartPos-WaveView1->SpecRes, WaveView1->EndPos+WaveView1->SpecRes);
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Amplify1Click(TObject *Sender)
{
  if (!EditorPanel->Visible)
  {
    GetTargetAudio(EditorPanel->targettype, EditorPanel->Channel, EditorPanel->From, EditorPanel->To, EditorPanel->target, EditorPanel->Before);
    if (EditorPanel->targettype==1) {delete EditorPanel->HS; EditorPanel->HS=new THS(HS);}

    EditorPanel->AmpEdit1->Text="1";
    EditorPanel->AmpDBEdit1->Text="0";
    EditorPanel->PitchEdit1->Text="0";
    EditorPanel->AMAEdit1->Text="0";
    EditorPanel->AMFEdit1->Text="4";
    EditorPanel->FMAEdit1->Text="0";
    EditorPanel->FMFEdit1->Text="4";
    EditorPanel->DeFMEdit1->Text="1";
    EditorPanel->DeFMEdit2->Text="1";
  }

  if (Sender==Amplify1) EditorPanel->PageControl1->ActivePage=EditorPanel->AmplifySheet;
  else if (Sender==Pitchshifting1) EditorPanel->PageControl1->ActivePage=EditorPanel->PitchSheet;
  else if (Sender==AM1) EditorPanel->PageControl1->ActivePage=EditorPanel->AMSheet;
  else if (Sender==FM1) EditorPanel->PageControl1->ActivePage=EditorPanel->FMSheet;
  else if (Sender==DeFM1) EditorPanel->PageControl1->ActivePage=EditorPanel->DeFMSheet;

  if (!EditorPanel->Visible) EditorPanel->Show();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::GetTargetAudio(int& targettype, int& channel, int& from, int& to, double*& target, __int16*& before)
{
	free8(target);
  delete[] before;
  if (WaveView1->ObjectAtPointer && WaveView1->ObjectAtPointer->ShortTag[0]==stAtom)
  {
    targettype=1;
    channel=HS->Channel;
		target=SynthesisHSp(HS, from, to);
    before=new __int16[to-from];
    memcpy(before, &WaveView1->Data16[channel][from], sizeof(__int16)*(to-from));
  }
  else
  {
    targettype=0;
    channel=WaveView1->FPanes.Channel[WaveView1->StartPane];
    to=WaveView1->EndPos;
    from=WaveView1->StartPos;
		target=(double*)malloc8(sizeof(double)*(to-from));
    before=new __int16[to-from];
    memcpy(before, &WaveView1->Data16[0][from], sizeof(__int16)*(to-from));
    IntToDouble(target, before, 2, to-from);
  }
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Events1Click(TObject *Sender)
{
  if (!EventBox->Visible)
  {
		EventBox->Left=Left+Width;
    EventBox->Top=Top;
    EventBox->Height=Height;
    EventBox->Load(NULL);
		EventBox->Show();
  }
	else
  {
    if (EventBox->Left>=Screen->Width) EventBox->Left=Left+Width;
		EventBox->BringToFront();
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButtonSaveClick(TObject *Sender)
{
  SaveDialog1->FileName="waveview.waveview1.wav";
  SaveDialog1->FilterIndex=1;
  int bps=WaveView1->BytesPerSample, rfb=WaveView1->StartPos*bps, rlen=WaveView1->EndPos-WaveView1->StartPos;
  if (SaveDialog1->Execute())
  {
    TWaveAudio* WA=new TWaveAudio(NULL);
    WA->GetWaveProperties(WaveAudio1);
    if (WA->Channels==1)
      WA->Write(&WaveView1->Data8[0][rfb], rlen*bps);
    else if (WA->Channels==2)
      WA->WriteSamplesInterleave(&WaveView1->Data8[0][rfb], &WaveView1->Data8[1][rfb], rlen);
    WA->SaveToFile(SaveDialog1->FileName);
    delete WA;
  }
}

void __fastcall TForm1::TimeZoom1Click(TObject *Sender)
{
  WaveView1->SetStartAndEndPos(0, WaveView1->Length);
}
//---------------------------------------------------------------------------


void __fastcall TForm1::FrequencyZoom1Click(TObject *Sender)
{
  WaveView1->SetStartAndEndDigiFreq(0, 0.5);  
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Vibratowizard1Click(TObject *Sender)
{
	TVibratoDemoForm* VF=VibratoDemoForm;
	VF->WaveView1->StartDigiFreq=WaveView1->StartDigiFreq;
	VF->WaveView2->StartDigiFreq=WaveView1->StartDigiFreq;
	VF->WaveView1->EndDigiFreq=WaveView1->EndDigiFreq;
	VF->WaveView2->EndDigiFreq=WaveView1->EndDigiFreq;
	VF->WaveView2->SpecAmp=WaveView1->SpecAmp;

  int SpecRes, SpecOffst;
	if (Sender==EventBox->Vibratowizard1)
  {
    SpecRes=HS->Partials[0][0].s;
    SpecOffst=HS->Partials[0][1].t-HS->Partials[0][0].t;
  }
  else
  {
    SpecRes=WaveView1->SpecRes;
    SpecOffst=WaveView1->SpecOffst;
  }
	VF->WaveView1->SpecRes=SpecRes;
	VF->WaveView1->SpecOffst=SpecOffst;

	VF->WaveAudio1->Clear(NULL);
	VF->WaveAudio1->SamplesPerSec=WaveAudio1->SamplesPerSec;
	VF->WaveAudio1->BitsPerSample=WaveAudio1->BitsPerSample;
  int ch=WaveView1->FPanes.Channel[WaveView1->StartPane];
  if (Sender==EventBox->Vibratowizard1) ch=HS->Channel;
  int st=(WaveView1->StartPos-SpecRes/2)/SpecOffst*SpecOffst;
  int en=(WaveView1->EndPos-SpecRes/2)/SpecOffst*SpecOffst+SpecRes;

  if (Sender==EventBox->Vibratowizard1)
  {
    st=HS->Partials[0][0].t-SpecOffst;
    en=HS->Partials[0][HS->Fr-1].t+SpecOffst;
  }

  if (st<0) st=0;
  if (en>WaveView1->Length) en=WaveView1->Length;

	VF->WaveAudio1->WriteSamples(&WaveView1->Data16[ch][st], en-st);
	VF->StartPos=st;

  {
		delete VF->HS;
		VF->HS=new THS(HS, st, en);
  }

	VF->StartPos=st;
  VF->Copydata();
	VF->Synthesize();
	VF->Reset();
  VF->Show();
}

//---------------------------------------------------------------------------

void __fastcall TForm1::Recent11Click(TObject *Sender)
{
  TIniFile* Ini=new TIniFile(ChangeFileExt(Application->ExeName, ".ini"));
  AnsiString S="RecentFile"; S=S+(((TMenuItem*)Sender)->Tag+1);
  AnsiString FileName=Ini->ReadString(S, "FileName", "");
  int start=Ini->ReadInteger(S, "Start", 0);
  int end=Ini->ReadInteger(S, "End", -1);
  double fstart=Ini->ReadFloat(S, "StartF", 0);
  double fend=Ini->ReadFloat(S, "EndF", 0.5);
  delete Ini;

  if (FileExists(FileName) && WaveAudio1->FileName!=FileName)
  {
    RecentFile(WaveAudio1->FileName);
    WaveAudio1->LoadFromFile(FileName);
    WaveView1->SetArea(start, end, fstart, fend);
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SpeedButtonRecordClick(TObject *Sender)
{
  if (WaveAudio2 && WaveAudio2->Recording)
  {
    WaveAudio2->PauseRecording(0);

    double second=1.0*WaveAudio2->WaveStream->Position/(WaveAudio2->SamplesPerSec*WaveAudio2->BitsPerSample/8*WaveAudio2->Channels);
    int secr=(second-floor(second))*100; TDateTime dt=second/86400;
    RecordingForm->Label1->Caption=dt.FormatString("'Recording finished:' h:mm:ss.")+AnsiString().sprintf("%02d", secr);

    WaveAudio2->CloseFile(true);
    SpeedButtonRecord->Glyph=BitmapRecord;
    RecordingForm->SpeedButtonRecord->Glyph=BitmapRecord;
    delete WaveAudio2;
    WaveAudio2=0;

    RecordingForm->SpeedButton1->Enabled=true; RecordingForm->SpeedButton2->Enabled=true;
    RecordingForm->Show();
  }
  else
  {
    WaveAudio2=new TWaveAudio(NULL);
    WaveAudio2->GetWaveProperties(WaveAudio1);
    WaveAudio2->CreateFile(ExtractFilePath(Application->ExeName)+"noname.wav");
    WaveAudio2->OnInAddBuffer=WaveAudio2InAddBuffer;
    WaveAudio2->StartRecording(0);
    SpeedButtonRecord->Glyph=BitmapRecording;
    RecordingForm->SpeedButtonRecord->Glyph=BitmapRecording;
    RecordingForm->Label1->Caption="Recording in progress: 0:00:00.00";
    RecordingForm->SpeedButton1->Enabled=false; RecordingForm->SpeedButton2->Enabled=false;
    RecordingForm->Show();
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::WaveAudio2InAddBuffer(TObject*)
{
  double second=1.0*WaveAudio2->WaveStream->Position/(WaveAudio2->SamplesPerSec*WaveAudio2->BitsPerSample/8*WaveAudio2->Channels);
  int secr=(second-floor(second))*100; TDateTime dt=second/86400;
  RecordingForm->Label1->Caption=dt.FormatString("'Recording in progress:' h:mm:ss.")+AnsiString().sprintf("%02d", secr);
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Close1Click(TObject *Sender)
{
  RecentFile(WaveAudio1->FileName);
  WaveAudio1->Clear(this);
  Navigator1->Resize();
}
//---------------------------------------------------------------------------


void __fastcall TForm1::AutoScrollCheckClick(TObject *Sender)
{
  WaveView1->AutoScroll=AutoScrollCheck->Checked;
}

//---------------------------------------------------------------------------
void __fastcall TForm1::WaveView1PlaybackStartAndEndPos(TObject* Sender, int& st, int& en, bool fromsel)
{
  TWaveView* WV=(TWaveView*)Sender;
  if (fromsel)
  {
    st=WV->Selections->StartPos; if (st<0) st=0;
    en=WV->Selections->EndPos; if (en>WV->Length) en=WV->Length;
  }
  else
  {
    st=WV->StartPos;
    if (PlayUntilRadio->ItemIndex==0) en=WV->Length;
    else if (PlayUntilRadio->ItemIndex==1) en=WV->EndPos;
	}
}

//---------------------------------------------------------------------------

void __fastcall TForm1::LoopCheckClick(TObject *Sender)
{
  if (LoopCheck->Checked)
  {
    WaveView1->LoopPlay=true;
  }
  else
  {
    WaveView1->LoopPlay=false;
    PlayUntilRadioClick(Sender);
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::PlayUntilRadioClick(TObject *Sender)
{
  if (PlayUntilRadio->ItemIndex==0)
    WaveView1->SectionEndPos=WaveView1->Length;
  else if (WaveView1->LoopMode==2)
    WaveView1->SectionEndPos=WaveView1->Selections->EndPos;
  else
    WaveView1->SectionEndPos=WaveView1->EndPos;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::MouseWheelZoomClick(TObject *Sender)
{
  WaveView1->DisableMouseWheelZoom=!MouseWheelZoom->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::AmpGridDblClick(TObject *Sender)
{
  if (GridSourcePane<0 || GridSourcePane>=WaveView1->FPanes.Count
    || !WaveView1->FPanes.HasFreqAxis[GridSourcePane]) return;

  TPoint P;
  GetCursorPos(&P);
  TStringGrid* Grid=(TStringGrid*)Sender;
  P=Grid->ScreenToClient(P);
  int col, row;
  Grid->MouseToCell(P.x, P.y, col, row);

  if (col<0 || row<0) return;
	if (Grid->Cells[col][row].IsEmpty()) return;
  int CurrentFr=Grid->Cells[col][0].ToInt(), CurrentBin=Grid->Cells[0][row].ToInt();
  int t=WaveView1->SpecRes/2+WaveView1->SpecOffst*CurrentFr;
  double f=(CurrentBin+0.5)/WaveView1->SpecRes;
  WaveView1->SetCursorTF(GridSourcePane, t, f);
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Sourcefilter1Click(TObject *Sender)
{
	TSFDemoForm* VF=SFDemoForm;
	VF->WaveView1->StartDigiFreq=WaveView1->StartDigiFreq;
	VF->WaveView2->StartDigiFreq=WaveView1->StartDigiFreq;
	VF->WaveView1->EndDigiFreq=WaveView1->EndDigiFreq;
	VF->WaveView2->EndDigiFreq=WaveView1->EndDigiFreq;
	VF->WaveView2->SpecAmp=WaveView1->SpecAmp;

  int SpecRes, SpecOffst;
	if (Sender==EventBox->Vibratowizard1)
  {
    SpecRes=HS->Partials[0][0].s;
    SpecOffst=HS->Partials[0][1].t-HS->Partials[0][0].t;
  }
  else
  {
    SpecRes=WaveView1->SpecRes;
    SpecOffst=WaveView1->SpecOffst;
  }
	VF->WaveView1->SpecRes=SpecRes;
	VF->WaveView1->SpecOffst=SpecOffst;

	VF->WaveAudio1->Clear(NULL);
	VF->WaveAudio1->SamplesPerSec=WaveAudio1->SamplesPerSec;
	VF->WaveAudio1->BitsPerSample=WaveAudio1->BitsPerSample;
  int ch=WaveView1->FPanes.Channel[WaveView1->StartPane];
  if (Sender==EventBox->Vibratowizard1) ch=HS->Channel;
  int st=(WaveView1->StartPos-SpecRes/2)/SpecOffst*SpecOffst;
	int en=(WaveView1->EndPos-SpecRes/2)/SpecOffst*SpecOffst+SpecRes;

  if (Sender==EventBox->Vibratowizard1)   
  {
    st=HS->Partials[0][0].t-SpecOffst;
    en=HS->Partials[0][HS->Fr-1].t+SpecOffst;
  }

  if (st<0) st=0;
  if (en>WaveView1->Length) en=WaveView1->Length;

	VF->WaveAudio1->WriteSamples(&WaveView1->Data8[ch][st*WaveAudio1->BitsPerSample/8], en-st);
	VF->StartPos=st;

  {
		delete VF->HS;
		VF->HS=new THS(HS, st, en);
  }

	VF->StartPos=st;
  VF->Copydata();
	VF->Synthesize();
	VF->Reset();
	VF->Show();
}
//---------------------------------------------------------------------------




//---------------------------------------------------------------------------

void __fastcall TForm1::PlayFilterComboSelect(TObject *Sender)
{
  WaveView1->PlaybackFilter=(TWaveViewPlaybackFilter)PlayFilterCombo->ItemIndex;
  PlaybackFilterRadio->ItemIndex=PlayFilterCombo->ItemIndex;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::PlaybackFilterRadioClick(TObject *Sender)
{
  PlayFilterCombo->ItemIndex=PlaybackFilterRadio->ItemIndex;  
}
//---------------------------------------------------------------------------




void __fastcall TForm1::Retrieve1Click(TObject *Sender)
{
  WaveView1->Retrieve(1);  
}
//---------------------------------------------------------------------------