changeset 0:a6a46af64546

first upload
author wenx <xue.wen@eecs.qmul.ac.uk>
date Wed, 10 Aug 2011 14:55:38 +0100
parents
children f3fd4e19cec0
files AudioPac.cpp AudioPac.h BackUpTool.cpp BackUpTool.dfm BackUpTool.h Documents/Example.doc Documents/QuickStart.1107.doc EditorPanelUnit.cpp EditorPanelUnit.dfm EditorPanelUnit.h EventBoxUnit.cpp EventBoxUnit.dfm EventBoxUnit.h Icon1.bmp Navigator.cpp Navigator.h RecordingUnit.cpp RecordingUnit.dfm RecordingUnit.h SFDemoUnit.cpp SFDemoUnit.dfm SFDemoUnit.h SUThread.cpp SUThread.h Unit1.cpp Unit1.dfm Unit1.h UnitRangeEdit.cpp UnitRangeEdit.dfm UnitRangeEdit.h VibratoDemoUnit.cpp VibratoDemoUnit.dfm VibratoDemoUnit.h WaveView.cpp WaveView.h bitmaps.rc cursortext.bmp freqselect.bmp hsselect.bmp hv.bdsproj hv.cpp hv.dfm hv.dsk hv.h hv.res multiselect.bmp paneinfo.bmp spectrogram.bmp timeselect.bmp timeselect.old.bmp vcrplay.bmp vcrrecrd.bmp vcrrecrd2.bmp vcrstop.bmp waveform.bmp
diffstat 55 files changed, 19941 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AudioPac.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,1534 @@
+/*
+    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 "AudioPac.h"
+#include <math.h>
+
+#pragma package(smart_init)
+//---------------------------------------------------------------------------
+void DoubleToInt(void* out, int BytesPerSample, double* in, int Count)
+{
+  if (BytesPerSample==1){unsigned char* out8=(unsigned char*)out; for (int k=0; k<Count; k++) *(out8++)=*(in++)+128.5;}
+  else if (BytesPerSample==2) {__int16* out16=(__int16*)out; for (int k=0; k<Count; k++) *(out16++)=floor(*(in++)+0.5);}
+  else {__pint24 out24=(__pint24)out; for (int k=0; k<Count; k++) {*(out24++)=floor(*(in++)+0.5);}}
+}
+
+void IntToDouble(double* out, void* in, int BytesPerSample, int Count)
+{
+  if (BytesPerSample==1){unsigned char* in8=(unsigned char*)in; for (int k=0; k<Count; k++) *(out++)=*(in8++)-128.0;}
+  else if (BytesPerSample==2) {__int16* in16=(__int16*)in; for (int k=0; k<Count; k++) *(out++)=*(in16++);}
+  else {__pint24 in24=(__pint24)in; for (int k=0; k<Count; k++) {*(out++)=*(in24++);}}
+}
+
+void DoubleToIntInterleave(void* out, int BytesPerSample, double* in1, double* in2, int Count)
+{
+  if (BytesPerSample==1)
+  {
+    unsigned char* out8=(unsigned char*)out;
+    for (int k=0; k<Count; k++) {*(out8++)=*(in1++)+128; *(out8++)=*(in2++)+128;}
+  }
+  else if (BytesPerSample==2)
+  {
+    __int16* out16=(__int16*)out;
+    for (int k=0; k<Count; k++) {*(out16++)=*(in1++); *(out16++)=*(in2++);}
+  }
+  else if (BytesPerSample==3)
+  {
+    __pint24 out24=(__pint24)out;
+    for (int k=0; k<Count; k++) {*(out24++)=*(in1++); *(out24++)=*(in2++); }
+  }
+}
+
+void IntToDoubleInterleave(double* out1, double* out2, void* in, int BytesPerSample, int Count)
+{
+  if (BytesPerSample==1)
+  {
+    unsigned char* in8=(unsigned char*)in;
+    for (int k=0; k<Count; k++) {*(out1++)=*(in8++)-128.0; *(out2++)=*(in8++)-128.0;}
+  }
+  else if (BytesPerSample==2)
+  {
+    __int16* in16=(__int16*)in;
+    for (int k=0; k<Count; k++) {*(out1++)=*(in16++); *(out2++)=*(in16++);}
+  }
+  else if (BytesPerSample==3)
+  {
+    __pint24 in24=(__pint24)in;
+    for (int k=0; k<Count; k++) {*(out1++)=*(in24++); *(out2++)=*(in24++);}
+  }
+}
+
+int IntToIntInterleave(void* dest, int bytesperunit, void* block1, void* block2, int Count)
+{
+  if (bytesperunit==1)
+  {
+    char* Dest=(char*)dest;
+    char* Block1=(char*)block1;
+    char* Block2=(char*)block2;
+    for (int i=0; i<Count; i++)
+    {
+      *(Dest++)=*(Block1++);
+      *(Dest++)=*(Block2++);
+    }
+    return 2*Count;
+  }
+  else if (bytesperunit==2)
+  {
+    __int16* Dest=(__int16*)dest;
+    __int16* Block1=(__int16*)block1;
+    __int16* Block2=(__int16*)block2;
+    for (int i=0; i<Count; i++)
+    {
+      *(Dest++)=*(Block1++);
+      *(Dest++)=*(Block2++);
+    }
+    return 4*Count;
+  }
+  else if (bytesperunit==3)
+  {
+    __pint24 Dest=(__pint24)dest;
+    __pint24 Block1=(__pint24)block1;
+    __pint24 Block2=(__pint24)block2;
+    for (int i=0; i<Count; i++)
+    {
+      *(Dest++)=*(Block1++);
+      *(Dest++)=*(Block2++);
+    }
+    return 6*Count;
+  }
+  else
+    return 0;
+}
+
+int IntToIntInterleave(void* dest1, void* dest2, int bytesperunit, void* block, int Count)
+{
+  if (bytesperunit==1)
+  {
+    char* Dest1=(char*)dest1;
+    char* Dest2=(char*)dest2;
+    char* Block=(char*)block;
+    for (int i=0; i<Count; i++)
+    {
+      *(Dest1++)=*(Block++);
+      *(Dest2++)=*(Block++);
+    }
+    return 2*Count;
+  }
+  else if (bytesperunit==2)
+  {
+    __int16* Dest1=(__int16*)dest1;
+    __int16* Dest2=(__int16*)dest2;
+    __int16* Block=(__int16*)block;
+    for (int i=0; i<Count; i++)
+    {
+      *(Dest1++)=*(Block++);
+      *(Dest2++)=*(Block++);
+    }
+    return 4*Count;
+  }
+  else if (bytesperunit==2)
+  {
+    __pint24 Dest1=(__pint24)dest1;
+    __pint24 Dest2=(__pint24)dest2;
+    __pint24 Block=(__pint24)block;
+    for (int i=0; i<Count; i++)
+    {
+      *(Dest1++)=*(Block++);
+      *(Dest2++)=*(Block++);
+    }
+    return 6*Count;
+  }
+  else
+    return 0;
+}
+
+int IntToIntMultiSingle(void* dest, int bytesperunit, int channels, int offset, void* block, int Count)
+{
+  if (channels==1)
+  {
+    memcpy(dest, &((char*)block)[offset*bytesperunit], bytesperunit*Count);
+    return Count;
+  }
+  else if (channels==2)
+  {
+    if (bytesperunit==1)
+    {
+      char* Dest=(char*)dest;
+      char* Block=&((char*)block)[offset];
+      for (int i=0; i<Count; i++)
+      {
+        *(Dest++)=*Block;
+        Block+=2;
+      }
+      return Count;
+    }
+    else if (bytesperunit==2)
+    {
+      __int16* Dest=(__int16*)dest;
+      __int16* Block=(__int16*)(&((char*)block)[offset*2]);
+      for (int i=0; i<Count; i++)
+      {
+        *(Dest++)=*Block;
+        Block+=2;
+      }
+      return Count*2;
+    }
+    else if (bytesperunit==3)
+    {
+      __pint24 Dest=(__pint24)dest;
+      __pint24 Block=(__pint24)(&((char*)block)[offset*3]);
+      for (int i=0; i<Count; i++)
+      {
+        *(Dest++)=*Block;
+        Block+=2;
+      }
+      return Count*3;
+    }
+    else
+      return 0;
+  }
+  else
+  {
+    if (bytesperunit==1)
+    {
+      char* Dest=(char*)dest;
+      char* Block=&((char*)block)[offset];
+      for (int i=0; i<Count; i++)
+      {
+        *(Dest++)=*Block;
+        Block+=channels;
+      }
+      return Count;
+    }
+    else if (bytesperunit==2)
+    {
+      __int16* Dest=(__int16*)dest;
+      __int16* Block=(__int16*)(&((char*)block)[offset*2]);
+      for (int i=0; i<Count; i++)
+      {
+        *(Dest++)=*Block;
+        Block+=channels;
+      }
+      return Count*2;
+    }
+    else if (bytesperunit==3)
+    {
+      __pint24 Dest=(__pint24)dest;
+      __pint24 Block=(__pint24)(&((char*)block)[offset*3]);
+      for (int i=0; i<Count; i++)
+      {
+        *(Dest++)=*Block;
+        Block+=channels;
+      }
+      return Count*3;
+    }
+    else return 0;
+  }
+}
+
+int IntToIntMultiChannel(int C, void** dest, int bytesperunit, int channels, void* block, int count)
+{
+  int tail=channels-C;
+  if (bytesperunit==1)
+  {
+    char* data=(char*)block;
+    for (int i=0; i<count; i++)
+    {
+      for (int c=0; c<C; c++) *(((char*)dest[c])++)=*(data++);
+      data=&data[tail];
+    }
+    return count;
+  }
+  else if (bytesperunit==2)
+  {
+    __int16* data=(__int16*)block;
+    for (int i=0; i<count; i++)
+    {
+      for (int c=0; c<C; c++) *(((__int16*)dest[c])++)=*(data++);
+      data=&data[tail];
+    }
+    return count*2;
+  }
+  else if (bytesperunit==3)
+  {
+    __pint24 data=(__pint24)block;
+    for (int i=0; i<count; i++)
+    {
+      for (int c=0; c<C; c++) {*(((__pint24)dest[c])++)=*(data++); }
+      data=&data[tail];
+    }
+    return count*3;
+  }
+  else
+    return 0;
+}
+
+__fastcall TAttachFileStream::TAttachFileStream(TFileStream* AFile)
+    : TStream()
+{
+  File=AFile;
+  StartOffset=0;
+  EndOffset=0;
+}
+
+__fastcall TAttachFileStream::~TAttachFileStream()
+{
+  delete File;
+}
+
+int __fastcall TAttachFileStream::Read(void *Buffer, int Count)
+{
+  return File->Read(Buffer, Count);
+}
+
+int __fastcall TAttachFileStream::Seek(int AnOffset, Word Origin)
+{
+  if (!File) return 0;
+  if (Origin==soFromBeginning)
+    return File->Seek(AnOffset+StartOffset, soFromBeginning)-StartOffset;
+  else if (Origin==soFromCurrent)
+    return File->Seek(AnOffset, soFromCurrent)-StartOffset;
+  else
+    return File->Seek(AnOffset+EndOffset, soFromEnd)-StartOffset;
+}
+
+__int64 __fastcall TAttachFileStream::Seek(const __int64 AnOffset, TSeekOrigin Origin)
+{
+  return Seek((int)AnOffset, (Word)Origin);
+}
+
+int __fastcall TAttachFileStream::Write(const void *Buffer, int Count)
+{
+  return File->Write(Buffer, Count);
+}
+
+//---------------------------------------------------------------------------
+// ValidCtrCheck is used to assure that the components created do not have
+// any pure virtual functions.
+//
+
+static inline void ValidCtrCheck(TWaveAudio *)
+{
+  new TWaveAudio(NULL);
+}
+//---------------------------------------------------------------------------
+__fastcall TWaveAudio::~TWaveAudio()
+{
+  delete FMemoryStream;
+  delete FFileStream;
+  DeallocateHWnd(HWndOut);
+  DeallocateHWnd(HWndIn);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::Clear(TObject* Sender)
+{
+  if (!FUseMemoryStream)
+  {
+    FUseMemoryStream=true;
+    delete FFileStream->File;
+    FFileStream->File=0;
+    FFileName="";
+  }
+  FMemoryStream->Position=0;
+  FMemoryStream->Size=0;
+  if (FOnAudioChange) FOnAudioChange(this);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::CloseFile(bool Close)
+{
+  if (UseMemoryStream) return;
+  int Position=FFileStream->Position;
+  delete FFileStream->File;
+  FFileStream->File=new TFileStream(FFileName, fmOpenWrite);
+  SaveHeader(FFileStream->File);
+  delete FFileStream->File;
+  FFileStream->File=0;
+  if (!Close)
+  {
+    FFileStream->File=new TFileStream(FFileName, fmOpenRead);
+    FFileStream->Position=Position;
+  }
+}
+
+//---------------------------------------------------------------------------
+void TWaveAudio::CopyFrom(TStream* AStream, int Count)
+{
+  WaveStream->CopyFrom(AStream, Count);
+  if (FOnAudioChange) FOnAudioChange(this);
+}
+
+void TWaveAudio::CopyFrom(TWaveAudio* AWaveAudio, int Count)
+{
+  WaveStream->CopyFrom(AWaveAudio->WaveStream, Count);
+  if (FOnAudioChange) FOnAudioChange(this);
+}
+
+//---------------------------------------------------------------------------
+void TWaveAudio::CopySamplesFrom(TStream* AStream, int Count)
+{
+  WaveStream->CopyFrom(AStream, Count*FChannels*(BitsPerSample/8));
+  if (FOnAudioChange) FOnAudioChange(this);
+}
+
+void TWaveAudio::CopySamplesFrom(TWaveAudio* AWaveAudio, int Count)
+{
+  WaveStream->CopyFrom(AWaveAudio->WaveStream, Count*FChannels*(BitsPerSample/8));
+  if (FOnAudioChange) FOnAudioChange(this);
+}
+
+//---------------------------------------------------------------------------
+void TWaveAudio::CreateFile(AnsiString FileName)
+{
+  UseMemoryStream=false;
+
+  TFileStream* OpenFile=new TFileStream(FileName, fmCreate);
+  SaveHeader(OpenFile);
+  delete OpenFile;
+
+  delete FFileStream->File;
+  FFileStream->File=new TFileStream(FileName, fmOpenReadWrite);
+  FFileStream->StartOffset=FFileStream->File->Size;
+  FFileStream->Position=0;
+  FFileName=FileName;
+}
+
+//---------------------------------------------------------------------------
+int __fastcall TWaveAudio::FillBlock(void* Block)
+{
+  return Stream->Read(Block, FBlockSize);
+}
+
+//---------------------------------------------------------------------------
+int __fastcall TWaveAudio::GetBytesPerSample()
+{
+  return FBitsPerSample/8;
+}
+
+//---------------------------------------------------------------------------
+__int32 __fastcall TWaveAudio::GetLength()
+{
+  return Stream->Size/FBlockAlign;
+}
+
+//---------------------------------------------------------------------------
+TStream* __fastcall TWaveAudio::GetStream()
+{
+  if (FUseMemoryStream) return FMemoryStream;
+  else return FFileStream;
+}
+
+//---------------------------------------------------------------------------
+void TWaveAudio::GetWaveProperties(TWaveAudio* WaveAudio1)
+{
+  FFormatTag=WaveAudio1->FormatTag;
+  SamplesPerSec=WaveAudio1->SamplesPerSec;
+  BitsPerSample=WaveAudio1->BitsPerSample;
+  Channels=WaveAudio1->Channels;
+  BlockSize=WaveAudio1->BlockSize;
+}
+
+//---------------------------------------------------------------------------
+bool __fastcall TWaveAudio::ReadHeader(TStream* AStream, __int32& length, bool allowunfinisheddata)
+{
+  bool success=true;
+  char s[10];
+  __int32 headerlen;
+  __int32 headerstart;
+
+  __int16 formattag;
+  __int16 channels;
+  __int32 samplespersec;
+  __int32 avgbytespersec;
+  __int16 blockalign;
+  __int16 bitspersample;
+
+  int rc=AStream->Read(s, 4); s[4]=0;
+  success=success&&(rc==4)&&!strcmp(s, "RIFF");
+  if (!success) return success;
+
+  rc=AStream->Read(&length, 4);
+  success=success&&(rc==4);
+
+  rc=AStream->Read(s, 4); if (rc!=4) return false;
+  s[4]=0;
+  success=success&&(rc==4)&&!strcmp(s, "WAVE");
+  if (!success) return success;
+
+  rc=AStream->Read(s, 4); s[4]=0;
+  while(rc==4 && strcmp(s, "fmt "))
+  {
+    AStream->Read(&length, 4);
+    AStream->Seek(length, soFromCurrent);
+    rc=AStream->Read(s, 4); s[4]=0;
+  }
+  success=success&&(rc==4);
+  if (!success) return success;
+
+    rc=AStream->Read(&headerlen, 4);
+    headerstart=AStream->Position;
+
+    AStream->Read(&formattag, 2);
+    AStream->Read(&channels, 2);
+    AStream->Read(&samplespersec, 4);
+    AStream->Read(&avgbytespersec, 4);
+    AStream->Read(&blockalign, 2);
+    AStream->Read(&bitspersample, 2);
+    success=success&&(formattag==1);
+    success=success&&(rc==4)&&(blockalign*8==channels*bitspersample);
+    success=success&&(avgbytespersec==samplespersec*blockalign);
+
+  if (!success) return success;
+  AStream->Seek(headerlen+headerstart, soFromBeginning);
+
+  rc=AStream->Read(s, 4); s[4]=0;
+  while(rc==4 && strcmp(s, "data"))
+  {
+    AStream->Read(&length, 4);
+    AStream->Seek(length, soFromCurrent);
+    rc=AStream->Read(s, 4); s[4]=0;
+  }
+  success=success&&(rc==4);
+  if (!success) return success;
+
+  rc=AStream->Read(&length, 4);
+  success=success&&(rc==4);
+  if (!success) return success;
+
+  if (AStream->Position+length>AStream->Size)
+  {
+    if (allowunfinisheddata) length=(AStream->Size-AStream->Position)/blockalign*blockalign;
+    else success=false;
+  }
+  if (!success) return success;
+
+  FFormatTag=formattag;
+  FChannels=channels;
+  FSamplesPerSec=samplespersec;
+  FAvgBytesPerSec=avgbytespersec;
+  FBlockAlign=blockalign;
+  FBitsPerSample=bitspersample;
+
+  return success;
+}
+
+void TWaveAudio::InsertFromFile(AnsiString FileName)
+{
+  TFileStream* OpenFile=new TFileStream(FileName, fmOpenRead|fmShareDenyNone);
+
+  __int32 length;
+  bool success=ReadHeader(OpenFile, length);
+
+  if (success)
+  {
+    FFileName=FileName;
+    if (FUseMemoryStream)
+    {
+      if (length>0)
+      {
+        FMemoryStream->Size=length;
+        OpenFile->Read(FMemoryStream->Memory, length);
+      }
+      delete OpenFile;
+    }
+    else
+    {
+      delete FFileStream->File;
+      FFileStream->File=OpenFile;
+      FFileStream->StartOffset=OpenFile->Position;
+      FFileStream->EndOffset=OpenFile->Position+length-OpenFile->Size;
+    }
+
+    if (FStreamLimit>0 && Stream->Size>=FStreamLimit && OnStreamFull) OnStreamFull(this);
+    if (FOnAudioChange) FOnAudioChange(this);
+  }
+  else
+  {
+    delete OpenFile;
+    throw EReadError("PCM error ecountered reading "+FileName);
+  }
+}
+
+//---------------------------------------------------------------------------
+bool TWaveAudio::IsValidWave(AnsiString FileName)
+{
+  bool success=true;
+  char s[10];
+  __int32 headerlen;
+  __int32 headerstart;
+
+  __int16 formattag;
+  __int16 channels;
+  __int32 samplespersec;
+  __int32 avgbytespersec;
+  __int16 blockalign;
+  __int16 bitspersample;
+  __int32 length;
+
+
+  TFileStream* OpenFile=new TFileStream(FileName,fmOpenRead|fmShareDenyNone);
+
+  OpenFile->Read(s, 4);
+  s[4]=0;
+  success=success&&!strcmp(s, "RIFF");
+
+  OpenFile->Read(&length, 4);
+  success=success&&(length+OpenFile->Position==OpenFile->Size);
+
+  OpenFile->Read(s, 8);
+  s[8]=0;
+  success=success&&!strcmp(s, "WAVEfmt ");
+
+  OpenFile->Read(&headerlen, 4);
+  headerstart=OpenFile->Position;
+
+  OpenFile->Read(&formattag, 2);
+  success=success&&(formattag==1);
+
+  OpenFile->Read(&channels, 2);
+  OpenFile->Read(&samplespersec, 4);
+  OpenFile->Read(&avgbytespersec, 4);
+  OpenFile->Read(&blockalign, 2);
+  OpenFile->Read(&bitspersample, 2);
+  success=success&&(blockalign*8==channels*bitspersample);
+  success=success&&(avgbytespersec==samplespersec*blockalign);
+
+  OpenFile->Seek(headerlen+headerstart, soFromBeginning);
+  OpenFile->Read(s, 4);
+  s[4]=0;
+  success=success&&!strcmp(s, "data");
+
+  OpenFile->Read(&length, 4);
+  success=success&&(length+OpenFile->Position==OpenFile->Size);
+
+  delete OpenFile;
+  return success;
+}
+
+//---------------------------------------------------------------------------
+void TWaveAudio::LoadFromFile(AnsiString FileName)
+{
+  if (FOnBeforeLoad) FOnBeforeLoad(this);
+  if (FAutoUseMemoryStream) UseMemoryStream=false;
+  if (FUseMemoryStream) FMemoryStream->Clear();
+  InsertFromFile(FileName);
+  if (FOnLoad) FOnLoad(this);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::OnWimClose(TMessage& Message)
+{
+  waveInUnprepareHeader(WaveIn,WaveHdr1,sizeof(WAVEHDR));
+  waveInUnprepareHeader(WaveIn,WaveHdr2,sizeof(WAVEHDR));
+  delete WaveHdr1;
+  delete WaveHdr2;
+  delete[] Buffer1;
+  delete[] Buffer2;
+  FRecording=false;
+  if (ResetInStream && FOnStreamFull)
+    FOnStreamFull(this);
+  ResetInStream=false;
+  ResetInUser=false;
+  if (FOnRecordingDone) FOnRecordingDone(this);
+  if (FOnAudioChange) FOnAudioChange(this);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::OnWimData(TMessage& Message)
+{
+  WAVEHDR* WaveHdr=(WAVEHDR*)Message.LParam;
+  if (!FRecording) return;
+
+  if (!ResetInStream)
+  {
+    ReleaseBlock(WaveHdr->lpData,WaveHdr->dwBytesRecorded);
+    if (FStreamLimit>0 && Stream->Size>=FStreamLimit)
+      ResetInStream=true;
+    waveInAddBuffer(WaveIn,WaveHdr,sizeof(WAVEHDR));
+    if (FOnInAddBuffer) FOnInAddBuffer(this);
+    if (ResetInUser)
+    {
+      waveInReset(WaveIn);
+      waveInClose(WaveIn);
+    }
+  }
+  else
+  {
+    waveInReset(WaveIn);
+    waveInClose(WaveIn);
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::OnWimOpen(TMessage& Message)
+{
+//
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::OnWomClose(TMessage& Message)
+{
+  waveOutUnprepareHeader(WaveOut,WaveHdr1,sizeof(WAVEHDR));
+  waveOutUnprepareHeader(WaveOut,WaveHdr2,sizeof(WAVEHDR));
+  delete WaveHdr1;
+  delete WaveHdr2;
+  delete[] Buffer1;
+  delete[] Buffer2;
+  WaveHdr1=WaveHdr2=0;
+  Buffer1=Buffer2=0;
+  FPlaying=false;
+  FPaused=false;
+  ResetOut=false;
+  ResetOutUser=false;
+  if (FOnPlaybackProgress) FOnPlaybackProgress(this, 1);
+  if (FOnPlaybackProg) FOnPlaybackProg(this, -2);
+
+  if (OnPlaybackDone) OnPlaybackDone(this);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::OnWomDone(TMessage& Message)
+{
+  WAVEHDR* WaveHdr=(WAVEHDR*)Message.LParam;
+
+  if (ResetOut)
+  {
+    if  (WaveHdr->dwBufferLength!=(unsigned)FBlockSize)
+    {
+      waveOutClose(WaveOut);
+    }
+  }
+  else
+  {
+    int rc;
+
+    if (ResetOutUser) rc=0;
+    else rc=FillBlock(WaveHdr->lpData);
+
+    if (rc!=FBlockSize)
+    {
+      ResetOut=true;
+      WaveHdr->dwBufferLength=rc;
+      if (BitsPerSample==8) memset(&WaveHdr->lpData[rc],0x80,FBlockSize-rc);
+      else memset(&WaveHdr->lpData[rc],0,FBlockSize-rc);
+      waveOutUnprepareHeader(WaveOut, WaveHdr, sizeof(WAVEHDR));
+      waveOutPrepareHeader(WaveOut, WaveHdr, sizeof(WAVEHDR));
+    }
+    waveOutWrite(WaveOut,WaveHdr,sizeof(WAVEHDR));
+    if (FOnPlaybackProgress)
+      FOnPlaybackProgress(this, (Stream->Position-FBlockSize)*1.0/Stream->Size);
+    if (FOnPlaybackProg)
+      FOnPlaybackProg(this, Stream->Position-FBlockSize);
+    if (FOnOutWrite) FOnOutWrite(this);
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::OnWomOpen(TMessage& Message)
+{
+//
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::Pause(TObject* Sender)
+{
+  if (FPlaying)
+  {
+    waveOutPause(WaveOut);
+    FPaused=true;
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::PausePlayback(TObject* Sender)
+{
+  if (Playing) ResetOutUser=true;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::PauseRecording(TObject* Sender)
+{
+  if (Recording) ResetInUser=true;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::Play(TObject* Sender)
+{
+  Rewind(this);
+  StartPlayback(this);
+}
+
+void __fastcall TWaveAudio::Play(TNotifyEvent AnOnPlaybackDone)
+{
+  Rewind(this);
+  OnPlaybackDone=AnOnPlaybackDone;
+  StartPlayback(this);
+}
+
+//---------------------------------------------------------------------------
+int __fastcall TWaveAudio::Read(void* Buffer, int Count)
+{
+  return Stream->Read(Buffer, Count);
+}
+
+int __fastcall TWaveAudio::ReadSamples(void* Buffer, int Count)
+{
+  return Stream->Read(Buffer, Count*FChannels*(BitsPerSample/8));
+}
+
+int __fastcall TWaveAudio::ReadSamples(double* Buffer, int Count)
+{
+  int FBytesPerSample=FBitsPerSample/8;
+  int countavailable=(Stream->Size-Stream->Position)/FBytesPerSample;
+  if (Count>countavailable) Count=countavailable;
+  if (FUseMemoryStream)
+  {
+    int Position=FMemoryStream->Position;
+    IntToDouble(Buffer, &((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Count);
+    FMemoryStream->Position=Position+Count*FBytesPerSample;
+  }
+  else
+  {
+    void *data=new char[FBlockSize];
+    double *Data=Buffer;
+    int CountPF=FBlockSize/FBytesPerSample;
+    int Fr=(Count/CountPF);
+    for (int i=0; i<Fr; i++)
+    {
+      Stream->Read(data, FBlockSize);
+      IntToDouble(Data, data, FBytesPerSample, CountPF);
+      Data=&Data[CountPF];
+    }
+    int CountLastF=Count%CountPF;
+    int lastblocksize=CountLastF*FBytesPerSample;
+    Stream->Read(data, lastblocksize);
+    IntToDouble(Data, data, FBytesPerSample, CountLastF);
+    delete[] data;
+  }
+
+  return Count*FBytesPerSample;
+}
+
+int __fastcall TWaveAudio::ReadSamplesInterleave(void* Buffer1, void* Buffer2, int Count)
+{
+  int FBytesPerSample=FBitsPerSample/8;
+  int SampleSize=FBytesPerSample*2;
+  int countavailable=(Stream->Size-Stream->Position)/SampleSize;
+  if (Count>countavailable) Count=countavailable;
+  if (FUseMemoryStream)
+  {
+    int Position=FMemoryStream->Position;
+    IntToIntInterleave(Buffer1, Buffer2, FBytesPerSample, &((char*)FMemoryStream->Memory)[Position], Count);
+    FMemoryStream->Position=Position+Count*SampleSize;
+  }
+  else
+  {
+    void *Data1=Buffer1, *Data2=Buffer2, *data=new char[FBlockSize];
+    int HBlockSize=FBlockSize/2, CountPF=FBlockSize/SampleSize;
+    int Fr=Count/CountPF;
+    for (int i=0; i<Fr; i++)
+    {
+      Stream->Read(data, FBlockSize);
+      IntToIntInterleave(Data1, Data2, FBytesPerSample, data, CountPF);
+      Data1=&((char*)Data1)[HBlockSize], Data2=&((char*)Data2)[HBlockSize];
+    }
+    int CountLastF=Count%CountPF;
+    int lastblocksize=CountLastF*SampleSize;
+    Stream->Read(data, lastblocksize);
+    IntToIntInterleave(Data1, Data2, FBytesPerSample, data, CountLastF);
+    delete[] data;
+  }
+  return Count*SampleSize;
+}
+
+int __fastcall TWaveAudio::ReadSamplesInterleave(double* Buffer1, double* Buffer2, int Count)
+{
+  int FBytesPerSample=FBitsPerSample/8;
+  int SampleSize=FBytesPerSample*2;
+  int countavailable=(Stream->Size-Stream->Position)/SampleSize;
+  if (Count>countavailable) Count=countavailable;
+  if (FUseMemoryStream)
+  {
+    int Position=FMemoryStream->Position;
+    IntToDoubleInterleave(Buffer1, Buffer2, &((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Count);
+    FMemoryStream->Position=Position+Count*SampleSize;
+  }
+  else
+  {
+    double *Data1=Buffer1, *Data2=Buffer2;
+    void *data=new char[FBlockSize];
+    int CountPF=FBlockSize/SampleSize;
+    int Fr=Count/CountPF;
+    for (int i=0; i<Fr; i++)
+    {
+      Stream->Read(data, FBlockSize);
+      IntToDoubleInterleave(Data1, Data2, data, FBytesPerSample, CountPF);
+      Data1=&Data1[CountPF], Data2=&Data2[CountPF];
+    }
+    int CountLastF=Count%CountPF;
+    int lastblocksize=CountLastF*SampleSize;
+    Stream->Read(data, lastblocksize);
+    IntToDoubleInterleave(Data1, Data2, data, FBytesPerSample, CountLastF);
+    delete[] data;
+  }
+  return Count*SampleSize;
+}
+
+int __fastcall TWaveAudio::ReadSamplesMultiSingle(void* Buffer, int Channel, int Count)
+{
+  int FBytesPerSample=FBitsPerSample/8;
+  int SampleSize=FBytesPerSample*FChannels;
+  int countavailable=(Stream->Size-Stream->Position)/SampleSize;
+  if (Count>countavailable) Count=countavailable;
+  if (FUseMemoryStream)
+  {
+    int Position=FMemoryStream->Position;
+    IntToIntMultiSingle(Buffer, FBytesPerSample, FChannels, Channel, &((char*)FMemoryStream->Memory)[Position], Count);
+    FMemoryStream->Position=Position+Count*SampleSize;
+  }
+  else
+  {
+    int CountPF=FBlockSize/SampleSize;
+    int ReadSize=CountPF*SampleSize, WriteSize=CountPF*FBytesPerSample;
+    int Fr=Count/CountPF;
+    void *Data=Buffer, *data=new char[ReadSize];
+    for (int i=0; i<Fr; i++)
+    {
+      Stream->Read(data, ReadSize);
+      IntToIntMultiSingle(Data, FBytesPerSample, FChannels, Channel, data, CountPF);
+      Data=&((char*)Data)[WriteSize];
+    }
+    int CountLastF=Count%CountPF;
+    ReadSize=CountLastF*SampleSize;
+    Stream->Read(data, ReadSize);
+    IntToIntMultiSingle(Data, FBytesPerSample, FChannels, Channel, data, CountLastF);
+    delete[] data;
+  }
+  return Count*FBytesPerSample;
+}
+
+int __fastcall TWaveAudio::ReadSamplesMultiChannel(int C, void** Buffer, int Count)
+{
+  if (C>FChannels) C=FChannels;
+  int FBytesPerSample=FBitsPerSample/8;
+  int SampleSize=FBytesPerSample*FChannels;
+  int countavailable=(Stream->Size-Stream->Position)/SampleSize;
+  if (Count>countavailable) Count=countavailable;
+  if (FUseMemoryStream)
+  {
+    int Position=FMemoryStream->Position;
+    IntToIntMultiChannel(C, Buffer, FBytesPerSample, FChannels, &((char*)FMemoryStream->Memory)[Position], Count);
+    FMemoryStream->Position=Position+Count*SampleSize;
+  }
+  else
+  {
+    int CountPF=FBlockSize/SampleSize;
+    int ReadSize=CountPF*SampleSize, WriteSize=CountPF*FBytesPerSample;
+    int Fr=Count/CountPF;
+    void* data=new char[ReadSize];
+    for (int i=0; i<Fr; i++)
+    {
+      Stream->Read(data, ReadSize);
+      IntToIntMultiChannel(C, Buffer, FBytesPerSample, FChannels, data, CountPF);
+      for (int c=0; c<C; c++) Buffer[c]=&((char*)Buffer[c])[WriteSize];
+    }
+    int CountLastF=Count*CountPF;
+    ReadSize=CountLastF*SampleSize;
+    Stream->Read(data, ReadSize);
+    IntToIntMultiChannel(C, Buffer, FBytesPerSample, FChannels, data, CountLastF);
+  }
+  return Count*SampleSize;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::ReleaseBlock(void* Block, int BytesRecorded)
+{
+  Stream->Write(Block, BytesRecorded);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::Restart(TObject* Sender)
+{
+  if (FPlaying)
+  {
+    waveOutRestart(WaveOut);
+    FPaused=false;
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::Rewind(TObject* Sender)
+{
+  Stream->Seek(0,soFromBeginning);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::SaveHeader(TStream* AStream)
+{
+  __int32 s32;
+  __int16 s16;
+
+  AStream->Write("RIFF",4);
+  s32=Stream->Size+38;
+  AStream->Write(&s32,4);
+  AStream->Write("WAVEfmt ",8);
+  s32=0x12;
+  AStream->Write(&s32,4);
+  s16=FFormatTag;
+  AStream->Write(&s16,2);
+  s16=FChannels;
+  AStream->Write(&s16,2);
+  s32=FSamplesPerSec;
+  AStream->Write(&s32,4);
+  s32=FAvgBytesPerSec;
+  AStream->Write(&s32,4);
+  s16=FBlockAlign;
+  AStream->Write(&s16,2);
+  s16=FBitsPerSample;
+  AStream->Write(&s16,2);
+  s16=0;
+  AStream->Write(&s16,2);
+  AStream->Write("data",4);
+  s32=Stream->Size;
+  AStream->Write(&s32,4);
+}
+
+void __fastcall TWaveAudio::SaveToFile(AnsiString FileName)
+{
+  TFileStream& SaveFile=*new TFileStream(FileName, fmCreate);
+  SaveHeader(&SaveFile);
+
+  if (FUseMemoryStream)
+    ((TMemoryStream*)Stream)->SaveToStream(&SaveFile);
+  else
+    SaveFile.CopyFrom(Stream, 0);
+  delete &SaveFile;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::Seek(int Offset, WORD Origin)
+{
+  WaveStream->Seek(Offset, Origin);
+}
+
+void __fastcall TWaveAudio::SeekSamples(int Offset, WORD Origin)
+{
+  WaveStream->Seek(Offset*FChannels*(BitsPerSample/8), Origin);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::SetBitsPerSample(__int16 ABitsPerSample)
+{
+  if (ABitsPerSample!=8 && ABitsPerSample!=16 && ABitsPerSample!=24) return;
+  FBitsPerSample=ABitsPerSample;
+  FAvgBytesPerSec=FSamplesPerSec*FBitsPerSample*FChannels/8;
+  FBlockAlign=FBitsPerSample*FChannels/8;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::SetBlockSize(int ABlockSize)
+{
+  FBlockSize=ABlockSize;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::SetChannels(__int16 AChannels)
+{
+  if (AChannels!=1 && AChannels!=2) return;
+  FChannels=AChannels;
+  FAvgBytesPerSec=FSamplesPerSec*FBitsPerSample*FChannels/8;
+  FBlockAlign=FBitsPerSample*FChannels/8;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::SetLVolume(unsigned __int16 ALVolume)
+{
+  if (ALVolume!=FLVolume)
+  {
+    FLVolume=ALVolume;
+    if (FPlaying) SetVolume();
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::SetRVolume(unsigned __int16 ARVolume)
+{
+  if (ARVolume!=FRVolume)
+  {
+    FRVolume=ARVolume;
+    if (FPlaying) SetVolume();
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::SetSamplesPerSec(__int32 ASamplesPerSec)
+{
+  FSamplesPerSec=ASamplesPerSec;
+  FAvgBytesPerSec=FSamplesPerSec*FBitsPerSample*FChannels/8;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::SetStreamLimit(int AStreamLimit)
+{
+  if (AStreamLimit>0 && Stream->Size>AStreamLimit)
+  {
+    if (OnStreamLimitFailure) OnStreamLimitFailure(this);
+       return;
+  }
+  FStreamLimit=AStreamLimit;
+}
+
+void __fastcall TWaveAudio::SetUseMemoryStream(bool AUseMemoryStream)
+{
+  if (FUseMemoryStream!=AUseMemoryStream)
+  {
+    FUseMemoryStream=AUseMemoryStream;
+  }
+}
+
+//---------------------------------------------------------------------------
+MMRESULT __fastcall TWaveAudio::SetVolume(void)
+{
+  unsigned __int32 Volume=FRVolume;
+  Volume=Volume<<16;
+  Volume+=FLVolume;
+  return waveOutSetVolume(WaveOut, Volume);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::StartPlayback(TObject* Sender)
+{
+  if (FPlaying) return;
+
+  WAVEFORMATEX wfx;
+  wfx.wFormatTag=FFormatTag;
+  wfx.nChannels=FChannels;
+  wfx.nSamplesPerSec=FSamplesPerSec;
+  wfx.nAvgBytesPerSec=FAvgBytesPerSec;
+  wfx.nBlockAlign=FBlockAlign;
+  wfx.wBitsPerSample=FBitsPerSample;
+  wfx.cbSize=FcbSize;
+
+	if (waveOutOpen(&WaveOut,WAVE_MAPPER,&wfx,(DWORD)HWndOut, NULL,
+          CALLBACK_WINDOW)!=MMSYSERR_NOERROR)
+  {
+    throw EWriteError("TWaveAudio Err: Failed opening device WaveOut");
+  }
+
+  SetVolume();
+
+  Buffer1=new char[FBlockSize];
+  Buffer2=new char[FBlockSize];
+  WaveHdr1=new WAVEHDR;
+  WaveHdr2=new WAVEHDR;
+
+  WaveHdr1->lpData=(char*)Buffer1;
+  WaveHdr1->dwBufferLength=FBlockSize;
+  WaveHdr1->dwBytesRecorded=0;
+  WaveHdr1->dwUser=0;
+  WaveHdr1->dwFlags=0;
+  WaveHdr1->dwLoops=1;
+  WaveHdr1->lpNext=NULL;
+  WaveHdr1->reserved=0;
+
+  WaveHdr2->lpData=(char*)Buffer2;
+  WaveHdr2->dwBufferLength=FBlockSize;
+  WaveHdr2->dwBytesRecorded=0;
+  WaveHdr2->dwUser=0;
+  WaveHdr2->dwFlags=0;
+  WaveHdr2->dwLoops=1;
+  WaveHdr2->lpNext=NULL;
+  WaveHdr2->reserved=0;
+
+  int rc;
+
+  ResetOut=false;
+  ResetOutUser=false;
+
+  rc=(FillBlock(WaveHdr1->lpData));
+  if (rc!=FBlockSize)
+  {
+    if (BitsPerSample==8) memset(&WaveHdr1->lpData[rc],0x80,FBlockSize-rc);
+    else memset(&WaveHdr1->lpData[rc],0,FBlockSize-rc);
+    WaveHdr1->dwBufferLength=rc;
+    ResetOut=true;
+  }
+  waveOutPrepareHeader(WaveOut,WaveHdr1,sizeof(WAVEHDR));
+  waveOutWrite(WaveOut,WaveHdr1,sizeof(WAVEHDR));
+
+  if (FOnPlaybackProgress)
+    FOnPlaybackProgress(this, 0);
+  if (FOnPlaybackProg)
+    FOnPlaybackProg(this, 0);
+
+  if (rc==BlockSize)
+  {
+    rc=(FillBlock(WaveHdr2->lpData));
+    if (rc!=FBlockSize)
+    {
+      if (BitsPerSample==8) memset(&WaveHdr2->lpData[rc],0x80,FBlockSize-rc);
+      else memset(&WaveHdr2->lpData[rc],0,FBlockSize-rc);
+      WaveHdr2->dwBufferLength=rc;
+      ResetOut=true;
+    }
+
+    waveOutPrepareHeader(WaveOut,WaveHdr2,sizeof(WAVEHDR));
+    waveOutWrite(WaveOut,WaveHdr2,sizeof(WAVEHDR));
+
+    if (FOnPlaybackProgress)
+      FOnPlaybackProgress(this, (Stream->Position-FBlockSize)*1.0/Stream->Size);
+    if (FOnPlaybackProg)
+      FOnPlaybackProg(this, Stream->Position-FBlockSize);
+
+  }
+  FPlaying=true;
+  if (FOnStartPlayback) FOnStartPlayback(this);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::StartRecording(TObject* Sender)
+{
+  if (FRecording) return;
+
+  WAVEFORMATEX wfx;
+  wfx.wFormatTag=FFormatTag;
+  wfx.nChannels=FChannels;
+  wfx.nSamplesPerSec=FSamplesPerSec;
+  wfx.nAvgBytesPerSec=FAvgBytesPerSec;
+  wfx.nBlockAlign=FBlockAlign;
+  wfx.wBitsPerSample=FBitsPerSample;
+  wfx.cbSize=FcbSize;
+
+  MMRESULT tr=waveInOpen(&WaveIn, WAVE_MAPPER, &wfx, (unsigned long)HWndIn, NULL,
+          CALLBACK_WINDOW);
+  if (tr!=MMSYSERR_NOERROR && tr!=MMSYSERR_ALLOCATED)
+  {
+      throw EReadError("TWaveAudio err: Failed opening device WaveIn");
+  }
+
+  Buffer1=new char[FBlockSize];
+  Buffer2=new char[FBlockSize];
+  WaveHdr1=new WAVEHDR;
+  WaveHdr2=new WAVEHDR;
+
+  WaveHdr1->lpData=(char*)Buffer1;
+  WaveHdr1->dwBufferLength=FBlockSize;
+  WaveHdr1->dwBytesRecorded=0;
+  WaveHdr1->dwUser=0;
+  WaveHdr1->dwFlags=0;
+  WaveHdr1->dwLoops=1;
+  WaveHdr1->lpNext=NULL;
+  WaveHdr1->reserved=0;
+
+  waveInPrepareHeader(WaveIn,WaveHdr1,sizeof(WAVEHDR));
+
+  WaveHdr2->lpData=(char*)Buffer2;
+  WaveHdr2->dwBufferLength=FBlockSize;
+  WaveHdr2->dwBytesRecorded=0;
+  WaveHdr2->dwUser=0;
+  WaveHdr2->dwFlags=0;
+  WaveHdr2->dwLoops=1;
+  WaveHdr2->lpNext=NULL;
+  WaveHdr2->reserved=0;
+
+  waveInPrepareHeader(WaveIn,WaveHdr2,sizeof(WAVEHDR));
+
+  waveInAddBuffer(WaveIn,WaveHdr1,sizeof(WAVEHDR));
+  waveInAddBuffer(WaveIn,WaveHdr2,sizeof(WAVEHDR));
+
+  ResetInStream=false;
+  ResetInUser=false;
+  FRecording=true;
+
+  waveInStart(WaveIn);
+
+  if (FOnStartRecording) FOnStartRecording(this);
+}
+
+//---------------------------------------------------------------------------
+__fastcall TWaveAudio::TWaveAudio(TComponent* Owner)
+  : TComponent(Owner)
+{
+  FBlockSize=12288;
+  FStreamLimit=0;
+  FUseMemoryStream=true;
+  FAutoUseMemoryStream=true;
+  FMemoryStream=new TMemoryStream;
+  FFileStream=new TAttachFileStream(NULL);
+
+  FPlaying=false;
+  FRecording=false;
+  FPaused=false;
+
+	FOnAudioChange=0;
+	FOnStartPlayback=0;
+  FOnStartRecording=0;
+  FOnPlaybackDone=0;
+  FOnRecordingDone=0;
+  FOnStreamLimitFailure=0;
+  FOnStreamFull=0;
+  FOnPlaybackProgress=0;
+  FOnPlaybackProg=0;
+  FOnInAddBuffer=0;
+  FOnOutWrite=0;
+
+  FSamplesPerSec=44100;
+  FBitsPerSample=16;
+  FChannels=1;
+  FFileName="";
+
+  FFormatTag=WAVE_FORMAT_PCM;
+  FcbSize=0;   //ignored for PCM
+  FAvgBytesPerSec=FSamplesPerSec*FBitsPerSample*FChannels/8;
+  FBlockAlign=FBitsPerSample*FChannels/8;
+
+  HWndOut=AllocateHWnd(WaveOutProc);
+  HWndIn=AllocateHWnd(WaveInProc);
+
+  unsigned long Volume;
+	waveOutGetVolume((void *)WAVE_MAPPER, &Volume);
+  FLVolume=Volume&0x0000FFFF;
+  FRVolume=Volume>>16;
+}
+
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::WaveInProc(TMessage& Message)
+{
+  switch(Message.Msg)
+  {
+    case MM_WIM_OPEN: OnWimOpen(Message); break;
+    case MM_WIM_DATA: OnWimData(Message); break;
+    case MM_WIM_CLOSE: OnWimClose(Message); break;
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TWaveAudio::WaveOutProc(TMessage& Message)
+{
+  switch(Message.Msg)
+  {
+    case MM_WOM_OPEN: OnWomOpen(Message); break;
+    case MM_WOM_DONE: OnWomDone(Message); break;
+    case MM_WOM_CLOSE: OnWomClose(Message); break;
+  }
+}
+
+//---------------------------------------------------------------------------
+int __fastcall TWaveAudio::Write(void* Buffer, int Count)
+{
+  if (!FUseMemoryStream)
+  {
+    int Position=FFileStream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenWrite);
+    FFileStream->Position=Position;
+  }
+  int result=Stream->Write(Buffer, Count);
+  if (!FUseMemoryStream)
+  {
+    int Position=FFileStream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenRead);
+    FFileStream->Position=Position;
+  }
+  if (FOnAudioChange) FOnAudioChange(this);
+  return result;
+}
+
+int __fastcall TWaveAudio::WriteSamples(void* Buffer, int Count)
+{
+  if (!FUseMemoryStream)
+  {
+    int Position=FFileStream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenWrite);
+    FFileStream->Position=Position;
+  }
+  int result=Stream->Write(Buffer, Count*FChannels*FBitsPerSample/8);
+  if (!FUseMemoryStream)
+  {
+    int Position=FFileStream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenRead);
+    FFileStream->Position=Position;
+  }
+  if (FOnAudioChange) FOnAudioChange(this);
+  return result;
+}
+
+int __fastcall TWaveAudio::WriteSamples(double* Buffer, int Count)
+{
+  int result=0;
+  if (!FUseMemoryStream)
+  {
+    int Position=FFileStream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenWrite);
+    FFileStream->Position=Position;
+  }
+
+  int FBytesPerSample=FBitsPerSample/8;
+  if (FUseMemoryStream)
+  {
+    int Position=FMemoryStream->Position;
+    result=Count*FBytesPerSample;
+    if (FMemoryStream->Size<Position+result) FMemoryStream->Size=Position+result;
+    DoubleToInt(&((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Buffer, Count);
+    FMemoryStream->Position=Position+result;
+  }
+  else
+  {
+    void *data=new char[FBlockSize];
+    double *Data=Buffer;
+    int CountPF=FBlockSize/FBytesPerSample;
+    int Fr=(Count/CountPF);
+    for (int i=0; i<Fr; i++)
+    {
+      DoubleToInt(data, FBytesPerSample, Data, CountPF);
+      result+=Stream->Write(data, FBlockSize);
+      Data=&Data[CountPF];
+    }
+    int CountLastF=Count%CountPF;
+    int lastblocksize=CountLastF*FBytesPerSample;
+    DoubleToInt(data, FBytesPerSample, Data, CountLastF);
+    result+=Stream->Write(data, lastblocksize);
+    delete[] data;
+  }
+
+  if (!FUseMemoryStream)
+  {
+    int Position=FFileStream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenRead);
+    FFileStream->Position=Position;
+  }
+  if (FOnAudioChange) FOnAudioChange(this);
+  return result;
+}
+
+int __fastcall TWaveAudio::WriteSamplesInterleave(void* Buffer1, void* Buffer2, int Count)
+{
+  int FBytesPerSample=FBitsPerSample/8;
+  int SampleSize=FBytesPerSample*2;
+  if (FUseMemoryStream)
+  {
+    int Position=FMemoryStream->Position;
+    int countavailable=(FMemoryStream->Size-Position)/SampleSize;
+    if (countavailable<Count) FMemoryStream->Size=Position+SampleSize*Count;
+    IntToIntInterleave(&((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Buffer1, Buffer2, Count);
+    FMemoryStream->Position=Position+SampleSize*Count;
+  }
+  else
+  {
+    int Position=Stream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenWrite);
+    FFileStream->Position=Position;
+
+    int CountPF=FBlockSize/SampleSize, HBlockSize=FBlockSize/2;
+    int Fr=Count/CountPF;
+    void *Data1=Buffer1, *Data2=Buffer2, *data=new char[FBlockSize];
+    for (int i=0; i<Fr; i++)
+    {
+      IntToIntInterleave(data, FBytesPerSample, Data1, Data2, CountPF);
+      Stream->Write(data, FBlockSize);
+      Data1=&((char*)Data1)[HBlockSize], Data2=&((char*)Data2)[HBlockSize];
+    }
+    int CountLastF=Count%CountPF;
+    int lastblocksize=CountLastF*SampleSize;
+    IntToIntInterleave(data, FBytesPerSample, Data1, Data2, CountLastF);
+    Stream->Write(data, lastblocksize);
+
+    Position=Stream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenRead);
+    FFileStream->Position=Position;
+  }
+  if (FOnAudioChange) FOnAudioChange(this);
+  return Count*SampleSize;
+}
+
+int __fastcall TWaveAudio::WriteSamplesInterleave(double* Buffer1, double* Buffer2, int Count)
+{
+  int FBytesPerSample=FBitsPerSample/8;
+  int SampleSize=FBytesPerSample*2;
+  if (FUseMemoryStream)
+  {
+    int Position=FMemoryStream->Position;
+    int countavailable=(FMemoryStream->Size-Position)/SampleSize;
+    if (countavailable<Count) FMemoryStream->Size=Position+SampleSize*Count;
+    DoubleToIntInterleave(&((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Buffer1, Buffer2, Count);
+    FMemoryStream->Position=Position+SampleSize*Count;
+  }
+  else
+  {
+    int Position=Stream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenWrite);
+    FFileStream->Position=Position;
+
+    int CountPF=FBlockSize/SampleSize;
+    int Fr=Count/CountPF;
+    double *Data1=Buffer1, *Data2=Buffer2;
+    void *data=new char[FBlockSize];
+    for (int i=0; i<Fr; i++)
+    {
+      DoubleToIntInterleave(data, FBytesPerSample, Data1, Data2, CountPF);
+      Stream->Write(data, FBlockSize);
+      Data1=&Data1[CountPF], Data2=&Data2[CountPF];
+    }
+    int CountLastF=Count%CountPF;
+    int lastblocksize=CountLastF*SampleSize;
+    DoubleToIntInterleave(data, FBytesPerSample, Data1, Data2, CountLastF);
+    Stream->Write(data, lastblocksize);
+
+    Position=Stream->Position;
+    delete FFileStream->File;
+    FFileStream->File=new TFileStream(FFileName, fmOpenRead);
+    FFileStream->Position=Position;
+  }
+  if (FOnAudioChange) FOnAudioChange(this);
+  return Count*SampleSize;
+}
+//---------------------------------------------------------------------------
+__fastcall TDataAudio::TDataAudio(TComponent* Owner)
+      : TWaveAudio(Owner)
+{
+  FCustomFillBlock=0;
+}
+
+int __fastcall TDataAudio::FillBlock(void* Block)
+{
+  if (FCustomFillBlock)
+    return FCustomFillBlock(Block);
+  else
+    return TWaveAudio::FillBlock(Block);
+}
+
+//---------------------------------------------------------------------------
+namespace Audiopac
+{
+  void __fastcall PACKAGE Register()
+  {
+    TComponentClass classes[1] = {__classid(TWaveAudio)};
+    RegisterComponents("Samples", classes, 0);
+  }
+}
+//---------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AudioPac.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,642 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+#ifndef AudioPacH
+#define AudioPacH
+//---------------------------------------------------------------------------
+/*
+
+  AudioPac.cpp implements a VCL component for linear PCM waveform audio operations on
+  Windows using Win32 WAVEMAPPER device.
+
+  Component class TWaveAudio
+  TWaveAudio is a VCL component that incapsulates the basic waveform audio i/o functions.
+
+    Properties
+
+      readwrite   AutoUseMemoryStream
+      readonly    AvgBytesPerSec
+      readwrite   BitsPerSample
+      readonly    BlockAlign
+      readwrite   BlockSize
+      readonly    BytesPerSample
+      readonly    cbSize
+      readwrite   Channels
+      readonly    FileName
+      readonly    FormatTag
+      readonly    Length
+      readwrite   LVolume
+      readonly    Paused
+      readonly    Playing
+      readonly    Recording
+      readwrite   RVolume
+      readwrite   SamplesPerSec
+      readwrite   StreamLimit
+      readwrite   UseMemoryStream
+      readonly    WaveStream
+
+
+      AutoUseMemoryStream
+      If set, the component automatically set UseMemoryStream to false when calling
+      LoadFromFile(...).
+
+      AvgBytesPerSec
+      Standard waveform format property.
+
+      BitsPerSample
+      Standard waveform format property. Usually 8, 16 or 24.
+
+      BlockAlign
+      Standard waveform property. Gives the size of a multi-channels sample.
+
+      BlockSize
+      Standard waveform format property. Specifies the size, in bytes, of the data
+      block used for audio recording and playback. In AudioPac42.cpp a total of
+      two data blocks are used.
+
+      BytesPerSample
+      Equals BitsPerSample/8.
+
+      cbSize
+      Standard waveform format property. Reserved.
+
+      Channels
+      Standard waveform format property. Specifies the number of channels.
+
+      FileName
+      The name of the file last loaded or inserted into this waveform.
+
+      FormatTag
+      Standard waveform format property. Must be WAVE_FORMAT_PCM.
+
+      Length
+      The length of waveform data held, in multi-channel samples.
+
+      LVolume
+      Specifies the playback volume of left channel.
+
+      Paused
+      Gives whether the playback is being suspended in pause mode.
+
+      Playing
+      Gives whether the playback is in progress, whether or not suspended in pause
+      mode.
+
+      Recording
+      Gives whether the recording is in progress.
+
+      RVolume
+      Specifies the playback volume of right channel.
+
+      SamplesPerSec
+      Standard waveform format property. As is.
+
+      StreamLimit
+      This property provides a way to control the size of wave stream. If StreamLimit>0,
+      TWaveAudio will generate an StreamFull event when the size of wave stream
+      goes above StreamLimit. StreamLimit is set to zero by default.
+
+      UseMemoryStream
+      Specifies whether the component loads the data samples into a memory stream.
+      If UseMemoryStream is set, a MemoryStream object is used to store the data
+      samples in the memroy. If UseMemoryStream is set to false, the WaveAudio must
+      be working on a wave file, where data samples are read from. Recording is
+      not allowed when UseMemoryStream is false.
+
+      WaveStream
+      The pointer to the Stream object that holds the data samples. If UseMemoryStream
+      is true, the stream is a MemoryStream. If false, the stream is an AttachFileStream,
+      which is based on a FileStream. The data samples are stored right from the
+      beginning of WaveStream.
+
+
+    Methods:
+
+      TWaveAudio & ~TWaveAudio
+      Default constructor and destructor.
+
+      void Clear();
+      void CloseFile(bool Close);
+      void CopyFrom(TStream* AStream, int Count);
+      void CopyFrom(TWaveAudio* AWaveAudio, int Count);
+      void CopySamplesFrom(TStream* AStream, int Count);
+      void CopySamplesFrom(TWaveAudio* AWaveAudio, int Count);
+      void CreateFile(AnsiString FileName);
+      void GetWaveProperties(TWaveAudio* WaveAudio1);
+      void InsertFromFile(AnsiString FileName);
+      bool IsValidWave(AnsiString FileName);
+      void LoadFromFile(AnsiString FileName);
+      void Pause();
+      void PausePlayback();
+      void PauseRecording();
+      void Play();
+      void Play(TNotifyEvent AnOnPlaybackDone);
+      int Read(void* Buffer, int Count);
+      bool ReadHeader(TStream* AStream, __int32& length, bool allowunfinisheddata);
+      int ReadSamples(void* Buffer, int Count);
+      int ReadSamples(double* Buffer, int Count);
+      int ReadSamplesMultiChannel(int C, void** Buffer, int Count);
+      int ReadSamplesMultiSingle(void* Buffer, int Channel, int Count);
+      int ReadSamplesInterleave(void* Buffer1, void* Buffer2, int Count);
+      void Restart();
+      void Rewind();
+      void SaveHeader(TStream* AStream);
+      void SaveToFile(AnsiString FileName);
+      void Seek(int Offset, WORD Origin);
+      void SeekSamples(int Offset, WORD Origin);
+      void StartPlayback();
+      void StartRecording();
+      int Write(void* Buffer, int Count);
+      int WriteSamples(void* Buffer, int Count);
+      int WriteSamples(double* Buffer, int Count);
+      int WriteSamplesInterleave(void* Buffer1, void* Buffer2, int Count);
+      int WriteSamplesInterleave(double* Buffer1, double* Buffer2, int Count);
+
+      Clear()
+      Clear the stored sound in the stream. Be cautious using Clear() when UseMemoryStream
+      is true.
+
+      CloseFile(bool Close)
+      Effective only if UseMemoryStream is false. A call to this method flushes the
+      audio content to the current working FileStream, closes the file handle of,
+      and reopens the audio file as a new FileStream if Close is false.
+
+      CopyFrom(TStream* AStream, int Count)
+      The same as WaveStream->CopyFrom(AStream, Count)
+
+      CopyFrom(TWaveAudio* AWaveAudio, int Count)
+      The same as WaveStream->CopyFrom(AWaveAudio->WaveStream, Count)
+
+      CopySamplesFrom(TStream* AStream, int Count)
+      Similar to CopyFrom(AStream, Count), yet Count indicates the number of multi-channel
+      samples to be copied, not bytes.
+
+      CopySamplesFrom(TWaveAudio* AWaveAudio, int Count)
+      Similar to CopyFrom(AWaveAudio, Count), yet Count indicates the numbet of
+      multi-channel samples to be copied, not bytes.
+
+      CreateFile(AnsiString FileName)
+      Creates a new empty audio file as the current working audio stream.
+
+      GetWaveProperties(TWaveAudio* WaveAudio1)
+      Fill the standard waveform audio properties with those of WaveAudio1.
+
+      InsertFromFile(AnsiString FileName)
+      Loads in a wave file while giving up the previous content. It also sets the
+      FileName property.
+
+      IsValidWave(AnsiString FileName)
+      Judge if a file specified with FileName is an valid waveform audio file.
+
+      LoadFromFile(AnsiString FileName)
+      Almost the same as InsertFromFile(...) but triggers the OnBeforeLoad and OnLoad events
+      as well.
+
+      Pause()
+      Suspends on-going playback in pause mode. It sets Paused property.
+
+      PausePlayback()
+      Terminate playback. It also resets the Playing property and triggers an OnPlaybackDone
+      event.
+
+      PauseRecording()
+      Terminate recording. It also resets the Recording property.
+
+      Play()
+      Rewind() then StartPlayback().
+
+      Play(TNotifyEvent AnOnPlaybackDone)
+      Rewind() then StartPlayback() with AnOnPlaybackDone assigned to OnPlaybackDone
+      event. It is recommended that OnPlaybackDone be assigned at designtime rather
+      than at runtime.
+
+      Read(void* Buffer, int Count)
+      The same as WaveStream->Read(Buffer, Count).
+
+      ReadHeader(TStream* AStream, __int32& length, bool allowunfinisheddata)
+      Reads RIFF waveform header from AStream.
+
+      ReadSamples(void* Buffer, int Count)
+      ReadSamples(double* Buffer, int Count);
+      Similar to Read(...), but Count is given in multi-channel samples, not in bytes.
+
+      ReadSamplesInterleave(void* Buffer1, void* Buffer2, int Count)
+      ReadSamplesInterleave(double* Buffer1, double* Buffer2, int Count)
+      Reads interleaved stereo data into two data buffers.
+
+      ReadSamplesMultiChannel(int C, void** Buffer, int Count)
+      Reads multi-channel audio stream into multiple buffers, one for each channel.
+
+      ReadSamplesMultiSingle(void* Buffer, int Channel, int Count)
+      Reads the data of one channel from a multi-channel WaveAudio into a data buffer.
+
+      Restart()
+      Resumes playback suspended in pause mode. It resets Paused property as well.
+
+      Rewind()
+      Set the position of Stream to the beginning.
+
+      SaveHeader(TStream* AStream)
+      Saves RIFF waveform header to AStream.
+
+      SaveToFile(AnsiString FileName)
+      Saves current waveform stream to disk as a wave file.
+
+      Seek(int Offset, WORD Origin)
+      The same as WaveStream->Seek(Offset, Origin).
+
+      SeekSamples(int Offset, WORD Origin)
+      Similar to Seek(Offset, Origin), yet Offset is of the number of multi-channel samples,
+        not bytes.
+
+      StartPlayback()
+      Start playback, starting from the current position of wave stream. It sets
+      Playing property. When playback is done, a PlaybackDone event is triggered
+      Playing is reset.
+
+      StartRecording()
+      Start recording. New data will be written to stream from the current position.
+      Old data, if any, are overwritten. It sets the property Recording. Be cautious
+      using StartRecording() when UseMemoryStream is true.
+
+      Write(void* Buffer, int Count)
+      The same as WaveStream->Write(Buffer, Count). Be cautious using Write(...)
+      when UseMemoryStream is false as in this case the audio file is overwritten.
+
+      WriteSamples(void* Buffer, int Count)
+      WriteSamples(double* Buffer, int Count)
+      Similar to Write(...), but Count is given in multi-channel samples, not in
+      bytes. By cautious using WriteSamples when UseMemoryStream is false as in
+      this case the audio file is overwritten.
+
+      WriteSamplesInterleave(void* Buffer1, void* Buffer2, int Count)
+      WriteSamplesInterleave(double* Buffer1, double* Buffer2, int Count)
+      Writes stereo data in two data buffers into the interleaved format of WaveAudio.
+      Be cautious using WriteSamplesInterleave when UseMemoryStream is false as
+      in this case the audio file is overwritten.
+
+
+    Events:
+
+      OnAudioChange
+      OnBeforeLoad
+      OnInAddBuffer
+      OnLoad
+      OnOutWrite
+      OnPlaybackDone
+      OnPlaybackProg
+      OnPlaybackProgress
+      OnRecordingDone
+      OnStartPlayback
+      OnStartRecording
+      OnStreamFull
+      OnStreamLimitFailure
+
+
+      OnAudioChange
+      Triggered when the contents of the audio changes.  This happens in the following cases:
+        1. InsertFromFile method is called.
+        2. A recording is finished.
+        3. CopyFrom or CopySamplesFrom method is called.
+        4. Clear method is called.
+      The change of audio content by calling methods of WaveAudio is not informed by this event.
+
+      OnBeforeLoad
+      Triggered when a wave file is to be loaded.
+
+      OnInAddBuffer
+      Triggered after a block received from the WaveIn device is released into local
+      data memory and the data block is returned to the WaveIn device. Handle this
+      event to access the latest received data in real time.
+
+      OnLoad
+      Triggered when a wave file is loaded.
+
+      OnOutWrite
+      Triggered when a data block has been sent to the WaveOut device.
+
+      OnPlaybackDone
+      Triggered when playback is finished, whetherever PausePlayback method is called.
+
+      OnPlaybackProg
+      OnPlaybackProgress
+      Triggered after each output data block is sent, and when playback is finished.
+      The two eveent differs in a progress parameter. While OnPlaybackProg uses an
+      integer parameter indicating the progress position in bytes, OnPlaybackProgress
+      uses a floating-point parameter indicating the progress position in percentage.
+
+      OnRecordingDone
+      Triggered when recording is terminated and the WaveIn device is to be closed.
+
+      OnStartPlayback
+      Triggered when playback is started.
+
+      OnStartRecording
+      Triggered when recording is started.
+
+      OnStreamFull
+      Triggered when the size of wave stream exceeds StreamLimit. No other operations
+      are done by TWaveForm. Application must handle this event to perform actual
+      size limit.
+
+      OnStreamLimitFailure
+      Triggered when trying to set StreamLimit to a value smaller than the current
+      size of wave stream. TWaveAudio refuses this operation and generates the event.
+
+
+    Exceptions:
+
+      "Failed opening device WaveIn"
+      Form: StartRecording
+      Thrown on failure of opening waveform audio input device.
+
+      "Failed opening devece WaveOut"
+      From: StartPlayback
+      Thrown on failure of opening waveform audio output device.
+
+
+  Component class TDataAudio
+  TDataAudio is a decendent class of TWaveAudio, providing an CustomFillBlock event
+  to enable on-the-fly data calculation for playback.
+
+  Events:
+
+    CustomFillBlock
+    Triggered when a data block is to be filled by the application before sent to
+    WaveOut device.
+
+  Current version Wen Xue 2009/7
+  First version Wen Xue 2003/3
+*/
+
+//---------------------------------------------------------------------------
+//#include <SysUtils.hpp>
+//#include <Controls.hpp>
+//#include <Classes.hpp>
+//#include <Forms.hpp>
+//#include <Messages.hpp>
+
+#include <mmsystem.h>
+
+//---------------------------------------------------------------------------
+#ifndef INT24
+#define INT24
+struct __int24;
+struct __pint24
+{
+  char* p;
+  __pint24(){}
+  __pint24(const void* ap){p=(char*)ap;}
+  __pint24& operator=(const void* ap){p=(char*)ap; return *this;}
+  __int24& operator*(){return *(__int24*)p;}
+  __int24& operator[](int index){return *(__int24*)&p[3*index];}
+  __pint24 operator++(int){__pint24 result=*this; p+=3; return result;}
+  __pint24& operator++(){p+=3; return *this;}
+  __pint24 operator--(int){__pint24 result=*this; p-=3; return result;}
+  __pint24& operator--(){p-=3; return *this;}
+  __pint24& operator+=(int a){p+=3*a; return *this;}
+  __pint24& operator-=(int a){p-=3*a; return *this;}
+  operator void*() const{return p;}
+};
+struct __int24
+{
+  __int16 loword;
+  __int8 hibyte;
+  __int24(){}
+  __int24(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];}
+  __int24(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];}
+  __int24& operator=(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;}
+  __int24& operator=(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;}
+  __int24& operator+=(const __int32 a){__int32 b=*this; b+=a; loword=*(__int16*)&b; hibyte=((__int16*)&b)[1]; return *this;}
+  __int24& operator-=(const __int32 a){__int32 b=*this; b-=a; loword=*(__int16*)&b; hibyte=((__int16*)&b)[1]; return *this;}
+  __int24& operator*=(const __int32 a){__int32 b=*this; b*=a; loword=*(__int16*)&b; hibyte=((__int16*)&b)[1]; return *this;}
+  operator __int32() const{__int32 result; *(__int16*)&result=loword; ((__int16*)&result)[1]=hibyte; return result;}
+  __pint24 operator &(){return (__pint24)this;}
+  void* operator new[](size_t count){void* result=malloc(3*count); return result;}
+  void operator delete[](void* p){free(p);}
+};
+#endif
+
+
+//---------------------------------------------------------------------------
+void DoubleToIntInterleave(void* _out, int BytesPerSample, double* in1, double* in2, int Count);
+void IntToDoubleInterleave(double* out1, double* out2, void* _in, int BytesPerSample, int Count);
+int IntToIntInterleave(void* dest, int bytesperunit, void* block1, void* block2, int Count);
+int IntToIntInterleave(void* dest1, void* dest2, int bytesperunit, void* block, int Count);
+int IntToIntMultiSingle(void* dest, int bytesperunit, int channels, int channel, void* block, int Count);
+
+typedef void __fastcall (__closure *TWaveAudioPlaybackProgressEvent)(System::TObject* Sender, double PlaybackPosition);
+
+class TAttachFileStream : public TStream
+{
+public:
+  TFileStream* File;
+  int StartOffset;
+  int EndOffset;
+protected:
+  virtual int __fastcall Seek(int AnOffset, Word Origin);
+  virtual __int64 __fastcall Seek(const __int64 AnOffset, TSeekOrigin Origin);
+  virtual int __fastcall Read(void *Buffer, int Count);
+  virtual int __fastcall Write(const void *Buffer, int Count);
+public:
+  __fastcall TAttachFileStream(TFileStream* AFileStream);
+  __fastcall ~TAttachFileStream();
+};
+
+class TWaveView;
+class PACKAGE TWaveAudio : public TComponent
+{
+friend TWaveView;
+
+protected:
+
+    bool FUseMemoryStream;
+    TMemoryStream* FMemoryStream;
+    TAttachFileStream* FFileStream;
+
+    AnsiString FFileName;
+    __int32 FSamplesPerSec;
+    __int16 FBitsPerSample;
+    __int16 FChannels;
+    __int32 FAvgBytesPerSec;
+    __int16 FBlockAlign;
+    __int16 FFormatTag;
+    __int16 FcbSize;
+    unsigned __int16 FLVolume;
+    unsigned __int16 FRVolume;
+    int FStreamLimit;
+    int FBlockSize;
+
+    TNotifyEvent FOnBeforeLoad;
+    TNotifyEvent FOnAudioChange;
+    TNotifyEvent FOnInAddBuffer;
+    TNotifyEvent FOnLoad;
+    TNotifyEvent FOnOutWrite;
+    TNotifyEvent FOnPlaybackDone;
+    TNotifyEvent FOnRecordingDone;
+    TNotifyEvent FOnStartPlayback;
+    TNotifyEvent FOnStartRecording;
+    TNotifyEvent FOnStreamFull;
+    TNotifyEvent FOnStreamLimitFailure;
+
+    TWaveAudioPlaybackProgressEvent FOnPlaybackProgress;
+    TWaveAudioPlaybackProgressEvent FOnPlaybackProg;
+
+    bool FAutoUseMemoryStream;
+    bool FRecording;
+    bool FPlaying;
+    bool FPaused;
+
+    __property TStream* Stream={read=GetStream};
+
+public:
+    HWAVEIN WaveIn;
+    HWAVEOUT WaveOut;
+
+protected:    
+    HWND HWndOut;
+    HWND HWndIn;
+
+    WAVEHDR* WaveHdr1;
+    WAVEHDR* WaveHdr2;
+    void* Buffer1;
+    void* Buffer2;
+    bool  ResetInStream;
+    bool  ResetInUser;
+    bool  ResetOut;
+    bool  ResetOutUser;
+
+protected:
+    virtual void __fastcall SetSamplesPerSec(__int32 ASamplesPerSec);
+    virtual void __fastcall SetBitsPerSample(__int16 ABitsPerSample);
+    virtual void __fastcall SetChannels(__int16 AChannels);
+    virtual void __fastcall SetBlockSize(int ABlockSize);
+    virtual void __fastcall SetStreamLimit(int AStreamLimit);
+    virtual void __fastcall SetLVolume(unsigned __int16 ALVolume);
+    virtual void __fastcall SetRVolume(unsigned __int16 ARVolume);
+    virtual void __fastcall SetUseMemoryStream(bool AUseMemoryStream);
+    virtual int __fastcall FillBlock(void* Block);
+    virtual int __fastcall GetBytesPerSample();
+    virtual __int32 __fastcall GetLength();
+    virtual TStream* __fastcall GetStream();
+    MMRESULT __fastcall SetVolume(void);
+    virtual void __fastcall ReleaseBlock(void* Block, int BytesRecorded);
+
+    virtual void __fastcall OnWomOpen(TMessage& Message);
+    virtual void __fastcall OnWomDone(TMessage& Message);
+    virtual void __fastcall OnWomClose(TMessage& Message);
+    virtual void __fastcall OnWimOpen(TMessage& Message);
+    virtual void __fastcall OnWimData(TMessage& Message);
+    virtual void __fastcall OnWimClose(TMessage& Message);
+    void __fastcall WaveOutProc(TMessage& Message);
+    void __fastcall WaveInProc(TMessage& Message);
+
+public:
+    __property AnsiString FileName={read=FFileName};
+    __property __int32 AvgBytesPerSec={read=FAvgBytesPerSec};
+    __property __int16 BlockAlign={read=FBlockAlign};
+    __property int BytesPerSample={read=GetBytesPerSample};
+    __property __int16 FormatTag={read=FFormatTag};
+    __property __int16 cbSize={read=FcbSize};
+    __property __int32 Length={read=GetLength};
+
+    __property TStream* WaveStream={read=GetStream};
+    __property bool Recording={read=FRecording};
+    __property bool Playing={read=FPlaying};
+    __property bool Paused={read=FPaused};
+
+    virtual __fastcall TWaveAudio(TComponent* Owner);
+    virtual __fastcall ~TWaveAudio();
+
+    void __fastcall Clear(TObject* Sender);
+    void __fastcall CloseFile(bool Close=true);
+    void CopyFrom(TStream* AStream, int Count);
+    void CopyFrom(TWaveAudio* AWaveAudio, int Count);
+    void CopySamplesFrom(TStream* AStream, int Count);
+    void CopySamplesFrom(TWaveAudio* AWaveAudio, int Count);
+    void CreateFile(AnsiString FileName);
+    void GetWaveProperties(TWaveAudio* WaveAudio1);
+    void InsertFromFile(AnsiString FileName);
+    bool IsValidWave(AnsiString FileName);
+    void LoadFromFile(AnsiString FileName);
+    void __fastcall OpenFile(AnsiString AFileName);
+    void __fastcall Pause(TObject* Sender);
+    void __fastcall PausePlayback(TObject* Sender);
+    void __fastcall PauseRecording(TObject* Sender);
+    void __fastcall Play(TObject* Sender);
+    void __fastcall Play(TNotifyEvent AnOnPlaybackDone);
+    int __fastcall Read(void* Buffer, int Count);
+    bool __fastcall ReadHeader(TStream* AStream, __int32& length, bool allowunfinisheddata=false);
+    int __fastcall ReadSamples(void* Buffer, int Count);
+    int __fastcall ReadSamples(double* Buffer, int Count);
+    int __fastcall ReadSamplesInterleave(void* Buffer1, void* Buffer2, int Count);
+    int __fastcall ReadSamplesInterleave(double* Buffer1, double* Buffer2, int Count);
+    int __fastcall ReadSamplesMultiChannel(int C, void** Buffer, int Count);
+    int __fastcall ReadSamplesMultiSingle(void* Buffer, int Channel, int Count);
+    void __fastcall Restart(TObject* Sender);
+    void __fastcall Rewind(TObject* Sender);
+    void __fastcall SaveHeader(TStream* AStream);
+    void __fastcall SaveToFile(AnsiString FileName);
+    void __fastcall Seek(int Offset, WORD Origin);
+    void __fastcall SeekSamples(int Offset, WORD Origin);
+    void __fastcall StartPlayback(TObject* Sender);
+    void __fastcall StartRecording(TObject* Sender);
+    int __fastcall Write(void* Buffer, int Count);
+    int __fastcall WriteSamples(void* Buffer, int Count);
+    int __fastcall WriteSamples(double* Buffer, int Count);
+    int __fastcall WriteSamplesInterleave(void* Buffer1, void* Buffer2, int Count);
+    int __fastcall WriteSamplesInterleave(double* Buffer1, double* Buffer2, int Count);
+
+__published:
+    __property bool AutoUseMemoryStream={read=FAutoUseMemoryStream, write=FAutoUseMemoryStream};
+    __property __int16  BitsPerSample={read=FBitsPerSample,write=SetBitsPerSample,default=8};
+    __property int BlockSize={read=FBlockSize,write=SetBlockSize,default=4096};
+    __property __int16  Channels={read=FChannels,write=SetChannels,default=1};
+    __property unsigned __int16 LVolume={read=FLVolume, write=SetLVolume, default=0xFFFF};
+    __property unsigned __int16 RVolume={read=FRVolume, write=SetRVolume, default=0xFFFF};
+    __property __int32 SamplesPerSec={read=FSamplesPerSec,write=SetSamplesPerSec,default=11025};
+    __property int StreamLimit={read=FStreamLimit,write=SetStreamLimit,default=0};
+    __property bool UseMemoryStream={read=FUseMemoryStream, write=SetUseMemoryStream};
+
+    __property TNotifyEvent OnAudioChange={read=FOnAudioChange,write=FOnAudioChange};
+    __property TNotifyEvent OnBeforeLoad={read=FOnBeforeLoad, write=FOnBeforeLoad};
+    __property TNotifyEvent OnInAddBuffer={read=FOnInAddBuffer, write=FOnInAddBuffer};
+    __property TNotifyEvent OnLoad={read=FOnLoad, write=FOnLoad};
+    __property TNotifyEvent OnOutWrite={read=FOnOutWrite, write=FOnOutWrite};
+    __property TNotifyEvent OnPlaybackDone={read=FOnPlaybackDone,write=FOnPlaybackDone};
+    __property TNotifyEvent OnRecordingDone={read=FOnRecordingDone,write=FOnRecordingDone};
+    __property TNotifyEvent OnStartPlayback={read=FOnStartPlayback, write=FOnStartPlayback};
+    __property TNotifyEvent OnStartRecording={read=FOnStartRecording, write=FOnStartRecording};
+    __property TNotifyEvent OnStreamFull={read=FOnStreamFull,write=FOnStreamFull};
+    __property TNotifyEvent OnStreamLimitFailure={read=FOnStreamLimitFailure,write=FOnStreamLimitFailure};
+    __property TWaveAudioPlaybackProgressEvent OnPlaybackProgress={read=FOnPlaybackProgress, write=FOnPlaybackProgress};
+    __property TWaveAudioPlaybackProgressEvent OnPlaybackProg={read=FOnPlaybackProg, write=FOnPlaybackProg};
+};
+
+typedef int __fastcall (__closure *TDataAudioFillBlockEvent)(void* ABlock);
+
+class TDataAudio : public TWaveAudio
+{
+private:
+  TDataAudioFillBlockEvent FCustomFillBlock;
+protected:
+  virtual int __fastcall FillBlock(void*);
+public:
+  virtual __fastcall TDataAudio(TComponent* Owner);
+__published:
+  __property TDataAudioFillBlockEvent CustomFillBlock={read=FCustomFillBlock, write=FCustomFillBlock};
+};
+
+//---------------------------------------------------------------------------
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BackUpTool.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,120 @@
+/*
+    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>
+#include <filectrl.hpp>
+#include <inifiles.hpp>
+#pragma hdrstop
+
+#include "BackUpTool.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+#pragma link "vclx.lib"
+TBackupForm1 *BackupForm1;
+//---------------------------------------------------------------------------
+__fastcall TBackupForm1::TBackupForm1(TComponent* Owner)
+  : TForm(Owner)
+{
+  AnsiString ApplicationIni=ChangeFileExt(Application->ExeName, ".ini");
+  TIniFile* Ini=new TIniFile(ApplicationIni);
+  ExtText=Ini->ReadString("BackUpForm", "Ext", ".bpr .bpk .dfm .cpp .ini .dsk .h .hpp .res .rc .dcr");
+  Edit1->Text=ExtText;
+	Edit2->Text=Ini->ReadString("BackUpForm", "Rar", "WinRAR.exe");
+	Edit3->Text=Ini->ReadString("BackUpForm", "Directory", ExtractFileDir(Application->ExeName));
+  delete Ini;
+}
+//---------------------------------------------------------------------------
+void __fastcall TBackupForm1::Button1Click(TObject *Sender)
+{
+	AnsiString Exts=Edit1->Text.LowerCase();
+	AnsiString Dir=Edit3->Text;
+  AnsiString TimeString=Now().FormatString("yymmddhhmmss");
+  AnsiString TempDir="C:\\Temp\\"+ExtractFileName(Dir)+TimeString;
+  if (!DirectoryExists(TempDir)) ForceDirectories(TempDir);
+
+  SetCurrentDir(Dir);
+  TSearchRec F;
+  if (FindFirst("*.*", 0x2f, F)==0)
+  {
+    do
+    {
+      AnsiString FileName=F.Name;
+      AnsiString FileExt=ExtractFileExt(FileName).LowerCase();
+      if (Exts.Pos(FileExt)>0)
+      {
+        AnsiString NewFileName=TempDir+"\\"+FileName;
+        CopyFile(FileName.c_str(), NewFileName.c_str(), false);
+      }
+    }
+    while (FindNext(F)==0);
+  }
+
+  AnsiString ArchivName="..\\"+ExtractFileName(Dir)+TimeString+".rar";
+  AnsiString command="\""+Edit2->Text+"\""+" a -r -ep1 "+ArchivName+" "+TempDir;
+  Memo1->Lines->Add(AnsiString(">>")+ExtractFileName(ArchivName)+"...");
+  system(command.c_str());
+  Memo1->Lines->Add(">>");
+  Memo1->Lines->Add("");
+}
+//---------------------------------------------------------------------------
+void __fastcall TBackupForm1::Button2Click(TObject *Sender)
+{
+  Close();  
+}
+//---------------------------------------------------------------------------
+void __fastcall TBackupForm1::Button3Click(TObject *Sender)
+{
+	OpenDialog1->FileName=Edit2->Text;
+	OpenDialog1->FilterIndex=1;
+	if (OpenDialog1->Execute())
+	{
+		Edit2->Text=OpenDialog1->FileName;
+		AnsiString ApplicationIni=ChangeFileExt(Application->ExeName, ".ini");
+		TIniFile* Ini=new TIniFile(ApplicationIni);
+		Ini->WriteString("BackUpForm", "Rar", OpenDialog1->FileName);
+		delete Ini;
+	}
+}
+//---------------------------------------------------------------------------
+void __fastcall TBackupForm1::FormClose(TObject *Sender, TCloseAction &Action)
+{
+	if (Edit1->Text!=ExtText)
+	{
+		ExtText=Edit1->Text;
+		AnsiString ApplicationIni=ChangeFileExt(Application->ExeName, ".ini");
+		TIniFile* Ini=new TIniFile(ApplicationIni);
+		Ini->WriteString("BackUpForm", "Ext", ExtText);
+		Ini->WriteString("BackUpForm", "Directory", Edit3->Text);
+		delete Ini;
+  }
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TBackupForm1::Button4Click(TObject *Sender)
+{
+	OpenDialog1->FilterIndex=2;
+	OpenDialog1->InitialDir=ExtractFileDir(Application->ExeName);
+	if (OpenDialog1->Execute())
+	{
+		Edit3->Text=ExtractFileDir(OpenDialog1->FileName);
+		AnsiString ApplicationIni=ChangeFileExt(Application->ExeName, ".ini");
+		TIniFile* Ini=new TIniFile(ApplicationIni);
+		Ini->WriteString("BackUpForm", "Directory", Edit3->Text);
+		delete Ini;
+	}
+
+}
+//---------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BackUpTool.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,125 @@
+object BackupForm1: TBackupForm1
+  Left = 359
+  Top = 177
+  Caption = 'Project backup tool'
+  ClientHeight = 339
+  ClientWidth = 367
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  OnClose = FormClose
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Label1: TLabel
+    Left = 8
+    Top = 8
+    Width = 58
+    Height = 13
+    Caption = 'Rar archiver'
+  end
+  object Label2: TLabel
+    Left = 8
+    Top = 48
+    Width = 120
+    Height = 13
+    Caption = 'File extensions to backup'
+  end
+  object Label3: TLabel
+    Left = 8
+    Top = 88
+    Width = 76
+    Height = 13
+    Caption = 'Project directory'
+  end
+  object Button1: TButton
+    Left = 8
+    Top = 131
+    Width = 345
+    Height = 25
+    Caption = 'Backup files in the project directory'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -16
+    Font.Name = 'MS Sans Serif'
+    Font.Style = [fsBold]
+    ParentFont = False
+    TabOrder = 0
+    OnClick = Button1Click
+  end
+  object Edit1: TEdit
+    Left = 8
+    Top = 64
+    Width = 345
+    Height = 21
+    TabOrder = 1
+    Text = '.bpr .dfm .cpp .ini .ddp .dsk .h  .res'
+  end
+  object Button2: TButton
+    Left = 8
+    Top = 162
+    Width = 345
+    Height = 49
+    Caption = 'Close'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -32
+    Font.Name = 'MS Sans Serif'
+    Font.Style = []
+    ParentFont = False
+    TabOrder = 2
+    OnClick = Button2Click
+  end
+  object Button3: TButton
+    Left = 304
+    Top = 24
+    Width = 49
+    Height = 25
+    Caption = 'Browse...'
+    TabOrder = 3
+    OnClick = Button3Click
+  end
+  object Edit2: TEdit
+    Left = 8
+    Top = 24
+    Width = 297
+    Height = 21
+    ReadOnly = True
+    TabOrder = 4
+  end
+  object Memo1: TMemo
+    Left = 8
+    Top = 217
+    Width = 345
+    Height = 112
+    Lines.Strings = (
+      'Messages'
+      '')
+    TabOrder = 5
+  end
+  object Edit3: TEdit
+    Left = 8
+    Top = 104
+    Width = 297
+    Height = 21
+    ReadOnly = True
+    TabOrder = 6
+  end
+  object Button4: TButton
+    Left = 304
+    Top = 104
+    Width = 49
+    Height = 25
+    Caption = 'Find...'
+    TabOrder = 7
+    OnClick = Button4Click
+  end
+  object OpenDialog1: TOpenDialog
+    Filter = '*.exe|*.exe|*.cpp|*.cpp'
+    Left = 240
+    Top = 8
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BackUpTool.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,55 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+#ifndef BackUpToolH
+#define BackUpToolH
+//---------------------------------------------------------------------------
+/*
+  BackUpTool.cpp implements a GUI for backing-up the source code of HV
+    project using winrar.exe.
+*/
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <Dialogs.hpp>
+//---------------------------------------------------------------------------
+class TBackupForm1 : public TForm
+{
+__published:	// IDE-managed Components
+  TButton *Button1;
+  TEdit *Edit1;
+  TButton *Button2;
+  TLabel *Label1;
+  TLabel *Label2;
+  TButton *Button3;
+  TEdit *Edit2;
+  TOpenDialog *OpenDialog1;
+  TMemo *Memo1;
+	TLabel *Label3;
+	TEdit *Edit3;
+	TButton *Button4;
+  void __fastcall Button1Click(TObject *Sender);
+  void __fastcall Button2Click(TObject *Sender);
+  void __fastcall Button3Click(TObject *Sender);
+  void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
+	void __fastcall Button4Click(TObject *Sender);
+private:	// User declarations
+  AnsiString ExtText;
+public:		// User declarations
+  __fastcall TBackupForm1(TComponent* Owner);
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TBackupForm1 *BackupForm1;
+//---------------------------------------------------------------------------
+#endif
Binary file Documents/Example.doc has changed
Binary file Documents/QuickStart.1107.doc has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EditorPanelUnit.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,252 @@
+/*
+    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>
+#include <math.h>
+#include <Math.hpp>
+#pragma hdrstop
+
+#include "EditorPanelUnit.h"
+#include "Unit1.h"
+#include "VibratoDemoUnit.h"
+#include "SFDemoUnit.h"
+#include "splines.h"
+#include "hsedit.h"
+
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+TEditorPanel *EditorPanel;
+//---------------------------------------------------------------------------
+__fastcall TEditorPanel::TEditorPanel(TComponent* Owner)
+  : TForm(Owner)
+{
+  target=0;
+  Before=0;
+  HS=0;
+}
+
+__fastcall TEditorPanel::~TEditorPanel()
+{
+  free8(target);
+  delete[] Before;
+  delete HS;
+}
+//---------------------------------------------------------------------------
+  void __fastcall TEditorPanel::AmpEdit1MouseWheel(int zDelta)
+  {
+    double a, db;
+    a=AmpEdit1->Text.ToDouble()*pow((zDelta>0)?2:0.5, 0.1); db=Log10(a)*20;
+    AmpEdit1->Text=a;
+    AmpDBEdit1->Text=db;
+    EditAmplify(a);
+  }
+  void __fastcall TEditorPanel::AMAEdit1MouseWheel(int zDelta)
+  {
+    double dep=AMAEdit1->Text.ToDouble()+((zDelta>0)?0.05:-0.05);
+    if (dep<0) dep=0;
+    AMAEdit1->Text=dep;
+    EditAM(dep, AMFEdit1->Text.ToDouble(), AMPhEdit1->Text.ToDouble());
+  }
+  void __fastcall TEditorPanel::DeFMEdit1MouseWheel(int zDelta)
+  {
+    double a=DeFMEdit1->Text.ToDouble()+((zDelta>0)?0.2:-0.2);
+    if (a<0) a=0;
+    DeFMEdit1->Text=a;
+    EditReFM(a, DeFMEdit2->Text.ToDouble());
+  }
+  void __fastcall TEditorPanel::FMAEdit1MouseWheel(int zDelta)
+  {
+    double a=FMAEdit1->Text.ToDouble()+((zDelta>0)?0.2:-0.2);
+    if (a<0) a=0;
+    FMAEdit1->Text=a;
+    EditFM(a, FMFEdit1->Text.ToDouble(), FMPhEdit1->Text.ToDouble());
+  }
+  void __fastcall TEditorPanel::FMFEdit1MouseWheel(int zDelta)
+  {
+    double fre=FMFEdit1->Text.ToDouble()+((zDelta>0)?0.5:-0.5);
+    if (fre<0) fre=0;
+    FMFEdit1->Text=fre;
+    EditFM(FMAEdit1->Text.ToDouble(), fre, FMPhEdit1->Text.ToDouble());
+  }
+void __fastcall TEditorPanel::WMMouseWheel(TWMMouseWheel Message)
+{
+  int zDelta=Message.WheelDelta;    // wheel rotation
+  if (AmpEdit1->Focused()) AmpEdit1MouseWheel(zDelta);
+  else if (AmpDBEdit1->Focused())
+  {
+    double a, db;
+    db=AmpDBEdit1->Text.ToDouble()+((zDelta>0)?0.5:-0.5); a=pow(10, db/20);
+    AmpEdit1->Text=a;
+    AmpDBEdit1->Text=db;
+    EditAmplify(a);
+  }
+  else if (PitchEdit1->Focused())
+  {
+    double ps=PitchEdit1->Text.ToDouble()+((zDelta>0)?1:-1);
+    PitchEdit1->Text=ps;
+    EditPitchShifting(ps);
+  }
+  else if (AMAEdit1->Focused()) AMAEdit1MouseWheel(zDelta);
+  else if (AMFEdit1->Focused())
+  {
+    double fre=AMFEdit1->Text.ToDouble()+((zDelta>0)?0.5:-0.5);
+    if (fre<0) fre=0;
+    AMFEdit1->Text=fre;
+    EditAM(AMAEdit1->Text.ToDouble(), fre, AMPhEdit1->Text.ToDouble());
+  }
+  else if (AMPhEdit1->Focused())
+  {
+    double ph=AMPhEdit1->Text.ToDouble()+((zDelta>0)?0.1:-0.1);
+    AMPhEdit1->Text=ph;
+    EditAM(AMAEdit1->Text.ToDouble(), AMFEdit1->Text.ToDouble(), ph);
+  }
+  else if (FMAEdit1->Focused()) FMAEdit1MouseWheel(zDelta);
+  else if (FMFEdit1->Focused()) FMFEdit1MouseWheel(zDelta);
+  else if (FMPhEdit1->Focused())
+  {
+    double ph=FMPhEdit1->Text.ToDouble()+((zDelta>0)?0.1:-0.1);
+    FMPhEdit1->Text=ph;
+    EditFM(FMAEdit1->Text.ToDouble(), FMFEdit1->Text.ToDouble(), ph);
+  }
+  else if (DeFMEdit1->Focused()) DeFMEdit1MouseWheel(zDelta);
+  else if (DeFMEdit2->Focused())
+  {
+    double r=DeFMEdit2->Text.ToDouble()+((zDelta>0)?0.1:-0.1);
+    if (r<0.2) r=0.2;
+    DeFMEdit2->Text=r;
+    EditReFM(DeFMEdit1->Text.ToDouble(), r);
+  }
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TEditorPanel::AmpEdit1MouseMove(TObject *Sender,
+      TShiftState Shift, int X, int Y)
+{
+  ((TWinControl*)Sender)->SetFocus();  
+}
+//---------------------------------------------------------------------------
+
+
+
+void __fastcall TEditorPanel::AmpEdit1KeyPress(TObject *Sender, char &Key)
+{
+	if (Key==VK_RETURN)
+  {
+    if (Sender==AmpEdit1) {double a=AmpEdit1->Text.ToDouble(); AmpDBEdit1->Text=double(Log10(a)*20); EditAmplify(a);}
+    else if (Sender==AmpDBEdit1) {double a=pow(10, AmpDBEdit1->Text.ToDouble()/20); AmpEdit1->Text=a; EditAmplify(a);}
+    else if (Sender==PitchEdit1) EditPitchShifting(PitchEdit1->Text.ToDouble());
+    else if (Sender==AMAEdit1 || Sender==AMFEdit1 || Sender==AMPhEdit1) EditAM(AMAEdit1->Text.ToDouble(), AMFEdit1->Text.ToDouble(), AMPhEdit1->Text.ToDouble());
+    else if (Sender==FMAEdit1 || Sender==FMFEdit1 || Sender==FMPhEdit1) EditFM(FMAEdit1->Text.ToDouble(), FMFEdit1->Text.ToDouble(), FMPhEdit1->Text.ToDouble());
+    else if (Sender==DeFMEdit1 || Sender==DeFMEdit2) EditReFM(DeFMEdit1->Text.ToDouble(), DeFMEdit2->Text.ToDouble());
+  }
+  else if ((Key<'0' || Key>'9') && Key!='.' && Key!='-' && Key!=VK_BACK) Key=NULL; 
+}
+//---------------------------------------------------------------------------
+
+
+
+double* SynthesisHSp(THS* HS, int& dst, int& den);
+void __fastcall TEditorPanel::EditAmplify(double a)
+{
+  for (int m=0; m<HS->M; m++) for (int fr=0; fr<HS->Fr; fr++) HS->Partials[m][fr].a=Form1->HS->Partials[m][fr].a*a;
+
+	double* data=SynthesisHSp(HS, dst, den);
+  int L=To-From;
+  for (int i=0; i<L; i++) data[i]=Before[i]-target[i]+data[i];
+  Form1->PostWaveViewData(data, Channel, From, To, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+  free8(data);
+}
+
+void __fastcall TEditorPanel::EditAM(double dep, double fre, double ph_00)
+{
+	HSAM(HS, Form1->HS, dep, fre/Form1->WaveView1->SamplesPerSec, ph_00*2*M_PI);
+	double* data=SynthesisHS(HS, dst, den);
+	int L=To-From; for (int i=0; i<L; i++) data[i]=Before[i]-target[i]+data[i];
+  Form1->PostWaveViewData(data, Channel, From, To, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+  free8(data);
+}
+
+void __fastcall TEditorPanel::EditFM(double a, double fre, double ph_00)
+{
+  HSFM(HS, Form1->HS, a, fre/Form1->WaveView1->SamplesPerSec, ph_00*2*M_PI);
+
+	double* data=SynthesisHS(HS, dst, den);
+	int L=To-From; for (int i=0; i<L; i++) data[i]=Before[i]-target[i]+data[i];
+	Form1->PostWaveViewData(data, Channel, From, To, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+	free8(data);
+}
+
+void __fastcall TEditorPanel::EditPitchShifting(double ps12)
+{
+	HSPitchShift(HS, Form1->HS, ps12);
+
+	double* data=SynthesisHS(HS, dst, den);
+  int L=To-From;
+  if (PitchCheck1->Checked) for (int i=0; i<L; i++) data[i]=Before[i]+data[i];
+  else for (int i=0; i<L; i++) data[i]=Before[i]-target[i]+data[i];
+  Form1->PostWaveViewData(data, Channel, From, To, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+  free8(data);
+}
+
+void __fastcall TEditorPanel::EditReFM(double amp, double rate)
+{
+  ReFM(Form1->HS->M, Form1->HS->Fr, Form1->HS->Partials, HS->Partials, amp, rate);
+	double* data=SynthesisHS(HS, dst, den);
+
+  int L=To-From;
+
+  for (int i=0; i<L; i++) data[i]=Before[i]-target[i]+data[i];
+  Form1->PostWaveViewData(data, Channel, From, To, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+	free8(data);
+}
+
+  void ClearObjectByShortTag0(TWaveView* WV, int tag0);
+void __fastcall TEditorPanel::FormClose(TObject *Sender, TCloseAction &Action)
+{
+  if (ModalResult==mrCancel) Form1->PostWaveViewData(Before, Channel, From, To);
+  else
+  {
+    DeAlloc2(Form1->HS->Partials);
+    Form1->HS->Channel=HS->Channel; Form1->HS->M=HS->M; Form1->HS->Fr=HS->Fr; Allocate2(atom, HS->M, HS->Fr, Form1->HS->Partials);
+    for (int m=0; m<HS->M; m++) memcpy(Form1->HS->Partials[m], HS->Partials[m], sizeof(atom)*HS->Fr);
+    ClearObjectByShortTag0(Form1->WaveView1, 1);
+    Form1->AddHSObject(Form1->HS);
+  }
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TEditorPanel::SpeedButton1Click(TObject *Sender)
+{
+  ModalResult=mrOk;
+  Close();  
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TEditorPanel::SpeedButton2Click(TObject *Sender)
+{
+  ModalResult=mrCancel;
+  Close();
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TEditorPanel::SpeedButton4Click(TObject *Sender)
+{
+  for (int m=0; m<HS->M; m++) memcpy(HS->Partials[m], Form1->HS->Partials[m], sizeof(atom)*HS->Fr);
+  Form1->PostWaveViewData(Before, Channel, From, To);
+}
+//---------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EditorPanelUnit.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,380 @@
+object EditorPanel: TEditorPanel
+  Left = 401
+  Top = 236
+  BorderStyle = bsToolWindow
+  Caption = 'Editor panel'
+  ClientHeight = 181
+  ClientWidth = 313
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnClose = FormClose
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Panel2: TPanel
+    Left = 0
+    Top = 0
+    Width = 313
+    Height = 161
+    Align = alTop
+    BevelOuter = bvLowered
+    Caption = 'Panel2'
+    TabOrder = 1
+    object PageControl1: TPageControl
+      Left = 1
+      Top = 1
+      Width = 311
+      Height = 159
+      ActivePage = DeFMSheet
+      Align = alClient
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'MS Sans Serif'
+      Font.Style = []
+      MultiLine = True
+      ParentFont = False
+      TabOrder = 0
+      object AmplifySheet: TTabSheet
+        Caption = 'Amplify'
+        ExplicitLeft = 0
+        ExplicitTop = 0
+        ExplicitWidth = 0
+        ExplicitHeight = 0
+        object Label1: TLabel
+          Left = 96
+          Top = 64
+          Width = 13
+          Height = 13
+          Caption = 'dB'
+        end
+        object AmpEdit1: TEdit
+          Left = 16
+          Top = 32
+          Width = 105
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 0
+          Text = '1.0'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+        object AmpDBEdit1: TEdit
+          Left = 16
+          Top = 64
+          Width = 73
+          Height = 19
+          BevelInner = bvNone
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 1
+          Text = '0.0'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+      end
+      object PitchSheet: TTabSheet
+        Caption = 'Pitch Shifting'
+        ImageIndex = 1
+        ExplicitLeft = 0
+        ExplicitTop = 0
+        ExplicitWidth = 0
+        ExplicitHeight = 0
+        object Label5: TLabel
+          Left = 104
+          Top = 32
+          Width = 42
+          Height = 13
+          Caption = 'semitone'
+        end
+        object PitchEdit1: TEdit
+          Left = 16
+          Top = 32
+          Width = 81
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 0
+          Text = '0'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+        object PitchCheck1: TCheckBox
+          Left = 16
+          Top = 64
+          Width = 97
+          Height = 17
+          Caption = 'Duplicate'
+          TabOrder = 1
+        end
+      end
+      object AMSheet: TTabSheet
+        Caption = 'AM'
+        ImageIndex = 2
+        ExplicitLeft = 0
+        ExplicitTop = 0
+        ExplicitWidth = 0
+        ExplicitHeight = 0
+        object TLabel
+          Left = 120
+          Top = 48
+          Width = 11
+          Height = 13
+          Caption = 'hz'
+        end
+        object Label6: TLabel
+          Left = 16
+          Top = 16
+          Width = 29
+          Height = 13
+          Caption = 'Depth'
+        end
+        object Label7: TLabel
+          Left = 8
+          Top = 48
+          Width = 50
+          Height = 13
+          Caption = 'Frequency'
+        end
+        object Label10: TLabel
+          Left = 24
+          Top = 80
+          Width = 30
+          Height = 13
+          Caption = 'Phase'
+        end
+        object Label11: TLabel
+          Left = 120
+          Top = 80
+          Width = 21
+          Height = 14
+          Caption = #215'2'#960
+          FocusControl = AMAEdit1
+          Font.Charset = ANSI_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Marlett'
+          Font.Style = []
+          ParentFont = False
+        end
+        object AMAEdit1: TEdit
+          Left = 56
+          Top = 16
+          Width = 57
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 0
+          Text = '0'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+        object AMFEdit1: TEdit
+          Left = 72
+          Top = 48
+          Width = 41
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 1
+          Text = '4'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+        object AMPhEdit1: TEdit
+          Left = 64
+          Top = 80
+          Width = 49
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 2
+          Text = '0'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+      end
+      object FMSheet: TTabSheet
+        Caption = 'FM'
+        ImageIndex = 3
+        ExplicitLeft = 0
+        ExplicitTop = 0
+        ExplicitWidth = 0
+        ExplicitHeight = 0
+        object TLabel
+          Left = 120
+          Top = 48
+          Width = 11
+          Height = 13
+          Caption = 'hz'
+        end
+        object Label2: TLabel
+          Left = 120
+          Top = 16
+          Width = 42
+          Height = 13
+          Caption = 'semitone'
+        end
+        object Label8: TLabel
+          Left = 16
+          Top = 16
+          Width = 29
+          Height = 13
+          Caption = 'Depth'
+        end
+        object Label9: TLabel
+          Left = 8
+          Top = 48
+          Width = 50
+          Height = 13
+          Caption = 'Frequency'
+        end
+        object Label12: TLabel
+          Left = 24
+          Top = 80
+          Width = 30
+          Height = 13
+          Caption = 'Phase'
+        end
+        object Label13: TLabel
+          Left = 120
+          Top = 80
+          Width = 21
+          Height = 14
+          Caption = #215'2'#960
+          FocusControl = AMAEdit1
+          Font.Charset = ANSI_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Marlett'
+          Font.Style = []
+          ParentFont = False
+        end
+        object FMAEdit1: TEdit
+          Left = 56
+          Top = 16
+          Width = 57
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 0
+          Text = '0'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+        object FMFEdit1: TEdit
+          Left = 72
+          Top = 48
+          Width = 41
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 1
+          Text = '4'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+        object FMPhEdit1: TEdit
+          Left = 64
+          Top = 80
+          Width = 49
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 2
+          Text = '0'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+      end
+      object DeFMSheet: TTabSheet
+        Caption = 'De-FM'
+        ImageIndex = 4
+        object Label3: TLabel
+          Left = 23
+          Top = 34
+          Width = 27
+          Height = 13
+          Caption = 'depth'
+        end
+        object Label4: TLabel
+          Left = 32
+          Top = 72
+          Width = 18
+          Height = 13
+          Caption = 'rate'
+        end
+        object DeFMEdit1: TEdit
+          Left = 56
+          Top = 32
+          Width = 57
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 0
+          Text = '1'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+        object DeFMEdit2: TEdit
+          Left = 56
+          Top = 72
+          Width = 57
+          Height = 19
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 1
+          Text = '1'
+          OnKeyPress = AmpEdit1KeyPress
+          OnMouseMove = AmpEdit1MouseMove
+        end
+      end
+    end
+  end
+  object Panel1: TPanel
+    Left = 0
+    Top = 146
+    Width = 313
+    Height = 35
+    Align = alBottom
+    BevelOuter = bvNone
+    TabOrder = 0
+    object SpeedButton1: TSpeedButton
+      Left = 6
+      Top = 0
+      Width = 97
+      Height = 25
+      Caption = 'Apply'
+      Flat = True
+      OnClick = SpeedButton1Click
+    end
+    object SpeedButton2: TSpeedButton
+      Left = 195
+      Top = 0
+      Width = 97
+      Height = 25
+      Caption = 'Cancel'
+      Flat = True
+      OnClick = SpeedButton2Click
+    end
+    object SpeedButton4: TSpeedButton
+      Left = 101
+      Top = 0
+      Width = 97
+      Height = 25
+      Caption = 'Discard'
+      Flat = True
+      OnClick = SpeedButton4Click
+    end
+  end
+  object OpenDialog1: TOpenDialog
+    Left = 5
+    Top = 113
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EditorPanelUnit.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,116 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+
+#ifndef EditorPanelUnitH
+#define EditorPanelUnitH
+//---------------------------------------------------------------------------
+/*
+  EditorPanelUnit.cpp implements the Editor panel GUI of HV.
+*/
+
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <Buttons.hpp>
+#include <ComCtrls.hpp>
+#include <ExtCtrls.hpp>
+#include "EventBoxUnit.h"
+#include <Dialogs.hpp>
+//---------------------------------------------------------------------------
+class TEditorPanel : public TForm
+{
+__published:	// IDE-managed Components
+  TPanel *Panel1;
+  TSpeedButton *SpeedButton1;
+  TSpeedButton *SpeedButton2;
+  TPanel *Panel2;
+  TPageControl *PageControl1;
+  TTabSheet *AmplifySheet;
+  TLabel *Label1;
+  TEdit *AmpEdit1;
+  TEdit *AmpDBEdit1;
+  TTabSheet *PitchSheet;
+  TEdit *PitchEdit1;
+  TCheckBox *PitchCheck1;
+  TTabSheet *AMSheet;
+  TEdit *AMAEdit1;
+  TEdit *AMFEdit1;
+  TTabSheet *FMSheet;
+  TLabel *Label2;
+  TEdit *FMAEdit1;
+  TEdit *FMFEdit1;
+  TTabSheet *DeFMSheet;
+  TLabel *Label3;
+  TLabel *Label4;
+  TEdit *DeFMEdit1;
+  TEdit *DeFMEdit2;
+  TLabel *Label5;
+  TLabel *Label6;
+  TLabel *Label7;
+  TLabel *Label8;
+  TLabel *Label9;
+  TLabel *Label10;
+  TEdit *AMPhEdit1;
+  TLabel *Label11;
+  TLabel *Label12;
+  TEdit *FMPhEdit1;
+  TLabel *Label13;
+  TOpenDialog *OpenDialog1;
+  TSpeedButton *SpeedButton4;
+  void __fastcall AmpEdit1MouseMove(TObject *Sender, TShiftState Shift,
+          int X, int Y);
+  void __fastcall AmpEdit1KeyPress(TObject *Sender, char &Key);
+  void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
+  void __fastcall SpeedButton1Click(TObject *Sender);
+  void __fastcall SpeedButton2Click(TObject *Sender);
+  void __fastcall SpeedButton4Click(TObject *Sender);
+private:	// User declarations
+public:		// User declarations
+  int From;
+  int To;
+  int FromAfter;
+  int ToAfter;
+  int Channel;
+  int targettype;
+  __int16* Before;
+  double* target;
+  int dst;
+  int den;
+  __fastcall TEditorPanel(TComponent* Owner);
+  __fastcall ~TEditorPanel();
+
+  void __fastcall WMMouseWheel(TWMMouseWheel Message);
+  void __fastcall AmpEdit1MouseWheel(int);
+  void __fastcall AMAEdit1MouseWheel(int);
+  void __fastcall DeFMEdit1MouseWheel(int);
+  void __fastcall FMAEdit1MouseWheel(int);
+  void __fastcall FMFEdit1MouseWheel(int);
+
+  void __fastcall EditAmplify(double a);
+  void __fastcall EditPitchShifting(double ps);
+  void __fastcall EditAM(double dep, double fre, double ph);
+  void __fastcall EditFM(double dep, double fre, double ph);
+  void __fastcall EditReFM(double a, double r);
+  THS* HS;
+
+BEGIN_MESSAGE_MAP
+  MESSAGE_HANDLER(WM_MOUSEWHEEL, TWMMouseWheel, WMMouseWheel)
+END_MESSAGE_MAP(TComponent)
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TEditorPanel *EditorPanel;
+//---------------------------------------------------------------------------
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EventBoxUnit.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,301 @@
+/*
+    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 "EventBoxUnit.h"
+#include "WaveView.h"
+#include "Unit1.h"
+#include "EditorPanelUnit.h"
+#include <Math.hpp>
+#include <math.h>
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+TEventBox *EventBox;
+//---------------------------------------------------------------------------
+__fastcall TEventBox::TEventBox(TComponent* Owner)
+  : TForm(Owner)
+{
+  HSCapacity=100;
+  HSCount=0;
+  HS=(THS**)malloc(sizeof(THS*)*HSCapacity);
+  memset(HS, 0, sizeof(THS*)*HSCapacity);
+}
+
+__fastcall TEventBox::~TEventBox()
+{
+  Clear();
+  free(HS);
+}
+
+void __fastcall TEventBox::Clear()
+{
+  ListBox1->Clear();
+  for(int i=0; i<HSCount; i++) delete HS[i];
+  HSCount=0;
+}
+//---------------------------------------------------------------------------
+THS* __fastcall TEventBox::NewHS(int M, int Fr)
+{
+  if (HSCount>=HSCapacity)
+  {
+    HSCapacity+=100;
+    HS=(THS**)realloc(HS, sizeof(THS*)*HSCapacity);
+    memset(&HS[HSCount], 0, sizeof(THS*)*(HSCapacity-HSCount));
+  }
+  THS* newhs;
+  if (M>0 && Fr>0) newhs=new THS(M, Fr);
+  else newhs=new THS;
+  HS[HSCount++]=newhs;
+  if (ListBox1->Enabled)
+  {
+    ListBox1->Items->Add("");
+    ListBox1->ItemIndex=ListBox1->Count-1;
+  }
+  return newhs;
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TEventBox::ListBox1MouseDown(TObject *Sender,
+      TMouseButton Button, TShiftState Shift, int X, int Y)
+{
+  int c=ListBox1->ItemAtPos(TPoint(X, Y), true);
+  SetItemIndex(c);
+}
+//---------------------------------------------------------------------------
+  void ClearObjectByShortTag0(TWaveView* WV, int tag0);
+void __fastcall TEventBox::SetItemIndex(int index)
+{
+  ListBox1->ItemIndex=index;
+  ClearObjectByShortTag0(Form1->WaveView1, 1);
+  if (index>=0)
+  {
+    Form1->HS=HS[index];
+    Form1->AddHSObject(Form1->HS);
+  }
+  else
+  {
+    Form1->HS=0;
+  }
+
+  bool alreadyinvalidated=false;
+  if (CheckBox1->Checked && Form1->HS)
+  {
+    TWaveView* WaveView1=Form1->WaveView1;
+    int eventst=Form1->HS->Partials[0][0].t, eventen=Form1->HS->Partials[0][Form1->HS->Fr-1].t,
+        wvlen=WaveView1->EndPos-WaveView1->StartPos;
+    if (eventst>WaveView1->EndPos || eventen<WaveView1->StartPos)
+    {
+      int newst=(eventst+eventen)/2-wvlen/2, newen=newst+wvlen;
+      if (newst<0) newst=0, newen=wvlen;
+      else if (newen>WaveView1->Length) newen=WaveView1->Length, newst=WaveView1->Length-wvlen;
+      WaveView1->SetStartAndEndPos(newst, newen);
+      alreadyinvalidated=true;
+    }
+  }
+  if (!alreadyinvalidated) Form1->WaveView1->Invalidate();
+}
+//---------------------------------------------------------------------------
+void __fastcall TEventBox::Save(TObject *Sender)
+{
+  Sort();
+  AnsiString FileName=ChangeFileExt(Form1->WaveAudio1->FileName, ".evt");
+  if (FileExists(FileName))
+  {
+    AnsiString BakName=ChangeFileExt(FileName, ".evt.bak."+Now().FormatString("yymmddhhnnss"));
+    RenameFile(FileName, BakName);
+  }
+  SaveToFile(FileName);
+}
+//---------------------------------------------------------------------------
+void __fastcall TEventBox::Load(TObject *Sender)
+{
+  LoadFromFile(ChangeFileExt(Form1->WaveAudio1->FileName, ".evt"));
+}
+//---------------------------------------------------------------------------
+void __fastcall TEventBox::Sort()
+{
+  for (int i=0; i<HSCount-1; i++)
+  {
+    int indmint=i;
+    for (int j=i+1; j<HSCount; j++) if (HS[j]->Partials[0][0].t<HS[indmint]->Partials[0][0].t) indmint=j;
+
+    if (indmint!=i)
+    {
+      THS* tmphs=HS[i];
+      HS[i]=HS[indmint];
+      HS[indmint]=tmphs;
+      AnsiString tmpstr=ListBox1->Items->Strings[i];
+      ListBox1->Items->Strings[i]=ListBox1->Items->Strings[indmint];
+      ListBox1->Items->Strings[indmint]=tmpstr;
+    }
+  }
+}
+
+void __fastcall TEventBox::SaveToFile(AnsiString FileName)
+{
+  TFileStream* File=new TFileStream(FileName, fmCreate);
+  File->Write(&HSCount, sizeof(int));
+  for (int i=0; i<HSCount; i++) HS[i]->WriteToStream(File);
+  delete File;
+}
+
+void __fastcall TEventBox::LoadFromFile(AnsiString FileName)
+{
+  Clear(); SetItemIndex(-1);
+  if (!FileExists(FileName)) return;
+  TFileStream* File=new TFileStream(FileName, fmOpenRead);
+  __int32 hsc; File->Read(&hsc, sizeof(__int32));
+  bool counted=memcmp(&hsc, "EVT", 4);
+  if (!counted) File->Seek(-4, soFromCurrent);
+  ListBox1->Enabled=false;
+
+  int i=0;
+  while (!counted || i<hsc)
+  {
+    THS* hs=NewHS(0, 0);
+    if (!hs->ReadFromStream(File))
+    {
+      if (!counted)
+      {
+        delete HS[i];
+        HSCount--;
+        break;
+      }
+      else
+      { //load old format file
+        char c[5]; c[4]=0;
+        int Channel, M, Fr;
+        File->Read(c, 4);
+        File->Read(&Channel, sizeof(int));
+        File->Read(&M, sizeof(int));
+        File->Read(&Fr, sizeof(int));
+        hs->Resize(M, Fr);
+        hs->Channel=Channel;
+        File->Read(hs->Partials[0], sizeof(atom)*M*Fr);
+        File->Read(c, 4);
+        if (strcmp(c, "EVT ")) hs->isconstf=*(int*)c;
+        else File->Seek(-4, soFromCurrent);
+      }
+    }
+    i++;
+  }
+  delete File;
+  TStringList* List=new TStringList;
+
+  for (int i=0; i<HSCount; i++)
+  {
+    List->Add(AnsiString(i)+" "+
+    (HS[i]->Channel==0?"left: ":"right: ")
+      +AnsiString().sprintf("%.2fs, ", HS[i]->Partials[0][0].t*1.0/Form1->WaveView1->SamplesPerSec)
+      +SemitoneToPitch(Log2(HS[i]->Partials[0][0].f*Form1->WaveView1->SamplesPerSec/C4)*12)
+    );
+  }
+    ListBox1->Items=List;
+    delete List;
+  ListBox1->Enabled=true;
+  SetItemIndex(-1);
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TEventBox::ListBox1KeyUp(TObject *Sender, WORD &Key,
+      TShiftState Shift)
+{
+  int LII=ListBox1->ItemIndex;
+  if (Key==VK_DELETE)
+  {
+    if (LII>=0)
+    {
+      delete HS[LII];
+      HSCount-=1;
+      memcpy(&HS[LII], &HS[LII+1], sizeof(THS*)*(HSCount-LII));
+      ListBox1->Items->Delete(LII);
+      ClearObjectByShortTag0(Form1->WaveView1, 1);
+      Form1->HS=0;
+      Form1->WaveView1->Invalidate();
+    }
+  }
+  else if (Key=='L') Load(NULL);
+  else if (Key=='S') Save(NULL);
+  else
+  {
+  }
+  LII=ListBox1->ItemIndex;
+  if (LII>=0 && Form1->HS!=HS[LII]) SetItemIndex(LII);
+  else if (LII<0 && Form1->HS!=0) SetItemIndex(LII);
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TEventBox::Vibratowizard1Click(TObject *Sender)
+{
+  if (Form1->Vibratowizard1->Enabled) Form1->Vibratowizard1Click(Sender);
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TEventBox::ListBox1DblClick(TObject *Sender)
+{
+	if (Form1->Vibratowizard1->Enabled)
+	{
+		if (GetKeyState(VK_SHIFT)>=0)
+			Form1->Sourcefilter1Click(Vibratowizard1);
+		else
+			Form1->Vibratowizard1Click(Vibratowizard1);
+	}
+}
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+
+void __fastcall TEventBox::FormClick(TObject *Sender)
+{
+  SetItemIndex(-1);  
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TEventBox::Cut1Click(TObject *Sender)
+{
+  if (Form1->Cut1->Enabled) Form1->Cut1Click(Sender);
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TEventBox::PopupMenu1Popup(TObject *Sender)
+{
+  bool hasselection=ListBox1->ItemIndex>=0;
+  Vibratowizard1->Visible=hasselection;
+  Sourcefilter1->Visible=hasselection;
+  Extract1->Visible=hasselection;
+  Cut1->Visible=hasselection;;
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TEventBox::Extract1Click(TObject *Sender)
+{
+  if (Form1->Extract1->Enabled) Form1->Extract1Click(Sender);
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TEventBox::Sourcefilter1Click(TObject *Sender)
+{
+	if (Form1->Vibratowizard1->Enabled)
+  	Form1->Sourcefilter1Click(Vibratowizard1);
+}
+//---------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EventBoxUnit.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,86 @@
+object EventBox: TEventBox
+  Left = 963
+  Top = 83
+  Caption = 'EventBox'
+  ClientHeight = 511
+  ClientWidth = 160
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnClick = FormClick
+  DesignSize = (
+    160
+    511)
+  PixelsPerInch = 96
+  TextHeight = 13
+  object SpeedButton1: TSpeedButton
+    Left = 0
+    Top = 455
+    Width = 81
+    Height = 25
+    Anchors = [akLeft, akBottom]
+    Caption = 'Save'
+    Flat = True
+    OnClick = Save
+    ExplicitTop = 418
+  end
+  object SpeedButton2: TSpeedButton
+    Left = 80
+    Top = 455
+    Width = 81
+    Height = 25
+    Anchors = [akLeft, akBottom]
+    Caption = 'Load'
+    Flat = True
+    OnClick = Load
+    ExplicitTop = 418
+  end
+  object ListBox1: TListBox
+    Left = 0
+    Top = 0
+    Width = 161
+    Height = 449
+    Anchors = [akLeft, akTop, akBottom]
+    ItemHeight = 13
+    PopupMenu = PopupMenu1
+    TabOrder = 0
+    OnDblClick = ListBox1DblClick
+    OnKeyUp = ListBox1KeyUp
+    OnMouseDown = ListBox1MouseDown
+  end
+  object CheckBox1: TCheckBox
+    Left = 32
+    Top = 486
+    Width = 97
+    Height = 17
+    Anchors = [akLeft, akBottom]
+    Caption = 'Locate event'
+    TabOrder = 1
+  end
+  object PopupMenu1: TPopupMenu
+    OnPopup = PopupMenu1Popup
+    Left = 32
+    Top = 80
+    object Vibratowizard1: TMenuItem
+      Caption = 'Vibrato...'
+      OnClick = Vibratowizard1Click
+    end
+    object Sourcefilter1: TMenuItem
+      Caption = 'Source-filter...'
+      OnClick = Sourcefilter1Click
+    end
+    object Cut1: TMenuItem
+      Caption = 'Cut'
+      OnClick = Cut1Click
+    end
+    object Extract1: TMenuItem
+      Caption = 'Extract'
+      OnClick = Extract1Click
+    end
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EventBoxUnit.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,75 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+
+#ifndef EventBoxUnitH
+#define EventBoxUnitH
+//---------------------------------------------------------------------------
+/*
+  EventBoxUnit.cpp implements the event (harmonic sinusoid) box used by HV to maintain
+  a list of harmonic sinusoidal events.
+*/
+
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <Buttons.hpp>
+#include <Menus.hpp>
+#include "hs.h"
+#include "arrayalloc.h"
+//---------------------------------------------------------------------------
+
+class TEventBox : public TForm
+{
+__published:	// IDE-managed Components
+  TListBox *ListBox1;
+  TSpeedButton *SpeedButton1;
+  TSpeedButton *SpeedButton2;
+  TPopupMenu *PopupMenu1;
+  TMenuItem *Vibratowizard1;
+  TCheckBox *CheckBox1;
+  TMenuItem *Cut1;
+  TMenuItem *Extract1;
+  TMenuItem *Sourcefilter1;
+  void __fastcall ListBox1MouseDown(TObject *Sender, TMouseButton Button,
+          TShiftState Shift, int X, int Y);
+  void __fastcall Save(TObject *Sender);
+  void __fastcall Load(TObject *Sender);
+  void __fastcall ListBox1KeyUp(TObject *Sender, WORD &Key,
+          TShiftState Shift);
+  void __fastcall Vibratowizard1Click(TObject *Sender);
+  void __fastcall ListBox1DblClick(TObject *Sender);
+  void __fastcall FormClick(TObject *Sender);
+  void __fastcall Cut1Click(TObject *Sender);
+  void __fastcall PopupMenu1Popup(TObject *Sender);
+  void __fastcall Extract1Click(TObject *Sender);
+  void __fastcall Sourcefilter1Click(TObject *Sender);
+private:	// User declarations
+public:		// User declarations
+  __fastcall TEventBox(TComponent* Owner);
+  __fastcall ~TEventBox();
+  void __fastcall Clear();
+  void __fastcall LoadFromFile(AnsiString FileName);
+  THS* __fastcall NewHS(int M, int Fr);
+  void __fastcall SaveToFile(AnsiString FileName);
+  void __fastcall SetItemIndex(int index);
+  void __fastcall Sort();
+  int HSCount;
+  int HSCapacity;
+  THS** HS;
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TEventBox *EventBox;
+//---------------------------------------------------------------------------
+#endif
Binary file Icon1.bmp has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Navigator.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,271 @@
+/*
+    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 "Navigator.h"
+#pragma package(smart_init)
+//---------------------------------------------------------------------------
+// ValidCtrCheck is used to assure that the components created do not have
+// any pure virtual functions.
+//
+
+static inline void ValidCtrCheck(TNavigator *)
+{
+  new TNavigator(NULL);
+}
+//---------------------------------------------------------------------------
+__fastcall TNavigator::TNavigator(TComponent* Owner)
+  : TCustomControl(Owner)
+{
+  x1=y1=0;
+  x2=y2=1;
+  FOnBackground=0;
+  BkgBmp=new Graphics::TBitmap;
+}
+
+__fastcall TNavigator::~TNavigator()
+{
+	delete BkgBmp;
+}
+
+void TNavigator::DrawArea()
+{
+  Canvas->Brush->Style=bsClear;
+  Canvas->Pen->Mode=pmXor;
+  Canvas->Pen->Color=AreaColorX;
+  X1=x1*Width, X2=x2*Width, Y1=y1*Height, Y2=y2*Height;
+  if (X1+1<X2 && Y1+1<Y2)
+    Canvas->Rectangle(X1, Y1, X2, Y2);
+  else if (X1+1>=X2)
+  {
+    Canvas->MoveTo(X1, Y1);
+    Canvas->LineTo(X1, Y2);
+  }
+  else
+  {
+    Canvas->MoveTo(X1, Y1);
+    Canvas->LineTo(X2, Y1);
+  }
+}
+
+TNavigatorHitTest TNavigator::HitTest(int X, int Y)
+{
+  int Xa=1, Ya=1; //borderouter
+  int Xb=1, Yb=1; //borderinner
+  if (X2-X1<=3) Xb=0;
+  if (Y2-Y1<=3) Yb=0;
+  if (X2-X1<=1) Xb=-1;
+  if (Y2-Y1<=1) Yb=-1;
+
+  TNavigatorHitTest XTest, YTest;
+
+  if (X<X1-Xa || X>X2+Xa) XTest=htOuter;
+  else if (X1-Xa<=X && X<=X1+Xb) XTest=htLeft;
+  else if (X1+Xb<X && X<X2-Xb) XTest=htInner;
+  else XTest=htRight;
+
+  if (Y<Y1-Ya || Y>Y2+Ya) YTest=htOuter;
+  else if (Y1-Ya<=Y && Y<=Y1+Yb) YTest=htTop;
+  else if (Y1+Yb<Y & Y<Y2-Yb) YTest=htInner;
+  else YTest=htBottom;
+
+  if (XTest==htInner && YTest==htInner)
+    return htInner;
+  if (YTest==htInner && XTest!=htOuter)
+    return XTest;
+  if (XTest==htInner && YTest!=htOuter)
+    return YTest;
+  return htOuter;
+}
+
+void __fastcall TNavigator::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y)
+{
+  if (Button==mbLeft)
+  {
+    X0=X, Y0=Y;
+    x01=x1, x02=x2, y01=y1, y02=y2;
+
+    FMouseAction=maNoAction;
+
+    FHitTest=HitTest(X, Y);
+    if (FHitTest!=htOuter) FMouseAction=maMove;
+
+    if (Shift.Contains(ssCtrl))
+    {
+      switch (FHitTest)
+      {
+        case htInner:
+          break;
+        case htLeft:
+        case htTop:
+        case htRight:
+        case htBottom:
+        case htTopLeft:
+        case htTopRight:
+        case htBottomRight:
+        case htBottomLeft:
+          FMouseAction=maSize; break;
+      }
+    }
+
+    if (FMouseAction==maMove)
+      Cursor=crSizeAll;
+    else if (FMouseAction==maSize)
+    {
+      if (FHitTest==htLeft || FHitTest==htRight)
+        Cursor=crSizeWE;
+      else
+        Cursor=crSizeNS;
+    }
+    ::SetCursor(Screen->Cursors[Cursor]);
+  }
+  if (Button==mbRight)
+  {
+    TPoint P=ClientToScreen(TPoint((X1+X2)/2, (Y1+Y2)/2));
+    SetCursorPos(P.x, P.y);
+  }
+}
+
+void __fastcall TNavigator::MouseMove(TShiftState Shift, int X, int Y)
+{
+  if (Shift.Contains(ssLeft))
+  {
+    double destx1=x1, destx2=x2, desty1=y1, desty2=y2;
+
+    int dX=X-X0;
+    int dY=Y-Y0;
+
+    double dx=dX*1.0/Width;
+    double dy=dY*1.0/Height;
+
+    if (FMouseAction==maMove)
+    {
+      if (x01+dx<0) dx=-x01;
+      if (x02+dx>1) dx=1-x02;
+      if (y01+dy<0) dy=-y01;
+      if (y02+dy>1) dy=1-y02;
+      destx1=x01+dx;
+      destx2=x02+dx;
+      desty1=y01+dy;
+      desty2=y02+dy;
+    }
+    else if (FMouseAction==maSize)
+    {
+      switch(FHitTest)
+      {
+        case htLeft:
+          if (x01+dx<0) dx=-x01;
+          if (x01+dx>1) dx=1-x01;
+          destx1=x01+dx;
+          if (destx1>x02) {destx2=destx1; destx1=x02;}
+          break;
+        case htRight:
+          if (x02+dx<0) dx=-x02;
+          if (x02+dx>1) dx=1-x02;
+          destx2=x02+dx;
+          if (x01>destx2) {destx1=destx2; destx2=x01;}
+          break;
+        case htTop:
+          if (y01+dy<0) dy=-y01;
+          if (y01+dy>1) dy=1-y01;
+          desty1=y01+dy;
+          if (desty1>y02) {desty2=desty1; desty1=y02;}
+          break;
+        case htBottom:
+          if (y02+dy<0) dy=-y02;
+          if (y02+dy>1) dy=1-y02;
+          desty2=y02+dy;
+          if (y01>desty2) {desty1=desty2; desty2=y01;}
+          break;
+      }
+    }
+
+    if (destx1!=x1 || destx2!=x2 || desty1!=y1 || desty2!=y2)
+    {
+      SetArea(destx1, destx2, desty1, desty2);
+      FOnAreaChange(this);
+    }
+  }
+  else if (Shift.Contains(ssCtrl))
+  {
+    TCursor NewCursor;
+    FHitTest=HitTest(X, Y);
+    if (FHitTest==htLeft || FHitTest==htRight)
+      NewCursor=crSizeWE;
+    else if (FHitTest==htTop || FHitTest==htBottom)
+      NewCursor=crSizeNS;
+    else if (FHitTest==htInner)
+      NewCursor=crSizeAll;
+    else
+      NewCursor=crArrow;
+    if (Cursor!=NewCursor)
+    {
+      Cursor=NewCursor;
+      ::SetCursor(Screen->Cursors[Cursor]);
+    }
+  }
+  else
+  {
+    if (Cursor!=crArrow)
+    {
+      Cursor=crArrow;
+      ::SetCursor(Screen->Cursors[Cursor]);
+    }
+  }
+}
+
+void __fastcall TNavigator::MouseUp(TMouseButton Button, TShiftState, int, int)
+{
+  if (Button==mbLeft)
+  {
+    Cursor=crArrow;
+    ::SetCursor(Screen->Cursors[Cursor]);
+  }
+}
+
+void __fastcall TNavigator::Paint()
+{
+  Canvas->CopyRect(ClientRect, BkgBmp->Canvas, ClientRect);//  if (FOnBackground) FOnBackground(this);
+  DrawArea();
+}
+
+void __fastcall TNavigator::Resize()
+{
+  BkgBmp->Width=Width;
+  BkgBmp->Height=Height;
+  if (FOnBackground) FOnBackground(this);
+  Invalidate();
+  TControl::Resize();
+}
+
+void TNavigator::SetArea(double ax1, double ax2, double ay1, double ay2)
+{
+  if (x1==ax1 && x2==ax2 && y1==ay1 && y2==ay2) return;
+  DrawArea();
+  x1=ax1, x2=ax2, y1=ay1, y2=ay2;
+  DrawArea();
+}
+//---------------------------------------------------------------------------
+namespace Navigator
+{
+  void __fastcall PACKAGE Register()
+  {
+    TComponentClass classes[1] = {__classid(TNavigator)};
+    RegisterComponents("Samples", classes, 0);
+  }
+}
+//---------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Navigator.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,78 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+
+#ifndef NavigatorH
+#define NavigatorH
+//---------------------------------------------------------------------------
+/*
+  Navigator.cpp implements TNavigator, a VCL control for specifying a rectangular
+  area inside a larger rectangular area. 
+*/
+#include <SysUtils.hpp>
+#include <Classes.hpp>
+#include <Controls.hpp>
+//---------------------------------------------------------------------------
+typedef enum {maNoAction, maMove, maSize} TNavigatorMouseAction;
+typedef enum {htOuter, htLeft, htTopLeft, htTop, htTopRight, htRight, htBottomRight, htBottom, htBottomLeft, htInner} TNavigatorHitTest;
+
+class PACKAGE TNavigator : public TCustomControl
+{
+private:
+  int X0;
+  int Y0;
+  int XL;
+  int YL;
+  double x01;
+  double x02;
+  double y01;
+  double y02;
+  int X1;
+  int X2;
+  int Y1;
+  int Y2;
+  TNavigatorMouseAction FMouseAction;
+  TNavigatorHitTest FHitTest;
+  TNotifyEvent FOnAreaChange;
+  TNotifyEvent FOnBackground;
+protected:
+  TNavigatorHitTest HitTest(int X, int Y);
+  virtual void __fastcall Paint();
+  DYNAMIC void __fastcall MouseDown(TMouseButton, TShiftState, int, int);
+  DYNAMIC void __fastcall MouseMove(TShiftState, int, int);
+  DYNAMIC void __fastcall MouseUp(TMouseButton, TShiftState, int, int);
+public:
+  Graphics::TBitmap* BkgBmp;
+
+  double x1;
+  double x2;
+  double y1;
+  double y2;
+
+  TColor AreaColorX;
+  __property Canvas;
+
+	__fastcall TNavigator(TComponent* Owner);
+	__fastcall ~TNavigator();
+  void DrawArea();
+  DYNAMIC void __fastcall Resize();
+  void SetArea(double, double, double, double);
+
+__published:
+  __property TNotifyEvent OnAreaChange={read=FOnAreaChange, write=FOnAreaChange};
+  __property TNotifyEvent OnBackground={read=FOnBackground, write=FOnBackground};
+  __property PopupMenu;
+
+};
+//---------------------------------------------------------------------------
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RecordingUnit.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,56 @@
+/*
+    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 "RecordingUnit.h"
+#include "Unit1.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+TRecordingForm *RecordingForm;
+//---------------------------------------------------------------------------
+__fastcall TRecordingForm::TRecordingForm(TComponent* Owner)
+  : TForm(Owner)
+{
+}
+//---------------------------------------------------------------------------
+void __fastcall TRecordingForm::SpeedButton1Click(TObject *Sender)
+{
+  Close();  
+}
+//---------------------------------------------------------------------------
+void __fastcall TRecordingForm::SpeedButton2Click(TObject *Sender)
+{
+  AnsiString FileName1=ExtractFilePath(Application->ExeName)+"noname.wav";
+  AnsiString FileName2=ExtractFilePath(Application->ExeName)+"noname"+Now().FormatString("yymmddhhmmss")+".wav";
+  Form1->RecentFile(Form1->WaveAudio1->FileName);
+  RenameFile(FileName1, FileName2);
+  Form1->WaveAudio1->LoadFromFile(FileName2);
+  Close();
+}
+//---------------------------------------------------------------------------
+void __fastcall TRecordingForm::FormDblClick(TObject *Sender)
+{
+  Form1->SpeedButtonRecordClick(Sender);
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TRecordingForm::SpeedButtonRecordClick(TObject *Sender)
+{
+  Form1->SpeedButtonRecordClick(Sender);
+}
+//---------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RecordingUnit.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,61 @@
+object RecordingForm: TRecordingForm
+  Left = 358
+  Top = 350
+  Caption = 'Recording'
+  ClientHeight = 94
+  ClientWidth = 354
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnDblClick = FormDblClick
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Label1: TLabel
+    Left = 0
+    Top = 16
+    Width = 353
+    Height = 19
+    Alignment = taCenter
+    AutoSize = False
+    Caption = 'Recording in progress'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -16
+    Font.Name = 'Times New Roman'
+    Font.Style = []
+    ParentFont = False
+  end
+  object SpeedButton1: TSpeedButton
+    Left = 128
+    Top = 64
+    Width = 49
+    Height = 25
+    Caption = 'Delete'
+    Enabled = False
+    Flat = True
+    OnClick = SpeedButton1Click
+  end
+  object SpeedButtonRecord: TSpeedButton
+    Left = 168
+    Top = 40
+    Width = 17
+    Height = 17
+    Flat = True
+    OnClick = SpeedButtonRecordClick
+  end
+  object SpeedButton2: TSpeedButton
+    Left = 176
+    Top = 64
+    Width = 81
+    Height = 25
+    Caption = 'Send to editor'
+    Enabled = False
+    Flat = True
+    OnClick = SpeedButton2Click
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RecordingUnit.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,47 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+
+#ifndef RecordingUnitH
+#define RecordingUnitH
+//---------------------------------------------------------------------------
+/*
+  RecordingUnit.cpp implements the recording panel of HV for making audio recordings
+  from WaveIn device.
+*/
+
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <Buttons.hpp>
+//---------------------------------------------------------------------------
+class TRecordingForm : public TForm
+{
+__published:	// IDE-managed Components
+  TLabel *Label1;
+  TSpeedButton *SpeedButton1;
+  TSpeedButton *SpeedButton2;
+  TSpeedButton *SpeedButtonRecord;
+  void __fastcall SpeedButton1Click(TObject *Sender);
+  void __fastcall SpeedButton2Click(TObject *Sender);
+  void __fastcall FormDblClick(TObject *Sender);
+  void __fastcall SpeedButtonRecordClick(TObject *Sender);
+private:	// User declarations
+public:		// User declarations
+  __fastcall TRecordingForm(TComponent* Owner);
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TRecordingForm *RecordingForm;
+//---------------------------------------------------------------------------
+#endif
--- /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;
+  }
+}
+//---------------------------------------------------------------------------
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SFDemoUnit.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,760 @@
+object SFDemoForm: TSFDemoForm
+  Left = 178
+  Top = 92
+  Caption = 'Source-filter modelling demo'
+  ClientHeight = 622
+  ClientWidth = 879
+  Color = cl3DDkShadow
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter2: TSplitter
+    Left = 369
+    Top = 0
+    Height = 622
+    Beveled = True
+    ExplicitTop = -2
+    ExplicitHeight = 605
+  end
+  object Panel1: TPanel
+    Left = 0
+    Top = 0
+    Width = 369
+    Height = 622
+    Align = alLeft
+    BevelOuter = bvNone
+    Caption = 'Panel1'
+    Color = cl3DDkShadow
+    Ctl3D = False
+    ParentCtl3D = False
+    TabOrder = 0
+    OnResize = Panel1Resize
+    object Splitter1: TSplitter
+      Left = 0
+      Top = 171
+      Width = 369
+      Height = 3
+      Cursor = crVSplit
+      Align = alTop
+      Beveled = True
+      ExplicitLeft = 1
+      ExplicitTop = 168
+    end
+    object Splitter5: TSplitter
+      Left = 0
+      Top = 338
+      Width = 369
+      Height = 3
+      Cursor = crVSplit
+      Align = alTop
+      ExplicitTop = 361
+      ExplicitWidth = 239
+    end
+    object Panel2: TPanel
+      Left = 0
+      Top = 0
+      Width = 369
+      Height = 171
+      Align = alTop
+      BevelOuter = bvNone
+      Color = cl3DDkShadow
+      Ctl3D = False
+      ParentCtl3D = False
+      TabOrder = 0
+    end
+    object Panel3: TPanel
+      Left = 0
+      Top = 174
+      Width = 369
+      Height = 164
+      Align = alTop
+      BevelOuter = bvNone
+      Color = cl3DDkShadow
+      Ctl3D = True
+      ParentCtl3D = False
+      TabOrder = 1
+    end
+    object PanelControl: TPanel
+      Left = 0
+      Top = 341
+      Width = 369
+      Height = 281
+      Align = alClient
+      Color = cl3DDkShadow
+      TabOrder = 2
+      ExplicitLeft = 1
+      ExplicitTop = 344
+      DesignSize = (
+        369
+        281)
+      object Splitter4: TSplitter
+        Left = 1
+        Top = 81
+        Width = 367
+        Height = 3
+        Cursor = crVSplit
+        Align = alTop
+        ExplicitTop = 42
+        ExplicitWidth = 215
+      end
+      object Splitter6: TSplitter
+        Left = 1
+        Top = 162
+        Width = 367
+        Height = 3
+        Cursor = crVSplit
+        Align = alTop
+        ExplicitLeft = 3
+        ExplicitTop = 173
+      end
+      object Label1: TLabel
+        Left = 218
+        Top = 171
+        Width = 87
+        Height = 13
+        Caption = 'Source-filter model'
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clSilver
+        Font.Height = -11
+        Font.Name = 'MS Sans Serif'
+        Font.Style = []
+        ParentFont = False
+      end
+      object MethodListBox: TListBox
+        Left = 218
+        Top = 187
+        Width = 49
+        Height = 63
+        Anchors = [akLeft, akBottom]
+        Ctl3D = True
+        ItemHeight = 13
+        Items.Strings = (
+          'FB'
+          'SV')
+        ParentCtl3D = False
+        TabOrder = 0
+        OnClick = MethodListBoxClick
+      end
+      object FEdit: TEdit
+        Left = 266
+        Top = 187
+        Width = 49
+        Height = 21
+        Anchors = [akLeft, akBottom]
+        Ctl3D = True
+        ParentCtl3D = False
+        TabOrder = 1
+        Text = '400'
+      end
+      object FScaleCombo: TComboBox
+        Left = 266
+        Top = 208
+        Width = 49
+        Height = 21
+        BevelInner = bvNone
+        BevelOuter = bvNone
+        Anchors = [akLeft, akBottom]
+        Ctl3D = True
+        ItemHeight = 13
+        ItemIndex = 0
+        ParentCtl3D = False
+        TabOrder = 2
+        Text = 'Hz'
+        Items.Strings = (
+          'Hz'
+          'mel')
+      end
+      object ThetaEdit: TEdit
+        Left = 266
+        Top = 229
+        Width = 49
+        Height = 21
+        Anchors = [akLeft, akBottom]
+        Ctl3D = True
+        ParentCtl3D = False
+        TabOrder = 3
+        Text = '0.5'
+      end
+      object Panel7: TPanel
+        Left = 1
+        Top = 1
+        Width = 367
+        Height = 80
+        Align = alTop
+        Color = cl3DDkShadow
+        TabOrder = 4
+        OnResize = Panel7Resize
+        object Image0: TImage
+          Left = 1
+          Top = 1
+          Width = 365
+          Height = 78
+          Align = alClient
+          OnMouseDown = AImage1MouseDown
+          OnMouseMove = Image1MouseMove
+          OnMouseUp = AImage1MouseUp
+          ExplicitWidth = 368
+        end
+      end
+      object Panel8: TPanel
+        Left = 1
+        Top = 84
+        Width = 367
+        Height = 78
+        Align = alTop
+        Color = cl3DDkShadow
+        TabOrder = 5
+        OnResize = Panel8Resize
+        object Image1: TImage
+          Left = 1
+          Top = 1
+          Width = 365
+          Height = 76
+          Align = alClient
+          OnMouseDown = AImage1MouseDown
+          OnMouseMove = Image1MouseMove
+          OnMouseUp = AImage1MouseUp
+          ExplicitLeft = -31
+          ExplicitTop = 41
+        end
+      end
+      object CheckBox1: TCheckBox
+        Left = 218
+        Top = 256
+        Width = 105
+        Height = 17
+        Hint = 'looped play'
+        Anchors = [akRight, akBottom]
+        Caption = 'Looped playback'
+        Checked = True
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clSilver
+        Font.Height = -11
+        Font.Name = 'MS Sans Serif'
+        Font.Style = []
+        ParentFont = False
+        ParentShowHint = False
+        ShowHint = True
+        State = cbChecked
+        TabOrder = 6
+        OnClick = CheckBox1Click
+      end
+      object TrackBar1: TTrackBar
+        Left = 13
+        Top = 223
+        Width = 126
+        Height = 11
+        Hint = 'depth'
+        Max = 20
+        Position = 10
+        TabOrder = 7
+        OnChange = UseButtonClick
+      end
+      object ComboBox1: TComboBox
+        Left = 19
+        Top = 192
+        Width = 113
+        Height = 21
+        Anchors = [akLeft, akBottom]
+        ItemHeight = 13
+        ItemIndex = 2
+        TabOrder = 8
+        Text = 'Source and filter'
+        Items.Strings = (
+          'Source'
+          'Filter'
+          'Source and filter'
+          'Towards'
+          'Towards and back')
+      end
+      object SaveButton: TButton
+        Left = 138
+        Top = 192
+        Width = 39
+        Height = 16
+        Anchors = [akLeft, akBottom]
+        Caption = 'Save'
+        TabOrder = 9
+        OnClick = SaveButtonClick
+      end
+      object UseButton: TButton
+        Left = 138
+        Top = 207
+        Width = 39
+        Height = 17
+        Anchors = [akLeft, akBottom]
+        Caption = 'Use'
+        TabOrder = 10
+        OnClick = UseButtonClick
+      end
+      object TrackBar2: TTrackBar
+        Left = 13
+        Top = 242
+        Width = 126
+        Height = 12
+        Hint = 'gain'
+        Max = 100
+        Position = 50
+        TabOrder = 11
+        OnChange = UseButtonClick
+      end
+    end
+  end
+  object Panel4: TPanel
+    Left = 372
+    Top = 0
+    Width = 507
+    Height = 622
+    Align = alClient
+    BevelOuter = bvNone
+    Caption = 'Panel4'
+    Color = cl3DDkShadow
+    Ctl3D = False
+    ParentCtl3D = False
+    TabOrder = 1
+    OnResize = Panel4Resize
+    object Splitter3: TSplitter
+      Left = 0
+      Top = 61
+      Width = 507
+      Height = 3
+      Cursor = crVSplit
+      Align = alTop
+      Beveled = True
+      ExplicitTop = 385
+      ExplicitWidth = 533
+    end
+    object Panel5: TPanel
+      Left = 0
+      Top = 0
+      Width = 507
+      Height = 61
+      Align = alTop
+      BevelOuter = bvNone
+      BiDiMode = bdLeftToRight
+      Color = cl3DDkShadow
+      Ctl3D = True
+      ParentBiDiMode = False
+      ParentCtl3D = False
+      TabOrder = 0
+      DesignSize = (
+        507
+        61)
+      object updbEdit: TEdit
+        Left = 8
+        Top = 8
+        Width = 41
+        Height = 21
+        TabOrder = 0
+        Text = '100'
+        OnKeyPress = fmaxEditKeyPress
+      end
+      object downdbEdit: TEdit
+        Left = 8
+        Top = 32
+        Width = 41
+        Height = 21
+        TabOrder = 1
+        Text = '-60'
+        OnKeyPress = fmaxEditKeyPress
+      end
+      object FShiftdBEdit: TEdit
+        Left = 55
+        Top = 8
+        Width = 34
+        Height = 21
+        TabOrder = 2
+        Text = '0'
+        OnKeyPress = fmaxEditKeyPress
+      end
+      object fmaxEdit: TEdit
+        Left = 456
+        Top = 8
+        Width = 41
+        Height = 21
+        Anchors = [akTop, akRight]
+        TabOrder = 3
+        Text = '0.25'
+        OnKeyPress = fmaxEditKeyPress
+      end
+      object SFPicShift: TEdit
+        Left = 56
+        Top = 32
+        Width = 33
+        Height = 21
+        TabOrder = 4
+        Text = '-40'
+        OnKeyPress = fmaxEditKeyPress
+      end
+      object TmplListBox: TListBox
+        Left = 96
+        Top = 8
+        Width = 145
+        Height = 49
+        ItemHeight = 13
+        TabOrder = 5
+      end
+      object Button1: TButton
+        Left = 456
+        Top = 32
+        Width = 41
+        Height = 21
+        Caption = '>>'
+        TabOrder = 6
+        OnClick = Button1Click
+      end
+    end
+    object Panel10: TPanel
+      Left = 0
+      Top = 64
+      Width = 507
+      Height = 558
+      Align = alClient
+      BevelOuter = bvNone
+      Color = cl3DDkShadow
+      Ctl3D = True
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clBlack
+      Font.Height = -11
+      Font.Name = 'MS Sans Serif'
+      Font.Style = []
+      ParentCtl3D = False
+      ParentFont = False
+      TabOrder = 1
+      DesignSize = (
+        507
+        558)
+      object Label13: TLabel
+        Left = 0
+        Top = 541
+        Width = 3
+        Height = 13
+        Anchors = [akLeft, akBottom]
+        ExplicitTop = 208
+      end
+      object PageControl1: TPageControl
+        Left = 0
+        Top = 0
+        Width = 507
+        Height = 539
+        ActivePage = AmpOverSheet
+        Align = alTop
+        Anchors = [akLeft, akTop, akRight, akBottom]
+        TabOrder = 0
+        OnChange = PageControl1Change
+        object AmpOverSheet: TTabSheet
+          Caption = 'Amplitudes: Overall'
+          ImageIndex = 2
+          OnResize = AmpOverSheetResize
+          object Splitter7: TSplitter
+            Left = 0
+            Top = 273
+            Width = 499
+            Height = 3
+            Cursor = crVSplit
+            Align = alTop
+            OnMoved = Splitter7Moved
+            ExplicitTop = 193
+            ExplicitWidth = 298
+          end
+          object Panel9: TPanel
+            Left = 0
+            Top = 0
+            Width = 499
+            Height = 273
+            Align = alTop
+            BevelOuter = bvNone
+            Caption = 'Panel9'
+            Color = cl3DDkShadow
+            TabOrder = 0
+            DesignSize = (
+              499
+              273)
+            object Label7: TLabel
+              Left = -1
+              Top = 4
+              Width = 493
+              Height = 9
+              Alignment = taCenter
+              Anchors = [akLeft, akTop, akRight]
+              AutoSize = False
+              Color = cl3DDkShadow
+              Font.Charset = DEFAULT_CHARSET
+              Font.Color = clAqua
+              Font.Height = 12
+              Font.Name = 'Arial'
+              Font.Style = []
+              ParentColor = False
+              ParentFont = False
+            end
+            object Panel15: TPanel
+              Left = 2
+              Top = 15
+              Width = 493
+              Height = 258
+              Anchors = [akLeft, akTop, akRight, akBottom]
+              BevelOuter = bvSpace
+              Color = cl3DDkShadow
+              TabOrder = 0
+              object AImage3: TImage
+                Left = 1
+                Top = 1
+                Width = 491
+                Height = 256
+                Align = alClient
+                IncrementalDisplay = True
+                OnDblClick = AImage3DblClick
+                OnMouseDown = AImage1MouseDown
+                OnMouseMove = AImage3MouseMove
+                OnMouseUp = AImage1MouseUp
+                ExplicitLeft = -4
+                ExplicitTop = -1
+              end
+            end
+          end
+          object Panel12: TPanel
+            Left = 0
+            Top = 276
+            Width = 499
+            Height = 235
+            Align = alClient
+            BevelOuter = bvNone
+            Caption = 'Panel12'
+            Color = cl3DDkShadow
+            TabOrder = 1
+            DesignSize = (
+              499
+              235)
+            object Panel13: TPanel
+              Left = 2
+              Top = 2
+              Width = 493
+              Height = 215
+              Anchors = [akLeft, akTop, akRight, akBottom]
+              BevelOuter = bvSpace
+              Color = cl3DDkShadow
+              TabOrder = 0
+              object AImage1: TImage
+                Left = 1
+                Top = 1
+                Width = 491
+                Height = 213
+                Align = alClient
+                OnDblClick = AImage3DblClick
+                OnMouseDown = AImage1MouseDown
+                OnMouseMove = AImage3MouseMove
+                OnMouseUp = AImage1MouseUp
+                ExplicitLeft = 0
+                ExplicitHeight = 203
+              end
+            end
+            object SFCheck: TCheckBox
+              Left = 5
+              Top = 218
+              Width = 124
+              Height = 17
+              Anchors = [akLeft, akBottom]
+              Caption = 'Source-filter output'
+              Font.Charset = DEFAULT_CHARSET
+              Font.Color = clSilver
+              Font.Height = -11
+              Font.Name = 'MS Sans Serif'
+              Font.Style = []
+              ParentFont = False
+              TabOrder = 1
+              OnClick = SFCheckClick
+            end
+            object MACheck: TCheckBox
+              Left = 120
+              Top = 218
+              Width = 97
+              Height = 17
+              Anchors = [akLeft, akBottom]
+              Caption = 'Moving average'
+              Font.Charset = DEFAULT_CHARSET
+              Font.Color = clSilver
+              Font.Height = -11
+              Font.Name = 'MS Sans Serif'
+              Font.Style = []
+              ParentFont = False
+              TabOrder = 2
+              OnClick = SFCheckClick
+            end
+          end
+        end
+        object AmpCycleSheet: TTabSheet
+          Caption = 'Amplitudes: Cycles'
+          ImageIndex = 3
+          OnResize = AmpCycleSheetResize
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
+          DesignSize = (
+            499
+            511)
+          object Label9: TLabel
+            Left = 8
+            Top = 160
+            Width = 225
+            Height = 9
+            Alignment = taCenter
+            AutoSize = False
+            Color = cl3DDkShadow
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clAqua
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentColor = False
+            ParentFont = False
+          end
+          object Label15: TLabel
+            Left = 8
+            Top = 490
+            Width = 225
+            Height = 9
+            Alignment = taCenter
+            Anchors = [akLeft, akBottom]
+            AutoSize = False
+            Color = cl3DDkShadow
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clAqua
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentColor = False
+            ParentFont = False
+            ExplicitTop = 160
+          end
+          object Label16: TLabel
+            Left = 219
+            Top = 490
+            Width = 273
+            Height = 12
+            Alignment = taCenter
+            Anchors = [akRight, akBottom]
+            AutoSize = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clBlack
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentFont = False
+            ExplicitLeft = 245
+            ExplicitTop = 160
+          end
+          object Splitter8: TSplitter
+            Left = 0
+            Top = 273
+            Width = 499
+            Height = 3
+            Cursor = crVSplit
+            Align = alTop
+            OnMoved = Splitter7Moved
+          end
+          object Panel6: TPanel
+            Left = 0
+            Top = 0
+            Width = 499
+            Height = 273
+            Align = alTop
+            BevelOuter = bvNone
+            Caption = 'Panel9'
+            Color = cl3DDkShadow
+            TabOrder = 0
+            DesignSize = (
+              499
+              273)
+            object Label8: TLabel
+              Left = -1
+              Top = 4
+              Width = 493
+              Height = 9
+              Alignment = taCenter
+              Anchors = [akLeft, akTop, akRight]
+              AutoSize = False
+              Color = cl3DDkShadow
+              Font.Charset = DEFAULT_CHARSET
+              Font.Color = clAqua
+              Font.Height = 12
+              Font.Name = 'Arial'
+              Font.Style = []
+              ParentColor = False
+              ParentFont = False
+            end
+            object Panel11: TPanel
+              Left = 2
+              Top = 15
+              Width = 493
+              Height = 258
+              Anchors = [akLeft, akTop, akRight, akBottom]
+              BevelOuter = bvSpace
+              Color = cl3DDkShadow
+              TabOrder = 0
+              object AImage4: TImage
+                Left = 1
+                Top = 1
+                Width = 491
+                Height = 256
+                Align = alClient
+                IncrementalDisplay = True
+                OnMouseDown = AImage1MouseDown
+                OnMouseMove = AImage3MouseMove
+                OnMouseUp = AImage1MouseUp
+                ExplicitLeft = 0
+              end
+            end
+          end
+          object Panel14: TPanel
+            Left = 0
+            Top = 276
+            Width = 499
+            Height = 235
+            Align = alClient
+            BevelOuter = bvNone
+            Caption = 'Panel12'
+            Color = cl3DDkShadow
+            TabOrder = 1
+            DesignSize = (
+              499
+              235)
+            object Panel16: TPanel
+              Left = 2
+              Top = 2
+              Width = 493
+              Height = 215
+              Anchors = [akLeft, akTop, akRight, akBottom]
+              BevelOuter = bvSpace
+              Color = cl3DDkShadow
+              TabOrder = 0
+              object AImage2: TImage
+                Left = 1
+                Top = 1
+                Width = 491
+                Height = 213
+                Align = alClient
+                OnMouseDown = AImage1MouseDown
+                OnMouseMove = AImage3MouseMove
+                OnMouseUp = AImage1MouseUp
+                ExplicitLeft = 33
+                ExplicitTop = -39
+                ExplicitWidth = 483
+                ExplicitHeight = 98
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+  object SaveDialog1: TSaveDialog
+    Left = 180
+    Top = 104
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SFDemoUnit.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,209 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+
+#ifndef SFDemoUnitH
+#define SFDemoUnitH
+//---------------------------------------------------------------------------
+/*
+  SFDemoUnit.cpp implements the source-filter modelling demo of HV.
+*/
+
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <ExtCtrls.hpp>
+#include "AudioPac.h"
+#include "WaveView.h"
+#include "EventBoxUnit.h"
+#include "hssf.h"
+#include "SUThread.h"
+#include <ComCtrls.hpp>
+#include <Dialogs.hpp>
+
+//---------------------------------------------------------------------------
+
+
+
+class TSFDemoForm : public TForm
+{
+__published:	// IDE-managed Components
+  TPanel *Panel1;
+  TPanel *Panel2;
+  TSplitter *Splitter1;
+  TSplitter *Splitter2;
+  TPanel *Panel3;
+  TSaveDialog *SaveDialog1;
+	TPanel *Panel4;
+	TSplitter *Splitter3;
+	TPanel *Panel5;
+	TPanel *Panel10;
+	TLabel *Label13;
+	TPageControl *PageControl1;
+	TTabSheet *AmpOverSheet;
+	TTabSheet *AmpCycleSheet;
+	TLabel *Label9;
+	TLabel *Label15;
+	TLabel *Label16;
+	TSplitter *Splitter5;
+	TPanel *PanelControl;
+  TListBox *MethodListBox;
+	TEdit *FEdit;
+	TComboBox *FScaleCombo;
+	TEdit *ThetaEdit;
+	TPanel *Panel7;
+	TSplitter *Splitter4;
+	TPanel *Panel8;
+	TSplitter *Splitter6;
+	TImage *Image0;
+	TImage *Image1;
+	TPanel *Panel9;
+	TLabel *Label7;
+	TPanel *Panel15;
+	TImage *AImage3;
+	TSplitter *Splitter7;
+	TPanel *Panel12;
+	TPanel *Panel13;
+	TImage *AImage1;
+	TPanel *Panel6;
+	TLabel *Label8;
+	TPanel *Panel11;
+	TImage *AImage4;
+	TSplitter *Splitter8;
+	TPanel *Panel14;
+	TPanel *Panel16;
+	TImage *AImage2;
+	TEdit *updbEdit;
+	TEdit *downdbEdit;
+	TEdit *FShiftdBEdit;
+	TCheckBox *CheckBox1;
+	TEdit *fmaxEdit;
+	TEdit *SFPicShift;
+  TListBox *TmplListBox;
+  TButton *Button1;
+  TCheckBox *SFCheck;
+  TCheckBox *MACheck;
+  TLabel *Label1;
+  TTrackBar *TrackBar1;
+  TComboBox *ComboBox1;
+  TButton *SaveButton;
+  TButton *UseButton;
+  TTrackBar *TrackBar2;
+  void __fastcall Image1MouseMove(TObject *Sender, TShiftState Shift,
+          int X, int Y);
+  void __fastcall SFCheckClick(TObject *Sender);
+  void __fastcall AImage3MouseMove(TObject *Sender, TShiftState Shift,
+          int X, int Y);
+  void __fastcall AImage1MouseDown(TObject *Sender, TMouseButton Button,
+          TShiftState Shift, int X, int Y);
+  void __fastcall AImage1MouseUp(TObject *Sender, TMouseButton Button,
+          TShiftState Shift, int X, int Y);
+  void __fastcall PageControl1Change(TObject *Sender);
+  void __fastcall SaveButtonClick(TObject *Sender);
+  void __fastcall UseButtonClick(TObject *Sender);
+  void __fastcall Panel4Resize(TObject *Sender);
+  void __fastcall Panel1Resize(TObject *Sender);
+  void __fastcall AmpCycleSheetResize(TObject *Sender);
+	void __fastcall MethodListBoxClick(TObject *Sender);
+	void __fastcall AmpOverSheetResize(TObject *Sender);
+	void __fastcall Splitter7Moved(TObject *Sender);
+	void __fastcall AImage3DblClick(TObject *Sender);
+	void __fastcall Panel7Resize(TObject *Sender);
+	void __fastcall Panel8Resize(TObject *Sender);
+	void __fastcall CheckBox1Click(TObject *Sender);
+  void __fastcall fmaxEditKeyPress(TObject *Sender, char &Key);
+  void __fastcall Button1Click(TObject *Sender);
+private:	// User declarations
+	bool analyze2;
+public:		// User declarations
+  __fastcall TSFDemoForm(TComponent* Owner);
+	__fastcall ~TSFDemoForm();
+
+	double dbrange;
+
+  bool ForceUpdate;
+
+	TSUThread* SUThread;
+	int pThread;
+	TSUThread* ThreadList[ThreadCaps];
+
+  void __fastcall SUTerminate(TObject* Sender);
+  DYNAMIC void __fastcall MouseWheelHandler(TMessage& Msg);
+	void __fastcall Image1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+	void __fastcall AImage3MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+
+  int StartPos;
+  TWaveAudio* WaveAudio1;
+  TWaveView* WaveView1;
+  TWaveAudio* WaveAudio2;
+  TWaveView* WaveView2;
+
+	TSF SF;
+  TSF SF0;
+
+  THS* HS;
+  double f_c, f_ex;
+  double* cyclefrs;
+  double* cyclefs;
+	int cyclefrcount;
+	int CurrentPartial;
+	int CurrentFB;
+	int CurrentFr;
+	int CurrentP;
+	int CurrentK;
+	int CurrentB;
+  int CurrentC;
+  double FXX[64];
+  double NAF[4096];
+	int SX[128]; //size related to number of partials
+	int FX[128]; //size related to number of filter control points
+	int FY[128]; //ditto
+  int SXcycle[128];
+  int KX1[64]; //size related to number of frames per cycle
+	int KX2[64];
+	int BX1[128];	//size related to number of cycles
+	int BX2[128];
+  int CX1[128];  //size related to number of cycles
+  int CX2[128];
+  int CY1[128];
+  int CY2[128];
+  int SXc;
+  int SXcyclec;
+  int FirstStartDrag;
+	int StartDrag;
+	int FirstStartDragX;
+	int StartDragX;
+
+  __int16* Wave1;
+
+  __int16* datain;
+
+  void Copydata();
+  void DrawModulator();
+  void __fastcall ExternalInput();
+  void FindNote();
+  void Reset();
+  void __fastcall SaveSF();
+  void __fastcall SaveSF0();
+  void __fastcall SaveWave();
+  void __fastcall S_U(bool sf=false);
+  void Synthesize();
+  void UpdateDisplay(bool f0=true, bool f0s=true, bool f0d=true, bool sf=true);
+  int __fastcall WaveView1CustomInfo(TObject*);
+  void __fastcall WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode);
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TSFDemoForm *SFDemoForm;
+//---------------------------------------------------------------------------
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SUThread.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,59 @@
+/*
+    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 "SUThread.h"
+#include "hs.h"
+#pragma package(smart_init)
+//---------------------------------------------------------------------------
+
+//   Important: Methods and properties of objects in VCL can only be
+//   used in a method called using Synchronize, for example:
+//
+//      Synchronize(UpdateCaption);
+//
+//   where UpdateCaption could look like:
+//
+//      void __fastcall TSUThread::UpdateCaption()
+//      {
+//        Form1->Caption = "Updated in a thread";
+//      }
+//---------------------------------------------------------------------------
+
+__fastcall TSUThread::TSUThread(bool CreateSuspended)
+  : TThread(CreateSuspended)
+{
+  xrec=0;
+  data=0;
+  sf=false;
+  HS=0;
+}
+
+__fastcall TSUThread::~TSUThread()
+{
+  free8(xrec);
+  delete[] data;
+  delete HS;
+}
+
+
+//---------------------------------------------------------------------------
+void __fastcall TSUThread::Execute()
+{
+  //---- Place thread code here ----
+  xrec=SynthesisHS(HS, dst, den, &Terminated);
+}
+//---------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SUThread.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,44 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+
+#ifndef SUThreadH
+#define SUThreadH
+//---------------------------------------------------------------------------
+/*
+  SUThread.cpp implements the harmonic sinusoid synthesis thread used by the vibrato
+  analysis/synthesis and source-filter modelling demos of HV for real-time response.
+*/
+
+#include <Classes.hpp>
+#include "EventBoxUnit.h"
+#include "VibratoDemoUnit.h"
+
+//---------------------------------------------------------------------------
+class TSUThread : public TThread
+{            
+private:
+protected:
+  void __fastcall Execute();
+public:
+  __fastcall TSUThread(bool CreateSuspended);
+  __fastcall ~TSUThread();
+  THS* HS;
+  double *xrec;
+  __int16* data;
+  int dst;
+  int den;
+  bool sf;
+};
+//---------------------------------------------------------------------------
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Unit1.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,2240 @@
+/*
+    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);  
+}
+//---------------------------------------------------------------------------
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Unit1.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,1456 @@
+object Form1: TForm1
+  Left = 229
+  Top = 92
+  Caption = 'hv'
+  ClientHeight = 615
+  ClientWidth = 836
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  Icon.Data = {
+    0000010001002020100000000000E80200001600000028000000200000004000
+    0000010004000000000080020000000000000000000000000000000000000000
+    000000008000008000000080800080000000800080008080000080808000C0C0
+    C0000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF000000
+    00000000000000000FFFFFF00000000000000000000000000FFFFFFF00000000
+    000000000000000000000FFF0000000000000000000000FFF00000FF00000000
+    00000000000000FFFFFF00FF00000000000000000000000FFFFFFFFF00000000
+    0000000000000000000FFFFFFFFF0000000000000000000FFF000FFFFFFF0000
+    000000000000FF0FFF0FFFFF00000000000000000000FF00FFFFFFF000000000
+    000000000000FF00FFFFFFF00000FFFFFFFFF00000FFFFFFF00FFFF00000FFFF
+    FFFFFFF00FFFFFFFFFFF000000000000000FFFFFFFFF000FFFFFFFF000FF0000
+    00000FFFFFF00000000FFFFFFFFF00000000FFFFF0000000FFF000FFFFFF0000
+    00FFFFFFF000000FFFF00000000F000000FFFF0FF00000FFFFFFF00000000000
+    0000000FF00000FFFFFFFF00000000000000000FF000000000FFFFFFF00000FF
+    FFF0000FF00000000000FFFFF00000FFFFFFFF00000000000000000000000000
+    0FFFFFFFFFFF000000000000000000000000FFFFFFFFFF000000000000000000
+    000FF000000FFF000000000000000000000FF000000000000000000000000000
+    00FFF0000000000000000000000000000FFFF000000000000000000000000000
+    0FFF000000000000000000000000000000000000000000000000000000000000
+    000000000000000000000000000000000000000000000000000000000000FFFF
+    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF}
+  Menu = MainMenu1
+  OldCreateOrder = False
+  PixelsPerInch = 96
+  TextHeight = 13
+  object PanelButtons: TPanel
+    Left = 819
+    Top = 29
+    Width = 17
+    Height = 567
+    Align = alRight
+    BevelOuter = bvNone
+    Color = clWindow
+    TabOrder = 2
+    DesignSize = (
+      17
+      567)
+    object PanelRightButton: TShape
+      Left = 0
+      Top = -2
+      Width = 17
+      Height = 25
+      Hint = 'show/hide right Panel'
+      Brush.Color = clSilver
+      ParentShowHint = False
+      Pen.Style = psClear
+      Shape = stCircle
+      ShowHint = True
+      OnMouseUp = PanelRightButtonMouseUp
+    end
+    object PanelRightButton2: TShape
+      Left = 0
+      Top = 539
+      Width = 17
+      Height = 25
+      Hint = 'show/hide data grid'
+      Anchors = [akLeft, akBottom]
+      Brush.Color = clTeal
+      ParentShowHint = False
+      Pen.Style = psClear
+      Shape = stCircle
+      ShowHint = True
+      OnMouseUp = PanelRightButtonMouseUp
+      ExplicitTop = 607
+    end
+  end
+  object CoolBar1: TCoolBar
+    Left = 0
+    Top = 0
+    Width = 836
+    Height = 29
+    BandMaximize = bmDblClick
+    Bands = <
+      item
+        Control = ToolBarFile
+        ImageIndex = -1
+        Width = 138
+      end
+      item
+        Break = False
+        Control = ToolBarMode
+        ImageIndex = -1
+        Width = 200
+      end
+      item
+        Break = False
+        Control = ToolBar1
+        ImageIndex = -1
+        MinHeight = 24
+        Width = 490
+      end
+      item
+        Control = ToolBarAudio
+        ImageIndex = -1
+        Width = 832
+      end>
+    object ToolBarFile: TToolBar
+      Left = 9
+      Top = 0
+      Width = 125
+      Height = 25
+      ButtonWidth = 25
+      Caption = 'ToolBarFile'
+      GradientEndColor = 11319229
+      Images = ImageList1
+      TabOrder = 0
+      object SpeedButtonOpen: TSpeedButton
+        Left = 0
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'open wave file'
+        Flat = True
+        Glyph.Data = {
+          76010000424D7601000000000000760000002800000020000000100000000100
+          04000000000000010000120B0000120B00001000000000000000000000000000
+          800000800000008080008000000080008000808000007F7F7F00BFBFBF000000
+          FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00555555555555
+          5555555555555555555555555555555555555555555555555555555555555555
+          555555555555555555555555555555555555555FFFFFFFFFF555550000000000
+          55555577777777775F55500B8B8B8B8B05555775F555555575F550F0B8B8B8B8
+          B05557F75F555555575F50BF0B8B8B8B8B0557F575FFFFFFFF7F50FBF0000000
+          000557F557777777777550BFBFBFBFB0555557F555555557F55550FBFBFBFBF0
+          555557F555555FF7555550BFBFBF00055555575F555577755555550BFBF05555
+          55555575FFF75555555555700007555555555557777555555555555555555555
+          5555555555555555555555555555555555555555555555555555}
+        NumGlyphs = 2
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = Open1Click
+      end
+      object SpeedButtonSave: TSpeedButton
+        Left = 23
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'save as'
+        Flat = True
+        Glyph.Data = {
+          76010000424D7601000000000000760000002800000020000000100000000100
+          04000000000000010000130B0000130B00001000000000000000000000000000
+          800000800000008080008000000080008000808000007F7F7F00BFBFBF000000
+          FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333333330070
+          7700333333337777777733333333008088003333333377F73377333333330088
+          88003333333377FFFF7733333333000000003FFFFFFF77777777000000000000
+          000077777777777777770FFFFFFF0FFFFFF07F3333337F3333370FFFFFFF0FFF
+          FFF07F3FF3FF7FFFFFF70F00F0080CCC9CC07F773773777777770FFFFFFFF039
+          99337F3FFFF3F7F777F30F0000F0F09999937F7777373777777F0FFFFFFFF999
+          99997F3FF3FFF77777770F00F000003999337F773777773777F30FFFF0FF0339
+          99337F3FF7F3733777F30F08F0F0337999337F7737F73F7777330FFFF0039999
+          93337FFFF7737777733300000033333333337777773333333333}
+        NumGlyphs = 2
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = SpeedButtonSaveClick
+      end
+      object SpeedButtonExit: TSpeedButton
+        Left = 46
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'exit'
+        Flat = True
+        Glyph.Data = {
+          76010000424D7601000000000000760000002800000020000000100000000100
+          04000000000000010000120B0000120B00001000000000000000000000000000
+          800000800000008080008000000080008000808000007F7F7F00BFBFBF000000
+          FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00330000000000
+          03333377777777777F333301BBBBBBBB033333773F3333337F3333011BBBBBBB
+          0333337F73F333337F33330111BBBBBB0333337F373F33337F333301110BBBBB
+          0333337F337F33337F333301110BBBBB0333337F337F33337F333301110BBBBB
+          0333337F337F33337F333301110BBBBB0333337F337F33337F333301110BBBBB
+          0333337F337F33337F333301110BBBBB0333337F337FF3337F33330111B0BBBB
+          0333337F337733337F333301110BBBBB0333337F337F33337F333301110BBBBB
+          0333337F3F7F33337F333301E10BBBBB0333337F7F7F33337F333301EE0BBBBB
+          0333337F777FFFFF7F3333000000000003333377777777777333}
+        NumGlyphs = 2
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = Exit1Click
+      end
+      object ToolButton1: TToolButton
+        Left = 69
+        Top = 0
+        Width = 8
+        Caption = 'ToolButton1'
+        Style = tbsSeparator
+      end
+      object SpeedButtonRecord: TSpeedButton
+        Left = 77
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'record '
+        Flat = True
+        NumGlyphs = 2
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = SpeedButtonRecordClick
+      end
+      object SpeedButtonPlay: TSpeedButton
+        Left = 100
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'play / stop'
+        Flat = True
+        NumGlyphs = 2
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = Play1Click
+      end
+    end
+    object ToolBarMode: TToolBar
+      Left = 149
+      Top = 0
+      Width = 187
+      Height = 25
+      Caption = 'ToolBarMode'
+      GradientEndColor = 11319229
+      TabOrder = 1
+      object SpeedButtonS: TSpeedButton
+        Left = 0
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'waveform / spectrogram'
+        AllowAllUp = True
+        Flat = True
+        Layout = blGlyphTop
+        NumGlyphs = 4
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = SpeedButtonSClick
+      end
+      object SpeedButtonCursorText: TSpeedButton
+        Left = 23
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'show/hide cursor text'
+        AllowAllUp = True
+        GroupIndex = 10
+        Flat = True
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = LogFreqCheckClick
+      end
+      object SpeedButtonPaneInfo: TSpeedButton
+        Left = 46
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'show/hide pane info'
+        AllowAllUp = True
+        GroupIndex = 11
+        Down = True
+        Flat = True
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = LogFreqCheckClick
+      end
+      object ToolButton2: TToolButton
+        Left = 69
+        Top = 0
+        Width = 8
+        Caption = 'ToolButton2'
+        ImageIndex = 0
+        Style = tbsDivider
+      end
+      object SpeedButtonT: TSpeedButton
+        Left = 77
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'time select'
+        AllowAllUp = True
+        GroupIndex = 2
+        Down = True
+        Flat = True
+        NumGlyphs = 4
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = SpeedButtonTClick
+      end
+      object SpeedButtonF: TSpeedButton
+        Left = 100
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'frequency select'
+        AllowAllUp = True
+        GroupIndex = 3
+        Flat = True
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = SpeedButtonFClick
+      end
+      object ToolButton4: TToolButton
+        Left = 123
+        Top = 0
+        Width = 8
+        Caption = 'ToolButton4'
+        ImageIndex = 2
+        Style = tbsDivider
+      end
+      object SpeedButtonM: TSpeedButton
+        Left = 131
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'multiple selection'
+        AllowAllUp = True
+        GroupIndex = 4
+        Flat = True
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+        OnClick = SpeedButtonMClick
+      end
+      object ToolButton3: TToolButton
+        Left = 154
+        Top = 0
+        Width = 8
+        Caption = 'ToolButton3'
+        ImageIndex = 3
+        Style = tbsDivider
+      end
+      object SpeedButtonSelect: TSpeedButton
+        Left = 162
+        Top = 0
+        Width = 23
+        Height = 22
+        Hint = 'select mode'
+        AllowAllUp = True
+        GroupIndex = 5
+        Flat = True
+        ParentShowHint = False
+        ShowHint = True
+        Transparent = False
+      end
+    end
+    object ToolBar1: TToolBar
+      Left = 351
+      Top = 0
+      Width = 477
+      Height = 24
+      ButtonHeight = 17
+      Caption = 'ToolBar1'
+      TabOrder = 2
+      object WindowTypeCombo: TComboBox
+        Left = 0
+        Top = 0
+        Width = 65
+        Height = 21
+        Style = csDropDownList
+        ItemHeight = 13
+        ItemIndex = 2
+        TabOrder = 0
+        Text = 'Hann'
+        OnChange = WindowTypeComboChange
+        Items.Strings = (
+          'Rectangular'
+          'Hamming'
+          'Hann'
+          'Blackman'
+          'Gaussian')
+      end
+      object WindowSizeCombo: TComboBox
+        Left = 65
+        Top = 0
+        Width = 64
+        Height = 21
+        Hint = 'window size'
+        Style = csDropDownList
+        ItemHeight = 13
+        ItemIndex = 6
+        ParentShowHint = False
+        ShowHint = True
+        TabOrder = 1
+        Text = '1024'
+        OnChange = WindowSizeComboChange
+        Items.Strings = (
+          '16'
+          '32'
+          '64'
+          '128'
+          '256'
+          '512'
+          '1024'
+          '2048'
+          '4096'
+          '8192'
+          '16384'
+          '32768'
+          '65536')
+      end
+      object PlayFilterCombo: TComboBox
+        Left = 129
+        Top = 0
+        Width = 56
+        Height = 21
+        Hint = 'playback filter'
+        ItemHeight = 13
+        ItemIndex = 0
+        ParentShowHint = False
+        ShowHint = True
+        TabOrder = 2
+        Text = 'none'
+        OnSelect = PlayFilterComboSelect
+        Items.Strings = (
+          'none'
+          'pass'
+          'stop')
+      end
+    end
+    object ToolBarAudio: TToolBar
+      Left = 9
+      Top = 27
+      Width = 819
+      Height = 25
+      Caption = 'ToolBarAudio'
+      GradientEndColor = 11319229
+      TabOrder = 3
+    end
+  end
+  object StatusBar1: TStatusBar
+    Left = 0
+    Top = 596
+    Width = 836
+    Height = 19
+    Panels = <
+      item
+        Width = 50
+      end
+      item
+        Width = 150
+      end
+      item
+        Width = 150
+      end
+      item
+        Width = 50
+      end>
+  end
+  object BackPanel: TPanel
+    Left = 0
+    Top = 29
+    Width = 819
+    Height = 567
+    Align = alClient
+    Caption = 'BackPanel'
+    TabOrder = 3
+    ExplicitHeight = 658
+    object Splitter1: TSplitter
+      Left = 643
+      Top = 1
+      Height = 565
+      Align = alRight
+      Beveled = True
+      ExplicitLeft = 669
+      ExplicitHeight = 567
+    end
+    object PanelMain: TPanel
+      Left = 1
+      Top = 1
+      Width = 642
+      Height = 565
+      Align = alClient
+      BevelInner = bvLowered
+      BevelOuter = bvNone
+      Caption = 'PanelMain'
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -24
+      Font.Name = 'MS Sans Serif'
+      Font.Style = [fsBold]
+      ParentFont = False
+      TabOrder = 0
+      ExplicitHeight = 656
+      object Splitter3: TSplitter
+        Left = 1
+        Top = 343
+        Width = 640
+        Height = 3
+        Cursor = crVSplit
+        Align = alBottom
+        Visible = False
+        ExplicitTop = 345
+        ExplicitWidth = 287
+      end
+      object PanelWaveView: TPanel
+        AlignWithMargins = True
+        Left = 4
+        Top = 4
+        Width = 634
+        Height = 336
+        Align = alClient
+        Caption = 'PanelWaveView'
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'MS Sans Serif'
+        Font.Style = []
+        ParentFont = False
+        TabOrder = 0
+        OnClick = SpeedButtonSClick
+        object ScrollBar1: TScrollBar
+          Left = 1
+          Top = 326
+          Width = 632
+          Height = 9
+          Align = alBottom
+          PageSize = 0
+          TabOrder = 0
+          TabStop = False
+        end
+      end
+      object PanelGrid: TPanel
+        Left = 1
+        Top = 346
+        Width = 640
+        Height = 218
+        Align = alBottom
+        Caption = 'PanelGrid'
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -10
+        Font.Name = 'MS Sans Serif'
+        Font.Style = []
+        ParentFont = False
+        TabOrder = 1
+        Visible = False
+        ExplicitTop = 437
+        DesignSize = (
+          640
+          218)
+        object PageControl2: TPageControl
+          Left = 1
+          Top = 1
+          Width = 638
+          Height = 216
+          ActivePage = AmpTab
+          Align = alClient
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -10
+          Font.Name = 'MS Sans Serif'
+          Font.Style = []
+          ParentFont = False
+          TabOrder = 0
+          object AmpTab: TTabSheet
+            Caption = 'Amp. Spec.'
+            ImageIndex = 1
+            object AmpGrid: TStringGrid
+              Left = 0
+              Top = 0
+              Width = 630
+              Height = 188
+              Align = alClient
+              ColCount = 2
+              DefaultRowHeight = 15
+              RowCount = 2
+              Font.Charset = DEFAULT_CHARSET
+              Font.Color = clWindowText
+              Font.Height = -10
+              Font.Name = 'MS Sans Serif'
+              Font.Style = []
+              ParentFont = False
+              TabOrder = 0
+              OnDblClick = AmpGridDblClick
+              ColWidths = (
+                64
+                65)
+            end
+          end
+          object ArcTab: TTabSheet
+            Caption = 'Phase Spec.'
+            ImageIndex = 2
+            ExplicitLeft = 0
+            ExplicitTop = 0
+            ExplicitWidth = 0
+            ExplicitHeight = 0
+            object PhaseGrid: TStringGrid
+              Left = 0
+              Top = 0
+              Width = 630
+              Height = 188
+              Align = alClient
+              ColCount = 2
+              DefaultRowHeight = 15
+              RowCount = 2
+              TabOrder = 0
+            end
+          end
+          object QPkTab: TTabSheet
+            Caption = 'Quick Peaks'
+            ImageIndex = 3
+            ExplicitLeft = 0
+            ExplicitTop = 0
+            ExplicitWidth = 0
+            ExplicitHeight = 0
+            DesignSize = (
+              630
+              188)
+            object TLabel
+              Left = 472
+              Top = 48
+              Width = 3
+              Height = 13
+            end
+            object QPkGrid: TStringGrid
+              Left = 0
+              Top = 4
+              Width = 627
+              Height = 209
+              Anchors = [akLeft, akTop, akRight, akBottom]
+              ColCount = 3
+              DefaultRowHeight = 15
+              RowCount = 2
+              Font.Charset = DEFAULT_CHARSET
+              Font.Color = clWindowText
+              Font.Height = -10
+              Font.Name = 'MS Sans Serif'
+              Font.Style = []
+              Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSelect]
+              ParentFont = False
+              TabOrder = 0
+              ColWidths = (
+                64
+                65
+                64)
+            end
+          end
+        end
+        object MBCheck: TCheckBox
+          Left = 584
+          Top = 3
+          Width = 67
+          Height = 17
+          Hint = 'hold Shift to auto-update if checked'
+          Anchors = [akTop, akRight]
+          Caption = 'Shift'
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = 10
+          Font.Name = 'MS Sans Serif'
+          Font.Style = []
+          ParentFont = False
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 1
+        end
+        object FormatEdit: TEdit
+          Left = 530
+          Top = 2
+          Width = 46
+          Height = 21
+          Hint = 'display format'
+          Anchors = [akTop, akRight]
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 2
+          Text = '%.3f'
+        end
+      end
+    end
+    object PanelRight: TPanel
+      Left = 646
+      Top = 1
+      Width = 172
+      Height = 565
+      Align = alRight
+      BevelOuter = bvLowered
+      Color = clWindow
+      TabOrder = 1
+      ExplicitHeight = 656
+      object Splitter2: TSplitter
+        Left = 1
+        Top = 113
+        Width = 170
+        Height = 3
+        Cursor = crVSplit
+        Align = alTop
+        Beveled = True
+        Color = clScrollBar
+        ParentColor = False
+      end
+      object PanelNavigator: TPanel
+        Left = 1
+        Top = 1
+        Width = 170
+        Height = 112
+        Align = alTop
+        BevelOuter = bvNone
+        Caption = 'PanelNavigator'
+        TabOrder = 0
+      end
+      object PanelRightBack: TPanel
+        Left = 1
+        Top = 116
+        Width = 170
+        Height = 448
+        Align = alClient
+        BevelOuter = bvNone
+        TabOrder = 1
+        ExplicitHeight = 539
+        object PageControl1: TPageControl
+          Left = 0
+          Top = 0
+          Width = 170
+          Height = 448
+          ActivePage = TabSheet1
+          Align = alClient
+          MultiLine = True
+          TabOrder = 0
+          TabPosition = tpRight
+          ExplicitHeight = 539
+          object TabSheet1: TTabSheet
+            Caption = 'Display'
+            ExplicitLeft = 0
+            ExplicitTop = 0
+            ExplicitWidth = 0
+            ExplicitHeight = 531
+            object DisplayChannelRadio: TRadioGroup
+              Left = 0
+              Top = 8
+              Width = 65
+              Height = 89
+              Caption = 'Channels'
+              ItemIndex = 1
+              Items.Strings = (
+                'Stereo'
+                'Left'
+                'Right')
+              TabOrder = 0
+              OnClick = LogFreqCheckClick
+            end
+            object PanesRadio: TRadioGroup
+              Left = 72
+              Top = 8
+              Width = 65
+              Height = 89
+              Caption = 'Panes'
+              ItemIndex = 0
+              Items.Strings = (
+                'Single'
+                'Double')
+              TabOrder = 1
+              OnClick = LogFreqCheckClick
+            end
+            object StaticText1: TStaticText
+              Left = -703
+              Top = 27
+              Width = 58
+              Height = 17
+              Caption = 'StaticText1'
+              TabOrder = 2
+            end
+            object GroupBox1: TGroupBox
+              Left = 1
+              Top = 103
+              Width = 137
+              Height = 89
+              Caption = 'Spectrogram'
+              TabOrder = 3
+              object LogFreqCheck: TCheckBox
+                Left = 8
+                Top = 32
+                Width = 97
+                Height = 17
+                Hint = 'log frequency scale'
+                Caption = 'Log Frequency'
+                ParentShowHint = False
+                ShowHint = True
+                TabOrder = 0
+                OnClick = LogFreqCheckClick
+              end
+              object FreqLineCheck: TCheckBox
+                Left = 8
+                Top = 56
+                Width = 97
+                Height = 17
+                Caption = 'Peaks only'
+                TabOrder = 1
+                OnClick = LogFreqCheckClick
+              end
+            end
+          end
+          object TabSheet2: TTabSheet
+            Caption = 'Playback'
+            ImageIndex = 1
+            ExplicitLeft = 0
+            ExplicitTop = 0
+            ExplicitWidth = 0
+            ExplicitHeight = 511
+            object PlaybackFilterRadio: TRadioGroup
+              Left = 1
+              Top = 8
+              Width = 137
+              Height = 73
+              Caption = 'PlaybackFilter'
+              ItemIndex = 0
+              Items.Strings = (
+                'none'
+                'pass'
+                'stop')
+              TabOrder = 0
+              OnClick = PlaybackFilterRadioClick
+            end
+            object PlayChannelRadio: TRadioGroup
+              Left = 1
+              Top = 87
+              Width = 137
+              Height = 90
+              Caption = 'Channels'
+              ItemIndex = 2
+              Items.Strings = (
+                'stereo'
+                'swap'
+                'left only'
+                'right only')
+              TabOrder = 1
+            end
+            object AutoScrollCheck: TCheckBox
+              Left = 1
+              Top = 302
+              Width = 97
+              Height = 17
+              Caption = 'Auto Scroll'
+              TabOrder = 2
+              OnClick = AutoScrollCheckClick
+            end
+            object PlayFromRadio: TRadioGroup
+              Left = 1
+              Top = 183
+              Width = 137
+              Height = 42
+              Caption = 'Play from...'
+              ItemIndex = 0
+              Items.Strings = (
+                'start of visible')
+              TabOrder = 3
+            end
+            object PlayUntilRadio: TRadioGroup
+              Left = 1
+              Top = 231
+              Width = 137
+              Height = 58
+              Caption = '...until'
+              ItemIndex = 1
+              Items.Strings = (
+                'end of file'
+                'end of visible')
+              TabOrder = 4
+              OnClick = PlayUntilRadioClick
+            end
+            object LoopCheck: TCheckBox
+              Left = 1
+              Top = 325
+              Width = 97
+              Height = 17
+              Caption = 'Loop'
+              TabOrder = 5
+              OnClick = LoopCheckClick
+            end
+          end
+          object TabSheet5: TTabSheet
+            Caption = 'HS'
+            ImageIndex = 4
+            ExplicitLeft = 0
+            ExplicitTop = 0
+            ExplicitWidth = 0
+            ExplicitHeight = 531
+            object Label1: TLabel
+              Left = 0
+              Top = 64
+              Width = 22
+              Height = 13
+              Caption = 'delm'
+            end
+            object Label2: TLabel
+              Left = 0
+              Top = 96
+              Width = 20
+              Height = 13
+              Caption = 'delp'
+            end
+            object Label3: TLabel
+              Left = 0
+              Top = 16
+              Width = 25
+              Height = 13
+              Caption = 'maxp'
+            end
+            object Label4: TLabel
+              Left = 0
+              Top = 128
+              Width = 26
+              Height = 13
+              Caption = 'maxB'
+            end
+            object Label5: TLabel
+              Left = 0
+              Top = 160
+              Width = 25
+              Height = 13
+              Caption = 'minf0'
+            end
+            object Label6: TLabel
+              Left = 72
+              Top = 160
+              Width = 11
+              Height = 13
+              Caption = 'hz'
+            end
+            object Label7: TLabel
+              Left = 0
+              Top = 192
+              Width = 28
+              Height = 13
+              Caption = 'maxf0'
+            end
+            object Label8: TLabel
+              Left = 72
+              Top = 192
+              Width = 11
+              Height = 13
+              Caption = 'hz'
+            end
+            object HSDelmEdit1: TEdit
+              Left = 32
+              Top = 64
+              Width = 41
+              Height = 21
+              TabOrder = 0
+              Text = '1.0'
+            end
+            object HSDelpEdit1: TEdit
+              Left = 32
+              Top = 96
+              Width = 41
+              Height = 21
+              TabOrder = 1
+              Text = '1.0'
+            end
+            object HSMaxpEdit1: TEdit
+              Left = 32
+              Top = 16
+              Width = 41
+              Height = 21
+              TabOrder = 2
+              Text = '50'
+            end
+            object HSMaxBEdit1: TEdit
+              Left = 32
+              Top = 128
+              Width = 41
+              Height = 21
+              TabOrder = 3
+              Text = '0.001'
+            end
+            object PartialSelectCombo: TListBox
+              Left = 96
+              Top = 8
+              Width = 25
+              Height = 425
+              Font.Charset = DEFAULT_CHARSET
+              Font.Color = clWindowText
+              Font.Height = -11
+              Font.Name = 'MS Sans Serif'
+              Font.Style = []
+              ItemHeight = 13
+              Items.Strings = (
+                '1'
+                '2'
+                '3'
+                '4'
+                '5'
+                '6'
+                '7'
+                '8'
+                '9'
+                '10'
+                '11'
+                '12'
+                '13'
+                '14'
+                '15'
+                '16'
+                '17'
+                '18'
+                '19'
+                '20'
+                '21'
+                '22'
+                '23'
+                '24'
+                '25'
+                '26'
+                '27'
+                '28'
+                '29'
+                '30'
+                '31'
+                '32')
+              ParentFont = False
+              TabOrder = 4
+            end
+            object HSMinF0Edit1: TEdit
+              Left = 32
+              Top = 160
+              Width = 41
+              Height = 21
+              TabOrder = 5
+              Text = '27.5'
+            end
+            object HSMaxF0Edit1: TEdit
+              Left = 32
+              Top = 192
+              Width = 41
+              Height = 21
+              TabOrder = 6
+              Text = '3520'
+            end
+          end
+          object TabSheet6: TTabSheet
+            Caption = 'Others'
+            ImageIndex = 5
+            ExplicitLeft = 0
+            ExplicitTop = 0
+            ExplicitWidth = 0
+            ExplicitHeight = 531
+            object MouseWheelZoom: TCheckBox
+              Left = 1
+              Top = 144
+              Width = 134
+              Height = 17
+              Caption = 'Mousewheel zoom'
+              Checked = True
+              State = cbChecked
+              TabOrder = 0
+              OnClick = MouseWheelZoomClick
+            end
+            object FadeInGroup: TGroupBox
+              Left = 1
+              Top = 2
+              Width = 137
+              Height = 89
+              Caption = 'Fade in'
+              TabOrder = 1
+              object FadeInLabel: TLabel
+                Left = 16
+                Top = 56
+                Width = 28
+                Height = 13
+                Caption = 'Buffer'
+              end
+              object FadeInCheck: TCheckBox
+                Left = 16
+                Top = 24
+                Width = 97
+                Height = 17
+                Caption = 'Use fade in'
+                Checked = True
+                State = cbChecked
+                TabOrder = 0
+                OnClick = FadeInCheckClick
+              end
+              object FadeInCombo: TComboBox
+                Left = 48
+                Top = 56
+                Width = 65
+                Height = 21
+                ItemHeight = 13
+                ItemIndex = 5
+                TabOrder = 1
+                Text = '1024'
+                Items.Strings = (
+                  '32'
+                  '64'
+                  '128'
+                  '256'
+                  '512'
+                  '1024'
+                  '2048'
+                  '4096'
+                  '8192')
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+  object MainMenu1: TMainMenu
+    Images = ImageList1
+    Left = 8
+    Top = 72
+    object File1: TMenuItem
+      Caption = '&File'
+      object Open1: TMenuItem
+        Caption = '&Open'
+        ImageIndex = 0
+        OnClick = Open1Click
+      end
+      object Save1: TMenuItem
+        Caption = '&Save'
+        Enabled = False
+      end
+      object Saveas1: TMenuItem
+        Caption = 'Save &as...'
+        OnClick = SpeedButtonSaveClick
+      end
+      object Close1: TMenuItem
+        Caption = '&Close'
+        OnClick = Close1Click
+      end
+      object N1: TMenuItem
+        Caption = '-'
+      end
+      object Recent00: TMenuItem
+        Caption = '-'
+      end
+      object Recent11: TMenuItem
+        Caption = '-'
+      end
+      object Exit1: TMenuItem
+        Caption = 'E&xit'
+        ImageIndex = 1
+        OnClick = Exit1Click
+      end
+    end
+    object View1: TMenuItem
+      Caption = '&View'
+      object Spectrogram2: TMenuItem
+        Caption = 'Spectrogram'
+        ShortCut = 116
+        OnClick = SpeedButtonSClick
+      end
+      object Events1: TMenuItem
+        Caption = 'Events'
+        ShortCut = 117
+        OnClick = Events1Click
+      end
+    end
+    object Project1: TMenuItem
+      Caption = '&Project'
+      object Backup1: TMenuItem
+        Caption = 'Backup'
+        OnClick = Backup1Click
+      end
+    end
+    object Help1: TMenuItem
+      Caption = '&Help'
+      Enabled = False
+      Visible = False
+    end
+  end
+  object ImageList1: TImageList
+    Left = 40
+    Top = 72
+    Bitmap = {
+      494C010103000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      0000000000003600000028000000400000001000000001002000000000000010
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      800000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      80000000800000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      8000000080000000800000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      800000008000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000000000000000000000FF
+      FF00BFBFBF0000FFFF00BFBFBF0000FFFF00BFBFBF0000FFFF00BFBFBF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      800000008000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF000000
+      000000FFFF00BFBFBF0000FFFF00BFBFBF0000FFFF00BFBFBF0000FFFF00BFBF
+      BF0000FFFF000000000000000000000000000000000000000000000000000000
+      800000008000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000FFFF00FFFF
+      FF000000000000FFFF00BFBFBF0000FFFF00BFBFBF0000FFFF00BFBFBF0000FF
+      FF00BFBFBF0000FFFF0000000000000000000000000000000000000000000000
+      800000008000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF0000FF
+      FF00FFFFFF000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      800000008000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000FFFF00FFFF
+      FF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      800000008000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF0000FF
+      FF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      8000000080000000800000FFFF000000000000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000FFFF00FFFF
+      FF0000FFFF00FFFFFF0000FFFF00FFFFFF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      800000008000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000000000000000000000FF
+      FF00FFFFFF0000FFFF00FFFFFF00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      800000008000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000000000007F7F7F000000
+      00000000000000000000000000007F7F7F000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      8000FFFF0000000080000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFF00000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      8000FFFF0000FFFF00000000000000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000424D3E000000000000003E000000
+      2800000040000000100000000100010000000000800000000000000000000000
+      000000000000000000000000FFFFFF00FFFFC007FEFF0000FFFFC007FDFF0000
+      FFFFC007F8BF0000FFFFC007FCFF0000C00FC007FCFF00008007C007FCFF0000
+      8003C007BCFB00008001C0077EFE00008001C0077EFF0000800FC007BCFB0000
+      800FC007FCFF0000801FC007FCFF0000C0FFC007FCFF0000C0FFC007F8BF0000
+      FFFFC007FDFF0000FFFFC007FF7F000000000000000000000000000000000000
+      000000000000}
+  end
+  object OpenDialog1: TOpenDialog
+    Filter = 'waveform files (*.wav)|*.wav'
+    Left = 72
+    Top = 72
+  end
+  object NavigatorPopup: TPopupMenu
+    Left = 104
+    Top = 72
+    object Waveform1: TMenuItem
+      Caption = 'Waveform'
+      Checked = True
+      GroupIndex = 1
+      RadioItem = True
+    end
+    object Spectrogram1: TMenuItem
+      Caption = 'Spectrogram'
+      GroupIndex = 1
+      RadioItem = True
+    end
+  end
+  object WaveView1PopupMenu: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = WaveView1PopupMenuPopup
+    Left = 135
+    Top = 72
+    object ZoomToSelection1: TMenuItem
+      Caption = 'Zoom to selection'
+      OnClick = ZoomToSelection1Click
+    end
+    object UndoZoom1: TMenuItem
+      Caption = 'Undo zoom'
+      OnClick = UndoZoom1Click
+    end
+    object Restore1: TMenuItem
+      Caption = 'Restore'
+      object TimeZoom1: TMenuItem
+        Caption = 'Time zoom'
+        OnClick = TimeZoom1Click
+      end
+      object FrequencyZoom1: TMenuItem
+        Caption = 'Frequency zoom'
+        OnClick = FrequencyZoom1Click
+      end
+      object AmplitudeZoom1: TMenuItem
+        Caption = 'Amplitude zoom'
+        OnClick = AmplitudeZoom1Click
+      end
+      object SpectrogramBrightness1: TMenuItem
+        Caption = 'Spectrogram brightness'
+        OnClick = SpectrogramBrightness1Click
+      end
+    end
+    object N3: TMenuItem
+      Caption = '-'
+    end
+    object Cut1: TMenuItem
+      Caption = 'Cut'
+      OnClick = Cut1Click
+    end
+    object Extract1: TMenuItem
+      Caption = 'Extract'
+      OnClick = Extract1Click
+    end
+    object Retrieve1: TMenuItem
+      Caption = 'Retrieve'
+      ShortCut = 113
+      OnClick = Retrieve1Click
+    end
+    object N6: TMenuItem
+      Caption = '-'
+    end
+    object Vibratowizard1: TMenuItem
+      Caption = 'Vibrato...'
+      Visible = False
+      OnClick = Vibratowizard1Click
+    end
+    object Sourcefilter1: TMenuItem
+      Caption = 'Source-filter...'
+      Visible = False
+      OnClick = Sourcefilter1Click
+    end
+    object Editorpanel1: TMenuItem
+      Caption = 'Editor panel...'
+      object Amplify1: TMenuItem
+        Caption = 'Amplify'
+        OnClick = Amplify1Click
+      end
+      object Timestretching1: TMenuItem
+        Caption = 'Time stretching'
+      end
+      object Pitchshifting1: TMenuItem
+        Caption = 'Pitch shifting'
+        OnClick = Amplify1Click
+      end
+      object AM1: TMenuItem
+        Caption = 'AM'
+        OnClick = Amplify1Click
+      end
+      object FM1: TMenuItem
+        Caption = 'FM'
+        OnClick = Amplify1Click
+      end
+      object DeFM1: TMenuItem
+        Caption = 'DeFM'
+        OnClick = Amplify1Click
+      end
+    end
+    object N2: TMenuItem
+      Caption = '-'
+    end
+    object Play1: TMenuItem
+      Caption = '&Play'
+      OnClick = Play1Click
+    end
+  end
+  object SaveDialog1: TSaveDialog
+    Filter = 
+      'Waveaudio File|*.wav|Bitmap|*.bmp|Text File|*.txt|Binary File|*.' +
+      'dat'
+    Options = [ofOverwritePrompt, ofHideReadOnly, ofEnableSizing]
+    Left = 168
+    Top = 72
+  end
+  object PopupMenu1: TPopupMenu
+    Left = 119
+    Top = 464
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Unit1.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,329 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+
+#ifndef Unit1H
+#define Unit1H
+//---------------------------------------------------------------------------
+/*
+  Unit1.cpp implements the main window of HV.
+*/
+
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <ComCtrls.hpp>
+#include <ExtCtrls.hpp>
+#include <Menus.hpp>
+#include <ToolWin.hpp>
+#include <Dialogs.hpp>
+#include <ActnList.hpp>
+#include <Buttons.hpp>
+#include <ImgList.hpp>
+#include "AudioPac.h"
+#include "WaveView.h"
+#include "Navigator.h"
+
+#include "hs.h"
+#include "EventBoxUnit.h"
+#include "procedures.h"
+#include <Grids.hpp>
+
+#define wopHS 16
+#define wopCrop 17
+#define wopSample 18
+#define wopEdit 32
+
+//---------------------------------------------------------------------------
+const MaxRecents=10;
+const MaxPartialsPerCR=32;
+enum objshorttag0 {stNULL, stAtom, stFreqDelimiter, stFloater, stDUMMY, stOnset};
+//if ShortTag[0]==stAtom, then ShortTag[1]=channel, [2]=m+1, [3]=0, Tag[2]=fr
+
+class TForm1 : public TForm
+{
+__published:  // IDE-managed Components
+  TMainMenu *MainMenu1;
+  TCoolBar *CoolBar1;
+  TStatusBar *StatusBar1;
+  TMenuItem *File1;
+  TMenuItem *Open1;
+  TMenuItem *Exit1;
+  TPanel *PanelButtons;
+  TShape *PanelRightButton;
+  TImageList *ImageList1;
+  TOpenDialog *OpenDialog1;
+  TToolBar *ToolBarFile;
+  TSpeedButton *SpeedButtonOpen;
+  TMenuItem *Project1;
+  TMenuItem *Backup1;
+  TToolBar *ToolBarMode;
+  TSpeedButton *SpeedButtonS;
+  TToolButton *ToolButton2;
+  TSpeedButton *SpeedButtonT;
+  TSpeedButton *SpeedButtonF;
+  TSpeedButton *SpeedButtonM;
+  TPanel *BackPanel;
+  TPanel *PanelMain;
+  TPanel *PanelRight;
+  TPanel *PanelNavigator;
+  TSplitter *Splitter1;
+  TPanel *PanelRightBack;
+  TSplitter *Splitter2;
+  TPageControl *PageControl1;
+  TTabSheet *TabSheet1;
+  TTabSheet *TabSheet2;
+  TRadioGroup *PlaybackFilterRadio;
+  TRadioGroup *PlayChannelRadio;
+  TRadioGroup *DisplayChannelRadio;
+  TRadioGroup *PanesRadio;
+  TStaticText *StaticText1;
+  TPopupMenu *NavigatorPopup;
+  TMenuItem *Waveform1;
+  TMenuItem *Spectrogram1;
+  TToolButton *ToolButton4;
+  TToolButton *ToolButton3;
+  TSpeedButton *SpeedButtonSelect;
+  TGroupBox *GroupBox1;
+  TCheckBox *LogFreqCheck;
+  TCheckBox *FreqLineCheck;
+  TPopupMenu *WaveView1PopupMenu;
+  TMenuItem *ZoomToSelection1;
+  TMenuItem *UndoZoom1;
+  TMenuItem *N2;
+  TMenuItem *Restore1;
+  TMenuItem *TimeZoom1;
+  TMenuItem *FrequencyZoom1;
+  TMenuItem *AmplitudeZoom1;
+  TMenuItem *SpectrogramBrightness1;
+  TMenuItem *Play1;
+  TSpeedButton *SpeedButtonExit;
+  TMenuItem *Help1;
+  TMenuItem *Save1;
+  TMenuItem *Saveas1;
+  TSpeedButton *SpeedButtonSave;
+  TMenuItem *N3;
+  TMenuItem *Cut1;
+  TMenuItem *Extract1;
+  TMenuItem *Editorpanel1;
+  TMenuItem *Amplify1;
+  TMenuItem *AM1;
+  TMenuItem *FM1;
+  TMenuItem *Timestretching1;
+  TMenuItem *Pitchshifting1;
+  TMenuItem *DeFM1;
+  TMenuItem *View1;
+  TMenuItem *Events1;
+  TTabSheet *TabSheet5;
+  TLabel *Label1;
+  TEdit *HSDelmEdit1;
+  TEdit *HSDelpEdit1;
+  TLabel *Label2;
+  TLabel *Label3;
+  TEdit *HSMaxpEdit1;
+  TLabel *Label4;
+  TEdit *HSMaxBEdit1;
+  TListBox *PartialSelectCombo;
+  TLabel *Label5;
+  TEdit *HSMinF0Edit1;
+  TLabel *Label6;
+  TLabel *Label7;
+  TEdit *HSMaxF0Edit1;
+  TLabel *Label8;
+  TSaveDialog *SaveDialog1;
+  TMenuItem *N6;
+  TMenuItem *Vibratowizard1;
+  TToolButton *ToolButton1;
+  TSpeedButton *SpeedButtonRecord;
+  TMenuItem *Close1;
+  TCheckBox *AutoScrollCheck;
+  TRadioGroup *PlayFromRadio;
+  TRadioGroup *PlayUntilRadio;
+  TCheckBox *LoopCheck;
+  TTabSheet *TabSheet6;
+  TCheckBox *MouseWheelZoom;
+  TPanel *PanelWaveView;
+  TScrollBar *ScrollBar1;
+  TSplitter *Splitter3;
+  TPanel *PanelGrid;
+  TShape *PanelRightButton2;
+  TPageControl *PageControl2;
+  TTabSheet *AmpTab;
+  TStringGrid *AmpGrid;
+  TTabSheet *ArcTab;
+  TStringGrid *PhaseGrid;
+  TCheckBox *MBCheck;
+  TEdit *FormatEdit;
+	TMenuItem *Sourcefilter1;
+  TTabSheet *QPkTab;
+  TStringGrid *QPkGrid;
+  TToolBar *ToolBar1;
+  TComboBox *WindowTypeCombo;
+  TComboBox *WindowSizeCombo;
+  TComboBox *PlayFilterCombo;
+  TPopupMenu *PopupMenu1;
+  TSpeedButton *SpeedButtonCursorText;
+  TSpeedButton *SpeedButtonPaneInfo;
+  TSpeedButton *SpeedButtonPlay;
+  TToolBar *ToolBarAudio;
+  TGroupBox *FadeInGroup;
+  TLabel *FadeInLabel;
+  TCheckBox *FadeInCheck;
+  TComboBox *FadeInCombo;
+  TMenuItem *Recent00;
+  TMenuItem *Recent11;
+  TMenuItem *Retrieve1;
+  TMenuItem *N1;
+  TMenuItem *Spectrogram2;
+  void __fastcall PanelRightButtonMouseUp(TObject *Sender,
+          TMouseButton Button, TShiftState Shift, int X, int Y);
+  void __fastcall Open1Click(TObject *Sender);
+  void __fastcall Exit1Click(TObject *Sender);
+  void __fastcall Backup1Click(TObject *Sender);
+  void __fastcall SpeedButtonTClick(TObject *Sender);
+  void __fastcall SpeedButtonFClick(TObject *Sender);
+  void __fastcall SpeedButtonMClick(TObject *Sender);
+  void __fastcall LogFreqCheckClick(TObject *Sender);
+  void __fastcall WindowSizeComboChange(TObject *Sender);
+  void __fastcall WindowTypeComboChange(TObject *Sender);
+  void __fastcall WaveView1PopupMenuPopup(TObject *Sender);
+  void __fastcall ZoomToSelection1Click(TObject *Sender);
+  void __fastcall UndoZoom1Click(TObject *Sender);
+  void __fastcall Play1Click(TObject *Sender);
+  void __fastcall SpectrogramBrightness1Click(TObject *Sender);
+  void __fastcall SpeedButtonSClick(TObject *Sender);
+  void __fastcall AmplitudeZoom1Click(TObject *Sender);
+  void __fastcall Extract1Click(TObject *Sender);
+  void __fastcall FadeInCheckClick(TObject *Sender);
+  void __fastcall Cut1Click(TObject *Sender);
+  void __fastcall Amplify1Click(TObject *Sender);
+  void __fastcall Events1Click(TObject *Sender);
+  void __fastcall SpeedButtonSaveClick(TObject *Sender);
+  void __fastcall TimeZoom1Click(TObject *Sender);
+  void __fastcall FrequencyZoom1Click(TObject *Sender);
+  void __fastcall Vibratowizard1Click(TObject *Sender);
+  void __fastcall Recent11Click(TObject *Sender);
+  void __fastcall SpeedButtonRecordClick(TObject *Sender);
+  void __fastcall Close1Click(TObject *Sender);
+  void __fastcall AutoScrollCheckClick(TObject *Sender);
+  void __fastcall LoopCheckClick(TObject *Sender);
+  void __fastcall PlayUntilRadioClick(TObject *Sender);
+  void __fastcall MouseWheelZoomClick(TObject *Sender);
+  void __fastcall AmpGridDblClick(TObject *Sender);
+	void __fastcall Sourcefilter1Click(TObject *Sender);
+  void __fastcall PlayFilterComboSelect(TObject *Sender);
+  void __fastcall PlaybackFilterRadioClick(TObject *Sender);
+  void __fastcall Retrieve1Click(TObject *Sender);
+private:	// User declarations
+  bool SpectrogramView;
+  int fcalculatespcount;
+  TSpeedButton* NavButton;
+  Graphics::TBitmap* BitmapPlay;
+  Graphics::TBitmap* BitmapStop;
+  Graphics::TBitmap* BitmapSpectrogram;
+  Graphics::TBitmap* BitmapWaveform;
+  Graphics::TBitmap* BitmapRecord;
+  Graphics::TBitmap* BitmapTimeSelect;
+	Graphics::TBitmap* BitmapFreqSelect;
+	Graphics::TBitmap* BitmapMultiSelect;
+	Graphics::TBitmap* BitmapHSSelect;
+	Graphics::TBitmap* BitmapCursorText;
+	Graphics::TBitmap* BitmapPaneInfo;
+	Graphics::TBitmap* BitmapRecording;
+	AnsiString ExePath;
+	AnsiString IniFileName;
+	AnsiString TmpOutFileName;
+	AnsiString TmpInFileName;
+  int GridSourcePane;
+public:		// User declarations
+
+  THS* HS;
+  TWaveAudio* WaveAudio1;
+  TWaveAudio* WaveAudio2;
+  TWaveView* WaveView1;
+  TNavigator* Navigator1;
+
+  double f1;
+  double f2;
+  int edfr;
+  int anccount;
+  int* ancps;
+  int* ancfrs;
+  double* ancfs;
+  double* ancts;
+  TMenuItem* Recents[MaxRecents];
+
+  struct ost {int count, wid, offst, *xfr; int** pitches; double** f0s;} onset;
+
+  __fastcall TForm1(TComponent* Owner);
+  __fastcall ~TForm1();
+
+  void __fastcall AddHSObject(THS* aHS);
+  void __fastcall NavButtonClick(TObject*);
+  void __fastcall PostWaveViewData(double* data, int Channel, int StartPos, int EndPos, bool fadein, int W);
+  void __fastcall PostWaveViewData(__int16* data, int Channel, int StartPos, int EndPos, bool fadein, int W);
+  void __fastcall PostWaveViewData(__int16* data, int Channel, int StartPos, int EndPos);
+  void Initialize();
+  void PrepareNMSettings(NMSettings* settings);
+  void RecentFile(AnsiString);
+  void SetGridContents();
+  void SetWaveViewContents();
+  void ShowPanel(TPanel* APanel, bool Hide);
+
+  void __fastcall ApplicationIdle(TObject*, bool&);
+  void __fastcall CropEventStart(TObject*, TShiftState);
+  void __fastcall CropEventEnd(TObject*, TShiftState);
+  void __fastcall GetTargetAudio(int& targettype, int& channel, int& from, int& to, double*& target, __int16*& before);
+  void __fastcall Navigator1AreaChange(TObject*);
+  void __fastcall Navigator1Background(TObject*);
+  void __fastcall WaveAudio1Load(TObject*);
+  void __fastcall WaveAudio2InAddBuffer(TObject*);
+  void __fastcall WaveView1AfterPaint(TObject*);
+  void __fastcall WaveView1BeforePlayback(TObject*);
+  int __fastcall WaveView1CustomPaneInfo(TObject*);
+  int __fastcall WaveView1CustomInfo(TObject*);
+  void __fastcall WaveView1DrawFreqLimiter(TObject*, TWaveViewObject&);
+  void __fastcall WaveView1DrawObject(TObject*, TWaveViewObject&);
+  void __fastcall WaveView1DrawAtom(TObject*, TWaveViewObject&);
+  void __fastcall WaveView1InfoDblClick(TObject*);
+  void __fastcall WaveView1KeyPress(TObject* Sender, char &Key);
+  void __fastcall WaveView1MouseDown(TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
+  void __fastcall WaveView1MouseMove(TObject* Sender, TShiftState Shift, int X, int Y);
+  void __fastcall WaveView1MousePointer(TObject* Sender, int Pane, int t, double f);
+  void __fastcall WaveView1MouseUp(TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
+  void __fastcall WaveView1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint& MousePos, bool& Handled);
+  void __fastcall WaveView1ObjectClick(TObject*);
+  void __fastcall WaveView1ObjectDblClick(TObject*);
+  void __fastcall WaveView1ObjectEnter(TObject*);
+  void __fastcall WaveView1ObjectMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint& MousePos, bool& Handled);
+  void __fastcall WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode);
+  void __fastcall WaveView1ParKeyDown(TObject*, Word &Key, TShiftState Shift);
+  void __fastcall WaveView1ParMouseDown(TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
+  void __fastcall WaveView1ParMouseMove(TObject* Sender, TShiftState Shift, int X, int Y);
+  void __fastcall WaveView1ParMouseUp(TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
+  void __fastcall WaveView1ParMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint& MousePos, bool& Handled);
+  void __fastcall WaveView1PlaybackDone(TObject*);
+  void __fastcall WaveView1PlaybackStart(TObject*);
+  void __fastcall WaveView1PlaybackStartAndEndPos(TObject*, int&, int&, bool);
+
+
+};
+
+
+
+
+//---------------------------------------------------------------------------
+extern PACKAGE TForm1 *Form1;
+//---------------------------------------------------------------------------
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitRangeEdit.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,33 @@
+/*
+    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 "UnitRangeEdit.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+TRangeEdit *RangeEdit;
+//---------------------------------------------------------------------------
+__fastcall TRangeEdit::TRangeEdit(TComponent* Owner)
+  : TForm(Owner)
+{
+}
+//---------------------------------------------------------------------------
+void __fastcall TRangeEdit::FormShow(TObject *Sender)
+{
+  Edit1->SetFocus();  
+}
+//---------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitRangeEdit.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,88 @@
+object RangeEdit: TRangeEdit
+  Left = 452
+  Top = 450
+  Caption = 'RangeEdit'
+  ClientHeight = 126
+  ClientWidth = 316
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  Icon.Data = {
+    0000010001002020100000000000E80200001600000028000000200000004000
+    0000010004000000000080020000000000000000000000000000000000000000
+    000000008000008000000080800080000000800080008080000080808000C0C0
+    C0000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF000000
+    00000000000000000FFFFFF00000000000000000000000000FFFFFFF00000000
+    000000000000000000000FFF0000000000000000000000FFF00000FF00000000
+    00000000000000FFFFFF00FF00000000000000000000000FFFFFFFFF00000000
+    0000000000000000000FFFFFFFFF0000000000000000000FFF000FFFFFFF0000
+    000000000000FF0FFF0FFFFF00000000000000000000FF00FFFFFFF000000000
+    000000000000FF00FFFFFFF00000FFFFFFFFF00000FFFFFFF00FFFF00000FFFF
+    FFFFFFF00FFFFFFFFFFF000000000000000FFFFFFFFF000FFFFFFFF000FF0000
+    00000FFFFFF00000000FFFFFFFFF00000000FFFFF0000000FFF000FFFFFF0000
+    00FFFFFFF000000FFFF00000000F000000FFFF0FF00000FFFFFFF00000000000
+    0000000FF00000FFFFFFFF00000000000000000FF000000000FFFFFFF00000FF
+    FFF0000FF00000000000FFFFF00000FFFFFFFF00000000000000000000000000
+    0FFFFFFFFFFF000000000000000000000000FFFFFFFFFF000000000000000000
+    000FF000000FFF000000000000000000000FF000000000000000000000000000
+    00FFF0000000000000000000000000000FFFF000000000000000000000000000
+    0FFF000000000000000000000000000000000000000000000000000000000000
+    000000000000000000000000000000000000000000000000000000000000FFFF
+    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF}
+  OldCreateOrder = False
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Label1: TLabel
+    Left = 8
+    Top = 40
+    Width = 23
+    Height = 13
+    Caption = 'From'
+  end
+  object Label2: TLabel
+    Left = 160
+    Top = 40
+    Width = 13
+    Height = 13
+    Caption = 'To'
+  end
+  object Edit1: TEdit
+    Left = 40
+    Top = 40
+    Width = 105
+    Height = 21
+    TabOrder = 0
+    Text = 'Edit1'
+  end
+  object Edit2: TEdit
+    Left = 184
+    Top = 40
+    Width = 105
+    Height = 21
+    TabOrder = 1
+    Text = 'Edit2'
+  end
+  object BitBtn1: TBitBtn
+    Left = 72
+    Top = 88
+    Width = 75
+    Height = 25
+    TabOrder = 2
+    Kind = bkOK
+  end
+  object BitBtn2: TBitBtn
+    Left = 160
+    Top = 88
+    Width = 75
+    Height = 25
+    TabOrder = 3
+    Kind = bkCancel
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitRangeEdit.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,43 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+#ifndef UnitRangeEditH
+#define UnitRangeEditH
+//---------------------------------------------------------------------------
+/*
+  UnitRangeEdit implements the time and frequency range input box of HV.
+*/
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <Buttons.hpp>
+//---------------------------------------------------------------------------
+class TRangeEdit : public TForm
+{
+__published:	// IDE-managed Components
+  TEdit *Edit1;
+  TEdit *Edit2;
+  TLabel *Label1;
+  TLabel *Label2;
+  TBitBtn *BitBtn1;
+  TBitBtn *BitBtn2;
+  void __fastcall FormShow(TObject *Sender);
+private:	// User declarations
+public:		// User declarations
+  __fastcall TRangeEdit(TComponent* Owner);
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TRangeEdit *RangeEdit;
+//---------------------------------------------------------------------------
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VibratoDemoUnit.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,1573 @@
+/*
+    Harmonic Visualiser
+
+    An audio file viewer and editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2011 Wen Xue.
+
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version. 
+*/
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+
+#include <Math.hpp>
+#include <math.h>
+#include "VibratoDemoUnit.h"
+#include "Matrix.h"
+#include "Unit1.h"
+#include "splines.h"
+#include "hssf.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+TVibratoDemoForm *VibratoDemoForm;
+//---------------------------------------------------------------------------
+const double updb=10, downdb=-80, dbrange=updb-downdb;
+const double log10e=Log10(exp(1));
+const Bdw=5, Bdwc=2;
+
+
+__fastcall TVibratoDemoForm::TVibratoDemoForm(TComponent* Owner)
+  : TForm(Owner)
+{
+  ForceUpdate=false;
+
+	SUThread=0;
+	pThread=0;
+	memset(ThreadList, 0, sizeof(TSUThread*)*ThreadCaps);
+
+  WaveAudio1=new TWaveAudio(NULL);
+  WaveAudio1->UseMemoryStream=true;
+	WaveAudio1->Channels=1;
+  WaveView1=new TWaveView(NULL);
+  WaveView1->Parent=Panel2;
+  WaveView1->Align=alClient;
+  WaveView1->WaveAudio=WaveAudio1;
+  WaveView1->OnGetOpMode=WaveView1OpMode;
+  WaveView1->CreatePanes(1, 1);
+  WaveView1->SetContent(0, 0, 0, 1);
+  WaveView1->ClickFocus=true;
+  WaveView1->DefaultPopupMenu=false;
+  WaveView1->CustomInfo=WaveView1CustomInfo;
+  WaveView1->InfoLeft=5; WaveView1->InfoTop=5;
+
+  WaveAudio2=new TWaveAudio(NULL);
+  WaveAudio2->UseMemoryStream=true;
+  WaveAudio2->Channels=1;
+  WaveView2=new TWaveView(NULL);
+  WaveView2->Parent=Panel3;
+  WaveView2->Align=alClient;
+  WaveView2->WaveAudio=WaveAudio2;
+  WaveView2->CreatePanes(1, 1);
+  WaveView2->SetContent(0, 0, 0, 1);
+  WaveView2->ClickFocus=true;
+  WaveView2->DefaultPopupMenu=false;
+  WaveView2->CustomInfo=WaveView1CustomInfo;
+  WaveView2->InfoLeft=5; WaveView2->InfoTop=5;
+
+
+  HS=0;
+  CurrentModCycle=-1;
+  peaky=0;
+  cyclefrs=0;
+  cyclefs=0;
+
+  datain=0;
+}
+
+__fastcall TVibratoDemoForm::~TVibratoDemoForm()
+{
+	delete WaveAudio1;
+	delete WaveAudio2;
+  delete WaveView1;
+  delete WaveView2;
+  delete HS;
+	delete[] peaky;
+  delete[] cyclefrs;
+	delete[] cyclefs;
+	for (int i=0; i<ThreadCaps; i++) if (ThreadList[i]) delete ThreadList[i];
+  delete[] datain;
+}
+//---------------------------------------------------------------------------
+void TVibratoDemoForm::FindNote(){}
+
+void TVibratoDemoForm::Reset()
+{
+	if (!HS) return;
+	if (HS->M<=0 || HS->Fr<=0) return;
+
+	if (ListBox1->ItemIndex<0) ListBox1->ItemIndex=0;
+	double Fs=WaveView1->SamplesPerSec;
+	int FSMode=ListBox1->ItemIndex;
+	double FSF=FEdit->Text.ToDouble();
+	int FSFScale=FScaleCombo->ItemIndex;
+	if (FSFScale==0) FSF/=Fs;
+  else FSF/=Amel*log(1+Fs/700);
+	double FStheta=ThetaEdit->Text.ToDouble();
+
+  double sps=WaveView1->SamplesPerSec;
+  double h=WaveView1->SpecOffst;
+	AnalyzeV(*HS, V, peaky, cyclefrs, cyclefs, sps, h, &cyclefrcount, FSMode, FSF, FSFScale, FStheta);
+	SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  SaveV();
+  UpdateDisplay();
+}
+
+void TVibratoDemoForm::Copydata()
+{
+  int dst, den;
+  double* xrec;
+  if (HS)
+  {
+    xrec=SynthesisHSp(HS, dst, den);
+    if (dst<0) dst=0;
+
+    delete[] datain;
+    datain=new __int16[den-dst];
+
+    DoubleToInt(datain, sizeof(__int16), xrec, den-dst);
+
+    free8(xrec);
+  }
+}
+
+void TVibratoDemoForm::Synthesize()
+{
+  int dst, den;
+  double* xrec;
+  if (HS)
+  {
+    double t=GetTickCount();
+    xrec=SynthesisHS(HS, dst, den);
+    t=GetTickCount()-t;
+    Label13->Caption=t;
+  }
+  int bips=WaveAudio1->BitsPerSample;
+	double max=(1<<(bips-1)); for (int i=dst; i<den; i++) if (xrec[i]>max) max=xrec[i]; else if (xrec[i]<-max) max=-xrec[i];
+	if (max>(1<<(bips-1)))
+	{
+		max=(1<<(bips-1))/max;
+		for (int i=dst; i<den; i++) xrec[i]*=max;
+	}
+  int bps=bips/8;
+  WaveAudio2->Clear(NULL);
+  WaveAudio2->GetWaveProperties(WaveAudio1);
+  if (HS)
+  {
+    if (dst<0) dst=0;
+    void* data=new char[(den-dst)*bps];
+    DoubleToInt(data, bps, xrec, den-dst);
+
+    WaveAudio2->Clear(NULL);
+    WaveAudio2->WriteSamples(data, den-dst);
+    free8(xrec);
+    delete[] data;
+  }
+}
+
+  //for frequency modulator shape
+  void DrawBarMap(Graphics::TBitmap* Bitmap, TRect Rect, int Count, double* data, bool res, int* KX1=0, int* KX2=0)
+  {
+    TCanvas* Canvas=Bitmap->Canvas;
+    Bitmap->Width=Rect.Width();
+    Bitmap->Height=Rect.Height();
+
+    TFont* F=Canvas->Font; F->Color=clWhite; F->Height=12; F->Name="Ariel";
+    int fh=Canvas->TextHeight("0");
+    int DrawCount=res?(Count+1):Count;
+
+    double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh;
+    Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect);
+    Canvas->Brush->Color=clAqua; Canvas->Pen->Color=clAqua; Canvas->Brush->Style=bsSolid;
+    int empspace=XX/(DrawCount+1)/4;
+    double r=0; for (int i=0; i<Count; i++) r+=data[i]*data[i];
+    double sqrtr=sqrt(r);
+    double res_amp=(r>1)?0:sqrt(1-r);
+    for (int i=0; i<DrawCount; i++)
+    {
+      double ldata;
+      if (res)
+      {
+        if (i==0) ldata=data[i];
+        else if (i<Count) ldata=data[i];
+        else ldata=res_amp;
+      }
+      else ldata=data[i]/sqrtr;
+      int X=floor(Bdw+XX*(i+1)/(DrawCount+1)+0.5);
+      int Y=floor(Bdw+YY*(1-ldata)+0.5);
+      if (empspace>=1)
+      {
+        Canvas->Brush->Style=bsSolid; Canvas->Brush->Color=TColor(0xFFFF00);
+        Canvas->Rectangle(X-empspace, Y, X+empspace, Bdw+YY);
+        if (KX1) KX1[i]=X-empspace, KX2[i]=X+empspace-1;
+      }
+      else
+      {
+        Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY);
+        if (KX1) KX1[i]=X-1, KX2[i]=X+1;
+      }
+      AnsiString S=i; if (i>=Count) S="R"; int fw=Canvas->TextWidth(S);
+      Canvas->Brush->Style=bsClear;
+      Canvas->TextOut(X-fw/2, Bdw+YY, S);
+      S.sprintf("%.3g", 100*ldata*ldata); if (S[1]=='0') S=S.SubString(2, S.Length()-1); fw=Canvas->TextWidth(S);
+      if (Y-Bdw>fh) Canvas->TextOut(X-fw/2, Y-fh, S);
+      else Canvas->TextOut(X+empspace+1, Y, S);
+    }
+    Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite;
+    Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY);
+  }
+
+  TColor RotateColors[10]={clWhite, clAqua, clLime, clYellow, clRed, clTeal, clGray, clGreen, clFuchsia, clBlue};
+  //draw A-F distribution
+	void DrawAF(Graphics::TBitmap* Bitmap, TRect Rect, double xst, double xen, double dbst, double dben, int M, int Fr, atom** Partials, double* A0C, bool MA, bool bars, int FrStart=0, int TextHeight=12)
+  {
+    Bitmap->Width=Rect.Width();
+    Bitmap->Height=Rect.Height();
+    TCanvas* Canvas=Bitmap->Canvas;
+    double idbrange=1.0/(dbst-dben);
+    TFont* F=Canvas->Font; F->Color=clWhite; F->Height=TextHeight; F->Name="Ariel";
+    int fh=Canvas->TextHeight("0");
+
+    double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh;
+    Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect);
+
+    Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5);
+
+    double *x=new double[(Fr-FrStart)*4], *y=&x[Fr-FrStart], *newa=&x[(Fr-FrStart)*2], *neww=&x[(Fr-FrStart)*3];
+
+    for (int m=0; m<M; m++)
+    {
+      Canvas->Pen->Color=RotateColors[m%10]; Canvas->Brush->Color=RotateColors[m%10];
+
+      int Sc=0;
+      bool visible=false;
+      atom* Partialsm=Partials[m];
+      for (int fr=FrStart; fr<Fr; fr++)
+      {
+        if (Partialsm[fr].f>0 && Partialsm[fr].a>0)
+        {
+          x[Sc]=Partials[m][fr].f;
+          y[Sc]=20*Log10(Partialsm[fr].a/A0C[fr]);
+          if (x[Sc]<xen) visible=true;
+          Sc++;
+        }
+      }
+      if (!visible) break;
+
+      if (MA)
+      {
+        double fw;
+        for (int c=0; c<Sc; c++) newa[c]=y[c], neww[c]=1;
+        for (int c=0; c<Sc; c++)
+        {
+          fw=0.002; if (fw>x[c]*0.05) fw=x[c]*0.05;
+
+          for (int c1=0; c1<c; c1++)
+          {
+            double df=fabs(x[c]-x[c1]);
+            if (df<fw)
+            {
+              double w=0.5+0.5*cos(M_PI*df/fw);
+              newa[c]+=y[c1]*w; neww[c]+=w;
+              newa[c1]+=y[c]*w; neww[c1]+=w;
+            }
+          }
+        }
+        for (int c=0; c<Sc; c++) y[c]=newa[c]/neww[c];
+      }
+
+      for (int c=0; c<Sc; c++)
+      {
+        if (x[c]<xst || x[c]>xen) continue;
+        double ldata=(y[c]-dben)*idbrange;
+        int X=floor(Bdw+XX*(x[c]-xst)/(xen-xst)+0.5);
+        int Y=floor(Bdw+YY*(1-ldata)+0.5);
+        if (bars) {Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY);}
+        else {Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2);}
+      }
+    }
+
+    AnsiString S="0hz"; Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
+    S="5.5khz"; int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
+    S="11khz"; fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S);
+    S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S);
+    S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S);
+    S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S);
+
+    Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite;
+    Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY);
+
+    delete[] x;
+
+  }   //*/
+  //for source-filter results
+	void DrawSFr(Graphics::TBitmap* Bitmap, TRect Rect, double xst, double xen, double dbst, double dben, int M, int Fr, int afres, atom** Partials, double* LogAF, double* LogAS, int TextHeight=12)
+  {
+    Bitmap->Width=Rect.Width();
+    Bitmap->Height=Rect.Height();
+    TCanvas* Canvas=Bitmap->Canvas;
+		TFont* F=Canvas->Font; F->Color=clWhite; F->Height=TextHeight; F->Name="Ariel";
+    int fh=Canvas->TextHeight("0");
+
+    double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh;
+    Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect);
+
+    Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5);
+
+    double xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange,
+           xrangeiXX=xrange/XX, xstafres=xst*afres, xrangeiXXafres=xrangeiXX*afres,
+           YYidbrange=YY/(dbst-dben);
+
+    int *XRec=new int[XX];
+    for (int m=0; m<M; m++)
+    {
+      bool visible=false;
+      atom* Partialsm=Partials[m];
+      Canvas->Brush->Color=RotateColors[m%10]; Canvas->Pen->Color=RotateColors[m%10];
+      memset(XRec, 0, sizeof(int)*XX);
+
+      for (int fr=0; fr<Fr; fr++)
+      {
+        if (Partialsm[fr].f>0 && Partialsm[fr].a>0)
+        {
+          double xx=Partialsm[fr].f;
+          if (xx<xen) visible=true;
+          if (xx<xst || xx>xen) continue;
+          int X=floor(XXixrange*xx-xstXXixrange+0.5);
+          if (X>=0 && X<XX && !XRec[X])
+          {
+            XRec[X]=true;
+            double yy=20*log10e*(LogAF[int(xstafres+X*xrangeiXXafres)]+LogAS[m]);
+            int Y=Bdw+floor((YY-YYidbrange*(yy-dben))+0.5);
+            X+=Bdw;
+            Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y);
+            Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2);
+          }
+        }
+      }
+      if (!visible) break;
+    }
+    delete[] XRec;
+
+    AnsiString S="0hz"; Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
+    S="5.5khz"; int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
+    S="11khz"; fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S);
+    S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S);
+    S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S);
+    S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S);
+
+    Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite;
+    Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY);
+  }   
+  //*for source-filter model
+	int DrawSF(Graphics::TBitmap* Bitmap, TRect Rect, double xst, double xen, double dbst, double dben, double f0, int SCount, double* LogAS, double fc0, int FCount, double* LogAF, int* SX=0, TColor* Colors=0, int TextHeight=12)
+  {
+    Bitmap->Width=Rect.Width();
+    Bitmap->Height=Rect.Height();
+    TCanvas* Canvas=Bitmap->Canvas;
+    double *Sx=new double[SCount];
+    for (int i=0; i<SCount; i++) Sx[i]=20*log10e*LogAS[i];
+
+    int result=0;
+		TFont* F=Canvas->Font; F->Color=clWhite; F->Height=TextHeight; F->Name="Ariel";
+    int fh=Canvas->TextHeight("0");
+
+    double XX=Rect.right-Bdw*2, YY=Rect.bottom-Bdw-Bdwc-fh;
+    Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->FillRect(Rect);
+    Canvas->Pen->Color=clSilver; Canvas->MoveTo(Bdw, Bdw+YY*0.5); Canvas->LineTo(Bdw+XX, Bdw+YY*0.5);
+
+    double idbrange=1.0/(dbst-dben), xrange=xen-xst, XXixrange=XX/xrange, xstXXixrange=xst*XXixrange,
+      YY20log10eidbrange=YY*20*log10e*idbrange, BdwpYYpYYdbenidbrange=Bdw+YY+YY*dben*idbrange,
+      Bdw_xstXXixrange=Bdw-xstXXixrange, YYidbrange=YY*idbrange;
+
+    double st=xst/fc0; int ist=ceil(st); if (ist<0) ist=0;
+    Canvas->Pen->Color=clWhite;
+    Canvas->MoveTo(Bdw+XX*(fc0*ist-xst)/xrange+0.5, BdwpYYpYYdbenidbrange-YY20log10eidbrange*LogAF[ist]+0.5);
+    //draw filter contour
+    int LineCount=xrange/fc0;
+    if (LineCount<XX)
+    {
+      for (int i=ist+1; i<FCount; i++)
+      {
+        double xi=fc0*i;
+        if (xi>xen) break;
+        int X=floor(Bdw_xstXXixrange+xi*XXixrange+0.5);
+        int Y=floor(BdwpYYpYYdbenidbrange-YY20log10eidbrange*LogAF[i]+0.5);
+        Canvas->LineTo(X, Y);
+      }
+    }
+    else
+    {
+      double di=xrange/(XX*fc0);
+      for (int x=0; x<XX; x++)
+      {
+        int i=st+x*di;
+        int Y=floor(BdwpYYpYYdbenidbrange-YY20log10eidbrange*LogAF[i]+0.5);
+        Canvas->LineTo(Bdw+x, Y);
+      }
+    }
+    //draw source lines
+    for (int i=0; i<SCount; i++)
+    {
+      double xi=f0*(i+1);
+      if (xi<xst || xi>xen) continue;
+      int X=floor(Bdw_xstXXixrange+XXixrange*xi+0.5);
+      int Y=floor(BdwpYYpYYdbenidbrange-YYidbrange*Sx[i]+0.5);
+      if (Colors) Canvas->Pen->Color=Colors[i];
+      else Canvas->Pen->Color=RotateColors[i%10];
+
+      Canvas->MoveTo(X, Y); Canvas->LineTo(X, Bdw+YY);
+
+      if (SX) SX[i]=X, result++;
+    }
+    AnsiString S="0hz"; Canvas->Brush->Style=bsClear; Canvas->TextOut(Bdw, Bdw+YY, S);
+    S="5.5khz"; int fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+(XX-fw)/2, Bdw+YY, S);
+    S="11khz"; fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY, S);
+    S.sprintf("%gdB", dbst); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw, S);
+    S.sprintf("%gdB", (dbst+dben)/2); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+(YY-fh)/2, S);
+    S.sprintf("%gdB", dben); fw=Canvas->TextWidth(S); Canvas->TextOut(Bdw+XX-fw, Bdw+YY-fh, S);
+
+    Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsClear; Canvas->Pen->Color=clWhite;
+    Canvas->Rectangle(Bdw, Bdw, Bdw+XX, Bdw+YY);
+    delete[] Sx;
+    return result;
+  }   //*/
+
+	void DrawF0(Graphics::TBitmap* Bitmap, TCanvas* Canvas, TRect Rect, double* lp, int npfr, double* F0, double f_c, double f_ex, double sps, double F0Overall, int Fr, atom** Partials, double L, bool Captions=true, TColor F0Color=clLime, bool peakmark=false, TColor peakmarkcolor=clYellow, double* peaky=0, TColor peakycolor=clYellow, double* frs=0, double* fs=0)
+  {
+    Canvas->Brush->Color=cl3DDkShadow; Canvas->FillRect(Rect);
+    int Width=Rect.Width(), Height=Rect.Height();
+    Bitmap->Width=Width; Bitmap->Height=Height;
+    TPen* P=Canvas->Pen;
+    TFont* F=Canvas->Font;
+
+    int X, Y, Y1=0, Y2=Height, Y_;
+    AnsiString S, as;
+
+    P->Color=clBlack; P->Style=psDot; F->Color=clBlack; F->Height=12; F->Name="Ariel";
+    double f0max=-0.5, f0min=0.5; for (int fr=lp[0]; fr<lp[npfr-1]; fr++){if (f0max<F0[fr]) f0max=F0[fr]; if (f0min>F0[fr]) f0min=F0[fr];}
+    Y1=Height*(0.5-(f0max-f_c)/f_ex); Canvas->MoveTo(0, Y1); Canvas->LineTo(Width, Y1);
+    if (Captions){as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f0max*sps)/C4)); S.sprintf("%.4ghz (%s)", f0max*sps, as.c_str()); Canvas->TextOut(1, Y1-Canvas->TextHeight(S)-1, S);}
+    Y2=Height*(0.5-(f0min-f_c)/f_ex); Canvas->MoveTo(0, Y2); Canvas->LineTo(Width, Y2);
+    if (Captions){as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f0min*sps)/C4)); S.sprintf("%.4ghz (%s)", f0min*sps, as.c_str()); Canvas->TextOut(1, Y2+1, S);}
+
+    if (peakmark)
+    {
+      int Y0=0.5*(Y1+Y2), Y0ex=0.5*(Y1-Y2);
+      if (peaky) {P->Color=peakmarkcolor; P->Style=psDot; Canvas->MoveTo(0, Y0); Canvas->LineTo(Width, Y0);}
+
+      for (int pfr=0; pfr<npfr; pfr++)
+      {
+        int fr=floor(lp[pfr]);
+        X=Width*(Partials[1][fr].t*(fr+1-lp[pfr])+Partials[1][fr+1].t*(lp[pfr]-fr))/L;
+        P->Color=peakmarkcolor; P->Style=psDot; Canvas->MoveTo(X, Y1); Canvas->LineTo(X, Y2);
+        if (peaky)
+        {
+          Y=Y0ex*peaky[pfr];
+          P->Color=peakycolor; P->Style=psSolid; Canvas->MoveTo(X, Y0); Canvas->LineTo(X, Y0+Y);
+        }
+      }
+    }
+
+    if (Captions) {Y_=Height*(0.5-(F0Overall-f_c)/f_ex); P->Color=clWhite; Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_);}
+
+    P->Style=psSolid; P->Color=F0Color;
+    for (int fr=0; fr<Fr; fr++)
+    {
+      if (fr>0) Canvas->MoveTo(X, Y);
+      X=Width*Partials[1][fr].t/L, Y=Height*(0.5-(F0[fr]-f_c)/f_ex);
+      if (fr>0) Canvas->LineTo(X, Y);
+    }
+
+    if (frs)
+    {
+      P->Color=clRed;
+      for (int pfr=0; pfr<npfr-1; pfr++)
+      {
+        int ifrs=frs[pfr]; double rfrs=frs[pfr]-ifrs;
+        X=(Width*Partials[1][ifrs].t*(1-rfrs)+Width*Partials[1][ifrs+1].t*rfrs)/L, Y=Height*(0.5-(fs[pfr]-f_c)/f_ex);
+        Canvas->MoveTo(X-4, Y); Canvas->LineTo(X+5, Y);
+        Canvas->MoveTo(X, Y-4); Canvas->LineTo(X, Y+5);
+      }
+    }
+
+    if (Captions)
+    {
+      as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Overall*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Overall*sps, as.c_str());
+      F->Color=clWhite; F->Style=F->Style<<fsBold; Canvas->TextOut(Width-Canvas->TextWidth(S), Y_+1, S); F->Style=F->Style>>fsBold;
+      F->Color=clSilver; S="F0"; Canvas->TextOut(1, Height-Canvas->TextHeight(S), S);
+      double f=(f_c+f_ex/2)*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str()); Canvas->TextOut(Width-Canvas->TextWidth(S), 0, S);
+      f=(f_c-f_ex/2)*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str()); Canvas->TextOut(Width-Canvas->TextWidth(S), Height-Canvas->TextHeight(S), S);
+    }
+  }
+
+	void DrawF0C(Graphics::TBitmap* Bitmap, TCanvas* Canvas, TRect Rect, double* F0C, double& F0Cmax, double& F0Cmin, double f_c, double f_ex, double sps, double F0Overall, int Fr, atom** Partials, double L, bool clearbackground=true, int frcount=0, double* frs=0, double* fs=0, int* CX1=0, int* CX2=0, int* CY1=0, int* CY2=0)
+  {
+    //Draw the F0 carrier
+    Canvas->Brush->Color=cl3DDkShadow; if (clearbackground) Canvas->FillRect(Rect);
+    int Width=Rect.Width(), Height=Rect.Height();
+    Bitmap->Width=Width; Bitmap->Height=Height;
+    TPen* P=Canvas->Pen;
+    TFont* F=Canvas->Font;
+
+    P->Color=clBlack;
+    F0Cmax=f_c-f_ex, F0Cmin=f_c+f_ex;
+    for (int fr=0; fr<Fr; fr++){if (F0Cmax<F0C[fr]) F0Cmax=F0C[fr]; if (F0Cmin>F0C[fr]) F0Cmin=F0C[fr];}
+    P->Style=psDot;
+    int X, Y=Height*(0.5-(F0Cmax-f_c)/f_ex);
+    Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y);
+    AnsiString as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Cmax*sps)/C4)); AnsiString S; S.sprintf("%.4ghz (%s)", F0Cmax*sps, as.c_str());
+    F->Color=clBlack; F->Height=12; F->Name="Ariel"; Canvas->TextOut(1, Y-Canvas->TextHeight(S)-1, S);
+    Y=Height*(0.5-(F0Cmin-f_c)/f_ex);
+    Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y);
+    as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Cmin*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Cmin*sps, as.c_str());
+    Canvas->TextOut(1, Y+1, S);
+    P->Color=clWhite;
+    as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(F0Overall*sps)/C4)); S.sprintf("%.4ghz (%s)", F0Overall*sps, as.c_str());
+    int Y_=Height*(0.5-(F0Overall-f_c)/f_ex);
+    Canvas->MoveTo(0, Y_); Canvas->LineTo(Width, Y_);
+    F->Color=clWhite; F->Style=F->Style<<fsBold;
+    if (Y_+1+Canvas->TextHeight(S)<Y) Canvas->TextOut(Width-Canvas->TextWidth(S), Y_+1, S);
+    else Canvas->TextOut(Width-Canvas->TextWidth(S), Y+1, S);
+    F->Style=F->Style>>fsBold;
+
+    P->Style=psSolid; P->Color=clLime;
+    for (int fr=0; fr<Fr; fr++)
+    {
+      if (fr>0) Canvas->MoveTo(X, Y);
+      X=Width*Partials[1][fr].t/L, Y=Height*(0.5-(F0C[fr]-f_c)/f_ex);
+      if (fr>0) Canvas->LineTo(X, Y);
+    }
+
+    if (frcount)
+    {
+      P->Color=clRed;
+      for (int p=0; p<frcount; p++)
+      {
+        int ifrs=frs[p]; double rfrs=frs[p]-ifrs;
+        X=(Width*Partials[1][ifrs].t*(1-rfrs)+Width*Partials[1][ifrs+1].t*rfrs)/L, Y=Height*(0.5-(fs[p]-f_c)/f_ex);
+        Canvas->MoveTo(X-4, Y); Canvas->LineTo(X+5, Y);
+        Canvas->MoveTo(X, Y-4); Canvas->LineTo(X, Y+5);
+        if (CX1) CX1[p]=X-4;
+        if (CX2) CX2[p]=X+4;
+        if (CY1) CY1[p]=Y-4;
+        if (CY2) CY2[p]=Y+4;
+      }
+    }
+
+		double f=(f_c+f_ex/2)*sps;
+		F->Color=clSilver;
+		as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str());
+		Canvas->TextOut(Width-Canvas->TextWidth(S), 0, S);
+		f=(f_c-f_ex/2)*sps; as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4)); S.sprintf("%.4ghz (%s)", f, as.c_str());
+		Canvas->TextOut(Width-Canvas->TextWidth(S), Height-Canvas->TextHeight(S), S);
+		F->Color=clSilver; S="F0 carrier";
+		Canvas->TextOut(1, Height-Canvas->TextHeight(S), S);
+	}
+
+	void DrawF0D(Graphics::TBitmap* Bitmap, TCanvas* Canvas, TRect Rect, double* lp, int npfr, double* F0D, double& F0Dmax, double& F0Dmin, double f_c, double f_ex, double sps, double F0Overall, int Fr, atom** Partials, double L)
+	{
+		int Width=Rect.Width(), Height=Rect.Height();
+		Bitmap->Width=Width; Bitmap->Height=Height;
+
+		Canvas->Brush->Style=bsSolid; Canvas->Brush->Color=cl3DDkShadow; Canvas->FillRect(Rect);
+
+		//this part draws the modulator itself
+		F0Dmax=-f_ex, F0Dmin=f_ex;
+		for (int fr=lp[0]; fr<lp[npfr-1]; fr++){if (F0Dmax<F0D[fr]) F0Dmax=F0D[fr]; if (F0Dmin>F0D[fr]) F0Dmin=F0D[fr];}
+		TPen* P=Canvas->Pen; P->Color=clBlack; P->Style=psDot;
+		int X, Y=Height*(0.5-F0Dmax/f_ex); Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y);
+		AnsiString S; S.sprintf("%.4ghz (%.3g%%)", F0Dmax*sps, F0Dmax/F0Overall*100);
+		TFont* F=Canvas->Font; F->Color=clBlack; F->Height=12; F->Name="Ariel";
+		Canvas->TextOut(1, Y-Canvas->TextHeight(S)-1, S);
+		Y=Height*(0.5-F0Dmin/f_ex);
+		Canvas->MoveTo(0, Y); Canvas->LineTo(Width, Y);
+		S.sprintf("%.4ghz (%.3g%%)", F0Dmin*sps, F0Dmin/F0Overall*100); Canvas->TextOut(1, Y+1, S);
+
+		P->Style=psSolid; P->Color=clSilver; Canvas->MoveTo(0, Height/2); Canvas->LineTo(Width, Height/2);
+		Canvas->Pen->Color=clLime;
+		for (int fr=0; fr<Fr; fr++)
+		{
+			if (fr>0) Canvas->MoveTo(X, Y);
+			X=Width*Partials[1][fr].t/L, Y=Height*(0.5-F0D[fr]/f_ex);
+			if (fr>0) Canvas->LineTo(X, Y);
+		}
+		P->Color=clBlue;
+		for (int fr=0; fr<Fr; fr++)
+		{
+			X=Width*Partials[1][fr].t/L, Y=Height*(0.5-F0D[fr]/f_ex);
+			Canvas->MoveTo(X-1, Y); Canvas->LineTo(X+2, Y); Canvas->MoveTo(X, Y-1); Canvas->LineTo(X, Y+2);
+		}
+		F->Color=clSilver; F->Height=12; F->Name="Ariel";
+		S.sprintf("%.4ghz (%.3g%%)", f_ex*sps/2, f_ex/2/F0Overall*100); Canvas->TextOut(Width-Canvas->TextWidth(S), 0, S);
+		S.sprintf("%.4ghz (%.3g%%)", -f_ex*sps/2, -f_ex/2/F0Overall*100); Canvas->TextOut(Width-Canvas->TextWidth(S), Height-Canvas->TextHeight(S), S);
+
+		F->Color=clSilver; S="F0 modulator"; Canvas->TextOut(1, Height-Canvas->TextHeight(S), S);
+	}
+
+	//y=ax+b
+	void linefit(int n, double* x, double* y, double* indi, double& a, double& b)
+  {
+    double sx=0, sy=0, sxy=0, sxx=0, m=0;
+    for (int i=0; i<n; i++) if (indi[i]>0) sx+=x[i], sy+=y[i], sxx+=x[i]*x[i], sxy+=x[i]*y[i], m++;
+    if (m<=0) {a=-1; b=-1; return;}
+    double id=1.0/(m*sxx-sx*sx);
+    a=(m*sxy-sx*sy)*id;
+    b=(sxx*sy-sx*sxy)*id;
+  }
+
+void TVibratoDemoForm::UpdateDisplay(bool f0, bool f0c, bool f0d, bool sf)
+{
+  int Fr=HS->Fr;
+  atom** Partials=HS->Partials;
+  //find the highest point of the 2nd partial
+  double f2min=1, f2max=0, fst=0, fen=0.25;
+  for (int fr=0; fr<Fr; fr++)
+  {
+		if (f2max<Partials[1][fr].f) f2max=Partials[1][fr].f;
+		if (f2min>Partials[1][fr].f) f2min=Partials[1][fr].f;
+	}
+	f_c=(f2min+f2max)/4; f_ex=f2max-f2min;
+
+	if (f0) DrawF0(Image0->Picture->Bitmap, Image0->Canvas, Image0->ClientRect, V.lp, V.P, V.F0, f_c, f_ex, WaveView1->SamplesPerSec, V.F0Overall, Fr, Partials, WaveView2->Length, true, clLime, PeakMarksCheck->Checked, clYellow, 0, TColor(0), 0/*cyclefrs*/, cyclefs);
+  if (f0c)
+  {
+    memset(CX1, 0xFF, sizeof(int)*128); memset(CX2, 0xFF, sizeof(int)*128); memset(CY1, 0xFF, sizeof(int)*128); memset(CY1, 0xFF, sizeof(int)*128);
+		DrawF0C(Image1->Picture->Bitmap, Image1->Canvas, Image1->ClientRect, V.F0C, V.F0Cmax, V.F0Cmin, f_c, f_ex, WaveView1->SamplesPerSec, V.F0Overall, Fr, Partials, WaveView2->Length, true, PeakMarksCheck->Checked?cyclefrcount:0, cyclefrs, cyclefs, CX1, CX2, CY1, CY2);
+  }
+  if (f0d)
+  {
+    //Draw the F0 modulator
+    DrawModulator();
+  //
+    double sps=WaveView1->SamplesPerSec;
+    DurationEdit->Text=AnsiString().sprintf("%.4gs", WaveView2->Length/sps);
+    RegEdit->Text=AnsiString().sprintf("%.4g", V.regularity);
+    RateEdit->Text=AnsiString().sprintf("%.4ghz", V.rate);
+    if (ResidueCheck->Checked) {FXX[0]=sqrt(1-V.FRes[0]); for (int i=1; i<V.K; i++) FXX[i]=sqrt(V.FRes[i-1]-V.FRes[i]);}
+    else {FXX[0]=fabs(V.FXR[0]); for (int i=1; i<V.K; i++) FXX[i]=2*sqrt(V.FXR[2*i]*V.FXR[2*i]+V.FXR[2*i-1]*V.FXR[2*i-1]);}
+    DrawBarMap(MImage1->Picture->Bitmap, MImage1->ClientRect, V.K, FXX, ResidueCheck->Checked, KX1, KX2);
+  }
+
+  if (sf)
+  {
+    if (SFCheck->Checked)
+			DrawSFr(AImage1->Picture->Bitmap, AImage1->ClientRect, fst, fen, updb, downdb, V.M, Fr, V.afres, Partials, V.LogAF, V.LogAS);
+		else
+      DrawAF(AImage1->Picture->Bitmap, AImage1->ClientRect, fst, fen, updb, downdb, V.M, Fr, Partials, V.A0C, MACheck->Checked, false);
+    SXc=DrawSF(AImage3->Picture->Bitmap, AImage3->ClientRect, fst, fen, updb, downdb, V.F0Overall, V.M, V.LogAS, 1.0/V.afres, V.afres/2, V.LogAF, SX);
+  }
+
+  ForceUpdate=false;
+}
+
+void __fastcall TVibratoDemoForm::WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode)
+{
+  if (Shift.Contains(ssShift)) OpMode=0; //drag mode
+  else OpMode=1; //select mode
+}
+
+int __fastcall TVibratoDemoForm::WaveView1CustomInfo(TObject* Sender)
+{
+  TWaveView* WV=(TWaveView*)Sender;
+  TStringList* List=new TStringList;
+  double fs=WV->StartPos*1.0/WV->SamplesPerSec, fe=WV->EndPos*1.0/WV->SamplesPerSec;
+  List->Add(AnsiString().sprintf(" Time (%.4gs): from %.4gs to %.4gs. ", fe-fs, fs, fe));
+  List->Add(AnsiString().sprintf(" Frequency: from %.1fhz to %.1fhz. ", WV->StartDigiFreq*WV->SamplesPerSec, WV->EndDigiFreq*WV->SamplesPerSec));
+  return int(List);
+}
+
+void __fastcall TVibratoDemoForm::Image1MouseMove(TObject *Sender,
+      TShiftState Shift, int X, int Y)
+{
+  if (!HS) return;
+  TImage* Image=(TImage*)Sender;
+  Image->Parent->SetFocus();
+
+  double t, sps=WaveView1->SamplesPerSec, f; AnsiString S, as; TFont* F=Image->Canvas->Font;
+
+  if (Sender==Image1)
+  {
+    if (Shift.Contains(ssLeft))
+    {
+      if (CurrentC<0 || CurrentC>=cyclefrcount) return;
+      double df=-(Y-StartDrag)*f_ex/Image->Height;
+      cyclefs[CurrentC]+=df;
+      StartDrag=Y;
+      Smooth_Interpolate(V.F0C, V.L, cyclefrcount+1, cyclefs, cyclefrs);
+      SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+      UpdateDisplay(true, true, true, false);
+
+        t=HS->Partials[0][0].t+V.h*cyclefrs[CurrentC];
+        f=cyclefs[CurrentC]*sps;
+        as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4));
+        S.sprintf("%.3gs, %.4ghz (%s)     ", t/sps, f, as.c_str());
+        F->Color=clRed;
+        Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
+
+    }
+    else
+    {
+      CurrentC=-1;
+      for (int i=0; i<cyclefrcount; i++)
+        if (X>=CX1[i] && X<=CX2[i] && Y>=CY1[i] && Y<=CY2[i]) {CurrentC=i; break;}
+    }
+      if (CurrentC>=0 && CurrentC<cyclefrcount)
+      {
+        t=HS->Partials[0][0].t+V.h*cyclefrs[CurrentC];
+        f=cyclefs[CurrentC]*sps;
+        as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4));
+        S.sprintf("%.3gs, %.4ghz (%s)     ", t/sps, f, as.c_str());
+        F->Color=clRed;
+        Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
+      }
+      else
+      {
+        S.sprintf("                                        ", t/sps, f, as.c_str());
+        Image->Canvas->TextOut(1, Image->Canvas->TextHeight("0"), S);
+      }
+  }
+
+  t=WaveView2->Length*1.0*(X+0.5)/Image->Width;
+  f=(f_c-(Y-0.5*Image->Height)*f_ex/Image->Height)*sps;
+  as=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(f)/C4));
+  S.sprintf("%.3gs, %.4ghz (%s)       ", t/sps, f, as.c_str());
+  F->Color=clAqua; F->Height=12; F->Name="Ariel";
+  Image->Canvas->TextOut(1, 0, S);
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::Image2MouseMove(TObject *Sender,
+      TShiftState Shift, int X, int Y)
+{
+  if (!HS) return;
+  if (Shift.Contains(ssLeft)) return;
+  atom** Partials=HS->Partials;
+  Image2->Parent->SetFocus();
+  double t=WaveView2->Length*1.0*(X+0.5)/Image2->Width, sps=WaveView1->SamplesPerSec;
+  double f=-(Y-0.5*Image2->Height)*f_ex/Image2->Height;
+
+  if (true || Shift.Contains(ssShift))
+  {
+    int modcycle=0;
+    if (t<Partials[0][0].t+V.lp[0]*V.h || t>Partials[0][0].t+V.lp[V.P-1]*V.h) modcycle=-1;
+    else while (t>Partials[0][0].t+V.lp[modcycle]*V.h) modcycle++;
+    if (CurrentModCycle!=modcycle)
+    {
+      CurrentModCycle=modcycle;
+
+      if (CurrentModCycle==-1)
+      {
+        if (PageControl1->ActivePage==ModCycleSheet)
+        {
+          PageControl1->ActivePage=ModOverSheet;
+          ResidueCheck->Parent=ModOverSheet;
+        }
+        else if (PageControl1->ActivePage==AmpCycleSheet)
+        {
+          PageControl1->ActivePage=AmpOverSheet;
+          SFCheck->Parent=AmpOverSheet;
+          MACheck->Parent=AmpOverSheet;
+        }
+      }
+      else
+      {
+        if (PageControl1->ActivePage==ModOverSheet)
+        {
+          PageControl1->ActivePage=ModCycleSheet;
+          ResidueCheck->Parent=ModCycleSheet;
+        }
+        else if (PageControl1->ActivePage==AmpOverSheet)
+        {
+          PageControl1->ActivePage=AmpCycleSheet;
+          SFCheck->Parent=AmpCycleSheet;
+          MACheck->Parent=AmpCycleSheet;
+        }
+        ModCycleSheet->Caption="Modulator Cycle "+AnsiString(CurrentModCycle);
+        AmpCycleSheet->Caption="Amplitudes Cycle "+AnsiString(CurrentModCycle);
+      }
+      DrawModulator();
+    }
+  }
+
+  AnsiString S;
+  S.sprintf("%.3gs, %.4ghz (%.3g%%)       ", t/sps, f*sps, f/V.F0Overall*100);
+  TFont* F=Image2->Canvas->Font; F->Color=clAqua; F->Height=12; F->Name="Ariel";
+  Image2->Canvas->TextOut(1, 0, S);
+}
+//---------------------------------------------------------------------------
+void TVibratoDemoForm::DrawModulator()
+{
+  double fst=0, fen=0.25;
+
+  Image2->Picture->Bitmap->Width=Image2->Width;
+  Image2->Picture->Bitmap->Height=Image2->Height;
+
+  int X, Y, L=WaveView2->Length, Fr=HS->Fr;
+  double sps=WaveView2->SamplesPerSec;
+  atom** Partials=HS->Partials;
+  TCanvas* I2Canvas=Image2->Canvas; I2Canvas->Brush->Style=bsSolid; I2Canvas->Brush->Color=cl3DDkShadow; I2Canvas->FillRect(Image2->ClientRect);
+  if (CurrentModCycle>=1 && CurrentModCycle<V.P)
+  {
+		CurrentModCycleStart=Partials[0][0].t+V.lp[CurrentModCycle-1]*WaveView1->SpecOffst;
+		CurrentModCycleEnd=Partials[0][0].t+V.lp[CurrentModCycle]*WaveView1->SpecOffst;
+
+		int X1=Image2->Width*CurrentModCycleStart/L;
+		int X2=Image2->Width*CurrentModCycleEnd/L;
+		I2Canvas->Brush->Color=clDkGray; I2Canvas->FillRect(TRect(X1, 0, X2, Image2->Height));
+		I2Canvas->Brush->Color=cl3DDkShadow;
+
+    //this part update the tab sheet
+    int frst=V.peakfr[CurrentModCycle-1], fren=V.peakfr[CurrentModCycle];
+    if (PageControl1->ActivePage==ModCycleSheet)
+    {
+      CycleDurationEdit->Text=AnsiString().sprintf("%.4gs (%.4gs~%.4gs)", (CurrentModCycleEnd-CurrentModCycleStart)/sps, CurrentModCycleStart/sps, CurrentModCycleEnd/sps);
+      CycleRateEdit->Text=AnsiString().sprintf("%.4ghz", sps/(CurrentModCycleEnd-CurrentModCycleStart));
+
+      double af0c=(V.F0C[frst]+V.F0C[fren])*0.5, f0dmax=V.F0D[frst], f0dmin=V.F0D[frst];
+      double np=1, nn=0;
+      double pdp=(V.F0D[frst]*V.F0D[frst]+V.F0D[fren]*V.F0D[fren])*0.5, pdn=0;
+      for (int fr=frst+1; fr<fren; fr++)
+      {
+        af0c+=V.F0C[fr];
+        if (V.F0D[fr]>f0dmax) f0dmax=V.F0D[fr];
+        if (V.F0D[fr]<f0dmin) f0dmin=V.F0D[fr];
+        if (V.F0D[fr]>0) pdp+=V.F0D[fr]*V.F0D[fr], np+=1;
+        else if (V.F0D[fr]<0) pdn+=V.F0D[fr]*V.F0D[fr], nn+=1;
+      }
+      af0c/=(fren-frst);
+      pdp=(np>0)?sqrt(pdp/np):0, pdn=(nn>0)?sqrt(pdn/nn):0;
+      AnsiString S=SemitoneToPitch(12*Log2(WV2_LOG_FREQ(af0c*sps)/C4));
+      CyclePitchEdit->Text=AnsiString().sprintf("%.4ghz (%s)", af0c*sps, S.c_str());
+      CycleExtentEdit->Text=AnsiString().sprintf("%.3g%%~%.3g%%", f0dmin/af0c*100, f0dmax/af0c*100);
+      CycleAvgPDEdit->Text=AnsiString().sprintf("-%.3g%%~%.3g%%", pdn/af0c*100, pdp/af0c*100);
+
+
+      if (ResidueCheck->Checked) {FXX[0]=sqrt(1-V.fres[CurrentModCycle][0]); for (int i=1; i<V.Kp[CurrentModCycle]; i++) FXX[i]=sqrt(V.fres[CurrentModCycle][i-1]-V.fres[CurrentModCycle][i]); for (int i=V.Kp[CurrentModCycle]; i<V.K; i++) FXX[i]=0;}
+      else {FXX[0]=fabs(V.fxr[CurrentModCycle][0]); for (int i=1; i<V.Kp[CurrentModCycle]; i++) FXX[i]=2*sqrt(V.fxr[CurrentModCycle][2*i]*V.fxr[CurrentModCycle][2*i]+V.fxr[CurrentModCycle][2*i-1]*V.fxr[CurrentModCycle][2*i-1]); for (int i=V.Kp[CurrentModCycle]; i<V.K; i++) FXX[i]=0;}
+      DrawBarMap(MImage2->Picture->Bitmap, MImage2->ClientRect, V.K, FXX, ResidueCheck->Checked, KX1, KX2);
+    }
+    else if (PageControl1->ActivePage==AmpCycleSheet)
+    {
+      if (SFCheck->Checked)
+        DrawSFr(AImage2->Picture->Bitmap, AImage2->ClientRect, fst, fen, updb, downdb, V.M, Fr, V.afres, Partials, V.LogAF, V.LogASp[CurrentModCycle]);
+      else
+        DrawAF(AImage2->Picture->Bitmap, AImage2->ClientRect, fst, fen, updb, downdb, V.M, V.peakfr[CurrentModCycle], Partials, V.A0C, MACheck->Checked, false, V.peakfr[CurrentModCycle-1]);
+			double cf0=0; for (int i=frst; i<fren; i++) cf0+=V.F0C[i]; cf0/=(fren-frst);
+      SXcyclec=DrawSF(AImage4->Picture->Bitmap, AImage4->ClientRect, 0, 0.25, updb, downdb, cf0, V.M, V.LogASp[CurrentModCycle], 1.0/V.afres, V.afres/2, V.LogAF, SXcycle);
+    }
+  }
+  else //CurrentCycle==-1
+  {
+  }
+
+  //this part draws the modulator itself
+  V.F0Dmax=-f_ex, V.F0Dmin=f_ex;
+  for (int fr=V.peakfr[0]; fr<=V.peakfr[V.P-1]; fr++){if (V.F0Dmax<V.F0D[fr]) V.F0Dmax=V.F0D[fr]; if (V.F0Dmin>V.F0D[fr]) V.F0Dmin=V.F0D[fr];}
+  I2Canvas->Pen->Color=clBlack; I2Canvas->Pen->Style=psDot;
+  Y=Image2->Height*(0.5-V.F0Dmax/f_ex);
+  I2Canvas->MoveTo(0, Y); I2Canvas->LineTo(Image2->Width, Y);
+  AnsiString S; S.sprintf("%.4ghz (%.3g%%)", V.F0Dmax*sps, V.F0Dmax/V.F0Overall*100);
+  TFont* F=I2Canvas->Font; F->Color=clBlack; F->Height=12; F->Name="Ariel";
+  I2Canvas->TextOut(1, Y-I2Canvas->TextHeight(S)-1, S);
+  Y=Image2->Height*(0.5-V.F0Dmin/f_ex);
+  I2Canvas->MoveTo(0, Y); I2Canvas->LineTo(Image2->Width, Y);
+  S.sprintf("%.4ghz (%.3g%%)", V.F0Dmin*sps, V.F0Dmin/V.F0Overall*100);
+  I2Canvas->TextOut(1, Y+1, S);
+  I2Canvas->Pen->Style=psSolid;
+
+  I2Canvas->Pen->Color=clSilver;
+  I2Canvas->MoveTo(0, Image2->Height/2); I2Canvas->LineTo(Image2->Width, Image2->Height/2);
+  I2Canvas->Pen->Color=clBlue;
+  for (int fr=0; fr<Fr; fr++)
+  {
+    if (fr>0) I2Canvas->MoveTo(X, Y);
+    X=Image2->Width*Partials[1][fr].t/L, Y=Image2->Height*(0.5-V.F0D[fr]/f_ex);
+    if (fr>0) I2Canvas->LineTo(X, Y);
+  }
+  I2Canvas->Pen->Color=clLime;
+  for (int fr=0; fr<Fr; fr++)
+  {
+    X=Image2->Width*Partials[1][fr].t/L, Y=Image2->Height*(0.5-V.F0D[fr]/f_ex);
+    I2Canvas->MoveTo(X-1, Y); I2Canvas->LineTo(X+2, Y); I2Canvas->MoveTo(X, Y-1); I2Canvas->LineTo(X, Y+2);
+  }
+  F->Color=clSilver; F->Height=12; F->Name="Ariel";
+  S.sprintf("%.4ghz (%.3g%%)", f_ex*sps/2, f_ex/2/V.F0Overall*100);
+  I2Canvas->TextOut(Image2->Width-I2Canvas->TextWidth(S), 0, S);
+  S.sprintf("%.4ghz (%.3g%%)", -f_ex*sps/2, -f_ex/2/V.F0Overall*100);
+  I2Canvas->TextOut(Image2->Width-I2Canvas->TextWidth(S), Image2->Height-I2Canvas->TextHeight(S), S);
+
+  F->Color=clSilver; S="F0 modulator";
+  I2Canvas->TextOut(1, Image2->Height-I2Canvas->TextHeight(S), S);
+
+}
+
+
+void __fastcall TVibratoDemoForm::SFCheckClick(TObject *Sender)
+{
+  if (Sender==SFCheck)
+  {
+    MACheck->Visible=!SFCheck->Checked;
+  }
+  UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TVibratoDemoForm::RegButtonClick(TObject *Sender)
+{
+  RegularizeV(*HS, V, WaveView1->SamplesPerSec, WaveView1->SpecOffst);
+  AnalyzeV(*HS, V, peaky, cyclefrs, cyclefs, WaveView1->SamplesPerSec, WaveView1->SpecOffst, &cyclefrcount);
+  SaveV();
+  Synthesize();
+  UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TVibratoDemoForm::ExternalInput()
+{
+  AnsiString FileName=ExtractFilePath(Application->ExeName)+"tvoin";
+  FILE* file;
+  if ((file=fopen(FileName.c_str(), "rb"))!=NULL)
+  {
+    V.LoadFromFileHandle(file);
+    fclose(file);
+    DeleteFile(FileName);
+    SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+    SaveV();
+    Synthesize();
+    UpdateDisplay();
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TVibratoDemoForm::SaveV()
+{
+  FILE* file;
+  if ((file=fopen((ExtractFilePath(Application->ExeName)+"tvoout").c_str(), "wb"))!=NULL)
+  {
+    V.SaveToFileHandle(file);
+    fclose(file);
+  }
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TVibratoDemoForm::MouseWheelHandler(TMessage& Msg)
+{
+  TWMMouseWheel* WMsg=(TWMMouseWheel*)&Msg;
+
+  bool Handled=false;
+  TMouseWheelEvent Event=NULL;
+  TControl* Sender;
+  TShiftState Shift; memcpy(&Shift, &WMsg->Keys, 1);
+
+  if (ActiveControl==Image1->Parent) Event=Image1MouseWheel, Sender=Image1;
+  else if (ActiveControl==Image2->Parent) Event=Image2MouseWheel, Sender=Image2;
+  else if (ActiveControl==AImage3->Parent) Event=AImage3MouseWheel, Sender=AImage3;
+	else if (ActiveControl==AImage1->Parent) Event=AImage3MouseWheel, Sender=AImage1;
+  else if (ActiveControl==AImage4->Parent) Event=AImage4MouseWheel, Sender=AImage4;
+  else if (ActiveControl==AImage2->Parent) Event=AImage4MouseWheel, Sender=AImage2;
+  else if (ActiveControl==MImage1->Parent) Event=MImage1MouseWheel, Sender=MImage1;
+  else if (ActiveControl==MImage2->Parent) Event=MImage1MouseWheel, Sender=MImage2;
+  else if (ActiveControl==RateEdit || ActiveControl==CycleRateEdit) Event=RateEditMouseWheel, Sender=ActiveControl;
+  else if (ActiveControl==DurationEdit || ActiveControl==CycleDurationEdit) Event=DurationEditMouseWheel, Sender=ActiveControl;
+  else if (ActiveControl==CyclePitchEdit) Event=PitchEditMouseWheel, Sender=ActiveControl;
+
+  if (Event) Event(Sender, Shift, WMsg->WheelDelta, Sender->ScreenToClient(TPoint(WMsg->Pos.x, WMsg->Pos.y)), Handled);
+  WMsg->Result=Handled;
+
+  if (!Handled) TCustomForm::MouseWheelHandler(Msg);
+}
+
+//---------------------------------------------------------------------------
+void __fastcall TVibratoDemoForm::Image1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
+{
+  double cent;
+  if (Shift.Contains(ssShift)) cent=1;
+  else if (Shift.Contains(ssCtrl)) cent=100;
+  else cent=10;
+
+  if (WheelDelta<0) cent=-cent;
+  double rate=pow(2, cent/1200);
+
+  for (int l=0; l<V.L; l++) V.F0C[l]*=rate; V.F0Overall*=rate;
+  for (int fr=0; fr<cyclefrcount; fr++) cyclefs[fr]*=rate;
+
+  SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  SaveV();
+  S_U();
+  Handled=true;
+}
+
+void __fastcall TVibratoDemoForm::Image2MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
+{
+  double rate;
+  if (Shift.Contains(ssShift)) rate=1.01;
+  else if (Shift.Contains(ssCtrl)) rate=1.282432;
+  else rate=1.05101;
+  if (WheelDelta<0) rate=1.0/rate;
+  if (CurrentModCycle>0) V.Dp[CurrentModCycle]=V.Dp[CurrentModCycle]*rate;
+  else for (int p=1; p<V.P; p++) V.Dp[p]=V.Dp[p]*rate;
+
+  SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  SaveV();
+  S_U();
+  Handled=true;
+}
+
+void __fastcall TVibratoDemoForm::AImage3MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
+{
+  double ddb;
+  if (Shift.Contains(ssShift)) ddb=0.2;
+  else if (Shift.Contains(ssCtrl)) ddb=5;
+  else ddb=1;
+  double db=20*log10e*V.LogAS[CurrentPartial];
+  if (WheelDelta<0) ddb=-ddb;
+
+  db+=ddb;
+  AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
+  if (Sender==AImage3) Label7->Caption=S;
+  else Label8->Caption=S;
+  ddb=ddb/(20*log10e);
+
+  for (int p=1; p<V.P; p++) V.LogASp[p][CurrentPartial]+=ddb;
+  V.LogAS[CurrentPartial]+=ddb;
+
+  SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  SaveV();
+  S_U(true);
+  Handled=true;
+}
+
+void __fastcall TVibratoDemoForm::AImage4MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
+{
+  double ddb;
+  if (Shift.Contains(ssShift)) ddb=0.2;
+  else if (Shift.Contains(ssCtrl)) ddb=5;
+  else ddb=1;
+  double db=20*log10e*V.LogASp[CurrentModCycle][CurrentPartial];
+  if (WheelDelta<0) ddb=-ddb;
+
+  db+=ddb;
+  AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
+  if (Sender==AImage4) Label9->Caption=S;
+  else Label10->Caption=S;
+  ddb=ddb/(20*log10e);
+
+  V.LogASp[CurrentModCycle][CurrentPartial]+=ddb;
+
+  SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  SaveV();
+  S_U(true);
+  Handled=true;
+}
+
+void __fastcall TVibratoDemoForm::MImage1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
+{
+  double rate;
+  if (Shift.Contains(ssShift)) rate=1.0192448764914566206520666016133;
+  else if (Shift.Contains(ssCtrl)) rate=1.61051;
+  else rate=1.1;
+  if (WheelDelta<0) rate=1.0/rate;
+
+  double* FXR;
+  TLabel* Label;
+  if (Sender==MImage1) FXR=V.FXR, Label=Label11;
+  else if (ActiveControl==MImage2->Parent) FXR=V.fxr[CurrentModCycle], Label=Label12;
+
+  if (CurrentK==0)
+  {
+    FXR[0]*=rate;
+    if (Sender==MImage1) for (int p=1; p<V.P; p++) V.fxr[p][0]*=rate;
+  }
+  else
+  {
+    FXR[2*CurrentK-1]*=rate, FXR[2*CurrentK]*=rate;
+    if (Sender==MImage1) for (int p=1; p<V.P; p++) V.fxr[p][2*CurrentK-1]*=rate, V.fxr[p][2*CurrentK]*=rate;
+  }
+
+  AnsiString S;
+  if (CurrentK>0) S.sprintf("%d: %.3g", CurrentK, sqrt(FXR[CurrentK*2-1]*FXR[CurrentK*2-1]+FXR[CurrentK*2]*FXR[CurrentK*2]));
+  else if (CurrentK==0) S.sprintf("%d: %.3g", CurrentK, fabs(FXR[0]));
+  Label->Caption=S;
+  Label->Left=ActiveControl->Left+0.5*(KX1[CurrentK]+KX2[CurrentK]-Label->Width);
+
+  SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  SaveV();
+  S_U();
+  Handled=true;
+}
+
+void __fastcall TVibratoDemoForm::RateEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
+{
+  double rate, irate;
+  if (Shift.Contains(ssShift)) rate=1.01;
+  else if (Shift.Contains(ssCtrl)) rate=1.282432;
+  else rate=1.05101;
+  if (WheelDelta<0) {irate=rate; rate=1.0/rate;}
+  else irate=1.0/rate;
+
+  if (Sender==CycleRateEdit)
+  {
+    if (CurrentModCycle>0)
+    {
+      double dlp=(V.lp[CurrentModCycle]-V.lp[CurrentModCycle-1])*(irate-1);
+      for (int p=CurrentModCycle; p<V.P; p++)
+      {
+        V.lp[p]+=dlp;
+        if (V.lp[p]>V.L) {V.P=p; break;}
+      }
+    }
+  }
+  else if (Sender==RateEdit)
+  {
+    double newP=V.GetOldP()*rate;
+    if (newP>2.5)
+    {
+      TVo* newV=InterpolateV(newP, rate, V);
+      V.~TVo();
+      memcpy(&V, newV, sizeof(TVo)); memset(newV, 0, sizeof(TVo));
+      delete newV;
+    }
+  }
+  SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  RateAndReg(V.rate, V.regularity, V.F0D, V.peakfr[0], V.peakfr[V.P-1], 8, WaveView1->SamplesPerSec, WaveView1->SpecOffst);
+  SaveV();
+  S_U();
+  Handled=true;
+}
+
+void __fastcall TVibratoDemoForm::DurationEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
+{
+  double rate;
+  if (Shift.Contains(ssShift)) rate=1.01;
+  else if (Shift.Contains(ssCtrl)) rate=1.282432;
+  else rate=1.05101;
+  if (WheelDelta<0) rate=1.0/rate;
+
+  if (Sender==CycleDurationEdit)
+  {
+    if (CurrentModCycle>0)
+    {
+      double dlp=(V.lp[CurrentModCycle]-V.lp[CurrentModCycle-1])*(rate-1);
+
+      for (int p=CurrentModCycle; p<V.P; p++)
+      {
+        V.lp[p]+=dlp;
+      }
+      int oldL=V.L, newL=V.L+dlp+0.5;
+
+      double *F0C=new double[V.L*2], *A0C=&F0C[V.L];
+      memcpy(F0C, V.F0C, sizeof(double)*oldL), memcpy(A0C, V.A0C, sizeof(double)*oldL);
+      V.AllocateL(newL);
+      for (int l=0; l<newL; l++)
+      {
+        double rl=1.0*l*oldL/newL;
+        int il=floor(rl); rl-=il;
+        if (fabs(rl)<1e-16)
+        {
+          V.F0C[l]=F0C[il];
+          V.A0C[l]=A0C[il];
+        }
+        else if (il>=oldL-1)
+        {
+          V.F0C[l]=F0C[oldL-1];
+          V.A0C[l]=A0C[oldL-1];
+        }
+        else
+        {
+          V.F0C[l]=F0C[il]*(1-rl)+F0C[il+1]*rl;
+          V.A0C[l]=A0C[il]*(1-rl)+A0C[il+1]*rl;
+        }
+      }
+
+      for (int c=0; c<cyclefrcount; c++)
+      {
+        cyclefrs[c]*=(1.0*newL/oldL);
+        int ic=floor(cyclefrs[c]);
+        if (ic<newL-1) cyclefs[c]=F0C[ic]*(ic+1-cyclefrs[c])+F0C[ic+1]*(cyclefrs[c]-ic);
+        else cyclefs[c]=F0C[newL-1];
+      }
+
+      delete[] F0C;
+    }
+  }
+  else if (Sender==DurationEdit)
+  {
+    double newP=V.GetOldP()*rate;
+    if (newP>2.5)
+    {
+      TVo* newV=InterpolateV(newP, 1, V); V.~TVo();
+      memcpy(&V, newV, sizeof(TVo)); memset(newV, 0, sizeof(TVo));
+      delete newV;
+
+      for (int c=0; c<cyclefrcount; c++)
+      {
+        cyclefrs[c]*=rate;
+        int ic=floor(cyclefrs[c]);
+        if (ic<V.L-1) cyclefs[c]=V.F0C[ic]*(ic+1-cyclefrs[c])+V.F0C[ic+1]*(cyclefrs[c]-ic);
+        else cyclefs[c]=V.F0C[V.L-1];
+      }
+    }
+  }
+  SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  RateAndReg(V.rate, V.regularity, V.F0D, V.peakfr[0], V.peakfr[V.P-1], 8, WaveView1->SamplesPerSec, WaveView1->SpecOffst);
+  SaveV();
+  S_U();
+  Handled=true;
+}
+
+void __fastcall TVibratoDemoForm::PitchEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
+{
+  if (CurrentModCycle<=0) return;
+
+  double cent;
+  if (Shift.Contains(ssShift)) cent=1;
+  else if (Shift.Contains(ssCtrl)) cent=100;
+  else cent=10;
+
+  if (WheelDelta<0) cent=-cent;
+  double rate_1=pow(2, cent/1200)-1;
+
+  int frst=ceil(V.lp[CurrentModCycle-1]), freninc=floor(V.lp[CurrentModCycle]);
+  for (int fr=frst; fr<=freninc; fr++) V.F0C[fr]=V.F0C[fr]*(1+rate_1);//(1+rate_1*0.5*(1-cos(2*M_PI*(fr-V.lp[CurrentModCycle-1])/(V.lp[CurrentModCycle]-V.lp[CurrentModCycle-1]))));
+
+
+  SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+  SaveV();
+  S_U();
+  Handled=true;
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TVibratoDemoForm::AImage3MouseMove(TObject *Sender,
+      TShiftState Shift, int X, int Y)
+{
+  if (!HS) return;
+  TImage* Image=(TImage*)Sender;
+
+  if (Shift.Contains(ssLeft))
+  {
+    if (CurrentPartial<0) return;
+    int fh=Image->Canvas->TextHeight("0");
+    int YY=Image->Height-Bdw-Bdwc-fh;
+    double dbperpixel=dbrange/YY;
+    int dY=Y-StartDrag;
+    StartDrag=Y;
+    double ddb=-dY*dbperpixel;
+
+    if (Sender==AImage1 || Sender==AImage3)
+    {
+      double db=20*log10e*V.LogAS[CurrentPartial];
+      db+=ddb;
+      AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
+      if (Sender==AImage3) Label7->Caption=S;
+      else Label8->Caption=S;
+      ddb=ddb/(20*log10e);
+
+      for (int p=1; p<V.P; p++) V.LogASp[p][CurrentPartial]+=ddb;
+      V.LogAS[CurrentPartial]+=ddb;
+    }
+    else if (Sender==AImage2 || Sender==AImage4)
+    {
+      double db=20*log10e*V.LogASp[CurrentModCycle][CurrentPartial];
+      db+=ddb;
+      AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, db);
+      if (Sender==AImage4) Label9->Caption=S;
+      else Label10->Caption=S;
+      ddb=ddb/(20*log10e);
+
+      V.LogASp[CurrentModCycle][CurrentPartial]+=ddb;
+    }
+
+    SynthesizeV(HS, &V, WaveView1->SamplesPerSec);
+    UpdateDisplay();
+  }
+  else
+  {
+    Image->Parent->SetFocus();
+
+    int lSXc, *lSX;
+    double* LogAS;
+    if (Sender==AImage1 || Sender==AImage3) lSXc=SXc, lSX=SX, LogAS=V.LogAS, X=Bdw+(X-Bdw)*AImage3->Width/((TImage*)Sender)->Width;
+    else if (Sender==AImage2 || Sender==AImage4) lSXc=SXcyclec, lSX=SXcycle, LogAS=V.LogASp[CurrentModCycle], X=Bdw+(X-Bdw)*AImage4->Width/((TImage*)Sender)->Width;
+
+    if (lSXc<=0) return;
+
+
+    CurrentPartial=0; while (CurrentPartial<lSXc && lSX[CurrentPartial]<X) CurrentPartial++;
+    if (CurrentPartial>=lSXc) CurrentPartial=lSXc-1;
+    if (CurrentPartial>=1 && X-lSX[CurrentPartial-1]<lSX[CurrentPartial]-X) CurrentPartial--;
+
+    double dB=20*log10e*LogAS[CurrentPartial];
+    AnsiString S; S.sprintf("Partial %d: %.2fdB", CurrentPartial+1, dB);
+
+    TLabel* Label;
+    if (Sender==AImage1) Label=Label8;
+    else if (Sender==AImage2) Label=Label10;
+    else if (Sender==AImage4) Label=Label9;
+    else Label=Label7;
+    Label->Font->Color=RotateColors[CurrentPartial%10]; Label->Caption=S;
+  }
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::MImage1MouseMove(TObject *Sender,
+      TShiftState Shift, int X, int Y)
+{
+  if (!HS) return;
+  if (Shift.Contains(ssLeft))
+  {
+    if (CurrentK<0) return;
+
+  }
+  else
+  {
+    TImage* Image=(TImage*)Sender;
+    Image->Parent->SetFocus();
+    CurrentK=-1; for (int i=0; i<V.K; i++) if (X>=KX1[i] && X<=KX2[i]) {CurrentK=i; break;}
+    if (CurrentK<0) return;
+
+    double* FXR;
+    TLabel* Label;
+    if (Sender==MImage1) FXR=V.FXR, Label=Label11;
+    else if (Sender==MImage2)
+    {
+      if (CurrentModCycle<0) return;
+      FXR=V.fxr[CurrentModCycle], Label=Label12;
+    }
+
+    AnsiString S;
+    if (CurrentK>0) S.sprintf("%d: %.3g", CurrentK, sqrt(FXR[CurrentK*2-1]*FXR[CurrentK*2-1]+FXR[CurrentK*2]*FXR[CurrentK*2]));
+    else if (CurrentK==0) S.sprintf("%d: %.3g", CurrentK, fabs(FXR[0]));
+    Label->Caption=S; Label->Left=Image->Parent->Left+0.5*(KX1[CurrentK]+KX2[CurrentK]-Label->Width);
+  }
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TVibratoDemoForm::Image2DblClick(TObject *Sender)
+{
+  TPoint P1; GetCursorPos(&P1);
+  TPoint P2=MImage1->ClientToScreen(TPoint(0, MImage1->Height*0.3819));
+  SetCursorPos(P1.x, P2.y);
+}
+//---------------------------------------------------------------------------
+
+
+
+void __fastcall TVibratoDemoForm::AImage1MouseDown(TObject *Sender,
+      TMouseButton Button, TShiftState Shift, int X, int Y)
+{
+  FirstStartDrag=StartDrag=Y;
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::AImage1MouseUp(TObject *Sender,
+      TMouseButton Button, TShiftState Shift, int X, int Y)
+{
+  if (Y!=FirstStartDrag)
+  {
+    SaveV();
+    Synthesize();
+    UpdateDisplay();
+  }
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::CycleRateEditMouseMove(TObject *Sender,
+      TShiftState Shift, int X, int Y)
+{
+  TEdit* Edit=(TEdit*)Sender;
+  Edit->SetFocus();
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::PageControl1Change(TObject *Sender)
+{
+  if (PageControl1->ActivePage==ModOverSheet || PageControl1->ActivePage==ModCycleSheet)
+    ResidueCheck->Parent=PageControl1->ActivePage;
+  else if (PageControl1->ActivePage==AmpOverSheet || PageControl1->ActivePage==AmpCycleSheet)
+   {SFCheck->Parent=PageControl1->ActivePage; MACheck->Parent=PageControl1->ActivePage;}
+  UpdateDisplay();
+}
+//---------------------------------------------------------------------------
+
+
+  void SourceResponse(double* SV, TVo* V)
+  {
+    int N=V->afres/2;
+    memset(SV, 0, sizeof(double)*N);
+    for (int p=1; p<V->P; p++)
+    {
+      double F0p=0;
+      int frst=V->lp[p-1], fren=V->lp[p];
+      for (int fr=frst; fr<fren; fr++) F0p+=V->F0C[fr];
+      F0p/=(fren-frst);
+      F0p*=V->afres;
+      int lastfp;
+      double lastsv;
+      for (int m=0; m<V->M; m++)
+      {
+        int fp=F0p*(m+1);
+        double sv=V->LogASp[p][m];
+        if (m==0) for (int n=0; n<fp; n++) SV[n]+=sv;
+        else for (int n=lastfp; n<fp; n++) SV[n]+=(sv*(n-lastfp)+lastsv*(fp-n))/(fp-lastfp);
+        lastfp=fp, lastsv=sv;
+      }
+      for (int n=lastfp; n<N; n++) SV[n]+=lastsv;
+    }
+    for (int n=0; n<N; n++) SV[n]/=(V->P-1);
+  }
+
+//S_U implements delayed updating of lengthy synthesizing to speed up operation
+//  in case the HS is updated frequently, s.a. during mouse wheeling.
+//This allows a later synthesis to start before an earlier synthesis finishes,
+//  at which the latter is terminated and its incomplete result is discarded.
+void __fastcall TVibratoDemoForm::S_U(bool sf)
+{
+  if (SUThread)
+  {
+    SUThread->Terminate();
+  }
+	SUThread=new TSUThread(true);
+	SUThread->sf=sf;
+	SUThread->OnTerminate=SUTerminate;
+	SUThread->HS=new THS(HS);
+	ThreadList[pThread++]=SUThread;
+	if (pThread==ThreadCaps/2 && ThreadList[pThread]) 
+		for (int i=pThread; i<ThreadCaps; i++) {delete ThreadList[i]; ThreadList[i]=0;}
+	else if (pThread==ThreadCaps)
+	{
+		for (int i=0; i<ThreadCaps/2; i++) {delete ThreadList[i]; ThreadList[i]=0;}
+		pThread=0;
+	}
+	SUThread->Resume();
+}
+
+void __fastcall TVibratoDemoForm::SUTerminate(TObject* Sender)
+{
+	TSUThread* CurrentThread=(TSUThread*)Sender;
+  if (CurrentThread==SUThread)
+  {
+    double* xrec=CurrentThread->xrec;
+    if (xrec)
+    {
+      int dst=CurrentThread->dst, den=CurrentThread->den;
+      if (dst<0) dst=0;
+      __int16* data=new __int16[den];
+      memset(data, 0, sizeof(__int16)*dst);
+      DoubleToInt(&data[dst], sizeof(__int16), xrec, den-dst);
+      WaveAudio2->Clear(NULL);
+      WaveAudio2->WriteSamples(data, den-dst);
+      delete[] data;
+      UpdateDisplay();
+    }
+    SUThread=0;
+  }
+  else
+  {
+    UpdateDisplay(true, true, true, CurrentThread->sf);
+  }
+  free8(CurrentThread->xrec); CurrentThread->xrec=0;
+}
+//---------------------------------------------------------------------------
+void __fastcall TVibratoDemoForm::Panel4Resize(TObject *Sender)
+{
+  Panel10->Height=Panel4->Height/3;
+  ForceUpdate=true;
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::Panel8Resize(TObject *Sender)
+{
+  int H=(Panel8->Height-Splitter4->Height-Splitter5->Height)/3;
+  Panel9->Height=H; Panel7->Height=H;
+  ForceUpdate=true;
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::Panel1Resize(TObject *Sender)
+{
+  Panel2->Height=(Panel1->Height-Splitter1->Height)/2;
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TVibratoDemoForm::AmpOverSheetResize(TObject *Sender)
+{
+  double W=(AmpOverSheet->Width-24)/20.0;
+  AImage3->Parent->Width=W*9;
+  Label7->Width=AImage3->Parent->Width;
+  AImage1->Parent->Left=AImage3->Parent->Left+AImage3->Parent->Width+8;
+  AImage1->Parent->Width=W*11;
+  Label8->Left=AImage1->Parent->Left;
+  Label8->Width=AImage1->Parent->Width;
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::AmpCycleSheetResize(TObject *Sender)
+{
+  double W=(AmpCycleSheet->Width-24)/20.0;
+  AImage4->Parent->Width=W*9;
+  Label9->Width=AImage4->Parent->Width;
+  AImage2->Parent->Left=AImage4->Parent->Left+AImage4->Parent->Width+8;
+  AImage2->Parent->Width=W*11;
+  Label10->Left=AImage2->Parent->Left;
+  Label10->Width=AImage2->Parent->Width;
+}
+//---------------------------------------------------------------------------
+
+
+void __fastcall TVibratoDemoForm::ListBox1Click(TObject *Sender)
+{
+  if (ListBox1->ItemIndex==1) ThetaEdit->Enabled=true;
+  else ThetaEdit->Enabled=false;
+	Reset();	
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::Button1Click(TObject *Sender)
+{
+  int N=WaveView1->Length, Channel=Form1->HS->Channel;
+
+  if (GetKeyState(VK_SHIFT)<0)
+  {
+    __int16* d2=WaveView2->Data16[0];
+    Form1->PostWaveViewData(d2, Channel, StartPos, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+  }
+  else
+  {
+    __int16 *data=new __int16[N], *data1=WaveView1->Data16[0], *data2=WaveView2->Data16[0];
+    int NN=N;
+    if (NN>WaveView2->Length) NN=WaveView2->Length;
+    for (int n=0; n<NN; n++) data[n]=data1[n]-datain[n]+data2[n];
+    for (int n=NN; n<N; n++) data[n]=data1[n]-datain[n];
+    Form1->PostWaveViewData(data, Channel, StartPos, StartPos+NN, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+    if (NN!=N) Form1->PostWaveViewData(&data[NN], Channel, StartPos+NN, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt());
+    delete[] data;
+  }
+}
+//---------------------------------------------------------------------------
+
+
+
+void __fastcall TVibratoDemoForm::Panel9Resize(TObject *Sender)
+{
+  ForceUpdate=true;
+}
+//---------------------------------------------------------------------------
+
+void __fastcall TVibratoDemoForm::Panel7Resize(TObject *Sender)
+{
+  ForceUpdate=true;
+}
+//---------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VibratoDemoUnit.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,965 @@
+object VibratoDemoForm: TVibratoDemoForm
+  Left = 165
+  Top = 72
+  Caption = 'Vibrato analysis/synthesis demo'
+  ClientHeight = 600
+  ClientWidth = 879
+  Color = cl3DDkShadow
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter2: TSplitter
+    Left = 369
+    Top = 0
+    Height = 600
+    Beveled = True
+    ExplicitHeight = 613
+  end
+  object Panel1: TPanel
+    Left = 0
+    Top = 0
+    Width = 369
+    Height = 600
+    Align = alLeft
+    BevelOuter = bvNone
+    Caption = 'Panel1'
+    Color = cl3DDkShadow
+    Ctl3D = False
+    ParentCtl3D = False
+    TabOrder = 0
+    OnResize = Panel1Resize
+    object Splitter1: TSplitter
+      Left = 0
+      Top = 305
+      Width = 369
+      Height = 3
+      Cursor = crVSplit
+      Align = alTop
+      Beveled = True
+    end
+    object Panel2: TPanel
+      Left = 0
+      Top = 0
+      Width = 369
+      Height = 305
+      Align = alTop
+      BevelOuter = bvNone
+      Color = cl3DDkShadow
+      Ctl3D = False
+      ParentCtl3D = False
+      TabOrder = 0
+    end
+    object Panel3: TPanel
+      Left = 0
+      Top = 308
+      Width = 369
+      Height = 292
+      Align = alClient
+      BevelOuter = bvNone
+      Color = cl3DDkShadow
+      Ctl3D = True
+      ParentCtl3D = False
+      TabOrder = 1
+    end
+  end
+  object Panel4: TPanel
+    Left = 372
+    Top = 0
+    Width = 507
+    Height = 600
+    Align = alClient
+    BevelOuter = bvNone
+    Caption = 'Panel4'
+    Color = cl3DDkShadow
+    Ctl3D = False
+    ParentCtl3D = False
+    TabOrder = 1
+    OnResize = Panel4Resize
+    object Splitter3: TSplitter
+      Left = 0
+      Top = 372
+      Width = 507
+      Height = 3
+      Cursor = crVSplit
+      Align = alBottom
+      Beveled = True
+      ExplicitTop = 385
+      ExplicitWidth = 533
+    end
+    object Panel5: TPanel
+      Left = 0
+      Top = 0
+      Width = 507
+      Height = 372
+      Align = alClient
+      BevelOuter = bvNone
+      BiDiMode = bdLeftToRight
+      Caption = 'Panel5'
+      Color = cl3DDkShadow
+      Ctl3D = True
+      ParentBiDiMode = False
+      ParentCtl3D = False
+      TabOrder = 0
+      ExplicitLeft = 3
+      ExplicitTop = -33
+      DesignSize = (
+        507
+        372)
+      object Splitter6: TSplitter
+        Left = 367
+        Top = 0
+        Height = 372
+        Beveled = True
+        ExplicitLeft = 393
+        ExplicitHeight = 385
+      end
+      object Label15: TLabel
+        Left = 392
+        Top = 112
+        Width = 87
+        Height = 13
+        Caption = 'Source-filter model'
+        Color = cl3DDkShadow
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clSilver
+        Font.Height = -11
+        Font.Name = 'MS Sans Serif'
+        Font.Style = []
+        ParentColor = False
+        ParentFont = False
+      end
+      object ListBox1: TListBox
+        Left = 392
+        Top = 129
+        Width = 49
+        Height = 60
+        Hint = 's-f technique to use'
+        ItemHeight = 13
+        Items.Strings = (
+          'AES124'
+          'AES126_SV')
+        ParentShowHint = False
+        ShowHint = True
+        TabOrder = 3
+        OnClick = ListBox1Click
+      end
+      object Panel8: TPanel
+        Left = 0
+        Top = 0
+        Width = 367
+        Height = 372
+        Align = alLeft
+        Anchors = [akLeft, akTop, akRight, akBottom]
+        BevelOuter = bvNone
+        Caption = 'Panel8'
+        Ctl3D = False
+        ParentCtl3D = False
+        TabOrder = 0
+        OnResize = Panel8Resize
+        object Splitter4: TSplitter
+          Left = 0
+          Top = 122
+          Width = 367
+          Height = 3
+          Cursor = crVSplit
+          Align = alTop
+          Beveled = True
+          Color = cl3DDkShadow
+          ParentColor = False
+          ExplicitLeft = 3
+          ExplicitTop = 123
+        end
+        object Splitter5: TSplitter
+          Left = 0
+          Top = 247
+          Width = 367
+          Height = 3
+          Cursor = crVSplit
+          Align = alTop
+          Beveled = True
+          Color = cl3DDkShadow
+          ParentColor = False
+          ExplicitTop = 257
+          ExplicitWidth = 393
+        end
+        object Panel7: TPanel
+          Left = 0
+          Top = 125
+          Width = 367
+          Height = 122
+          Align = alTop
+          BevelOuter = bvNone
+          Color = cl3DDkShadow
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 0
+          OnResize = Panel7Resize
+          object Image1: TImage
+            Left = 0
+            Top = 0
+            Width = 367
+            Height = 122
+            Align = alClient
+            AutoSize = True
+            OnMouseDown = AImage1MouseDown
+            OnMouseMove = Image1MouseMove
+            OnMouseUp = AImage1MouseUp
+            ExplicitWidth = 393
+            ExplicitHeight = 125
+          end
+        end
+        object Panel6: TPanel
+          Left = 0
+          Top = 250
+          Width = 367
+          Height = 122
+          Align = alClient
+          BevelOuter = bvNone
+          Color = cl3DDkShadow
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 1
+          object Image2: TImage
+            Left = 0
+            Top = 0
+            Width = 367
+            Height = 122
+            Align = alClient
+            AutoSize = True
+            IncrementalDisplay = True
+            OnDblClick = Image2DblClick
+            OnMouseMove = Image2MouseMove
+            ExplicitWidth = 393
+            ExplicitHeight = 125
+          end
+        end
+        object Panel9: TPanel
+          Left = 0
+          Top = 0
+          Width = 367
+          Height = 122
+          Align = alTop
+          BevelOuter = bvNone
+          Color = cl3DDkShadow
+          Ctl3D = False
+          ParentCtl3D = False
+          TabOrder = 2
+          OnResize = Panel9Resize
+          object Image0: TImage
+            Left = 0
+            Top = 0
+            Width = 367
+            Height = 122
+            Align = alClient
+            OnMouseMove = Image1MouseMove
+          end
+        end
+      end
+      object PeakMarksCheck: TCheckBox
+        Left = 387
+        Top = 16
+        Width = 110
+        Height = 17
+        Anchors = [akTop, akRight]
+        Caption = 'Cycle boundaries'
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clYellow
+        Font.Height = -11
+        Font.Name = 'MS Sans Serif'
+        Font.Style = []
+        ParentFont = False
+        TabOrder = 1
+        OnClick = SFCheckClick
+      end
+      object RegButton: TButton
+        Left = 392
+        Top = 47
+        Width = 97
+        Height = 18
+        Anchors = [akTop, akRight]
+        Caption = 'Regulate'
+        TabOrder = 2
+        OnClick = RegButtonClick
+      end
+      object FEdit: TEdit
+        Left = 439
+        Top = 129
+        Width = 49
+        Height = 21
+        Hint = 'bandwidth for s-f modelling'
+        ParentShowHint = False
+        ShowHint = True
+        TabOrder = 4
+        Text = '400'
+      end
+      object FScaleCombo: TComboBox
+        Left = 439
+        Top = 148
+        Width = 49
+        Height = 21
+        Hint = 'freq. scale for s-f modelling'
+        ItemHeight = 13
+        ItemIndex = 0
+        ParentShowHint = False
+        ShowHint = True
+        TabOrder = 5
+        Text = 'Hz'
+        Items.Strings = (
+          'Hz'
+          'mel')
+      end
+      object Button1: TButton
+        Left = 392
+        Top = 71
+        Width = 97
+        Height = 18
+        Caption = '>>'
+        TabOrder = 7
+        OnClick = Button1Click
+      end
+      object ThetaEdit: TEdit
+        Left = 439
+        Top = 168
+        Width = 49
+        Height = 21
+        Hint = 'balancing factor of slow-variation SF modelling'
+        Enabled = False
+        ParentShowHint = False
+        ShowHint = True
+        TabOrder = 6
+        Text = '0.5'
+      end
+    end
+    object Panel10: TPanel
+      Left = 0
+      Top = 375
+      Width = 507
+      Height = 225
+      Align = alBottom
+      BevelOuter = bvNone
+      Color = cl3DDkShadow
+      Ctl3D = True
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clBlack
+      Font.Height = -11
+      Font.Name = 'MS Sans Serif'
+      Font.Style = []
+      ParentCtl3D = False
+      ParentFont = False
+      TabOrder = 1
+      DesignSize = (
+        507
+        225)
+      object Label13: TLabel
+        Left = 0
+        Top = 208
+        Width = 3
+        Height = 13
+        Anchors = [akLeft, akBottom]
+      end
+      object PageControl1: TPageControl
+        Left = 0
+        Top = 0
+        Width = 507
+        Height = 209
+        ActivePage = ModOverSheet
+        Align = alTop
+        Anchors = [akLeft, akTop, akRight, akBottom]
+        TabOrder = 0
+        OnChange = PageControl1Change
+        object ModOverSheet: TTabSheet
+          Caption = 'Modulator: Overall'
+          DesignSize = (
+            499
+            181)
+          object Label1: TLabel
+            Left = 10
+            Top = 80
+            Width = 47
+            Height = 13
+            Alignment = taRightJustify
+            Caption = 'Regularity'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+          end
+          object Label2: TLabel
+            Left = 34
+            Top = 48
+            Width = 23
+            Height = 13
+            Alignment = taRightJustify
+            Caption = 'Rate'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+          end
+          object Label11: TLabel
+            Left = 240
+            Top = 160
+            Width = 3
+            Height = 12
+            Alignment = taCenter
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clAqua
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentFont = False
+          end
+          object Label14: TLabel
+            Left = 17
+            Top = 16
+            Width = 40
+            Height = 13
+            Alignment = taRightJustify
+            Caption = 'Duration'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+          end
+          object ResidueCheck: TCheckBox
+            Left = 367
+            Top = 3
+            Width = 120
+            Height = 17
+            Anchors = [akTop, akRight]
+            Caption = 'Show Fourier residue'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+            TabOrder = 4
+            OnClick = SFCheckClick
+          end
+          object RegEdit: TEdit
+            Left = 64
+            Top = 80
+            Width = 65
+            Height = 19
+            BevelEdges = []
+            BevelInner = bvNone
+            BevelOuter = bvNone
+            BorderStyle = bsNone
+            Color = cl3DDkShadow
+            Ctl3D = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentCtl3D = False
+            ParentFont = False
+            TabOrder = 0
+            Text = '1.0'
+          end
+          object RateEdit: TEdit
+            Left = 64
+            Top = 48
+            Width = 65
+            Height = 19
+            BevelEdges = []
+            BevelInner = bvNone
+            BevelOuter = bvNone
+            BorderStyle = bsNone
+            Color = cl3DDkShadow
+            Ctl3D = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentCtl3D = False
+            ParentFont = False
+            ReadOnly = True
+            TabOrder = 1
+            Text = '1.0'
+            OnMouseMove = CycleRateEditMouseMove
+          end
+          object Panel11: TPanel
+            Left = 240
+            Top = 22
+            Width = 247
+            Height = 147
+            Anchors = [akLeft, akTop, akRight, akBottom]
+            BevelOuter = bvSpace
+            Color = cl3DDkShadow
+            TabOrder = 2
+            object MImage1: TImage
+              Left = 1
+              Top = 1
+              Width = 245
+              Height = 145
+              Align = alClient
+              OnMouseDown = AImage1MouseDown
+              OnMouseMove = MImage1MouseMove
+              ExplicitTop = 6
+              ExplicitHeight = 143
+            end
+          end
+          object DurationEdit: TEdit
+            Left = 64
+            Top = 16
+            Width = 161
+            Height = 19
+            BevelEdges = []
+            BevelInner = bvNone
+            BevelOuter = bvNone
+            BorderStyle = bsNone
+            Color = cl3DDkShadow
+            Ctl3D = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentCtl3D = False
+            ParentFont = False
+            ReadOnly = True
+            TabOrder = 3
+            Text = '1.0'
+            OnMouseMove = CycleRateEditMouseMove
+          end
+        end
+        object ModCycleSheet: TTabSheet
+          Caption = 'Modulator: Cycles'
+          ImageIndex = 1
+          DesignSize = (
+            499
+            181)
+          object Label3: TLabel
+            Left = 34
+            Top = 48
+            Width = 23
+            Height = 13
+            Alignment = taRightJustify
+            Caption = 'Rate'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+          end
+          object Label4: TLabel
+            Left = 17
+            Top = 16
+            Width = 40
+            Height = 13
+            Alignment = taRightJustify
+            Caption = 'Duration'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+          end
+          object Label5: TLabel
+            Left = 27
+            Top = 112
+            Width = 30
+            Height = 13
+            Alignment = taRightJustify
+            Caption = 'Extent'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+          end
+          object Label6: TLabel
+            Left = 6
+            Top = 144
+            Width = 51
+            Height = 13
+            Alignment = taRightJustify
+            Caption = 'Avg. Dept.'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+          end
+          object TLabel
+            Left = 8
+            Top = 80
+            Width = 49
+            Height = 13
+            Alignment = taRightJustify
+            Caption = 'Avg. Pitch'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+          end
+          object Label12: TLabel
+            Left = 240
+            Top = 160
+            Width = 3
+            Height = 12
+            Alignment = taCenter
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clAqua
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentFont = False
+          end
+          object CycleRateEdit: TEdit
+            Left = 64
+            Top = 48
+            Width = 65
+            Height = 19
+            BevelEdges = []
+            BevelInner = bvNone
+            BevelOuter = bvNone
+            BorderStyle = bsNone
+            Color = cl3DDkShadow
+            Ctl3D = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentCtl3D = False
+            ParentFont = False
+            ReadOnly = True
+            TabOrder = 0
+            Text = '1.0'
+            OnMouseMove = CycleRateEditMouseMove
+          end
+          object CycleDurationEdit: TEdit
+            Left = 64
+            Top = 16
+            Width = 161
+            Height = 19
+            BevelEdges = []
+            BevelInner = bvNone
+            BevelOuter = bvNone
+            BorderStyle = bsNone
+            Color = cl3DDkShadow
+            Ctl3D = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentCtl3D = False
+            ParentFont = False
+            ReadOnly = True
+            TabOrder = 1
+            Text = '1.0'
+            OnMouseMove = CycleRateEditMouseMove
+          end
+          object CycleExtentEdit: TEdit
+            Left = 64
+            Top = 112
+            Width = 89
+            Height = 19
+            BevelEdges = []
+            BevelInner = bvNone
+            BevelOuter = bvNone
+            BorderStyle = bsNone
+            Color = cl3DDkShadow
+            Ctl3D = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentCtl3D = False
+            ParentFont = False
+            TabOrder = 2
+            Text = '1.0'
+          end
+          object CycleAvgPDEdit: TEdit
+            Left = 64
+            Top = 144
+            Width = 89
+            Height = 19
+            BevelEdges = []
+            BevelInner = bvNone
+            BevelOuter = bvNone
+            BorderStyle = bsNone
+            Color = cl3DDkShadow
+            Ctl3D = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentCtl3D = False
+            ParentFont = False
+            TabOrder = 3
+            Text = '1.0'
+          end
+          object CyclePitchEdit: TEdit
+            Left = 64
+            Top = 80
+            Width = 89
+            Height = 19
+            BevelEdges = []
+            BevelInner = bvNone
+            BevelOuter = bvNone
+            BorderStyle = bsNone
+            Color = cl3DDkShadow
+            Ctl3D = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentCtl3D = False
+            ParentFont = False
+            ReadOnly = True
+            TabOrder = 4
+            Text = '1.0'
+            OnMouseMove = CycleRateEditMouseMove
+          end
+          object Panel12: TPanel
+            Left = 240
+            Top = 22
+            Width = 247
+            Height = 147
+            Anchors = [akLeft, akTop, akRight, akBottom]
+            BevelOuter = bvSpace
+            Color = cl3DDkShadow
+            TabOrder = 5
+            object MImage2: TImage
+              Left = 1
+              Top = 1
+              Width = 245
+              Height = 145
+              Align = alClient
+              OnMouseDown = AImage1MouseDown
+              OnMouseMove = MImage1MouseMove
+              ExplicitWidth = 271
+              ExplicitHeight = 143
+            end
+          end
+        end
+        object AmpOverSheet: TTabSheet
+          Caption = 'Amplitudes: Overall'
+          ImageIndex = 2
+          OnResize = AmpOverSheetResize
+          DesignSize = (
+            499
+            181)
+          object Label7: TLabel
+            Left = 8
+            Top = 160
+            Width = 225
+            Height = 9
+            Alignment = taCenter
+            Anchors = [akLeft, akBottom]
+            AutoSize = False
+            Color = cl3DDkShadow
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clAqua
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentColor = False
+            ParentFont = False
+          end
+          object Label8: TLabel
+            Left = 219
+            Top = 160
+            Width = 273
+            Height = 12
+            Alignment = taCenter
+            Anchors = [akRight, akBottom]
+            AutoSize = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clBlack
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentFont = False
+            ExplicitLeft = 245
+          end
+          object Panel13: TPanel
+            Left = 219
+            Top = 20
+            Width = 275
+            Height = 145
+            Anchors = [akTop, akRight, akBottom]
+            BevelOuter = bvSpace
+            Color = cl3DDkShadow
+            TabOrder = 0
+            object AImage1: TImage
+              Left = 1
+              Top = 1
+              Width = 273
+              Height = 143
+              Align = alClient
+              OnMouseDown = AImage1MouseDown
+              OnMouseMove = AImage3MouseMove
+              OnMouseUp = AImage1MouseUp
+              ExplicitWidth = 271
+            end
+          end
+          object Panel15: TPanel
+            Left = 8
+            Top = 20
+            Width = 225
+            Height = 145
+            Anchors = [akLeft, akTop, akBottom]
+            BevelOuter = bvSpace
+            Color = cl3DDkShadow
+            TabOrder = 1
+            object AImage3: TImage
+              Left = 1
+              Top = 1
+              Width = 223
+              Height = 143
+              Align = alClient
+              IncrementalDisplay = True
+              OnMouseDown = AImage1MouseDown
+              OnMouseMove = AImage3MouseMove
+              OnMouseUp = AImage1MouseUp
+              ExplicitLeft = -6
+              ExplicitTop = 9
+            end
+          end
+          object SFCheck: TCheckBox
+            Left = 230
+            Top = 3
+            Width = 115
+            Height = 17
+            Anchors = [akTop, akRight]
+            Caption = 'Source-filter output'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+            TabOrder = 2
+            OnClick = SFCheckClick
+          end
+          object MACheck: TCheckBox
+            Left = 351
+            Top = 3
+            Width = 97
+            Height = 17
+            Anchors = [akTop, akRight]
+            Caption = 'Moving average'
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clSilver
+            Font.Height = -11
+            Font.Name = 'MS Sans Serif'
+            Font.Style = []
+            ParentFont = False
+            TabOrder = 3
+            OnClick = SFCheckClick
+          end
+        end
+        object AmpCycleSheet: TTabSheet
+          Caption = 'Amplitudes: Cycles'
+          ImageIndex = 3
+          OnResize = AmpCycleSheetResize
+          DesignSize = (
+            499
+            181)
+          object Label9: TLabel
+            Left = 8
+            Top = 160
+            Width = 225
+            Height = 9
+            Alignment = taCenter
+            AutoSize = False
+            Color = cl3DDkShadow
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clAqua
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentColor = False
+            ParentFont = False
+          end
+          object Label10: TLabel
+            Left = 245
+            Top = 160
+            Width = 273
+            Height = 12
+            Alignment = taCenter
+            AutoSize = False
+            Font.Charset = DEFAULT_CHARSET
+            Font.Color = clBlack
+            Font.Height = 12
+            Font.Name = 'Arial'
+            Font.Style = []
+            ParentFont = False
+          end
+          object Panel14: TPanel
+            Left = 219
+            Top = 20
+            Width = 275
+            Height = 145
+            Anchors = [akTop, akRight, akBottom]
+            BevelOuter = bvSpace
+            Color = cl3DDkShadow
+            TabOrder = 0
+            object AImage2: TImage
+              Left = 1
+              Top = 1
+              Width = 273
+              Height = 143
+              Align = alClient
+              OnMouseDown = AImage1MouseDown
+              OnMouseMove = AImage3MouseMove
+              OnMouseUp = AImage1MouseUp
+              ExplicitWidth = 271
+            end
+          end
+          object Panel16: TPanel
+            Left = 8
+            Top = 20
+            Width = 225
+            Height = 145
+            Anchors = [akLeft, akTop, akBottom]
+            BevelOuter = bvSpace
+            Color = cl3DDkShadow
+            TabOrder = 1
+            object AImage4: TImage
+              Left = 1
+              Top = 1
+              Width = 223
+              Height = 143
+              Align = alClient
+              OnMouseDown = AImage1MouseDown
+              OnMouseMove = AImage3MouseMove
+              OnMouseUp = AImage1MouseUp
+            end
+          end
+        end
+      end
+    end
+  end
+  object SaveDialog1: TSaveDialog
+    Left = 724
+    Top = 40
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VibratoDemoUnit.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,214 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+#ifndef VibratoDemoUnitH
+#define VibratoDemoUnitH
+//---------------------------------------------------------------------------
+/*
+    VibratoDemoUnit implements the Vibrato analysis and synthesis demo GUI
+      of HV.
+*/
+
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+#include <ExtCtrls.hpp>
+#include "AudioPac.h"
+#include "WaveView.h"
+#include "EventBoxUnit.h"
+#include "SUThread.h"
+#include <ComCtrls.hpp>
+#include <Dialogs.hpp>
+#include "vibrato.h"
+//---------------------------------------------------------------------------
+
+
+class TSUThread;
+const ThreadCaps=1024;
+
+class TVibratoDemoForm : public TForm
+{
+__published:	// IDE-managed Components
+  TPanel *Panel1;
+  TPanel *Panel2;
+  TSplitter *Splitter1;
+  TSplitter *Splitter2;
+  TPanel *Panel3;
+  TPanel *Panel4;
+  TPanel *Panel5;
+  TSplitter *Splitter3;
+  TPanel *Panel8;
+  TPanel *Panel7;
+  TImage *Image1;
+  TPanel *Panel6;
+  TImage *Image2;
+  TSplitter *Splitter4;
+  TPanel *Panel9;
+  TSplitter *Splitter5;
+  TImage *Image0;
+  TSplitter *Splitter6;
+  TPanel *Panel10;
+  TPageControl *PageControl1;
+  TTabSheet *ModOverSheet;
+  TTabSheet *ModCycleSheet;
+  TLabel *Label1;
+  TEdit *RegEdit;
+  TLabel *Label2;
+  TEdit *RateEdit;
+  TLabel *Label3;
+  TEdit *CycleRateEdit;
+  TLabel *Label4;
+  TEdit *CycleDurationEdit;
+  TPanel *Panel11;
+  TImage *MImage1;
+  TLabel *Label5;
+  TEdit *CycleExtentEdit;
+  TLabel *Label6;
+  TEdit *CycleAvgPDEdit;
+  TEdit *CyclePitchEdit;
+  TPanel *Panel12;
+  TImage *MImage2;
+  TTabSheet *AmpOverSheet;
+  TPanel *Panel13;
+  TImage *AImage1;
+  TTabSheet *AmpCycleSheet;
+  TPanel *Panel14;
+  TImage *AImage2;
+  TCheckBox *PeakMarksCheck;
+  TButton *RegButton;
+  TPanel *Panel15;
+  TImage *AImage3;
+  TPanel *Panel16;
+  TImage *AImage4;
+  TLabel *Label7;
+  TLabel *Label8;
+  TLabel *Label9;
+  TLabel *Label10;
+  TLabel *Label11;
+  TLabel *Label12;
+  TLabel *Label13;
+  TLabel *Label14;
+  TEdit *DurationEdit;
+  TSaveDialog *SaveDialog1;
+	TListBox *ListBox1;
+	TEdit *FEdit;
+	TComboBox *FScaleCombo;
+	TEdit *ThetaEdit;
+  TButton *Button1;
+  TCheckBox *ResidueCheck;
+  TCheckBox *SFCheck;
+  TCheckBox *MACheck;
+  TLabel *Label15;
+  void __fastcall Image1MouseMove(TObject *Sender, TShiftState Shift,
+          int X, int Y);
+  void __fastcall Image2MouseMove(TObject *Sender, TShiftState Shift,
+          int X, int Y);
+  void __fastcall SFCheckClick(TObject *Sender);
+  void __fastcall RegButtonClick(TObject *Sender);
+  void __fastcall AImage3MouseMove(TObject *Sender, TShiftState Shift,
+          int X, int Y);
+  void __fastcall MImage1MouseMove(TObject *Sender, TShiftState Shift,
+          int X, int Y);
+  void __fastcall Image2DblClick(TObject *Sender);
+  void __fastcall AImage1MouseDown(TObject *Sender, TMouseButton Button,
+          TShiftState Shift, int X, int Y);
+  void __fastcall AImage1MouseUp(TObject *Sender, TMouseButton Button,
+          TShiftState Shift, int X, int Y);
+  void __fastcall CycleRateEditMouseMove(TObject *Sender,
+          TShiftState Shift, int X, int Y);
+  void __fastcall PageControl1Change(TObject *Sender);
+  void __fastcall Panel4Resize(TObject *Sender);
+  void __fastcall Panel8Resize(TObject *Sender);
+  void __fastcall Panel1Resize(TObject *Sender);
+  void __fastcall AmpOverSheetResize(TObject *Sender);
+  void __fastcall AmpCycleSheetResize(TObject *Sender);
+	void __fastcall ListBox1Click(TObject *Sender);
+  void __fastcall Button1Click(TObject *Sender);
+  void __fastcall Panel9Resize(TObject *Sender);
+  void __fastcall Panel7Resize(TObject *Sender);
+private:	// User declarations
+public:		// User declarations
+  __fastcall TVibratoDemoForm(TComponent* Owner);
+  __fastcall ~TVibratoDemoForm();
+
+  bool ForceUpdate;
+
+	TSUThread* SUThread;
+	int pThread;
+	TSUThread* ThreadList[ThreadCaps];
+
+  void __fastcall SUTerminate(TObject* Sender);
+  DYNAMIC void __fastcall MouseWheelHandler(TMessage& Msg);
+  void __fastcall Image1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+  void __fastcall Image2MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+  void __fastcall AImage3MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+  void __fastcall AImage4MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+  void __fastcall MImage1MouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+  void __fastcall RateEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+  void __fastcall DurationEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+  void __fastcall PitchEditMouseWheel(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
+
+  int StartPos;
+  TWaveAudio* WaveAudio1;
+  TWaveView* WaveView1;
+  TWaveAudio* WaveAudio2;
+  TWaveView* WaveView2;
+
+  TVo V;
+  
+  THS* HS;
+  double f_c, f_ex;
+  double* peaky;
+  double* cyclefrs;
+  double* cyclefs;
+	int cyclefrcount;
+  int CurrentModCycle;
+  double CurrentModCycleStart;
+  double CurrentModCycleEnd;
+  int CurrentPartial;
+  int CurrentK;
+  int CurrentC;
+  double FXX[64];
+  double NAF[4096];
+  int SX[128]; //size related to number of partials
+  int SXcycle[128];
+  int KX1[64]; //size related to number of frames per cycle
+  int KX2[64];
+  int CX1[128];  //size related to number of cycles
+  int CX2[128];
+  int CY1[128];
+  int CY2[128];
+  int SXc;
+  int SXcyclec;
+  int FirstStartDrag;
+  int StartDrag;
+
+  __int16* datain;
+
+  void Copydata();
+  void DrawModulator();
+  void __fastcall ExternalInput();
+  void FindNote();
+  void Reset();
+  void __fastcall SaveV();
+  void __fastcall S_U(bool sf=false);
+  void Synthesize();
+  void UpdateDisplay(bool f0=true, bool f0s=true, bool f0d=true, bool sf=true);
+  int __fastcall WaveView1CustomInfo(TObject*);
+  void __fastcall WaveView1OpMode(TObject* Sender, TShiftState Shift, int& OpMode);
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TVibratoDemoForm *VibratoDemoForm;
+//---------------------------------------------------------------------------
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WaveView.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,3656 @@
+/*
+    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>
+#include <values.h>
+#pragma hdrstop
+
+#include "WaveView.h"
+#include <math.h>
+#include <math.hpp>
+#pragma package(smart_init)
+#define HEIGHT (Height)
+#define WIDTH (Width)
+#define FATP FromAmplitudeToPixel
+#define FPTA FromPixelToAmplitude
+#define FDFTP FromDigiFreqToPixel
+#define FPTDF FromPixelToDigiFreq
+#define FPTS FromPixelToSample
+#define FSTP FromSampleToPixel
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+
+void DoubleToInt(void* out, int BytesPerSample, double* in, int Count)
+{
+  if (BytesPerSample==1){unsigned char* out8=(unsigned char*)out; for (int k=0; k<Count; k++) *(out8++)=floor(*(in++)+128.5);}
+  else if (BytesPerSample==2) {__int16* out16=(__int16*)out; for (int k=0; k<Count; k++) *(out16++)=floor(*(in++)+0.5);}
+  else {__pint24 out24=(__pint24)out; for (int k=0; k<Count; k++) *(out24++)=floor(*(in++)+0.5);}
+}
+
+//convert int array to double. truncate int24 to int16.
+void IntToDouble2416(double* out, void* in, int BytesPerSample, int Count)
+{
+  if (BytesPerSample==1){unsigned char* in8=(unsigned char*)in; for (int k=0; k<Count; k++) *(out++)=*(in8++)-128.0;}
+  else if (BytesPerSample==2) {__int16* in16=(__int16*)in; for (int k=0; k<Count; k++) *(out++)=*(in16++);}
+  else {__pint24 in24=(__pint24)in; for (int k=0; k<Count; k++) *(out++)=*(in24++)>>8;}
+}
+
+//dest-=src*amp
+void MultiSub(void* dest, void* src, int BytesPerSample, double* amp, int Count)
+{
+  if (BytesPerSample==1){unsigned char *dest8=(unsigned char*)dest, *src8=(unsigned char*)src; for (int k=0; k<Count; k++) *(dest8++)-=(*(src8++)-128.0)**(amp++);}
+  else if (BytesPerSample==2) {__int16 *dest16=(__int16*)dest, *src16=(__int16*)src; for (int k=0; k<Count; k++) *(dest16++)-=(*(src16++)**(amp++));}
+  else {__pint24 dest24=(__pint24)dest, src24=(__pint24)src; for (int k=0; k<Count; k++) *(dest24++)-=(*(src24++)**(amp++));}
+}
+
+void AddDoubleToInt1624(void* dest, int BytesPerSample, double* src, int Count, double a)
+{
+  if (BytesPerSample==1){unsigned char* dest8=(unsigned char*)dest; for (int k=0; k<Count; k++) *(dest8++)+=*(src++)*a;}
+  else if (BytesPerSample==2) {__int16* dest16=(__int16*)dest; for (int k=0; k<Count; k++) *(dest16++)+=*(src++)*a;}
+  else {a*=256; __pint24 dest24=(__pint24)dest; for (int k=0; k<Count; k++) *(dest24++)+=*(src++)*a;}
+}
+
+void PlayNote(double f, bool semitone=true)
+{
+  if (f<=0) return;
+  TWaveAudio* WV=new TWaveAudio(NULL); int Sps=WV->SamplesPerSec;
+  double Sps25=Sps/4.0; __int16 data[48000]; int amp=2048, har=3;
+  if (semitone) f=440*pow(2.0l, floor(Log2(f/440)*12+0.5)/12.0);
+  if (f<200) har=600/f, amp*=pow(200/f, 0.7);
+  for (int i=0; i<Sps; i++){double fdata=0; for (int j=1; j<=har; j++){if (j*f<Sps/2) fdata+=sin(2*M_PI*i*j*f/Sps)/j/j;} data[i]=amp*fdata*exp(-i/Sps25);}
+  WV->WriteSamples(data, Sps);
+  AnsiString FileName=ExtractFilePath(Application->ExeName)+"temp0";
+  WV->SaveToFile(FileName); delete WV;
+  PlaySound(FileName.c_str(), 0, SND_FILENAME|SND_ASYNC);
+}
+
+AnsiString SemitoneToPitch(double f)
+{
+  static char* notename[]={"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
+  int fd=floor(f+0.5);
+  double fr=f-fd;
+  int oct=floor(fd/12.0);
+  int note=fd-oct*12;
+  int fr2=floor(fr*100+0.5);
+  if (fr2==0) return AnsiString().sprintf("%s%d", notename[note], oct+4, fr2);
+  else if (fr2>0)
+  {
+    if (fr2%10==0) {fr2/=10; return AnsiString().sprintf("%s%d+.%d", notename[note], oct+4, fr2);}
+    else return AnsiString().sprintf("%s%d+.%02d", notename[note], oct+4, fr2);
+  }
+  else
+  {
+    fr2=-fr2;
+    if (fr2%10==0) {fr2/=10; return AnsiString().sprintf("%s%d-.%d", notename[note], oct+4, fr2);}
+    else return AnsiString().sprintf("%s%d-.%02d", notename[note], oct+4, fr2);
+  }
+}
+
+void TextOutline(TCanvas* Canv, AnsiString Text, int X, int Y, TColor FC, TColor BC)
+{
+  Canv->Font->Color=BC; Canv->TextOut(X-1, Y, Text); Canv->TextOut(X+1, Y, Text); Canv->TextOut(X, Y-1, Text);
+  Canv->TextOut(X, Y+1, Text); Canv->Font->Color=FC; Canv->TextOut(X, Y, Text);
+}
+
+//*
+//TFFilter: TF-filtering with cosinal interpolation
+//Identical data and dataout allowed.
+void TFFilter(TWaveView* WV, int Channel, TWaveViewSelections* Selections, bool Pass, bool allduration=false)
+{
+  int Count=WV->Length, Wid=WV->SpecRes, Offst=WV->SpecOffst;
+  int hWid=Wid/2, Order=Log2(Wid), frst, fren;
+  {
+    int Fr=(Count-Wid)/Offst+1;
+    if (allduration) frst=0, fren=Fr;
+    else
+    {
+      frst=floor((WV->StartPos-hWid)*1.0/Offst+0.5); if (frst<0) frst=0;
+      fren=floor((WV->EndPos-hWid)*1.0/Offst+0.5); if (fren>Fr) fren=Fr;
+    }
+  }
+  int frcount=fren-frst;
+  int** filter=new int*[frcount]; //signals if man atom is kept or discarded
+  filter[0]=new int[frcount*Wid]; for (int i=1; i<frcount; i++) filter[i]=&filter[0][i*Wid];
+
+  //fill local filter table: entries "1" in the table are kept, "0" are discarded
+  if (Pass) memset(filter[0], 0, sizeof(int)*frcount*Wid);
+  else for (int i=0; i<frcount; i++) for (int j=0; j<Wid; j++) filter[i][j]=1;
+  for (int i=0; i<Selections->Count; i++)
+  {
+    int lx1, lx2, ly1, ly2;
+    lx1=floor((Selections->Items[i].StartPos-hWid)*1.0/Offst+0.5)-frst;
+    lx2=floor((Selections->Items[i].EndPos-hWid)*1.0/Offst+0.5)-frst;
+    ly1=Selections->Items[i].StartDigiFreq*Wid;
+    ly2=Selections->Items[i].EndDigiFreq*Wid;
+    if (lx1<0) lx1=0; if (lx2>=frcount) lx2=frcount-1;
+    if (ly1<0) ly1=0; if (ly1>hWid) ly1=hWid;
+    if (Pass) for (int x=lx1; x<=lx2; x++) for (int y=ly1; y<=ly2; y++) filter[x][y]=1;
+    else for (int x=lx1; x<=lx2; x++) for (int y=ly1; y<=ly2; y++) filter[x][y]=0;
+  }
+  double* lxfr=new double[frcount]; //the ratio of kept atoms of each frame
+  for (int i=0; i<frcount; i++)
+  {
+    lxfr[i]=0;
+    for (int j=0; j<=hWid; j++) if (filter[i][j]) lxfr[i]=lxfr[i]+1;
+    lxfr[i]/=(hWid+1);
+  }
+
+  //construct the window used for interpolation
+  double* winf=WV->fwin;  //this is the one used to compute Spec
+  double* wini=NewWindow8(wtHann, Wid, NULL, NULL, 0); //this is an idea COLA window
+  if (hWid!=Offst){double tmp=Offst*1.0/hWid; for (int i=0; i<Wid; i++) wini[i]*=tmp;} //this normalizes COLA to perfect reconstruction OLA
+  double* winrec; //this window is the one actually to be applied after IFFT
+  if (WV->SpecWindowType==wtHann) winrec=0;
+  else
+  {
+    winrec=new double[Wid];
+    for (int i=0; i<Wid; i++)
+      if (winf[i]!=0) winrec[i]=wini[i]/winf[i];
+      else winrec[i]=0;
+  }
+  AllocateFFTBuffer(Wid, ldata, w, x);
+  int* hbitinv=CreateBitInvTable(Order-1);
+
+  int bps=WV->BytesPerSample;
+  char* data8=&WV->Data8[Channel][frst*Offst*bps];
+
+  for (int fr=0; fr<frcount; fr++)
+  {
+    if (lxfr[fr]!=0 && lxfr[fr]!=1) WV->Spec[Channel][frst+fr];
+  }
+
+  int prefetchcount=Wid/Offst;
+  char** prefetch=new char*[prefetchcount]; prefetch[0]=new char[prefetchcount*bps*Wid]; for (int i=1; i<prefetchcount; i++) prefetch[i]=&prefetch[0][i*Wid*bps];
+
+  for (int fr=0; fr<frcount; fr++)
+  {
+    if (fr==0)
+    {
+      //prefetch frames
+      for (int i=0; i<prefetchcount; i++)
+        if (i<frcount && lxfr[i]==0) memcpy(prefetch[i], &data8[i*Offst*bps], Wid*bps);
+    }
+    //prefetch[fr%prefetchcount] now contains the fr-th frame
+    char* wvdata=&data8[fr*Offst*bps];
+    char* fdata=prefetch[fr%prefetchcount];
+    if (lxfr[fr]==0)
+    {
+      //remove original frame (windowed) from signal
+      MultiSub(wvdata, fdata, bps, wini, Wid);
+    }
+    else if (lxfr[fr]==1)
+    {
+      //do nothing = leave originl frame (windowed) as is
+    }
+    else
+    {
+      //replace original frame (windowed) with syntheszed frame, but here
+      //  is a subtractive approach: you synthesize what is subtracted instead
+      //  and remove it directly without windowing original data
+      cmplx<QSPEC_FORMAT>* spec=WV->Spec[Channel][frst+fr];
+      for (int i=0; i<=hWid; i++)
+        if (filter[fr][i]==0) x[i]=spec[i];
+        else x[i]=0;
+      CIFFTR(x, Order, w, ldata, hbitinv);
+      if (winrec) for (int i=0; i<Wid; i++) ldata[i]*=winrec[i];
+      AddDoubleToInt1624(wvdata, bps, ldata, Wid, -1);
+    }
+    //prefetch next
+    if (fr+prefetchcount<frcount && lxfr[fr+prefetchcount]==0) memcpy(fdata, &data8[(fr+prefetchcount)*Offst*bps], bps*Wid);
+  }
+
+  FreeFFTBuffer(ldata);
+  free(hbitinv);
+
+  delete[] filter[0]; delete[] filter;
+  delete[] prefetch[0]; delete[] prefetch;
+  delete[] lxfr;
+	delete[] winrec;
+	free8(wini);
+}  //*/
+
+//---------------------------------------------------------------------------
+void FeedFFTBuffers(int Id, cdouble* &w, cdouble* &x, double* &win, int* &hbi, void* Parent)
+{
+  TWaveView* WV=(TWaveView*)Parent;
+  w=WV->fw;
+  x=WV->fx;
+  win=WV->fwin;
+  hbi=WV->fhbi;
+}
+
+//---------------------------------------------------------------------------
+static inline void ValidCtrCheck(TWaveView *)
+{
+  new TWaveView(NULL);
+}
+//---------------------------------------------------------------------------
+__fastcall TWaveView::TWaveView(TComponent* Owner, bool usex, bool usep)
+  : TCustomControl(Owner)
+{
+  if (!dynamic_cast<TCustomForm*>(Owner))
+    Parent=dynamic_cast<TWinControl*>(Owner);
+
+  DisableMouseWheelZoom=false;
+
+  FTools.Clear();
+  FPitchScalePart=1;
+  FSectionProgress=-1;
+
+  FShowCursor=true;
+  FShowCursorText=true;
+  FShowInfo=true;
+  FShowPaneInfo=true;
+  FPlayNoteInSemitone=true;
+
+  FAutoSpecAmp=false;
+  FSpecAmp=1;
+
+  for (int i=0; i<WV2_MAX_CHANNEL; i++) FSpectrogram[i]=new TQuickSpectrogram(this, i, usex, usep, FeedFFTBuffers);
+
+  FSpecRes=1024;
+  FSpecOffst=FSpecRes/2;
+  FSpecWindowType=wtHamming;
+  FSpecWindowParamD[0]=32*log(2.0)/(M_PI*M_PI);
+
+  FLocalDataTimeGrid=true;
+  FForceHamming=true;
+  FCurrentPane=-1;
+  FCalculateFrameCount=0;
+  FSamplesPerSec=44100;
+  FBlockSize=8192;
+  FCaption="";
+  FOnGetOpMode=0;
+  FOnGetPlaybackStartAndEndPos=0;
+  FOnInfoDblClick=0;
+  FOnMousePointer=0;
+  FOnMouseLocalData=0;
+  FOnSelectedChange=0;
+  FCustomCursorText=0;
+  FOnCustomPaint=0;
+  FCustomInfo=0;
+  FCustomPaneInfo=0;
+  FCustomProperty=0;
+  FOnPageChange=0;
+  FOnScaleChange=0;
+  FOnPlaybackDone=0;
+  FOnPaint=0;
+  FCustomItemExtractClick=0;
+  FCustomXZoomClick=0;
+  FCustomYZoomClick=0;
+  FLength=0;
+  InfoRectAtPointer=-1;
+  ObjectAtPointer=0;
+  StartObject=0;
+
+  FSection=new TDataAudio(this);
+  PlayBuffer0=0;
+  PlayBuffer1=0;
+
+  FSelectionBorderWidth=1;
+
+  FBytesPerSample=2;
+  FStereoMode=wvpStereo;
+  TimeStamp1=0;
+  TimeStamp2=0;
+
+  FAxisColor=clBlack;
+  FBackColor=clLtGray;
+  FCursorColorBright=clLime;
+  FCursorColorDim=clRed;
+  FInfoColor0=clWhite;
+  FInfoColor1=clBlack;
+  FInfoColor2=clRed;
+  FWaveColor=clBlack;
+  WaveBackColor=clWhite;
+  Brush->Color=FBackColor;
+
+  FSelectedAreaColorX=clWhite;
+  FSelectedFrameColorX=clWhite;
+  FSelectingFrameColorX=clWhite;
+
+  Height=150;
+  Width=150;
+  FWaveAudio=0;
+  
+  InfoLeft=0;
+  InfoTop=0;
+
+  FExtractMode=WV2_HSELECT;
+  FSelectMode=WV2_HSELECT;
+  FOpMode=wopIdle;
+  FAutoExtractMode=true;
+  FRulerAlignX=alTop;
+  FRulerAlignY=alLeft;
+
+  FLocalDataOn=false;
+  FClickFocus=false;
+  FMultiSelect=false;
+  FDefaultPopupMenu=true;
+  FDefaultPropertyItems=true;
+  FProgressCursor=true;
+  FYZoomRate=1;
+  FStartDigiFreq=0;
+	FEndDigiFreq=0.5;
+
+  FSelections=new TWaveViewSelections;
+
+  FFonts[0]=new TFont; FFonts[0]->Color=clBlue; FFonts[0]->Height=12; FFonts[0]->Name="Ariel";
+  FFonts[1]=new TFont; FFonts[1]->Color=clYellow; FFonts[1]->Height=12; FFonts[1]->Name="Ariel";
+  FFonts[2]=new TFont; FFonts[2]->Color=clYellow; FFonts[2]->Height=12; FFonts[2]->Name="Ariel";
+  FFonts[3]=new TFont; FFonts[3]->Color=clWhite; FFonts[3]->Height=12; FFonts[3]->Name="Ariel";
+  FFonts[4]=new TFont; FFonts[4]->Color=clBlack; FFonts[4]->Height=12; FFonts[4]->Name="Ariel";
+	FFonts[5]=new TFont; FFonts[5]->Color=clBlack; FFonts[5]->Height=12; FFonts[5]->Name="Ariel";
+
+	TWaveViewRulerSetting ASetting={clRed, clWhite, clBlack, TColor(clGray/2), clSilver, 4, 3, FFonts[0], true};
+	DefaultRulerSetting[0]=ASetting;
+	TWaveViewRulerSetting ASetting1={clLime, clBlack, clYellow, clSilver, clBlack, 4, 3, FFonts[1], false};
+	DefaultRulerSetting[1]=ASetting1;
+	TWaveViewRulerSetting ASetting2={clLime, clBlack, clYellow, clSilver, clBlack, 4, 3, FFonts[2], false};
+	DefaultRulerSetting[2]=ASetting2;
+	TWaveViewRulerSetting ASetting3={clRed, clBlack, clYellow, clRed, clBlack, 4, 3, FFonts[3], false};
+	DefaultRulerSetting[3]=ASetting3;
+	FRulerUnitTime=0;
+	FRulerUnitFreq=0;
+	FRulerUnitAmp=0;
+
+  DefaultPaneInfoFont=FFonts[4];
+  DefaultInfoFont=FFonts[5];
+
+  ItemExtract=NewItem(WV2_STRINGS_Extract,NULL,false,true,NULL,NULL,"ItemExtract");
+  ItemPlay=NewItem(WV2_STRINGS_Play, NULL,false,true,NULL,NULL,"ItemPlay");
+  ItemProperty=NewItem(WV2_STRINGS_Properties,NULL,false, true,NULL,NULL,"ItemProperty");
+  ItemSeparator1=NewItem("-",NULL,false,false,NULL,NULL,"ItemSeparator1");
+  ItemXZoomRestore=NewItem(WV2_STRINGS_X_zoom_all,NULL,false,true,NULL,NULL,"ItemXZoomRestore");
+  ItemYZoomRestore=NewItem(WV2_STRINGS_Y_zoom_all,NULL,false,true,NULL,NULL,"ItemYZoomRestore");
+
+  TMenuItem** Items=new TMenuItem*[6];
+  Items[0]=ItemExtract;
+  Items[1]=ItemPlay;
+  Items[2]=ItemProperty;
+  Items[3]=ItemSeparator1;
+  Items[4]=ItemXZoomRestore;
+	Items[5]=ItemYZoomRestore;
+	FMenu=NewPopupMenu(this, "FMenu", paLeft, true, Items, 5);
+  FMenu->AutoHotkeys=maManual;
+  FMenu->OnPopup=FMenuPopup;
+  delete[] Items;
+  PopupMenu=FMenu;
+
+  ItemExtract->OnClick=ItemExtractClick;
+  ItemPlay->OnClick=ItemPlayClick;
+  ItemProperty->OnClick=ItemPropertyClick;
+  ItemXZoomRestore->OnClick=ItemXZoomClick;
+  ItemYZoomRestore->OnClick=ItemYZoomClick;
+  ItemXZoomRestore->Tag=ITEMXZOOMRESTORE_TAG;
+  ItemYZoomRestore->Tag=ITEMYZOOMRESTORE_TAG;
+  FScrollBar=0;
+
+  CheckWaveOutDevCaps(this);
+
+  DoubleBuffered=true;
+
+  fw=(cdouble*)malloc8(sizeof(cdouble)*FSpecRes*2); //fft buffer
+  fx=&fw[FSpecRes/2]; famp=(double*)&fx[FSpecRes];  //fft buffer
+  SetTwiddleFactors(FSpecRes, fw);
+  fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0); //window function
+  fhbi=CreateBitInvTable(Log2(FSpecRes)-1);
+
+  memset(Basic0, 0, sizeof(Graphics::TBitmap*)*WV2_MAX_CHANNEL);
+  memset(Basic1, 0, sizeof(Graphics::TBitmap*)*WV2_MAX_CHANNEL);
+
+
+
+  AutoScroll=false;
+  ForceOLA=false;
+  LoopPlay=false;
+  LoopMode=0;
+}
+
+__fastcall TWaveView::~TWaveView()
+{
+  delete FSelections;
+
+  FreeData(FChannels);
+  FreeInternalBitmaps(FChannels);
+  FreeSpectrograms();
+
+	free8(fwin);
+	free8(fw);
+	free(fhbi);
+
+  for (int i=0; i<WV2_FONT_NUMBER; i++) delete FFonts[i];
+}
+
+//This counts the number of frames to be computed for displaying dX columns of pixels located as frames xx[0:dX-1].
+int TWaveView::CalculateSpectrogramX(int channel, double* xx, int dX, bool interpolate)
+{
+  TQuickSpectrogram* FS=FSpectrogram[channel];
+  if (FS->Capacity==0) FS->SetFrCapacity((FLength-FSpecRes)/FSpecOffst+2);
+  int calculatefrcount=0;
+  for (int x=0; x<dX; x++)
+  {
+    double ffr=xx[x];
+    int fr=floor(ffr);
+    if (fr>=0 && fr<FS->Capacity && (interpolate || ffr-fr<=0.5))
+    {
+      if (FS->Frame[fr]<0 || FS->Valid[fr]==0) calculatefrcount++;
+    }
+    if (fr+1>=0 && fr+1<FS->Capacity && (interpolate || ffr-fr>=0.5))
+    {
+      if (FS->Frame[fr+1]<0 || FS->Valid[fr+1]==0) calculatefrcount++;
+    }
+  }
+  return calculatefrcount;  
+}
+
+//Set the state of Play menuitem according to device capacity
+void __fastcall TWaveView::CheckWaveOutDevCaps(TObject* Sender)
+{
+  WAVEOUTCAPS woc;
+  if (waveOutGetDevCaps(WAVE_MAPPER, &woc, sizeof(woc))==MMSYSERR_NOERROR)
+    ItemPlay->Enabled=true;
+  else
+    ItemPlay->Enabled=false;
+}
+
+void __fastcall TWaveView::ClearSelections(TObject* Sender)
+{
+  FSelections->Clear();
+}
+
+void __fastcall TWaveView::Click()
+{
+  if (ObjectAtPointer && ObjectAtPointer->OnClick) ObjectAtPointer->OnClick(this);
+  TControl::Click();
+}
+
+void TWaveView::ClearSpectrogram(int index)
+{
+  FSpectrogram[index]->FreeBuffers();
+}
+
+void TWaveView::ClearSpectrograms()
+{
+  for (int i=0; i<FChannels; i++) FSpectrogram[i]->FreeBuffers();
+}
+
+TCursor __fastcall TWaveView::ControlCursorAtPos(int X, int Y)
+{
+  TWaveViewSelHitTest ht=SelHitTest(X, Y);
+  if (ht==selInner)
+    return crSizeAll;
+  if (ht==selLeft || ht==selRight)
+    return crSizeWE;
+  if (ht==selTop || ht==selBottom)
+    return crSizeNS;
+  if (ht==selTopLeft || ht==selBottomRight)
+    return crSizeNWSE;
+  if (ht==selTopRight || ht==selBottomLeft)
+    return crSizeNESW;
+  return crArrow;
+}
+
+int __fastcall TWaveView::CreatePanes(int X, int Y)
+{
+  return FPanes.CreatePanes(ClientRect, X, Y);
+}
+
+void __fastcall TWaveView::DblClick()
+{
+  if (FShowInfo && InfoRectAtPointer>=0 && FOnInfoDblClick) FOnInfoDblClick(this);
+  if (ObjectAtPointer && ObjectAtPointer->OnDblClick) ObjectAtPointer->OnDblClick(this);
+  TControl::DblClick();
+}
+
+
+void __fastcall TWaveView::DefaultShowProperty(bool selection)
+{
+  if (!selection)
+    ShowMessage(AnsiString().sprintf(WV2_STRINGS_1,
+                WV2_STRINGS_Properties_current_audio,
+                WV2_STRINGS_Time, FEndPos-FStartPos, (FEndPos-FStartPos)*1.0/FSamplesPerSec,
+                WV2_STRINGS_From, FStartPos, FStartPos*1.0/FSamplesPerSec,
+                WV2_STRINGS_To, FEndPos, FEndPos*1.0/FSamplesPerSec,
+                WV2_STRINGS_Frequency, FEndDigiFreq-FStartDigiFreq,
+                WV2_STRINGS_From, FStartDigiFreq,
+                WV2_STRINGS_To, FEndDigiFreq,
+                WV2_STRINGS_Total_time, FLength, FLength*1.0/FSamplesPerSec,
+                WV2_STRINGS_Samples_per_second, FSamplesPerSec,
+                WV2_STRINGS_Bits_per_sample, FWaveAudio->BitsPerSample
+                ));
+  else
+    ShowMessage(AnsiString().sprintf(WV2_STRINGS_1,
+                WV2_STRINGS_Properties_selection,
+                WV2_STRINGS_Time, FSelections->Length, (FSelections->Length)*1.0/FSamplesPerSec,
+                WV2_STRINGS_From, FSelections->StartPos, FSelections->StartPos*1.0/FSamplesPerSec,
+                WV2_STRINGS_To, FSelections->EndPos, FSelections->EndPos*1.0/FSamplesPerSec,
+                WV2_STRINGS_Frequency, FSelections->EndDigiFreq-FSelections->StartDigiFreq,
+                WV2_STRINGS_From, FSelections->StartDigiFreq,
+                WV2_STRINGS_To, FSelections->EndDigiFreq,
+                WV2_STRINGS_Total_time, FLength, FLength*1.0/FSamplesPerSec,
+                WV2_STRINGS_Samples_per_second, FSamplesPerSec,
+                WV2_STRINGS_Bits_per_sample, FWaveAudio->BitsPerSample
+                ));
+}
+
+void __fastcall TWaveView::DoExtract(TObject* Sender)
+{
+  if (FCustomItemExtractClick) FCustomItemExtractClick(Sender);
+  else
+  {
+    UndoExtractSelection=GetCurrentRange();
+    bool pagechange=false;
+    bool spanchange=false;
+    if (FExtractMode & WV2_HSELECT)
+    {
+      if (FEndPos!=FSelections->EndPos) FEndPos=FSelections->EndPos, pagechange=spanchange=true;
+      if (FStartPos!=FSelections->StartPos) FStartPos=FSelections->StartPos, pagechange=spanchange=true;
+    }
+    if (FExtractMode & WV2_VSELECT)
+    {
+      if (FEndDigiFreq!=FSelections->EndDigiFreq) FEndDigiFreq=FSelections->EndDigiFreq, spanchange=true;
+      if (FStartDigiFreq!=FSelections->StartDigiFreq) FStartDigiFreq=FSelections->StartDigiFreq, spanchange=true;
+    }
+    if (spanchange) Invalidate();
+    if (pagechange) PageChange();
+  }
+}
+
+void __fastcall TWaveView::DrawBitmap(TObject* Sender)
+{
+  Graphics::TBitmap* bmp=(Graphics::TBitmap*)Sender;
+  Canvas->Draw(0, 0, bmp);
+}
+
+void __fastcall TWaveView::DrawCaption(AnsiString ACaption)
+{
+  TSize ASize=Canvas->TextExtent(ACaption);
+  SetBkMode(Canvas->Handle, TRANSPARENT);
+  Canvas->TextOut(Width-ASize.cx-4, 2, ACaption);
+}
+
+void __fastcall TWaveView::DrawCursor(int PaneIndex, int X, int Y)
+{
+  int m=FPanes.Margin;
+  TRect Rect=FPanes.Rect[PaneIndex];
+  Canvas->Brush->Style=bsSolid; Canvas->Pen->Mode=pmCopy;
+  TColor AColor=(FPanes.Type[PaneIndex]==0)?FCursorColorDim:FCursorColorBright;
+  Canvas->Brush->Color=AColor; Canvas->Pen->Color=AColor;
+
+  int xtip, xbott, ytip, ybott;
+  TPoint Points[3];
+  if (FRulerAlignX==alTop) xtip=Rect.top+2, xbott=Rect.top-m+1;
+  else xtip=Rect.bottom-2, xbott=Rect.bottom+m-1;
+  Points[0]=Point(X, xtip); Points[1]=Point(X-m/2, xbott); Points[2]=Point(X+m/2, xbott);
+  Canvas->Polygon(Points, 2);
+  if (FRulerAlignY==alLeft) ytip=Rect.left+2, ybott=Rect.left-m+1;
+  else ytip=Rect.right-2, ybott=Rect.right+m-1;
+  Points[0]=Point(ytip, Y); Points[1]=Point(ybott, Y-m/2); Points[2]=Point(ybott, Y+m/2);
+  Canvas->Polygon(Points, 2);
+
+  Canvas->Brush->Style=bsClear;
+  if (FShowCursorText)
+  {
+    int type=FPanes.Type[PaneIndex];
+    TWaveViewRulerSetting RS=DefaultRulerSetting[type];
+    Canvas->Font=RS.UnitFont;
+    TColor FC=RS.FrontColor, BC=RS.BackColor;
+    int textheight=Canvas->TextHeight("0")-2;
+
+    TStringList* List;
+    if (FCustomCursorText) List=(TStringList*)FCustomCursorText(this);
+    else
+    {
+      List=new TStringList;
+      List->Add(CurrentTime);
+      List->Add(AnsiString().sprintf("%.4gs", CurrentTime*1.0/FSamplesPerSec));
+      if (FPanes.HasFreqAxis[PaneIndex])
+      {
+        List->Add(AnsiString().sprintf("%.1ffr", (this->CurrentTime-FSpecRes/2)*1.0/FSpecOffst));
+      }
+      List->Add("");
+      if (FPanes.HasFreqAxis[PaneIndex])
+      {
+        double f=CurrentDigiFreq*FSamplesPerSec;
+        List->Add(AnsiString().sprintf("%.6ghz", f));
+        List->Add(AnsiString().sprintf("%.5gbin", CurrentDigiFreq*FSpecRes));
+        if (f<WV2_MIN_LOG_FREQ) f=WV2_MIN_LOG_FREQ;
+        List->Add(SemitoneToPitch(12*Log2(f/C4)));
+      }
+      else if (FPanes.Type[PaneIndex]==0)
+      {
+        int a=floor(FPTA(PaneIndex, Y)+0.5);
+        List->Add(AnsiString().sprintf("%d", a));
+      }
+    }
+
+    int i=0, y=(FRulerAlignX==alTop)?xtip:(xtip-textheight), dtextheight=(FRulerAlignX==alTop)?textheight:-textheight;
+    while (i<List->Count && List->Strings[i]!="")
+    {
+      TextOutline(Canvas, List->Strings[i], X-Canvas->TextWidth(List->Strings[i])/2+1, y, FC, BC);
+      y+=dtextheight; i++;
+    }
+    while (i<List->Count && List->Strings[i]=="") i++;
+    y=Y-textheight*(List->Count-i)*0.5;
+    while (i<List->Count)
+    {
+      if (FRulerAlignY==alLeft) TextOutline(Canvas, List->Strings[i], ytip, y, FC, BC);
+      else TextOutline(Canvas, List->Strings[i], ytip-Canvas->TextWidth(List->Strings[i]), y, FC, BC);
+      y+=textheight; i++;
+    }
+
+    delete List;
+  }
+}
+
+void __fastcall TWaveView::DrawInfo()
+{
+  TStringList* List;
+  if (FCustomInfo) List=(TStringList*)FCustomInfo(this);
+  else
+  {
+    List=new TStringList;
+    List->Add(AnsiString().sprintf(" %d-channel, %dhz, %dbit. ", FChannels, FSamplesPerSec, FBytesPerSample*8));
+    double fs=FStartPos*1.0/FSamplesPerSec, fe=FEndPos*1.0/FSamplesPerSec;
+    List->Add(AnsiString().sprintf(" Time(%.4gs): from %.4gs to %.4gs. ", fe-fs, fs, fe));
+    List->Add(AnsiString().sprintf(" Frequency: from %.1fhz to %.1fhz. ", FStartDigiFreq*FSamplesPerSec, FEndDigiFreq*FSamplesPerSec));
+  }
+  InfoRectCount=List->Count;
+  Canvas->Font=DefaultInfoFont;
+  Canvas->Brush->Style=bsSolid; Canvas->Font->Color=FInfoColor0;
+  int textheight=Canvas->TextHeight("0");
+  int left=InfoLeft, right, top=InfoTop, bottom=top+textheight;
+  for (int i=0; i<InfoRectCount; i++)
+  {
+    if (i==InfoRectAtPointer)
+    {
+      Canvas->Brush->Color=FInfoColor2;
+      Canvas->TextOut(left, top, List->Strings[i]);
+    }
+    else
+    {
+      Canvas->Brush->Color=FInfoColor1;
+      Canvas->TextOut(left, top, List->Strings[i]);
+    }
+    right=left+Canvas->TextWidth(List->Strings[i]);
+    if (i<WV2_INFORECTCOUNT) InfoRect[i]=TRect(left, top, right, bottom);
+    left=right;
+  }
+
+  delete List;
+}
+
+  void DrawRuler(double t1, double t2, TCanvas* Canv, TRect& Rect, TWaveViewRulerSetting RS, TAlign Align, bool ticking)
+  {
+    double trange=fabs(t2-t1);
+    if (trange<=0) return;
+    double unit=pow(10, floor(Log10(trange))), tick;
+    trange/=unit;
+
+    int tickperunit;
+    if (trange<2) {unit*=0.5; tickperunit=5;}
+    else if (trange<5) {tickperunit=5;}
+    else {unit*=2; tickperunit=4;}
+    tick=unit/tickperunit;
+
+    if (!ticking)
+    {
+      int Y0=Rect.top, Y1=Rect.bottom;
+      Canv->Pen->Color=RS.GridColor;
+      int u1=ceil(t1/tick), u2=floor(t2/tick);
+      if (u1>=u2) {int u3=u1; u1=u2; u2=u3;}
+      for (int u=u1; u<=u2; u++)
+      {
+        double t=(u*tick-t1)/(t2-t1);
+        int pos=Rect.left+(Rect.right-Rect.left)*t;
+        Canv->MoveTo(pos, Y0);
+        Canv->LineTo(pos, Y1);
+      }
+    }
+    else
+    {
+      Canv->Brush->Style=bsClear;
+      Canv->Font=RS.UnitFont;
+      int Y0, Y1tick, Y1unit, YText;
+      if (Align==alTop) Y0=Rect.top, Y1tick=Rect.top+RS.TickSize, Y1unit=Rect.top+RS.UnitTickSize, YText=Y1unit;
+      else Y0=Rect.bottom, Y1tick=Rect.bottom-RS.TickSize, Y1unit=Rect.bottom-RS.UnitTickSize, YText=Y1unit-Canv->TextHeight("0");
+
+      int u1=ceil(t1/tick), u2=floor(t2/tick);
+      if (u1>=u2) {int u3=u1; u1=u2; u2=u3;}
+      for (int u=u1; u<=u2; u++)
+      {
+        double t=(u*tick-t1)/(t2-t1);
+        int pos=Rect.left+(Rect.right-Rect.left)*t;
+        Canv->MoveTo(pos, Y0);
+        if (u%tickperunit==0)
+        {
+          Canv->Pen->Color=RS.UnitTickColor; Canv->LineTo(pos, Y1unit);
+          AnsiString text=u*tick;
+          TextOutline(Canv, text, pos-Canv->TextWidth(text)/2+1, YText, RS.UnitFont->Color, RS.BackColor);
+        }
+        else {Canv->Pen->Color=RS.TickColor; Canv->LineTo(pos, Y1tick);}
+      }
+    }
+  }
+
+  void DrawRulerV(double t1, double t2, TCanvas* Canv, TRect& Rect, TWaveViewRulerSetting RS, TAlign Align, bool ticking, AnsiString (*CustomText)(double)=NULL, void (*CustomUnit)(double, double&, int&)=0)
+  {
+    double trange=fabs(t2-t1);
+    if (trange<=0) return;
+    double unit=pow(10, floor(Log10(trange)));
+    int tickperunit;
+
+    trange/=unit;
+    if (CustomUnit) CustomUnit(trange, unit, tickperunit);
+    else
+    {
+      if (trange<2) {unit*=0.2; tickperunit=4;}
+      else if (trange<5) {unit*=0.5; tickperunit=5;}
+      else {tickperunit=5;}
+    }
+
+    double tick=unit/tickperunit;
+    if (!ticking)
+    {
+      int X0=Rect.left, X1=Rect.right;
+      Canv->Pen->Color=RS.GridColor;
+      int u1=ceil(t1/tick), u2=floor(t2/tick);
+      if (u1>=u2) {int u3=u1; u1=u2; u2=u3;}
+      for (int u=u1; u<=u2; u++)
+      {
+        double t=(u*tick-t1)/(t2-t1);
+        int pos=Rect.top+(Rect.bottom-Rect.top)*t;
+        Canv->MoveTo(X0, pos);
+        Canv->LineTo(X1, pos);
+      }
+    }
+    else
+    {
+      Canv->Brush->Style=bsClear;
+      Canv->Font=RS.UnitFont;
+      int X0, X1tick, X1unit, XText;
+      if (Align==alLeft) X0=Rect.left, X1tick=Rect.left+RS.TickSize, X1unit=Rect.left+RS.UnitTickSize, XText=X1unit;
+      else X0=Rect.right, X1tick=Rect.right-RS.TickSize, X1unit=Rect.right-RS.UnitTickSize, XText=X1unit;
+
+      int u1=ceil(t1/tick), u2=floor(t2/tick);
+      if (u1>=u2) {int u3=u1; u1=u2; u2=u3;}
+      for (int u=u1; u<=u2; u++)
+      {
+        double t=(u*tick-t1)/(t2-t1);
+        int pos=Rect.top+(Rect.bottom-Rect.top)*t;
+        Canv->MoveTo(X0, pos);
+        if (u%tickperunit==0)
+        {
+          Canv->Pen->Color=RS.UnitTickColor; Canv->LineTo(X1unit, pos);
+          AnsiString text=CustomText?CustomText(u*tick):AnsiString(u*tick);
+          TextOutline(Canv, text, (Align==alLeft)?XText:XText-Canv->TextWidth(text), pos-Canv->TextHeight(text)/2, RS.UnitFont->Color, RS.BackColor);
+        }
+        else {Canv->Pen->Color=RS.TickColor; Canv->LineTo(X1tick, pos);}
+      }
+    }
+  }
+
+  AnsiString SemitoneToHz(double f)
+  {
+    return AnsiString().sprintf("%.1f", 440*pow(2, f/12));
+  }
+
+  void SemitoneUnit(double range, double& unit, int& tickperunit)
+  {
+    if (range<2) {unit*=0.2; tickperunit=4;}
+    else if (range<5) {unit*=0.5; tickperunit=5;}
+    else {tickperunit=5;}
+
+    if (unit>2)
+    {
+      if (unit<6) unit=6, tickperunit=6;
+      else if (unit<12) unit=12, tickperunit=6;
+      else if (unit<24) unit=24, tickperunit=6;
+      else if (unit<36) unit=36, tickperunit=6;
+      else if (unit<48) unit=48, tickperunit=4;
+      else unit=60, tickperunit=5;
+    }
+    else if (unit<0.01)
+    {
+      unit=0.01;
+      tickperunit=5;
+    }
+  }
+
+void __fastcall TWaveView::DrawPane(int Channel, int Type, int YScale, int Rulers, TCanvas* Canv, TRect& Rect)
+{
+  if (Channel>=FChannels) return;
+
+  Canv->Pen->Mode=pmCopy; Canv->Pen->Style=psSolid; Canv->Brush->Style=bsSolid;
+
+  if (Type==0) {Canv->Brush->Color=FWaveBackColor; Canv->FillRect(Rect);}
+
+  HRGN Rgn=CreateRectRgn(Rect.left, Rect.top, Rect.right, Rect.bottom);
+  SelectClipRgn(Canv->Handle, Rgn);
+
+  double TStart, TEnd;
+  if (FRulerUnitTime==0) TStart=FStartPos, TEnd=FEndPos;
+  else TStart=FStartPos*1.0/FSamplesPerSec, TEnd=FEndPos*1.0/FSamplesPerSec;
+  double AStart, AEnd;
+  if (FRulerUnitAmp==0) {AStart=-1.0/YZoomRate; AEnd=-AStart;}
+  else {AStart=-(1<<(FBytesPerSample*8-1))/YZoomRate; AEnd=-AStart;}
+  double FStart, FEnd; AnsiString (*ATranslateFreq)(double); void (*AUnit)(double, double&, int&);
+  if (YScale==0)
+  {
+    if (FRulerUnitFreq==0) FStart=FStartDigiFreq*FSamplesPerSec, FEnd=FEndDigiFreq*FSamplesPerSec;
+    else if (FRulerUnitFreq==1) FStart=FStartDigiFreq*FSpecRes, FEnd=FEndDigiFreq*FSpecRes;
+    ATranslateFreq=0; AUnit=0;
+  }
+  else
+  {
+    FStart=12*Log2(WV2_LOG_FREQ(FStartDigiFreq)*FSamplesPerSec/C4), FEnd=12*Log2(WV2_LOG_FREQ(FEndDigiFreq)*FSamplesPerSec/C4);
+    if (FRulerUnitFreq==0) ATranslateFreq=SemitoneToHz;
+    else ATranslateFreq=SemitoneToPitch;
+    AUnit=SemitoneUnit;
+  }
+
+  if (DefaultRulerSetting[Type].pre_drawing)
+  {
+    if (Rulers&WV2_HSELECT) DrawRuler(TStart, TEnd, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignX, false);
+    if (Rulers&WV2_VSELECT && TWaveViewPanes::FreqAxis(Type)) {}
+    if (Rulers&WV2_AMP && !TWaveViewPanes::FreqAxis(Type)) DrawRulerV(AEnd, AStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, false);
+  }
+  switch(Type)
+  {
+    case 0:
+      DrawWaveForm(Channel, Canv, Rect, FStartPos, FEndPos, FYZoomRate, true);
+      break;
+    case 1:
+    case 2:
+      DrawSpectrogramX(Channel, CurrentRange, YScale, Canv, Rect, FSpecAmp, false, true, Type);
+      break;
+  }
+
+  if (FSelections->Count) DrawSelections(Type, Canv, Rect, YScale);
+  if (TWaveViewPanes::FreqAxis(Type) && FTools.Contains(wvtPitchScale)) DrawPitchScale(Type, Canv, Rect, YScale);
+  if (FSectionProgress>0 && FProgressCursor) DrawPlaybackCursor(FSectionProgress, Canv, Rect, Type);
+  {
+    if (Rulers&WV2_HSELECT) DrawRuler(TStart, TEnd, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignX, true);
+    if (Rulers&WV2_VSELECT && TWaveViewPanes::FreqAxis(Type)) DrawRulerV(FEnd, FStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, true, ATranslateFreq, AUnit);
+    if (Rulers&WV2_AMP && !TWaveViewPanes::FreqAxis(Type)) DrawRulerV(AEnd, AStart, Canv, Rect, DefaultRulerSetting[Type], FRulerAlignY, true);
+  }
+
+  SelectClipRgn(Canv->Handle, NULL);
+  DeleteObject(Rgn);
+}
+
+void __fastcall TWaveView::DrawPaneInfo(int Channel, int Type, int YScale, TCanvas* Canv, TRect& Rect)
+{
+  TStringList* List;
+  if (FCustomPaneInfo) List=(TStringList*)FCustomPaneInfo(this);
+  else
+  {
+    List=new TStringList;
+    if (FSelections->Count>0 && FSelections->Focus>=0)
+    {
+      List->Add("Current Selection");
+      List->Add(AnsiString().sprintf("Time: from %d to %d", FSelections->StartPos, FSelections->EndPos));
+      List->Add(AnsiString().sprintf("Frequency: from %.1fhz to %.1fhz", FSelections->StartDigiFreq*FSamplesPerSec, FSelections->EndDigiFreq*FSamplesPerSec));
+    }
+  }
+
+  if (List->Count>0)
+  {
+    Canvas->Font=DefaultPaneInfoFont;
+    int textheight=Canvas->TextHeight("0"), textwidth=Canvas->TextWidth("0");
+    int height=textheight*List->Count+textheight;
+    int width=Canvas->TextWidth(List->Strings[0]); for (int i=1; i<List->Count; i++) {int AW=Canvas->TextWidth(List->Strings[i]); if (width<AW) width=AW;} width+=textwidth*2;
+    int left, right, top, bottom;
+    if (FRulerAlignY==alLeft) {right=Rect.right*0.95+Rect.left*0.05; left=right-width;}
+    else {left=Rect.left*0.95+Rect.right*0.05; right=left+width;}
+    top=Rect.top*0.9+Rect.bottom*0.1; bottom=top+height;
+
+    Canvas->Pen->Style=psClear; Canvas->Pen->Mode=pmMerge; Canvas->Brush->Style=bsSolid;
+    if (Type==0) Canvas->Brush->Color=(TColor)RGB(224, 224, 224);
+    else Canvas->Brush->Color=TColor(clGray/2);
+    Canvas->Rectangle(left, top, right, bottom);
+
+    Canvas->Brush->Style=bsClear;
+    if (Type==0) Canvas->Font->Color=FCursorColorDim;
+    else Canvas->Font->Color=FCursorColorBright;
+    for (int i=0; i<List->Count; i++)
+    {
+      if (FRulerAlignY==alLeft) Canvas->TextOut(right-textwidth-Canvas->TextWidth(List->Strings[i]), top+(i+0.5)*textheight, List->Strings[i]);
+      else Canvas->TextOut(left+textwidth, top+(i+0.5)*textheight, List->Strings[i]);
+    }
+  }
+  delete List;
+}
+
+void __fastcall TWaveView::DrawPanes(int Type)
+{
+  for (int i=0; i<FPanes.Count; i++)
+  {
+    int Content=FPanes.Content[i];
+    if (Content<0) {Canvas->Brush->Color=FBackColor; Canvas->FillRect(FPanes.Rect[i]);}
+    else
+    {
+      int type=Content/WV2_MAX_CHANNEL, channel=Content%WV2_MAX_CHANNEL;
+      if (Type<0 || Type==type) DrawPane(channel, type, FPanes.YScale[i], FPanes.Rulers[i], Canvas, FPanes.Rect[i]);
+    }
+  }
+  if (FCurrentPane>=0 && FShowPaneInfo) DrawPaneInfo(FCurrentPane, FPanes.Type[FCurrentPane], FPanes.YScale[FCurrentPane], Canvas, FPanes.Rect[FCurrentPane]);
+}
+
+void __fastcall TWaveView::DrawPitchScale(int Type, TCanvas* Canv, TRect& Rect, int yscale)
+{
+  int pswidth=100;
+  int NumberOfTicks=25;
+  double endl=0.7;
+  int X=FSTP(CurrentTime, Rect.left, Rect.right);
+  int X1=X-pswidth, X2=X+pswidth;
+  if (X1-Rect.left<(X-Rect.left)*2/3) X1=Rect.left+(X-Rect.left)*2/3;
+  if (Rect.right-X2<(Rect.right-X)*2/3) X2=Rect.right-(Rect.right-X)*2/3;
+  int psl=X1-X;
+  int psr=X2-X;
+
+  double f0=CurrentDigiFreq/FPitchScalePart;
+  int Y0=FDFTP(f0, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale);
+
+  double f6=f0*(NumberOfTicks+3);
+  int Y6=FDFTP(f6, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale);
+
+  Canvas->Pen->Color=TColor(clGray/2);
+  Canvas->Pen->Style=psDot;
+  Canvas->MoveTo(X, Y0+5);
+  Canvas->LineTo(X, Y6);
+  Canvas->MoveTo(X1, Y0);
+  Canvas->LineTo(X2, Y0);
+  Canvas->Pen->Color=clGray;
+
+  for (int k=2; k<=NumberOfTicks; k++)
+  {
+    f6=(NumberOfTicks-k*endl+1.0)/NumberOfTicks;
+    X1=X+psl*f6;
+    X2=X+psr*f6;
+    Y6=FDFTP(f0*k, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale);
+    Canvas->MoveTo(X1, Y6);
+    Canvas->LineTo(X2, Y6);
+  }
+
+  Canvas->Pen->Style=psSolid;
+}
+
+void __fastcall TWaveView::DrawPlaybackCursor(int Position, TCanvas* Canv, TRect& Rect, int Type)
+{
+  int X=FSTP(Position, Rect.left, Rect.right);
+  if (X>=Rect.left && X<Rect.right)
+  {
+    Canv->Pen->Mode=pmCopy;
+    Canv->Pen->Style=psSolid;
+    Canv->Pen->Color=clGreen;
+    if (TWaveViewPanes::FreqAxis(Type))
+    {
+      Canv->MoveTo(X, Rect.top*0.5+Rect.bottom*0.5);
+      Canv->LineTo(X, Rect.bottom);
+    }
+    else
+    {
+      Canv->MoveTo(X, Rect.top*0.75+Rect.bottom*0.25);
+      Canv->LineTo(X, Rect.top*0.25+Rect.bottom*0.75);
+    }
+  }
+}
+
+void __fastcall TWaveView::DrawSelection(int Type, TCanvas* Canv, TRect& Rect, int yscale, int Index, TColor FrameColorX)
+{
+  if (Index<0 || Index>=FSelections->Count) return;
+  TWaveViewSelection sel=FSelections->Items[Index];
+
+  double x1=FSTP(sel.StartPos, Rect.left, Rect.right);
+  double x2=FSTP(sel.EndPos, Rect.left, Rect.right);
+
+  if (!TWaveViewPanes::FreqAxis(Type))
+  {
+    Canvas->Pen->Mode=pmCopy;
+//    Canvas->Pen->Style=psSolid;
+    Canvas->Pen->Color=FrameColorX;
+    Canvas->MoveTo(x1, Rect.top); Canvas->LineTo(x1, Rect.bottom);
+    Canvas->MoveTo(x2, Rect.top); Canvas->LineTo(x2, Rect.bottom);
+  }
+  else
+  {
+    int y2=ceil(FDFTP(sel.StartDigiFreq, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale));
+    int y1=floor(FDFTP(sel.EndDigiFreq, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale));
+    Canvas->Pen->Mode=pmCopy;
+//    Canvas->Pen->Style=psSolid;
+    Canvas->Pen->Color=FrameColorX;
+    Canvas->Brush->Style=bsClear;
+    if (x1==x2 || y1==y2) {Canvas->MoveTo(x1, y1); Canvas->LineTo(x2, y2);}
+    else Canvas->Rectangle(x1, y1, x2+1, y2+1);
+  }
+}
+
+void __fastcall TWaveView::DrawSelections(int Type, TCanvas* Canv, TRect& Rect, int yscale)
+{
+  for (int i=0; i<FSelections->Count; i++)
+  {
+    if (i==FSelections->Focus && FOpMode<=wopReselect)
+      Canvas->Pen->Style=psSolid;
+    else
+      Canvas->Pen->Style=psDot;
+    DrawSelection(Type, Canv, Rect, yscale, i, FSelectedFrameColorX);
+  }
+}
+
+void __fastcall TWaveView::DrawSemitones(int start, int end, TCanvas* Canv, TRect& Rect, int yscale)
+{
+  for (int i=start; i<end; i++)
+  {
+    int f=FDFTP(440*pow(2, i/12.0)/FSamplesPerSec, FStartDigiFreq, FEndDigiFreq, Rect.top, Rect.bottom, yscale);
+    Canv->Pen->Mode=pmXor;
+    Canv->Pen->Style=psSolid;
+    if (i%12==0)
+      Canv->Pen->Color=clGray;
+    else
+      Canv->Pen->Color=TColor(clGray/2);
+    Canv->MoveTo(0, f);
+    Canv->LineTo(Width, f);
+  }
+}
+
+void __fastcall TWaveView::DrawSpectrogramX(int channel, TWaveViewSelection Sel, int yscale, TCanvas* ACanvas, TRect ARect, double amp, bool forceresample, bool basic, int specstyle)
+{
+  int dX=ARect.Width(), dY=ARect.Height(), HWid=FSpecRes/2;
+  double *xx=(double*)malloc8(sizeof(double)*(dX+dY)), *yy=&xx[dX];
+  FPTS(xx, dX, Sel.StartPos, Sel.EndPos); for (int x=0; x<dX; x++) xx[x]=(xx[x]-HWid)/FSpecOffst;
+
+  double framepersample=(Sel.EndPos-Sel.StartPos)*1.0/FSpecOffst/dX;
+  bool interpolate=(framepersample<1);
+  int Fr=CalculateSpectrogramX(channel, xx, dX, interpolate);
+  double ampnorm=1.0/(1<<(BytesPerSample*8-4))/sqrt(1.0*FSpecRes);
+  if (basic)
+  {
+  //draw on the internal bitmap Basic1, ignoring ARect and Sel arguments
+  //check is the content of Basic1 should be resampled since last time
+    bool resample=forceresample|(Fr>0);
+    if (!Basic1[channel])
+    {
+      Graphics::TBitmap* NewBmp=new Graphics::TBitmap;
+      NewBmp->PixelFormat=pf32bit;
+      NewBmp->Transparent=true;
+      NewBmp->TransparentMode=tmAuto;
+      Basic1[channel]=NewBmp;
+      resample=true;
+    }
+    sBasic1Settings BS; BS.X=ARect.Width(), BS.Y=ARect.Height(), BS.Sel=Sel, BS.amp=amp, BS.yscale=yscale, BS.specstyle=specstyle;
+    if (Basic1Settings[channel]!=BS) {Basic1Settings[channel]=BS; Basic1[channel]->Width=BS.X; Basic1[channel]->Height=BS.Y; resample=true;}
+
+    //resample records sampled range change and picture size change
+    if (resample)
+    {
+      if (FAutoSpecAmp) SetAutomaticSpecAmp(channel, xx, Sel.StartDigiFreq, Sel.EndDigiFreq, BS.X, BS.Y);
+      QSPEC_FORMAT maxvisiblespec;
+      if (specstyle==1)
+      {
+        FPTDF(yscale, yy, dY, Sel.StartDigiFreq, Sel.EndDigiFreq); for (int y=0; y<dY; y++) yy[y]=FSpecRes*yy[y];
+        maxvisiblespec=SampleSpectrogramX(channel, Basic1[channel], xx, yy, BS.X, BS.Y, amp*ampnorm, interpolate);
+      }
+      else if (specstyle==2) maxvisiblespec=SamplePeakSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, Basic1[channel], xx, BS.X, BS.Y, amp*ampnorm);
+      else if (specstyle==3) maxvisiblespec=SampleSinuSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, Basic1[channel], xx, BS.X, BS.Y, amp*ampnorm);
+      if (!FAutoSpecAmp) maxv_specamp=maxvisiblespec*FSpecAmp;      
+    }
+    ACanvas->CopyRect(ARect, Basic1[channel]->Canvas, TRect(0, 0, BS.X, BS.Y));
+  }
+  else
+  {
+    Graphics::TBitmap* bmp=new Graphics::TBitmap;
+    bmp->PixelFormat=pf32bit; bmp->Width=ARect.Width(); bmp->Height=ARect.Height();
+    if (specstyle==1)
+    {
+      FPTDF(yscale, yy, dY, Sel.StartDigiFreq, Sel.EndDigiFreq); for (int y=0; y<dY; y++) yy[y]=FSpecRes*yy[y];
+      SampleSpectrogramX(channel, bmp, xx, yy, bmp->Width, bmp->Height, amp*ampnorm, interpolate);
+    }
+    else if (specstyle==2) SamplePeakSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, bmp, xx, bmp->Width, bmp->Height, amp*ampnorm);
+    else if (specstyle==3) SampleSinuSpectrogramX(yscale, channel, Sel.StartDigiFreq, Sel.EndDigiFreq, bmp, xx, bmp->Width, bmp->Height, amp*ampnorm);
+    ACanvas->CopyRect(ARect, bmp->Canvas, TRect(0, 0, bmp->Width, bmp->Height));
+    delete bmp;
+  }
+  free8(xx);
+}
+
+  void __fastcall DrawWaveForm(TCanvas* Canv, TRect ARect, void* data, int BytesPerSample, int startpos, int endpos, double amp, TColor Color1, TColor Color2)
+  {
+    int i, j, X=ARect.Width(), Y=ARect.Height(), Xs=ARect.left, Ys=ARect.top, Y0=Y/2, hundred=100;
+    double Ymax, Ymin;
+    int LengthRatio=(endpos-startpos)/X;
+    Canv->Pen->Color=Color1;
+
+    amp=Y*amp/(1<<(BytesPerSample*8));
+
+    bool b8=(BytesPerSample==1), b16=(BytesPerSample==2), b24=(BytesPerSample==3);
+
+    if (false)
+    {
+      unsigned char* Data8=(unsigned char*)data;
+      Canv->MoveTo(Xs+0, Ys+Y0-(Data8[startpos]-0x80)*amp);
+      if (LengthRatio<4)
+        for (i=1; i<X; i++)
+          Canv->LineTo(Xs+i, Ys+Y0-(Data8[__int32(startpos+__int64(endpos-startpos)*i/X)]-0x80)*amp);
+      else
+      {
+        for (i=0; i<X; i++)
+        {
+          int localstart=startpos+__int64(endpos-startpos)*i/X;
+          int vlocal, vlocalmin=Data8[localstart];
+          int vlocalmax=vlocalmin;
+
+          for (j=1; j<LengthRatio; j++)
+          {
+            vlocal=Data8[localstart+j];
+            if (vlocal<vlocalmin) vlocalmin=vlocal;
+            if (vlocal>vlocalmax) vlocalmax=vlocal;
+          }
+          Ymax=Y0-(vlocalmin-0x80)*amp;
+          Ymin=Y0-(vlocalmax-0x80)*amp;
+          if (Canv->PenPos.y*2>Ymin+Ymax)
+          {
+            Canv->LineTo(Xs+i, Ys+Ymax);
+            Canv->LineTo(Xs+i, Ys+Ymin);
+          }
+          else
+          {
+            Canv->LineTo(Xs+i, Ys+Ymin);
+            Canv->LineTo(Xs+i, Ys+Ymax);
+          }
+        }
+      }
+    }
+    else
+    {
+      unsigned __int8* data8; __int16* data16; __pint24 data24;
+
+      if (b16) {data16=(__int16*)data; Canv->MoveTo(Xs, Ys+Y0-data16[startpos]*amp);}
+      else if (b24) {data24=(__pint24)data; Canv->MoveTo(Xs, Ys+Y0-data24[startpos]*amp);}
+      else if (b8) {data8=(unsigned __int8*)data; Canv->MoveTo(Xs, Ys+Y0-(data8[startpos]-0x80)*amp);}
+
+      if (LengthRatio<1)
+        for (i=1; i<X; i++)
+        {
+          if (b16) Canv->LineTo(Xs+i, Ys+Y0-data16[__int32(startpos+__int64(endpos-startpos)*i/X)]*amp);
+          else if (b24) Canv->LineTo(Xs+i, Ys+Y0-data24[__int32(startpos+__int64(endpos-startpos)*i/X)]*amp);
+          else if (b8) Canv->LineTo(Xs+i, Ys+Y0-(data8[__int32(startpos+__int64(endpos-startpos)*i/X)]-0x80)*amp);
+        }
+      else
+      {
+        for (i=0; i<X; i++)
+        {
+          int vlocalmin, vlocalmax;
+          int localstart=startpos+__int64(endpos-startpos)*i/X;
+          int vlocal, jump=LengthRatio/hundred+1;
+          if (b16) vlocalmin=vlocalmax=data16[localstart];
+          else if (b24) vlocalmin=vlocalmax=data24[localstart]; //(*data24)[localstart];
+          else if (b8) vlocalmin=vlocalmax=data8[localstart]-0x80;
+          for (j=LengthRatio-1; j>0; j-=jump)
+          {
+            if (b16) vlocal=data16[localstart+j];
+            else if (b24) vlocal=data24[localstart+j]; //(*data24)[localstart+j];
+            else if (b8) vlocal=data8[localstart+j]-0x80;
+            if (vlocal<vlocalmin) vlocalmin=vlocal;
+            if (vlocal>vlocalmax) vlocalmax=vlocal;
+          }
+          double rmin=vlocalmin*amp, rmax=vlocalmax*amp;
+          Ymax=Y0-rmin, Ymin=Y0-rmax;
+          if (rmin<0 && rmax>0)
+          {
+            int Y1=(rmax-rmin)/4;
+            int Y2=Y0+Y1;
+            Y1=Y0-Y1;
+            if (Canv->PenPos.y*2>Ymin+Ymax)
+            {
+              Canv->LineTo(Xs+i, Ys+Ymax);
+              Canv->LineTo(Xs+i, Ys+Y2);
+              Canv->Pen->Color=Color2;
+              Canv->LineTo(Xs+i, Ys+Y1);
+              Canv->Pen->Color=Color1;
+              Canv->LineTo(Xs+i, Ys+Ymin);
+            }
+            else
+            {
+              Canv->LineTo(Xs+i, Ys+Ymin);
+              Canv->LineTo(Xs+i, Ys+Y1);
+              Canv->Pen->Color=Color2;
+              Canv->LineTo(Xs+i, Ys+Y2);
+              Canv->Pen->Color=Color1;
+              Canv->LineTo(Xs+i, Ys+Ymax);
+            }
+          }
+          else
+          {
+            if (Canv->PenPos.y*2>Ymin+Ymax)
+            {
+              Canv->LineTo(Xs+i, Ys+Ymax);
+              Canv->LineTo(Xs+i, Ys+Ymin);
+            }
+            else
+            {
+              Canv->LineTo(Xs+i, Ys+Ymin);
+              Canv->LineTo(Xs+i, Ys+Ymax);
+            }
+          }
+        }
+      }
+    }
+  }
+
+/*
+  The internal bitmap Basic0 is used to contain the default waveform bitmap.
+  Whenever this method is called with FCanvas assigned to ACanvas, it draws the
+  waveform of the current section to Basic1, regardless of AStartPos or AnEndPos.
+*/
+void __fastcall TWaveView::DrawWaveForm(int channel, TCanvas* ACanvas, TRect ARect, int AStartPos, int AnEndPos, double amp, bool basic)
+{
+  if (AnEndPos<=AStartPos) return;
+  TRect bmpRect;
+  Graphics::TBitmap* bmp;
+  if (basic)
+  {
+    bool resample=false;
+    if (!Basic0[channel])
+    {
+      Graphics::TBitmap* NewBmp=new Graphics::TBitmap;
+      NewBmp->PixelFormat=pf32bit;
+      NewBmp->Transparent=true;
+      NewBmp->TransparentMode=tmFixed;
+      Basic0[channel]=NewBmp;
+      resample=true;
+    }
+    sBasic0Settings BS={ARect.Width(), ARect.Height(), FStartPos, FEndPos, FYZoomRate};
+    if (Basic0Settings[channel]!=BS)
+    {
+      Basic0Settings[channel]=BS;
+      Basic0[channel]->Width=BS.X;
+      Basic0[channel]->Height=BS.Y;
+      resample=true;
+    }
+    if (!resample)
+    {
+      ACanvas->CopyRect(ARect, Basic0[channel]->Canvas, TRect(0, 0, BS.X, BS.Y));
+//      ACanvas->Draw(ARect.left, ARect.top, Basic0[channel]);
+      return;
+    }
+    AStartPos=FStartPos, AnEndPos=FEndPos;
+    bmp=Basic0[channel];
+    bmpRect=TRect(0, 0, BS.X, BS.Y);
+  }
+  else
+  {
+    bmp=new Graphics::TBitmap;
+    bmp->PixelFormat=pf32bit;
+    bmp->Width=ARect.Width();
+    bmp->Height=ARect.Height();
+    bmpRect=TRect(0, 0, bmp->Width, bmp->Height);
+  }
+
+  TCanvas* Canv=bmp->Canvas;
+  if (ACanvas==Canvas) Canv->CopyRect(bmpRect, ACanvas, ARect);
+  else {Canv->Brush->Color=FWaveBackColor; Canv->FillRect(bmpRect);}
+  Canv->Pen->Mode=pmCopy;
+  Canv->Pen->Style=psSolid;
+  int Y=bmpRect.Height(), X=bmpRect.Width(), Y0=Y/2;
+  Canv->Pen->Color=FAxisColor; Canv->MoveTo(0, Y0); Canv->LineTo(X, Y0);
+  ::DrawWaveForm(Canv, bmpRect, FData[channel], FBytesPerSample, AStartPos, AnEndPos, FYZoomRate, FWaveColor, FWaveColor2);
+
+  ACanvas->CopyRect(ARect, Canv, bmpRect);
+  if (!basic) delete bmp;
+}
+
+//Call this when the waveview data buffer is updated externally
+void __fastcall TWaveView::ExtDataChange(TObject* Sender)
+{
+  ClearSpectrograms();
+  InvalidateBasic(-1, 0);
+}
+
+void __fastcall TWaveView::ExtDataChange(TObject* Sender, int Channel, int From, int To)
+{
+  FSpectrogram[Channel]->Invalidate(From, To);
+  InvalidateBasic(Channel, 0);
+  Invalidate();
+}
+
+  void WaveViewPlayLoadFrame(double* frame, int n, int readfrom, char* data, int bps, int datalen, int datast, int dataen, bool loop, double* win, double* &loopframe)
+  {
+    int hn=n/2;
+    if (readfrom+n<dataen) IntToDouble2416(frame, &data[readfrom*bps], bps, n);
+    else if (readfrom<dataen)
+    {
+			IntToDouble2416(frame, &data[readfrom*bps], bps, dataen-readfrom);
+		}
+    else memset(frame, 0, sizeof(double)*n);  //this line shall never be reached
+
+    if (readfrom+n>dataen-hn)
+    {                  
+      if (!loop)
+      {
+
+				if (readfrom>dataen-hn)
+				{
+					double* lwin=&win[n-(dataen-readfrom)];
+					for (int i=0; i<dataen-readfrom; i++) frame[i]*=lwin[i];
+				}
+				else if (readfrom>dataen-n)
+				{
+					double* lwin=&win[n-(dataen-readfrom)];
+					for (int i=dataen-hn-readfrom; i<dataen-readfrom; i++) frame[i]*=lwin[i];
+				}
+				else
+				{
+					double *lframe=&frame[dataen-hn-readfrom], *lwin=&win[hn];
+					for (int i=0; i<hn; i++) lframe[i]*=lwin[i];
+				}
+			}
+			else if (readfrom+n>dataen-hn/2) //notice it is during looped playback
+			{
+				if (readfrom>dataen-hn/2 && loopframe)
+				{
+					memcpy(frame, &loopframe[readfrom-(dataen-hn/2)], sizeof(double)*(hn-readfrom+dataen-hn/2));
+					IntToDouble2416(&frame[dataen-readfrom+hn/2], &data[(datast+hn/2)*bps], bps, n-dataen+readfrom-hn/2);
+				}
+				else if (readfrom+hn>dataen-hn/2 && loopframe)
+				{
+					memcpy(&frame[dataen-hn/2-readfrom], loopframe, sizeof(double)*hn);
+					IntToDouble2416(&frame[dataen+hn/2-readfrom], &data[(datast+hn/2)*bps], bps, n-dataen+readfrom-hn/2);
+				}
+				else
+				{
+				//calculate loopframe, of size hn
+					free8(loopframe);
+					loopframe=(double*)malloc8(sizeof(double)*n);
+					double* looped=&loopframe[hn];
+					if (dataen+hn/2<=datalen) IntToDouble2416(loopframe, &data[(dataen-hn/2)*bps], bps, hn);
+					else
+					{
+						IntToDouble2416(loopframe, &data[(dataen-hn/2)*bps], bps, datalen-(dataen-hn/2));
+						memset(&loopframe[datalen-(dataen-hn/2)], 0, sizeof(double)*(dataen+hn/2-datalen));
+					}
+          if (datast>hn/2) IntToDouble2416(looped, &data[(datast-hn/2)*bps], bps, hn);
+          else
+          {
+            memset(looped, 0, sizeof(double)*(hn/2-datast));
+            IntToDouble2416(&looped[hn/2-datast], data, bps, datast+hn/2);
+          }
+          for (int i=0; i<hn; i++) loopframe[i]=loopframe[i]*(1-win[i])+looped[i]*(win[i]);
+
+          memcpy(&frame[dataen-readfrom-hn/2], loopframe, sizeof(double)*(readfrom+n-(dataen-hn/2)));
+        }
+      }
+    }
+    else if (loop && readfrom<datast+hn/2 && loopframe)
+    {
+      memcpy(frame, &loopframe[hn/2+readfrom-datast], sizeof(double)*(hn/2-readfrom+datast));
+    }
+  }
+
+//playback filter used for unbuffered play has in-frame time alias
+int __fastcall TWaveView::FillBlock(void* ABlock)
+{
+  char* Block=(char*)ABlock;
+  FSectionBlocks++;
+  bool stereo=(FSection->Channels==2);
+  int PlayBytesPerSample=(FBytesPerSample<3)?FBytesPerSample:2;
+
+  int BlockSize=FSection->BlockSize/PlayBytesPerSample/FSection->Channels;
+  if (LoopPlay && LoopMode)
+  {
+    if (LoopMode==1) //loop visible
+      FSectionStartPos=FStartPos, FSectionEndPos=FEndPos;
+    else if (LoopMode==2)//loop selection
+			FSectionStartPos=FSelections->StartPos, FSectionEndPos=FSelections->EndPos;
+		if (PBPR<FSectionStartPos) PBPR=FSectionStartPos, ForceOLA=true;
+  }
+
+  char *lData0, *lData1;
+
+  if (stereo)
+  {
+    if (FStereoMode==wvpSwap) lData0=(char*)FData[1], lData1=(char*)FData[0];
+    else lData0=(char*)FData[0], lData1=(char*)FData[1];
+  }
+  else lData0=(char*)((FChannels>1 && FStereoMode==wvpRight)?FData[1]:FData[0]);
+
+  int Wid=FSpecRes, HWid=Wid/2;
+  while (PBPA<BlockSize && PBPR<FSectionEndPos)
+  {
+    int newPBPR=PBPR+HWid, newPBPA;
+    if (newPBPR>=FSectionEndPos)
+    {
+      if (!LoopPlay) newPBPR=FSectionEndPos, newPBPA=PBPA+FSectionEndPos-PBPR;
+      else newPBPR=newPBPR-FSectionEndPos+FSectionStartPos, newPBPA=PBPA+HWid;// looping=true;
+    }
+    else newPBPA=PBPA+HWid;
+
+    double k=GetFMask(famp, PBPR, FPlaybackFilter);
+
+    if (k==0)
+    {
+      if (prevk==1)
+      {
+        for (int i=0; i<HWid; i++) PlayBuffer0[PBPA+i]*=fw2[HWid+i];
+        if (stereo) for (int i=0; i<HWid; i++) PlayBuffer1[PBPA+i]*=fw2[HWid+i];
+      }
+      memset(&PlayBuffer0[PBPA+HWid], 0, sizeof(double)*HWid);
+      if (stereo) memset(&PlayBuffer1[PBPA+HWid], 0, sizeof(double)*HWid);
+    }
+    else
+    {
+      double* dbfx=(double*)fx;
+      WaveViewPlayLoadFrame(dbfx, Wid, PBPR, lData0, FBytesPerSample, FLength, FSectionStartPos, FSectionEndPos, LoopPlay, fw2, loopframe0);
+
+      //filtering
+      if (k!=1)
+      {
+        RFFTCW(dbfx, fw1, NULL, NULL, Log2(Wid), fw, fx, fhbi);
+        for (int i=0; i<=HWid; i++) fx[i].x*=famp[i], fx[i].y*=famp[i];
+        CIFFTR(fx, Log2(Wid), fw, dbfx, fhbi);
+      }
+
+      //first half frame
+      if (k==1 && prevk==1 && !ForceOLA) {}
+      else
+      {
+        if (prevk==1) for(int i=0; i<HWid; i++) PlayBuffer0[PBPA+i]*=fw2[HWid+i];
+        if (k==1) for (int i=0; i<HWid; i++) PlayBuffer0[PBPA+i]+=dbfx[i]*fw2[i];
+        else for (int i=0; i<HWid; i++) PlayBuffer0[PBPA+i]+=dbfx[i]*fw2_fw1[i];
+        ForceOLA=false;
+      }
+
+      //second half frame
+      if (k==1) for (int i=HWid; i<Wid; i++) PlayBuffer0[PBPA+i]=dbfx[i];
+      else for (int i=HWid; i<Wid; i++) PlayBuffer0[PBPA+i]=dbfx[i]*fw2_fw1[i];
+
+      if (stereo)
+      {
+        //load frame
+        WaveViewPlayLoadFrame(dbfx, Wid, PBPR, lData1, FBytesPerSample, FLength, FSectionStartPos, FSectionEndPos, LoopPlay, fw2, loopframe1);
+
+        //filtering
+        if (k!=1)
+        {
+          RFFTCW(dbfx, fw1, NULL, NULL, Log2(Wid), fw, fx, fhbi);
+          for (int i=0; i<=HWid; i++) fx[i].x*=famp[i], fx[i].y*=famp[i];
+          CIFFTR(fx, Log2(Wid), fw, dbfx, fhbi);
+        }
+
+        //first half frame
+        if (k==1 && prevk==1 && !ForceOLA) {}
+        else
+        {
+          if (prevk==1) for(int i=0; i<HWid; i++) PlayBuffer1[PBPA+i]*=fw2[HWid+i];
+          if (k==1) for (int i=0; i<HWid; i++) PlayBuffer1[PBPA+i]+=dbfx[i]*fw2[i];
+          else for (int i=0; i<HWid; i++) PlayBuffer1[PBPA+i]+=dbfx[i]*fw2_fw1[i];
+        }
+
+        //second half frame
+        if (k==1) for (int i=HWid; i<Wid; i++) PlayBuffer1[PBPA+i]=dbfx[i];
+        else for (int i=HWid; i<Wid; i++) PlayBuffer1[PBPA+i]=dbfx[i]*fw2_fw1[i];
+      }
+    }
+    PBPR=newPBPR;
+    PBPA=newPBPA;
+    prevk=k;
+  }
+
+  if (stereo) DoubleToIntInterleave(Block, PlayBytesPerSample, &PlayBuffer0[PBPW], &PlayBuffer1[PBPW], BlockSize);
+  else DoubleToInt(Block, PlayBytesPerSample, &PlayBuffer0[PBPW], BlockSize);
+
+  PBPW+=BlockSize;
+  if (PBPA-PBPW<BlockSize)
+  {
+    if (PBPA-PBPW+HWid>0)
+    {
+      memmove(PlayBuffer0, &PlayBuffer0[PBPW], sizeof(double)*(PBPA-PBPW+HWid));
+      if (stereo) memmove(PlayBuffer1, &PlayBuffer1[PBPW], sizeof(double)*(PBPA-PBPW+HWid));
+    }
+    PBPA-=PBPW; PBPW=0;
+  }
+  if (PBPA>0) return FSection->BlockSize;
+  else return (BlockSize+PBPA)*PlayBytesPerSample*FSection->Channels;
+}
+
+void __fastcall TWaveView::FMenuPopup(TObject* Sender)
+{
+  ItemExtract->Visible=(FLength>0 && FSelections->Count>0 && FSelections->Focus>=0);
+  ItemPlay->Visible=(FLength>0);
+  ItemProperty->Visible=(FLength>0);
+  ItemXZoomRestore->Visible=(FLength>0 && (FStartPos!=0 || FEndPos!=FLength));
+  bool hfa=FPanes.HasFreqAxis[FCurrentPane];
+  ItemYZoomRestore->Visible=(FLength>0 && (!hfa && YZoomRate!=1 || hfa && (FStartDigiFreq!=0 || FEndDigiFreq!=0.5)));
+}
+
+void __fastcall TWaveView::FocusSelection(int Index)
+{
+  if (Index>=0 && Index<FSelections->Count && Index!=FSelections->Focus)
+  {
+    FSelections->Focus=Index;
+    if (FOnSelectedChange) FOnSelectedChange(this);
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::FreeData(int ch)
+{
+  if (ch>=FChannels || ch<0)
+  {
+    for (int i=0; i<FChannels; i++)
+    {
+      delete[] FData[i];
+      FData[i]=0;
+    }
+  }
+  else
+  {
+    delete[] FData[ch];
+    FData[ch]=0;
+  }
+}
+
+void __fastcall TWaveView::FreeInternalBitmaps(int ch)
+{
+  if (ch>=FChannels || ch<0)
+  {
+    for (int i=0; i<FChannels; i++)
+    {
+      delete Basic0[i]; Basic0[i]=0;
+      delete Basic1[i]; Basic1[i]=0;
+    }
+  }
+  else
+  {
+    delete Basic0[ch]; Basic0[ch]=0;
+    delete Basic1[ch]; Basic1[ch]=0;
+  }
+}
+
+void __fastcall TWaveView::FreeSpectrograms()
+{
+  for (int i=0; i<WV2_MAX_CHANNEL; i++)
+  {
+    delete FSpectrogram[i]; FSpectrogram[i]=0;
+  }
+}
+
+double __fastcall TWaveView::FromAmplitudeToPixel(int PaneIndex, double Amplitude)
+{
+  if (FPanes.Type[PaneIndex]) return 0;
+  int top=FPanes.Rect[PaneIndex].top, height=FPanes.Rect[PaneIndex].Height();
+  if (FBytesPerSample==0) Amplitude-=128;
+  return top+height/2-Amplitude*YZoomRate*height/(1<<(FBytesPerSample*8));
+}
+
+double __fastcall TWaveView::FromPixelToAmplitude(int PaneIndex, double Y)
+{
+  if (FPanes.Type[PaneIndex]) return 0;
+  int top=FPanes.Rect[PaneIndex].top, height=FPanes.Rect[PaneIndex].Height();
+  double ap=-1.0*(Y-(top+height/2))/height;
+  double result=(1<<(FBytesPerSample*8))*ap/YZoomRate;
+  if (FBytesPerSample==1) result+=128;
+  return result;
+}
+
+double __fastcall TWaveView::FromDigiFreqToPixel(int PaneIndex, double DigiFreq)
+{
+  if (FEndDigiFreq-FStartDigiFreq<=0) return 0;
+  if (!FPanes.HasFreqAxis[PaneIndex]) return 0;
+  if (FPanes.YScale[PaneIndex]==1) //log scale
+  {
+    double AStartDigiFreq=WV2_LOG_FREQ(FStartDigiFreq),
+           AnEndDigiFreq=WV2_LOG_FREQ(FEndDigiFreq);
+    DigiFreq=WV2_LOG_FREQ(DigiFreq);
+    return FPanes.Rect[PaneIndex].top+FPanes.Rect[PaneIndex].Height()*log(DigiFreq/AnEndDigiFreq)/log(AStartDigiFreq/AnEndDigiFreq);
+  }
+  else
+    return FPanes.Rect[PaneIndex].top+FPanes.Rect[PaneIndex].Height()*(DigiFreq-FEndDigiFreq)/(FStartDigiFreq-FEndDigiFreq);
+}
+
+double __fastcall TWaveView::FromDigiFreqToPixel(double DigiFreq, double AStartDigiFreq, double AnEndDigiFreq, int Y1, int Y2, int YScale)
+{
+  if (FEndDigiFreq-FStartDigiFreq<=0) return 0;
+  if (YScale==1) //log scale
+  {
+    AStartDigiFreq=WV2_LOG_FREQ(AStartDigiFreq),
+    AnEndDigiFreq=WV2_LOG_FREQ(AnEndDigiFreq);
+    DigiFreq=WV2_LOG_FREQ(DigiFreq);
+    return Y1+(Y2-Y1)*log(DigiFreq/AnEndDigiFreq)/log(AStartDigiFreq/AnEndDigiFreq);
+  }
+  else
+    return Y1+(Y2-Y1)*(DigiFreq-AnEndDigiFreq)/(AStartDigiFreq-AnEndDigiFreq);
+}
+
+double __fastcall TWaveView::FromPixelToDigiFreq(int PaneIndex, double Y)
+{
+  if (FEndDigiFreq-FStartDigiFreq<0) return 0;
+  if (!FPanes.HasFreqAxis[PaneIndex]) return 0;
+  double ap=1.0*(Y-FPanes.Rect[PaneIndex].top)/FPanes.Rect[PaneIndex].Height();
+  if (FPanes.YScale[PaneIndex]==1) //log scale
+  {
+    double AStartDigiFreq=WV2_LOG_FREQ(FStartDigiFreq),
+           AnEndDigiFreq=WV2_LOG_FREQ(FEndDigiFreq);
+    return AnEndDigiFreq*pow(AStartDigiFreq/AnEndDigiFreq, ap);
+  }
+  else
+    return FEndDigiFreq+(FStartDigiFreq-FEndDigiFreq)*ap;
+}
+
+void __fastcall TWaveView::FromPixelToDigiFreq(int YScale, double* DigiFreq, int Count, double AStartDigiFreq, double AnEndDigiFreq)
+{
+  if (FEndDigiFreq-FStartDigiFreq<0) {memset (DigiFreq, 0, sizeof(double)*Count); return;}
+  if (YScale==0) //linear scale
+  {
+    double StartEndDigiFreq=(AnEndDigiFreq-AStartDigiFreq)/Count;
+    double AS=AStartDigiFreq+StartEndDigiFreq*0.5;
+    for (int i=0; i<Count; i++) DigiFreq[i]=AS+StartEndDigiFreq*i;
+  }
+  else if (YScale==1) //log scale
+  {
+    if (AStartDigiFreq<WV2_MIN_LOG_FREQ) AStartDigiFreq=WV2_MIN_LOG_FREQ;
+    if (AnEndDigiFreq<WV2_MIN_LOG_FREQ) AnEndDigiFreq=WV2_MIN_LOG_FREQ;
+    double StartEndDigiFreq=pow(AnEndDigiFreq/AStartDigiFreq, 1.0/Count);
+    for (int i=0; i<Count; i++) DigiFreq[i]=AStartDigiFreq*pow(StartEndDigiFreq, i+0.5);
+  }
+}
+
+double __fastcall TWaveView::FromPixelToSample(int PaneIndex, double X)
+{
+  if (PaneIndex<0) return 0;
+  if (FEndPos-FStartPos<0) return 0;
+  else if (FEndPos-FStartPos==0) return FStartPos;
+  else return FStartPos+(X-FPanes.Rect[PaneIndex].left)*(FEndPos-FStartPos)/FPanes.Rect[PaneIndex].Width();
+}
+
+double __fastcall TWaveView::FromPixelToSample(double X, int AStartPos, int AnEndPos, int X1, int X2)
+{
+  if (AnEndPos-AStartPos<0) return 0;
+  else if (AnEndPos-AStartPos==0) return FStartPos;
+  else return AStartPos+(X-X1)*(AnEndPos-AStartPos)/(X2-X1);
+}
+
+void __fastcall TWaveView::FromPixelToSample(double* Sample, int Count, int AStartPos, int AnEndPos)
+{
+  if (AnEndPos-AStartPos<0) memset(Sample, 0, sizeof(double)*Count);
+  else if (AnEndPos-AStartPos==0) for (int i=0; i<Count; i++) Sample[i]=AStartPos;
+  else
+  {
+    double EndStartCount=(AnEndPos-AStartPos)*1.0/Count;
+    double As=AStartPos+0.5*EndStartCount;
+    for (int i=0; i<Count; i++) Sample[i]=As+i*EndStartCount;
+  }
+}
+
+double __fastcall TWaveView::FromSampleToPixel(int PaneIndex, double Pos)
+{
+  return FPanes.Rect[PaneIndex].left+(Pos-FStartPos)*1.0*FPanes.Rect[PaneIndex].Width()/(FEndPos-FStartPos);
+}
+
+double __fastcall TWaveView::FromSampleToPixel(double Pos, int X1, int X2)
+{
+  return X1+(Pos-FStartPos)*(X2-X1)/(FEndPos-FStartPos);
+}
+
+int __fastcall TWaveView::GetCurrentChannel()
+{
+  return FPanes.Channel[FCurrentPane];
+}
+
+double __fastcall TWaveView::GetCurrentDigiFreq()
+{
+  double result=(FCurrentDigiFreq1+FCurrentDigiFreq2)/2;
+  if (result<0) return 0;
+  else if (result>0.5) return 0.5;
+  else return result;
+}
+
+QSPEC_FORMAT* __fastcall TWaveView::GetA(int Channel, int fr)
+{
+  return FSpectrogram[Channel]->A(fr);
+}
+
+double __fastcall TWaveView::GetCurrentAmplitude()
+{
+  return FPTA(FCurrentPane, FY);
+}
+
+//There is no SetCurrentRange() method. Use SetArea().
+TWaveViewSelection __fastcall TWaveView::GetCurrentRange()
+{
+  TWaveViewSelection sel={FStartPos, FEndPos, FStartDigiFreq, FEndDigiFreq};
+  return sel;
+}
+
+__int16 __fastcall TWaveView::GetCurrentSample16()
+{
+  return Data16[FPanes.Channel[FCurrentPane]][CurrentTime];
+}
+
+int __fastcall TWaveView::GetCurrentSampleInPixel()
+{
+  if (FBytesPerSample==1) return FATP(FCurrentPane, Data8[FPanes.Channel[FCurrentPane]][CurrentTime]);
+  else if (FBytesPerSample==2) return FATP(FCurrentPane, Data16[FPanes.Channel[FCurrentPane]][CurrentTime]);
+  else return FATP(FCurrentPane, Data24[FPanes.Channel[FCurrentPane]][CurrentTime]);
+}
+
+int __fastcall TWaveView::GetCurrentTimeEx()
+{
+  return (FCurrentTime1+FCurrentTime2)/2;//+0.5;
+}
+
+void* __fastcall TWaveView::GetData(int Channel)
+{
+  return FData[Channel];
+}
+
+__int16* __fastcall TWaveView::GetData16(int Channel)
+{
+  return (__int16*)(FData[Channel]);
+}
+
+__pint24 __fastcall TWaveView::GetData24(int Channel)
+{
+  return (__pint24)(FData[Channel]);
+}
+
+char* __fastcall TWaveView::GetData8(int Channel)
+{
+  return (char*)(FData[Channel]);
+}
+
+double __fastcall TWaveView::GetFMask(double* mask, int t, TWaveViewPlaybackFilter Filter)
+{
+  double result=0;
+
+  if (Filter==wvfPass) memset(mask, 0, FSpecRes*sizeof(double));
+  else for (int i=0; i<FSpecRes; i++) mask[i]=1;
+
+  if (Filter==wvfNone) result=1;
+  else
+  {
+    int LF1, LF2;
+    for (int i=0; i<FSelections->Count; i++)
+    {
+      TWaveViewSelection sel=FSelections->Items[i];
+      if (t<sel.StartPos || t>sel.EndPos) continue;
+      LF1=sel.StartDigiFreq*FSpecRes+0.5;
+      LF2=sel.EndDigiFreq*FSpecRes+0.5;
+      if (LF1<0) LF1=0;
+      if (LF2>FSpecRes/2+1) LF2=FSpecRes/2+1;
+      if (Filter==wvfPass) for (int j=LF1; j<=LF2; j++) mask[j]=1;
+      else for (int j=LF1; j<=LF2; j++) mask[j]=0;
+    }
+    for (int i=FSpecRes/2+1; i<FSpecRes; i++) mask[i]=mask[FSpecRes-i];
+    for (int i=0; i<FSpecRes; i++) result+=mask[i];
+    result/=FSpecRes;
+  }
+  return result;
+}
+
+void __fastcall TWaveView::GetObjectAtPointer(int X, int Y)
+{
+  ObjectAtPointer=0;
+  for (int i=0; i<FObjects.Count; i++)
+  {
+    if (FObjects.Items[i].Options & wvoNoMouseFocus) continue;
+    TRect Rect=FObjects.Items[i].Rect;
+    if (X>=Rect.left && X<Rect.right && Y>=Rect.top && Y<Rect.bottom)
+    {
+      ObjectAtPointer=&FObjects.Items[i];
+      break;
+    }
+  }
+}
+
+//WaveView.cpp implements basic idle mode (-1), drag mode (0), select mode (1) and re-select mode (2)
+//other modes are defined externally
+void __fastcall TWaveView::GetOpMode(Word Key, TMouseButton Button, TShiftState Shift)
+{
+  if (FCurrentPane>=0)
+  {
+    FOpMode=wopSelect;
+    if (FOnGetOpMode) FOnGetOpMode(this, Shift, FOpMode);
+  }
+  else
+    FOpMode=wopIdle; //Idle mode
+
+  TCursor ACursor;
+  if (FOpMode==wopDrag) ACursor=crHandPoint;
+  else if (FOpMode==wopSelect) ACursor=crArrow;
+  else ACursor=Cursor;
+  if (ACursor!=Cursor) {Cursor=ACursor;::SetCursor(Screen->Cursors[Cursor]);}
+}
+
+QSPEC_FORMAT* __fastcall TWaveView::GetPh(int Channel, int fr)
+{
+  return FSpectrogram[Channel]->Ph(fr);
+}
+
+cmplx<QSPEC_FORMAT>* __fastcall TWaveView::GetSpec(int Channel, int fr)
+{
+  return FSpectrogram[Channel]->Spec(fr);
+}
+
+TQuickSpectrogram* __fastcall TWaveView::GetSpectrogram(int Channel)
+{
+	return FSpectrogram[Channel];
+}
+
+bool __fastcall TWaveView::GetPlaying()
+{
+  return FSection->Playing;
+}
+
+double __fastcall TWaveView::GetSpecWindowParamD(int Index)
+{
+  return FSpecWindowParamD[Index];
+}
+
+void __fastcall TWaveView::InvalidateBasic(int channel, int basic)
+{
+  if (basic==0)
+    if (channel>=0) Basic0Settings[channel].Y=0;
+    else for (int i=0; i<WV2_MAX_CHANNEL; i++) Basic0Settings[i].Y=0;
+  if (basic==1)
+    if (channel>=0) Basic1Settings[channel].Y=0;
+    else for (int i=0; i<WV2_MAX_CHANNEL; i++) Basic1Settings[i].Y=0;
+}
+
+void __fastcall TWaveView::InvalidateBasics(int channel)
+{
+  Basic0Settings[channel].Y=0;
+  Basic1Settings[channel].Y=0;
+}
+
+void __fastcall TWaveView::ItemExtractClick(TObject* Sender)
+{
+  if (FLength>0)
+  {
+    bool Shift=(GetKeyState(VK_SHIFT)<0);
+    DoExtract(Sender);
+    if (!Shift) RemoveSelection(-1);
+  }
+}
+
+void __fastcall TWaveView::ItemPlayClick(TObject* Sender)
+{
+  StartPlayback(Sender);
+}
+
+void __fastcall TWaveView::ItemPropertyClick(TObject* Sender)
+{
+  if (FLength>0)
+  {
+    if (FStartSelR<FSelections->StartPos ||FStartSelR>=FSelections->EndPos
+        ||FPanes.HasFreqAxis[FStartPane] && (FVStartSelR<FSelections->StartDigiFreq||FVStartSelR>=FSelections->EndDigiFreq))
+    {
+      if (DefaultPropertyItems) DefaultShowProperty(false);
+      else if (FCustomProperty) FCustomProperty(this, false);
+    }
+    else
+    {
+      if (DefaultPropertyItems) DefaultShowProperty(true);
+      else if (FCustomProperty) FCustomProperty(this, true);
+    }
+  }
+}
+
+void __fastcall TWaveView::ItemXZoomClick(TObject* Sender)
+{
+  if (FCustomXZoomClick) FCustomXZoomClick(Sender);
+  else
+  {
+    if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMXZOOMIN_TAG)
+      Zoom(FStartSelR, 0.8);
+    else if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMXZOOMOUT_TAG)
+      Zoom(FStartSelR, 3);
+    else if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMXZOOMRESTORE_TAG)
+      Zoom(FStartSelR, 0);
+  }
+}
+
+void __fastcall TWaveView::ItemYZoomClick(TObject* Sender)
+{
+  if (FCustomYZoomClick) FCustomYZoomClick(Sender);
+  else
+  {
+    if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMYZOOMIN_TAG) YZoomRate*=1.5;
+    else if (dynamic_cast<TComponent*>(Sender)->Tag==ITEMYZOOMRESTORE_TAG)
+    {
+      YZoomRate=1;
+      FStartDigiFreq=0;
+      FEndDigiFreq=0.5;
+    }
+  }
+}
+
+void __fastcall TWaveView::KeyDown(Word &Key, TShiftState Shift)
+{
+  GetOpMode(0, TMouseButton(0), Shift);
+  if (FLength>0)
+  {
+    if (FOpMode<=wopReselect && FCurrentPane>=0)
+    {
+      switch(Key)
+      {
+        case VK_BACK:
+        {
+          int k=Selections->Count-1;
+          RemoveSelection(k);
+          break;
+        }
+        case VK_DELETE:
+          RemoveSelection(-1);
+          break;
+        case VK_ESCAPE:
+          ClearSelections(this);
+          break;
+        case VK_NEXT:
+          if (Selections->Count>0)
+          {
+            int k=(Selections->Focus+1)%Selections->Count;
+            FocusSelection(k);
+          }
+          break;
+        case VK_PRIOR:
+          if (Selections->Count>0)
+          {
+            int k=(Selections->Focus+Selections->Count-1)%Selections->Count;
+            FocusSelection(k);
+          }
+          break;
+      }
+    }
+    else if (ObjectAtPointer && ObjectAtPointer->OnKeyDown) ObjectAtPointer->OnKeyDown(this, Key, Shift);
+  }
+
+  TWinControl::KeyDown(Key, Shift);
+}
+
+void __fastcall TWaveView::KeyUp(Word &Key, TShiftState Shift)
+{
+  GetOpMode(0, TMouseButton(0), Shift);
+  TWinControl::KeyUp(Key, Shift);
+}
+
+void __fastcall TWaveView::MouseCursor(TShiftState Shift, int X, int Y)
+{
+  FX=X, FY=Y, FLastShiftState=Shift;
+}
+
+void __fastcall TWaveView::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y)
+{
+  WaveViewHitTest(X, Y);
+  GetOpMode(0, Button, Shift);
+
+  MouseCursor(Shift, X, Y);
+  if (Button==mbLeft && FOnMousePointer) MousePointer(Shift, X, Y);
+
+  if (Shift.Contains(ssShift) && FTools.Contains(wvtPlayNote)){double f=FSamplesPerSec*CurrentDigiFreq; if (f>0){if (FTools.Contains(wvtPitchScale)) PlayNote(f/FPitchScalePart, FPlayNoteInSemitone); else PlayNote(f, FPlayNoteInSemitone);}}
+
+  if (FLength>=1)
+  {
+    FStartSel=CurrentTime;
+    FVStartSel=CurrentDigiFreq;
+    FStartPane=FCurrentPane;
+    if (FStartPane>=0)
+    {
+      FStartSelR=FPTS(FCurrentPane, X);
+      FVStartSelR=FPTDF(FCurrentPane, Y);
+    }
+    FStartSelX=X;
+    FStartSelY=Y;
+
+    if (FOpMode==wopSelect)
+    {
+      if (Button==mbLeft && FCurrentPane>=0)
+      {
+        if (FMultiSelect)
+        {
+          int slp=SelectionAtPos(CurrentTime, CurrentDigiFreq);
+          FLastFocus=(slp>=0)?slp:FSelections->Focus;
+        }
+
+        if (FSelections->Count && !MultiSelect) Selections->Clear();
+
+        FStartSelX=X;
+        FStartSelY=Y;
+
+        TWaveViewSelection sel;
+        if (FSelectMode==WV2_HSELECT)
+        {
+          sel.StartPos=sel.EndPos=FStartSel;
+          sel.StartDigiFreq=FStartDigiFreq, sel.EndDigiFreq=FEndDigiFreq;
+          FSelections->Add(sel);
+        }
+        else if (FSelectMode==WV2_VSELECT)
+        {
+          sel.StartPos=FStartPos, sel.EndPos=FEndPos;
+          sel.StartDigiFreq=sel.EndDigiFreq=FVStartSel;
+          FSelections->Add(sel);
+        }
+        else if (FSelectMode==(WV2_HSELECT|WV2_VSELECT))
+        {
+          sel.StartPos=sel.EndPos=FStartSel;
+          sel.StartDigiFreq=sel.EndDigiFreq=FVStartSel;
+          FSelections->Add(sel);
+        }
+        else {}
+        if (FOnMouseLocalData && !FLocalDataOn) MouseLocalData(X, Y, 1);
+      }
+    }
+    else if (FOpMode==wopDrag) //drag mode
+    {
+      StartDrag(X, Y);
+    }
+    else if (FOpMode==wopReselect && Button==mbLeft && FCurrentPane>=0)
+    {
+      if (Button==mbLeft)
+      {
+        FStartSelHitTest=SelHitTest(X, Y);
+        FStartSelSel=(*FSelections)[FSelections->Focus];
+      }
+    }
+    else //external mode
+    {
+      if (ObjectAtPointer && ObjectAtPointer->OnMouseDown)
+      {
+        StartObject=ObjectAtPointer;
+        ObjectAtPointer->OnMouseDown(this, Button, Shift, X, Y);
+      }
+      else
+      {
+        StartObject=0;
+      }
+    }
+  }
+  TControl::MouseDown(Button, Shift, X, Y);
+  FLastX=X, FLastY=Y;
+  Invalidate();
+}
+
+//Down=1: mouse down; -1, -2: mouse move pair; -3: mouse up
+void __fastcall TWaveView::MouseLocalData(int X, int Y, int Down)
+{
+  int t=CurrentTime, Wid=FSpecRes, HWid=Wid/2;
+  int FLength_Wid=FLength-Wid;
+
+  int t0=t-HWid, tp=t, tn=t-Wid;
+
+  if (FLocalDataTimeGrid)
+  {
+    int hoffst=FSpecOffst/2;
+    t0=(t0+hoffst)/FSpecOffst*FSpecOffst;
+    tp=(tp+hoffst)/FSpecOffst*FSpecOffst;
+    tn=(tn+hoffst)/FSpecOffst*FSpecOffst;
+    t=(t+hoffst)/FSpecOffst*FSpecOffst;
+  }
+
+  if (t0<0) t0=0;
+  else if (t0>FLength_Wid) t0=FLength_Wid;
+  if (tp<0) tp=0;
+  else if (tp>FLength_Wid) tp=FLength_Wid;
+  if (tn<0) tn=0;
+  else if (tn>FLength_Wid) tn=FLength_Wid;
+
+  FLocalDataOn=true;
+  FOnMouseLocalData(this, &Data8[0][t0*FBytesPerSample], &Data8[0][tp*FBytesPerSample], &Data8[0][tn*FBytesPerSample], Wid, FBytesPerSample, CurrentTime, CurrentDigiFreq, Down);
+  FLocalDataOn=false;
+}
+
+void __fastcall TWaveView::MousePointer(TShiftState Shift, int X, int Y)
+{
+  FOnMousePointer(this, FCurrentPane, CurrentTime, CurrentDigiFreq);
+}
+
+void __fastcall TWaveView::MouseMove(TShiftState Shift, int X, int Y)
+{
+  WaveViewHitTest(X, Y);
+  MouseCursor(Shift, X, Y);
+  if (Shift.Contains(ssLeft) && FOnMousePointer) if (X!=FLastX || Y!=FLastY) MousePointer(Shift, X, Y);
+
+  if (!Shift.Contains(ssLeft)) GetOpMode(0, (TMouseButton)0, Shift);
+
+  if (FLength>=1)
+  {
+    if (FOpMode==wopSelect && FStartPane>=0) //select mode
+    {
+      if ((X!=FLastX || Y!=FLastY) && Shift.Contains(ssLeft))
+      {
+        TWaveViewSelection sel;
+        int ACurrentTime=FPTS(FStartPane, X+0.5)+0.5; if (ACurrentTime<0) ACurrentTime=0; else if (ACurrentTime>FLength) ACurrentTime=FLength;
+        double ACurrentDigiFreq=FPTDF(FStartPane, Y+0.5); if (ACurrentDigiFreq<0) ACurrentDigiFreq=0; else if (ACurrentDigiFreq>0.5) ACurrentDigiFreq=0.5;
+        if (FSelectMode==WV2_HSELECT)
+        {
+          if (ACurrentTime>FStartSel) sel.StartPos=FStartSel, sel.EndPos=ACurrentTime;
+          else sel.StartPos=ACurrentTime, sel.EndPos=FStartSel;
+          sel.StartDigiFreq=FStartDigiFreq, sel.EndDigiFreq=FEndDigiFreq;
+          FSelections->Items[FSelections->Focus]=sel;
+        }
+        else if (FSelectMode==WV2_VSELECT)
+        {
+          sel.StartPos=FStartPos, sel.EndPos=FEndPos;
+          if (ACurrentDigiFreq>FVStartSel) sel.StartDigiFreq=FVStartSel, sel.EndDigiFreq=ACurrentDigiFreq;
+          else sel.StartDigiFreq=ACurrentDigiFreq, sel.EndDigiFreq=FVStartSel;
+          FSelections->Items[FSelections->Focus]=sel;
+        }
+        else if (FSelectMode==(WV2_HSELECT|WV2_VSELECT))
+        {
+          if (ACurrentTime>FStartSel) sel.StartPos=FStartSel, sel.EndPos=ACurrentTime;
+          else sel.StartPos=ACurrentTime, sel.EndPos=FStartSel;
+          if (ACurrentDigiFreq>FVStartSel) sel.StartDigiFreq=FVStartSel, sel.EndDigiFreq=ACurrentDigiFreq;
+          else sel.StartDigiFreq=ACurrentDigiFreq, sel.EndDigiFreq=FVStartSel;
+          FSelections->Items[FSelections->Focus]=sel;
+        }
+        if (FOnMouseLocalData && !FLocalDataOn) MouseLocalData(X, Y, -2);
+      }
+    }
+    else if (FOpMode==wopDrag && FStartPane>=0) //drag mode
+    {
+      if ((Shift.Contains(ssLeft)||true)  && (X!=FLastX || Y!=FLastY))
+      {
+        double lLength=FStartSelSel.EndPos-FStartSelSel.StartPos;
+        if (lLength>0)
+        {
+          double lWidth=FPanes.Rect[FStartPane].Width();
+          FStartPos=FStartSelSel.StartPos-(X-FStartSelX)*lLength/lWidth;
+          if (FStartPos<0) FStartPos=0;
+          FEndPos=FStartPos+lLength;
+          if (FEndPos>FLength) {FEndPos=FLength; FStartPos=FEndPos-lLength;}
+          if (!FPanes.HasFreqAxis[FStartPane]) {}//waveform
+          else
+          {
+            if (FPanes.YScale[FStartPane]==0) //linear scale
+            {
+              lLength=FStartSelSel.EndDigiFreq-FStartSelSel.StartDigiFreq;
+              lWidth=FPanes.Rect[FStartPane].Height();
+              FStartDigiFreq=FStartSelSel.StartDigiFreq-(FStartSelY-Y)*lLength/lWidth;
+              if (FStartDigiFreq<0) FStartDigiFreq=0;
+              FEndDigiFreq=FStartDigiFreq+lLength;
+              if (FEndDigiFreq>0.5) {FEndDigiFreq=0.5; FStartDigiFreq=FEndDigiFreq-lLength;}
+            }
+            else //log scale
+            {
+              lLength=WV2_LOG_FREQ(FStartSelSel.EndDigiFreq)/WV2_LOG_FREQ(FStartSelSel.StartDigiFreq);
+              lWidth=FPanes.Rect[FStartPane].Height();
+              FStartDigiFreq=WV2_LOG_FREQ(FStartSelSel.StartDigiFreq)*pow(lLength, (Y-FStartSelY)/lWidth);
+              FEndDigiFreq=FStartDigiFreq*lLength;
+              if (FEndDigiFreq>0.5) {FEndDigiFreq=0.5; FStartDigiFreq=FEndDigiFreq/lLength;}
+            }
+          }
+          PageChange();
+        }
+      }
+    }
+    else if (FOpMode==wopReselect && FStartPane>=0) //re-selecting mode
+    {
+      if (Shift.Contains(ssLeft) && FStartSelHitTest!=selOuter)
+      {
+        int NewStartPos, NewEndPos;
+        double NewStartDigiFreq, NewEndDigiFreq;
+
+        if ((FStartSelHitTest & WV2_LEFT) && FStartSelX!=X) NewStartPos=FPTS(FStartPane, FSTP(FStartPane, FStartSelSel.StartPos)+X-FStartSelX)+0.5;
+        else NewStartPos=FStartSelSel.StartPos;
+        if ((FStartSelHitTest & WV2_RIGHT) && FStartSelX!=X) NewEndPos=FPTS(FStartPane, FSTP(FStartPane, FStartSelSel.EndPos)+X-FStartSelX)+0.5;
+        else NewEndPos=FStartSelSel.EndPos;
+        if ((FStartSelHitTest & WV2_TOP) && FPanes.HasFreqAxis[FStartPane] && FStartSelY!=Y) NewEndDigiFreq=FPTDF(FStartPane, FDFTP(FStartPane, FStartSelSel.EndDigiFreq)+Y-FStartSelY);
+        else NewEndDigiFreq=FStartSelSel.EndDigiFreq;
+        if ((FStartSelHitTest & WV2_BOTTOM) && FPanes.HasFreqAxis[FStartPane] && FStartSelY!=Y) NewStartDigiFreq=FPTDF(FStartPane, FDFTP(FStartPane, FStartSelSel.StartDigiFreq)+Y-FStartSelY);
+        else NewStartDigiFreq=FStartSelSel.StartDigiFreq;
+
+        TWaveViewSelection sel={NewStartPos, NewEndPos, NewStartDigiFreq, NewEndDigiFreq};
+        if (NewStartPos>NewEndPos) sel.StartPos=NewEndPos, sel.EndPos=NewStartPos;
+        if (NewStartDigiFreq>NewEndDigiFreq) sel.StartDigiFreq=NewEndDigiFreq, sel.EndDigiFreq=NewStartDigiFreq;
+        if (sel.StartPos<0) sel.StartPos=0; else if (sel.EndPos>FLength) sel.EndPos=FLength;
+        if (sel.StartDigiFreq<0) sel.StartDigiFreq=0; else if (sel.EndDigiFreq>0.5) sel.EndDigiFreq=0.5;
+        FSelections->Items[FSelections->Focus]=sel;
+      }
+      else 
+      {
+        TCursor ACursor=ControlCursorAtPos(X, Y);;
+        if (Cursor!=ACursor)
+        {
+          Cursor=ACursor;
+          ::SetCursor(Screen->Cursors[Cursor]);
+        }
+      }
+    }
+    else //external mode
+    {
+      if (Shift.Contains(ssLeft) && StartObject)
+      {
+        if (StartObject->OnMouseMove) StartObject->OnMouseMove(this, Shift, X, Y);
+      }
+      else if (ObjectAtPointer && ObjectAtPointer->OnMouseMove)
+        ObjectAtPointer->OnMouseMove(this, Shift, X, Y);
+    }
+
+    if (Shift.Contains(ssLeft) || Shift.Contains(ssRight)) FLastX=X, FLastY=Y;
+  }
+  if (FClickFocus && !Focused()) SetFocus();
+  TControl::MouseMove(Shift, X, Y);
+  Invalidate();
+}
+
+void __fastcall TWaveView::MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y)
+{
+  WaveViewHitTest(X, Y);
+  MouseCursor(Shift, X, Y);
+  if (FLength>=1)
+  {
+    if (FOpMode==wopSelect && FStartPane>=0)
+    {
+      if (Button==mbLeft)
+      {
+        if (FSelections->Focus>=0)
+        {
+          TWaveViewSelection sel=FSelections->Items[FSelections->Focus];
+          if (sel.StartPos==sel.EndPos || sel.StartDigiFreq==sel.EndDigiFreq)
+          {
+            FSelections->Delete(FSelections->Focus);
+            if (FMultiSelect) FSelections->Focus=FLastFocus;
+          }
+        }
+      }
+    }
+    else if (FOpMode==wopReselect && FStartPane>=0)
+    {
+      if (FSelections->Focus>=0  && FStartSelHitTest!=selOuter)
+      {
+        TWaveViewSelection sel=FSelections->Items[FSelections->Focus];
+        if (FSTP(FStartPane, sel.EndPos)-FSTP(FStartPane, sel.StartPos)<0.01
+          || FPanes.HasFreqAxis[FStartPane] && FDFTP(FStartPane, sel.StartDigiFreq)-FDFTP(FStartPane, sel.EndDigiFreq)<0.01)
+        {
+          FSelections->Delete(FSelections->Focus);
+        }
+      }
+    }
+    else //external mode
+    {
+      if (StartObject)
+      {
+        if (StartObject->OnMouseUp) StartObject->OnMouseUp(this, Button, Shift, X, Y);
+        StartObject=0;
+      }
+      else if (ObjectAtPointer && ObjectAtPointer->OnMouseUp)
+        ObjectAtPointer->OnMouseUp(this, Button, Shift, X, Y);
+    }
+  }
+
+  if (Button==mbLeft || Button==mbRight) FLastX=X, FLastY=Y;
+  TControl::MouseUp(Button, Shift, X, Y);
+  Invalidate();
+}
+
+void __fastcall TWaveView::MouseWheelHandler(TMessage& Msg)
+{
+  TWMMouseWheel* WMsg=(TWMMouseWheel*)&Msg;
+
+  bool Handled=false; TShiftState Shift; memcpy(&Shift, &WMsg->Keys, 1);
+  if (ObjectAtPointer && ObjectAtPointer->OnMouseWheel) ObjectAtPointer->OnMouseWheel(this, Shift, WMsg->WheelDelta, TPoint(WMsg->Pos.x, WMsg->Pos.y), Handled);
+  else if (FCurrentPane>=0 && !DisableMouseWheelZoom)
+  {
+    if (Shift.Empty())
+    {
+      int X=CurrentTime;
+
+      if (X>=FStartPos && X<=FEndPos)
+      {
+        if (WMsg->WheelDelta<0) Zoom(X, 0.9);
+        else Zoom(X, 10.0/9);
+      }
+    }
+    else
+    {
+      if (!FPanes.HasFreqAxis[FCurrentPane])
+      {
+        if (WMsg->WheelDelta>0) ZoomY(0.9);
+        else ZoomY(10.0/9);
+      }
+      else
+      {
+        double Y=CurrentDigiFreq;
+        if (Y>=FStartDigiFreq && Y<=FEndDigiFreq)
+        {
+          if (WMsg->WheelDelta<0) ZoomF(Y, 0.9, FPanes.YScale[FCurrentPane]);
+          else ZoomF(Y, 10.0/9, FPanes.YScale[FCurrentPane]);
+        }
+      }
+    }
+  }
+  if (OnMouseWheel) OnMouseWheel(this, Shift, WMsg->WheelDelta, TPoint(WMsg->Pos.x, WMsg->Pos.y), Handled);
+  if (!Handled) TCustomControl::MouseWheelHandler(Msg);
+}
+
+void __fastcall TWaveView::PageChange(bool updatescrollbar)
+{
+  if (FScrollBar && updatescrollbar) UpdateScrollBar(this);
+  if (FOnPageChange) FOnPageChange(this);
+}
+
+//The Paint() methos draws form StartPos to EndPos in the
+//WaveAudio stream, stretching it to fit the whole width
+//Selected area is highlighted.
+void __fastcall TWaveView::Paint()
+{
+  if (FOnCustomPaint)
+  {
+    bool Done;
+    FOnCustomPaint(this, Done);
+    if (Done)
+    {
+      if (FOnPaint) FOnPaint(this);
+      return;
+    }
+  }
+
+  if (FLength>0)
+  {
+    Canvas->Brush->Color=FBackColor; Canvas->FillRect(ClientRect);
+    DrawPanes();
+    if (FOnPaint) FOnPaint(this);
+    if (FShowInfo) DrawInfo();
+  }
+  if (FObjects.Count>0) for (int i=0; i<FObjects.Count; i++) if (FObjects.Items[i].DrawObject) FObjects.Items[i].DrawObject(this, FObjects.Items[i]);
+
+  if (FShowCursor && FCurrentPane>=0) DrawCursor(FCurrentPane, FX, FY);
+}
+
+void __fastcall TWaveView::PausePlayback(TObject* Sender)
+{
+  if (FSection && FSection->Playing) FSection->PausePlayback(this);
+}
+
+void __fastcall TWaveView::Post(int Mode)
+{
+  if (!FWaveAudio) return;
+  FWaveAudio->OnAudioChange=NULL;
+
+  //for a waveaudio using file stream, set file mode to RW
+  if (!FWaveAudio->UseMemoryStream)
+  {
+    int pos=FWaveAudio->FFileStream->Position;
+    delete FWaveAudio->FFileStream->File;
+    FWaveAudio->FFileStream->File=new TFileStream(FWaveAudio->FileName, fmOpenReadWrite);
+    FWaveAudio->FFileStream->Position=pos;
+  }
+
+  int Channels=FWaveAudio->Channels;
+
+  int writefrom, writelength;
+  if (Mode==0)
+  {
+    writefrom=0;
+    writelength=FLength;
+  }
+  else if (Mode==1)
+  {
+    writefrom=FStartPos;
+    writelength=FEndPos-FStartPos;
+  }
+  int writefrombytes=writefrom*FBytesPerSample*Channels;
+
+  if (Channels==1)
+  {
+    FWaveAudio->Seek(writefrombytes, soFromBeginning);
+    FWaveAudio->Write(&Data8[0][writefrombytes], writelength*FBytesPerSample);
+  }
+  else
+  {
+    //-------------------------
+    {
+      if (FWaveAudio->UseMemoryStream)
+      {
+        char* databuf=&((unsigned char*)((TMemoryStream*)FWaveAudio->WaveStream)->Memory)[writefrombytes];
+        char* data=&((char*)FData)[writefrom*FBytesPerSample];
+        for (int k=0; k<writelength; k++)
+        {
+          memcpy(data, databuf, FBytesPerSample);
+          data+=FBytesPerSample;
+          databuf+=FBytesPerSample*Channels;
+        }
+      }
+      else
+      {
+        FWaveAudio->Seek(writefrombytes, soFromCurrent);
+        char* data=&((char*)FData)[writefrom*FBytesPerSample];
+        for (int k=0; k<writelength; k++)
+        {
+          FWaveAudio->WaveStream->Read(data, FBytesPerSample);
+          data+=FBytesPerSample;
+          FWaveAudio->Seek(FBytesPerSample*(Channels-1), soFromCurrent);
+        }
+      }
+    }
+    //---------------------------
+  }
+
+  //for a waveaudio using file stream, set file mode to back to R after posting
+  if (!FWaveAudio->UseMemoryStream)
+  {
+    int pos=FWaveAudio->FFileStream->Position;
+    delete FWaveAudio->FFileStream->File;
+    FWaveAudio->FFileStream->File=new TFileStream(FWaveAudio->FileName, fmOpenRead);
+    FWaveAudio->FFileStream->Position=pos;
+  }
+  FWaveAudio->OnAudioChange=WaveViewAudioChange;
+}
+
+void __fastcall TWaveView::RemoveSelection(int Index)
+{
+  if (Index==-1) Index=FSelections->Focus;
+  if (Index<0 || Index>=FSelections->Count) return;
+  if (Index==FSelections->Focus)
+  {
+    FSelections->Delete(Index);
+    if (FOnSelectedChange) FOnSelectedChange(this);
+  }
+  else
+  {
+    FSelections->Delete(Index);
+  }
+  Invalidate();
+}
+
+void __fastcall TWaveView::Resize()
+{
+  FPanes.ResizePanes(ClientRect);
+  TControl::Resize();
+}
+
+void __fastcall TWaveView::Retrieve(int Mode, int from, int length)
+{
+  if (!FWaveAudio || FWaveAudio->Length==0) return;
+
+  int readfrom, readlength;
+  if (Mode==0)
+  {
+    readfrom=0;
+    readlength=FLength;
+  }
+  else if (Mode==1)
+  {
+    readfrom=FStartPos;
+    readlength=FEndPos-FStartPos;
+  }
+  else if (Mode==2)
+  {
+    readfrom=from;
+    readlength=length;
+  }
+  int readfrombytes=readfrom*FBytesPerSample*FChannels;
+  FWaveAudio->Seek(readfrombytes, soFromBeginning);
+
+  if (FChannels==1)
+  {
+    FWaveAudio->Read(&Data8[0][readfrombytes], readlength*FBytesPerSample);
+    ExtDataChange(this, 0, readfrom, readfrom+readlength);
+  }
+  else if (FChannels==2)
+  {
+    void *FFData0=&Data8[0][readfrom*FBytesPerSample],
+         *FFData1=&Data8[1][readfrom*FBytesPerSample];
+    FWaveAudio->ReadSamplesInterleave(FFData0, FFData1, readlength);
+    ExtDataChange(this, 0, readfrom, readfrom+readlength);
+    ExtDataChange(this, 1, readfrom, readfrom+readlength);
+  }
+  else
+  {
+    void* FFData[WV2_MAX_CHANNEL];
+    for (int i=0; i<FChannels; i++) FFData[i]=&Data8[i][readfrom*FBytesPerSample];
+    FWaveAudio->ReadSamplesMultiChannel(FChannels, FFData, readlength);
+    for (int i=0; i<FChannels; i++) ExtDataChange(this, i, readfrom, readfrom+readlength);
+  }
+}
+
+#define MyRGB(R, G, B) RGB(B, G, R)
+//#define MyRGB(R, G, B) RGB(R, G, B)
+
+  void SampleImageLine(double* vyy, int dY, double* yy, TQuickSpectrogram* Spectrogram, int fr)
+  {
+    QSPEC_FORMAT* Spec=Spectrogram->A(fr);
+    if (!Spec) {memset(vyy, 0, sizeof(double)*dY); return;}
+    else
+    {
+      int yyd, oldyyd=-2, hWid=Spectrogram->Wid/2;
+      double yyr, v0, v1, v2, v3, a, b, c;
+      for (int y=0; y<dY; y++)
+      {
+        if (yy[y]<0 || yy[y]>hWid) vyy[y]=0;
+        else
+        {
+          yyd=floor(yy[y]); yyr=yy[y]-yyd;
+          if (yyr==0) vyy[y]=Spec[yyd];
+          else
+          {
+            if (yyd!=oldyyd)
+            {
+              oldyyd=yyd; v1=Spec[yyd], v2=Spec[yyd+1];
+              if (yyd==0) v0=Spec[1]; else v0=Spec[yyd-1];
+              if (yyd==hWid-1) v3=Spec[hWid-1]; else v3=Spec[yyd+2];
+
+              if (v1>v0 && v1>v3 && v2>v0 && v2>v3) //a local peak -> use quadratic interpolation
+              {
+                if (v0<v3) //use v1, v2, v3
+                {
+                  c=v1; a=(v3+c)/2-v2; b=v2-a-c;
+                }
+                else //use v0, v1, v2
+                {
+                  b=(v2-v0)/2; c=v1; a=v2-b-c;
+                }
+              }
+              else //use linear interpolation
+              {
+                a=0; b=v2-v1; c=v1;
+              }
+            }
+            vyy[y]=(a*yyr+b)*yyr+c;
+          }
+        }
+      }
+    }
+  }
+
+QSPEC_FORMAT __fastcall SampleImageX(TQuickSpectrogram* Spectrogram, Graphics::TBitmap* ABmp, int dX, int dY, double* xx, double* yy, double amp, bool interpolate)
+{
+  BITMAPFILEHEADER bh;
+  bh.bfType=0x4d42;
+  bh.bfSize=0x36+4*dX*dY;
+  bh.bfReserved1=bh.bfReserved2=0;
+  bh.bfOffBits=0x36;
+
+  BITMAPINFOHEADER bi;
+  memset(&bi, 0, sizeof(bi));
+  bi.biSize=0x28;
+  bi.biWidth=dX;
+  bi.biHeight=dY;
+  bi.biPlanes=1;
+  bi.biBitCount=0x20;
+  bi.biSizeImage=4*dX*dY;
+
+  TMemoryStream* AS=new TMemoryStream;
+  AS->Size=bh.bfSize;
+  char* ASM=(char*)AS->Memory;
+  memcpy(ASM, &bh, sizeof(bh));
+  memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi));
+  int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)];
+
+  double xxr, maxv=0;
+  int xxd, sampr, sampg, sampb;
+
+  double *vyys0=(double*)malloc8(sizeof(double)*(dY+dY)), *vyys1=&vyys0[dY];
+
+  int oldxxd=-3;
+
+  if (interpolate)
+  {
+    for (int x=0; x<dX; x++)
+    {
+      xxd=floor(xx[x]);
+      xxr=xx[x]-xxd;
+      if (xxd<-1 || xxd>=Spectrogram->Capacity)
+      {
+        for (int y=0; y<dY; y++) pixs[x+y*dX]=0;
+        continue;
+      }
+
+      if (xxd==oldxxd) {}
+      else if (xxd==oldxxd+1)
+      {
+        memcpy(vyys0, vyys1, sizeof(double)*dY);
+        for (int i=0; i<dY; i++) if (maxv<vyys0[i]) maxv=vyys0[i];
+        if (xxd+1<Spectrogram->Capacity) SampleImageLine(vyys1, dY, yy, Spectrogram, xxd+1);
+        else memset(vyys1, 0, sizeof(double)*dY);
+      }
+      else
+      {
+        if (xxd>=0 && xxd<Spectrogram->Capacity)
+        {
+          SampleImageLine(vyys0, dY, yy, Spectrogram, xxd);
+          for (int i=0; i<dY; i++) if (maxv<vyys0[i]) maxv=vyys0[i];
+        }
+        else memset(vyys0, 0, sizeof(double)*dY);
+        if (xxd+1<Spectrogram->Capacity) SampleImageLine(vyys1, dY, yy, Spectrogram, xxd+1);
+        else memset(vyys1, 0, sizeof(double)*dY);
+      }
+
+      for (int y=0; y<dY; y++)
+      {
+        double vyy=vyys0[y]+(vyys1[y]-vyys0[y])*xxr;
+        double samp=amp*vyy;
+        if (samp>=1)
+          sampr=255, sampg=samp*32, sampb=0;
+        else
+          sampg=0, sampr=255*samp, sampb=0;
+        pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb));
+      }
+      oldxxd=xxd;
+    }
+  }
+  else
+  {
+    for (int x=0; x<dX; x++)
+    {
+      xxd=floor(xx[x]+0.5);
+      if (xxd<-1 || xxd>=Spectrogram->Capacity)
+      {
+        for (int y=0; y<dY; y++) pixs[x+y*dX]=0;
+        continue;
+      }
+
+      if (xxd==oldxxd)
+      {
+        for (int y=0; y<dY; y++) pixs[x+y*dX]=pixs[x-1+y*dX]; //this shall rarely be executed
+        continue;
+      }
+      else
+      {
+        if (xxd>=0 && xxd<Spectrogram->Capacity)
+        {
+          SampleImageLine(vyys0, dY, yy, Spectrogram, xxd);
+          for (int i=0; i<dY; i++) if (maxv<vyys0[i]) maxv=vyys0[i];
+        }
+        else memset(vyys0, 0, sizeof(double)*dY); //this shall be never executed
+        for (int y=0; y<dY; y++)
+        {
+          double samp=amp*vyys0[y];
+          if (samp>=1)
+            sampr=255, sampg=samp*32, sampb=0;
+          else
+            sampg=0, sampr=255*samp, sampb=0;
+          pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb));
+        }
+      }
+      oldxxd=xxd;
+    }
+  }
+
+  AS->Position=0;
+  ABmp->LoadFromStream(AS);
+  delete AS;
+
+  free8(vyys0);
+  return maxv;
+}
+
+QSPEC_FORMAT __fastcall TWaveView::SampleSpectrogramX(int channel, Graphics::TBitmap* ABmp, double* xx, double* yy, int dX, int dY, double amp, bool interpolate)
+{
+  return SampleImageX(FSpectrogram[channel], ABmp, dX, dY, xx, yy, amp, interpolate);
+}
+
+QSPEC_FORMAT __fastcall TWaveView::SamplePeakSpectrogramX(int yscale, int channel, double AStartDigiFreq, double AnEndDigiFreq, Graphics::TBitmap* ABmp, double* xx, int dX, int dY, double amp)
+{
+  TQuickSpectrogram* Spectrogram=FSpectrogram[channel];
+
+  BITMAPFILEHEADER bh;
+  bh.bfType=0x4d42;
+  bh.bfSize=0x36+4*dX*dY;
+  bh.bfReserved1=bh.bfReserved2=0;
+  bh.bfOffBits=0x36;
+
+  BITMAPINFOHEADER bi;
+  memset(&bi, 0, sizeof(bi));
+  bi.biSize=0x28;
+  bi.biWidth=dX;
+  bi.biHeight=dY;
+  bi.biPlanes=1;
+  bi.biBitCount=0x20;
+  bi.biSizeImage=4*dX*dY;
+
+  TMemoryStream* AS=new TMemoryStream;
+  AS->Size=bh.bfSize;
+  char* ASM=(char*)AS->Memory;
+  memcpy(ASM, &bh, sizeof(bh));
+  memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi));
+  int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)];
+
+  int xxd, sampr, sampg, sampb;
+
+  double *vyys0=(double*)malloc8(sizeof(double)*dY), maxv=0;
+
+  int oldxxd=-3;
+
+  for (int x=0; x<dX; x++)
+  {
+    xxd=floor(xx[x]+0.5);
+    if (xxd<0 || xxd>=Spectrogram->Capacity)
+    {
+      for (int y=0; y<dY; y++) pixs[x+y*dX]=0;
+      continue;
+    }
+
+    if (xxd==oldxxd) {}
+    else
+    {
+      memset(vyys0, 0, sizeof(double)*dY);
+      QSPEC_FORMAT* spec=Spectrogram->A(xxd);
+      int istart=AStartDigiFreq*FSpecRes-1;
+      int iend=AnEndDigiFreq*FSpecRes+1;
+      if (istart<1) istart=1;
+      if (iend>FSpecRes/2) iend=FSpecRes/2;
+      for (int i=istart; i<iend; i++)
+      {
+        if (spec[i]>spec[i-1] && spec[i]>spec[i+1])
+        {
+          if (maxv<spec[i]) maxv=spec[i];
+          double digif=(i+0.5*(spec[i-1]-spec[i+1])/(spec[i-1]+spec[i+1]-2*spec[i]))/FSpecRes;
+          int p=FDFTP(digif, AStartDigiFreq, AnEndDigiFreq, dY, 0, yscale);
+          if (p>=0 && p<dY) vyys0[p]=spec[i];
+        }
+      }
+    }
+
+    for (int y=0; y<dY; y++)
+    {
+      double samp=amp*vyys0[y];
+      if (samp>=1) sampr=255, sampg=samp*32, sampb=0;
+      else sampg=0, sampr=255*samp, sampb=0;
+      pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb));
+    }
+    oldxxd=xxd;
+  }
+
+  AS->Position=0;
+  ABmp->LoadFromStream(AS);
+  delete AS;
+
+  free8(vyys0);
+  return maxv;
+}
+
+QSPEC_FORMAT __fastcall TWaveView::SampleSinuSpectrogramX(int yscale, int channel, double AStartDigiFreq, double AnEndDigiFreq, Graphics::TBitmap* ABmp, double* xx, int dX, int dY, double amp)
+{
+  TQuickSpectrogram* Spectrogram=FSpectrogram[channel];
+
+  BITMAPFILEHEADER bh;
+  bh.bfType=0x4d42;
+  bh.bfSize=0x36+4*dX*dY;
+  bh.bfReserved1=bh.bfReserved2=0;
+  bh.bfOffBits=0x36;
+
+  BITMAPINFOHEADER bi;
+  memset(&bi, 0, sizeof(bi));
+  bi.biSize=0x28;
+  bi.biWidth=dX;
+  bi.biHeight=dY;
+  bi.biPlanes=1;
+  bi.biBitCount=0x20;
+  bi.biSizeImage=4*dX*dY;
+
+  TMemoryStream* AS=new TMemoryStream;
+  AS->Size=bh.bfSize;
+  char* ASM=(char*)AS->Memory;
+  memcpy(ASM, &bh, sizeof(bh));
+  memcpy(&ASM[sizeof(bh)], &bi, sizeof(bi));
+  int* pixs=(int*)&ASM[sizeof(bh)+sizeof(bi)];
+
+  int xxd, sampr, sampg, sampb;
+
+  double *vyys0=(double*)malloc8(sizeof(double)*dY), maxv=0;
+
+  int oldxxd=-3;
+
+  for (int x=0; x<dX; x++)
+  {
+    xxd=floor(xx[x]+0.5);
+    if (xxd<0 || xxd>=Spectrogram->Capacity)
+    {
+      for (int y=0; y<dY; y++) pixs[x+y*dX]=0;
+      continue;
+    }
+
+    if (xxd==oldxxd) {}
+    else
+    {
+      memset(vyys0, 0, sizeof(double)*dY);
+      QSPEC_FORMAT* spec=Spectrogram->A(xxd);
+      int istart=AStartDigiFreq*FSpecRes-1;
+      int iend=AnEndDigiFreq*FSpecRes+1;
+      if (istart<1) istart=1;
+      if (iend>FSpecRes/2) iend=FSpecRes/2;
+      for (int i=istart; i<iend; i++)
+      {
+        if (spec[i]>spec[i-1] && spec[i]>spec[i+1])
+        {
+          if (maxv<spec[i]) maxv=spec[i];
+          double digif=(i+0.5*(spec[i-1]-spec[i+1])/(spec[i-1]+spec[i+1]-2*spec[i]))/FSpecRes;
+          int p=FDFTP(digif, AStartDigiFreq, AnEndDigiFreq, dY, 0, yscale);
+          if (p>=0 && p<dY) vyys0[p]=spec[i];
+        }
+      }
+    }
+
+    for (int y=0; y<dY; y++)
+    {
+      double samp=amp*vyys0[y];
+      if (samp>=1) sampr=255, sampg=samp*32, sampb=0;
+      else sampg=0, sampr=255*samp, sampb=0;
+      pixs[x+y*dX]=TColor(MyRGB(sampr, sampg, sampb));
+    }
+    oldxxd=xxd;
+  }
+
+  AS->Position=0;
+  ABmp->LoadFromStream(AS);
+  delete AS;
+
+  free8(vyys0);
+  return maxv;
+}
+
+void __fastcall TWaveView::ScrollBarChange(TObject* Sender)
+{
+  int ALength=FEndPos-FStartPos;
+  if (ALength==0) return;
+  if (FScrollBar->Position>FScrollBar->Max-FScrollBar->PageSize)
+    FScrollBar->Position=FScrollBar->Max-FScrollBar->PageSize;
+  int startpos=FScrollBar->Position;
+  bool willdozoom=true;
+  if (willdozoom)
+  {
+    FStartPos=startpos;
+    FEndPos=FStartPos+ALength;
+    Invalidate();
+    PageChange(false);
+  }
+  else UpdateScrollBar(this);
+}
+
+int __fastcall TWaveView::SelectionAtPos(int Pos, double DigiFreq)
+{
+  int result=-1;
+  double marea;
+  for (int i=0; i<FSelections->Count; i++)
+  {
+    TWaveViewSelection sel=FSelections->Items[i];
+    if (Pos>=sel.StartPos && Pos<sel.EndPos && DigiFreq>=sel.StartDigiFreq && DigiFreq<sel.EndDigiFreq)
+    {
+      if (result==-1) result=i, marea=(sel.EndDigiFreq-sel.StartDigiFreq)*(sel.EndPos-sel.StartPos);
+      else
+      {
+        double area=(sel.EndDigiFreq-sel.StartDigiFreq)*(sel.EndPos-sel.StartPos);
+        if (area<marea) result=i, marea=area;
+      }
+    }
+  }
+  return result;
+}
+
+TWaveViewSelHitTest __fastcall TWaveView::SelHitTest(int X, int Y)
+{
+  TWaveViewSelHitTest result=selNone;
+  int BW=FSelectionBorderWidth;
+
+  if (FSelections->Count==0) result=selOuter;
+  else
+  {
+    int lleft=FSTP(FCurrentPane, FSelections->StartPos);
+    int lright=FSTP(FCurrentPane, FSelections->EndPos), ltop, lbottom;
+    if (FPanes.HasFreqAxis[FCurrentPane])
+    {
+      ltop=FDFTP(FCurrentPane, FSelections->EndDigiFreq);
+      lbottom=FDFTP(FCurrentPane, FSelections->StartDigiFreq);
+    }
+    else
+    {
+      ltop=FPanes.Rect[FCurrentPane].top-2*BW-1, lbottom=FPanes.Rect[FCurrentPane].bottom+2*BW+1;
+    }
+
+    enum {sOuter, sIBorder, sInner, sSBorder} sx, sy;
+    if (X<lleft-BW || X>lright+BW) sx=sOuter;
+    else if (X<=lleft+BW) sx=sIBorder;
+    else if (X<lright-BW) sx=sInner;
+    else sx=sSBorder;
+    if (Y<ltop-BW || Y>lbottom+BW) sy=sOuter;
+    else if (Y<=ltop+BW) sy=sIBorder;
+    else if (Y<lbottom-BW) sy=sInner;
+    else sy=sSBorder;
+
+    if (sx==sOuter || sy==sOuter) result=selOuter;
+    else if (sx==sInner)
+    {
+      if (sy==sInner) result=selInner;
+      else if (sy==sIBorder) result=selTop;
+      else result=selBottom;
+    }
+    else if (sx==sIBorder)
+    {
+      if (sy==sInner) result=selLeft;
+      else if (sy==sIBorder) result=selTopLeft;
+      else result=selBottomLeft;
+    }
+    else
+    {
+      if (sy==sInner) result=selRight;
+      else if (sy==sIBorder) result=selTopRight;
+      else result=selBottomRight;
+    }
+  }
+  return result;
+}
+
+void __fastcall TWaveView::SetArea(int AStartPos, int AnEndPos, double AStartDigiFreq, double AnEndDigiFreq)
+{
+  if (FStartPos==AStartPos && FEndPos==AnEndPos && FStartDigiFreq==AStartDigiFreq && FEndDigiFreq==AnEndDigiFreq) return;
+  if (AStartPos>AnEndPos) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos."));
+  bool willdozoom=true;
+  if (willdozoom)
+  {
+    FStartPos=AStartPos;
+    FEndPos=AnEndPos;
+    if (AStartDigiFreq>AnEndDigiFreq) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos."));
+    FStartDigiFreq=AStartDigiFreq;
+    FEndDigiFreq=AnEndDigiFreq;
+
+    Invalidate();
+    PageChange();
+  }
+}
+
+void __fastcall TWaveView::SetAutoExtractMode(bool AnAutoExtractMode)
+{
+  if (FAutoExtractMode!=AnAutoExtractMode)
+  {
+    FAutoExtractMode=AnAutoExtractMode;
+    if (AnAutoExtractMode) FExtractMode=FSelectMode;
+  }
+}
+
+void __fastcall TWaveView::SetAutomaticSpecAmp(int channel, double* xx, double AStartDigiFreq, double AnEndDigiFreq, int dX, int dY)
+{
+  if (maxv_specamp<=0) return;
+  TQuickSpectrogram* Spectrogram=FSpectrogram[channel];
+
+  int xxd, sampr, sampg, sampb;
+  int oldxxd=-3;
+  double maxv=0;
+  for (int x=0; x<dX; x++)
+  {
+    xxd=floor(xx[x]+0.5);
+    if (xxd<0 || xxd>=Spectrogram->Capacity) continue;
+
+    if (xxd==oldxxd) {}
+    else
+    {
+      QSPEC_FORMAT* spec=Spectrogram->A(xxd);
+      int istart=AStartDigiFreq*FSpecRes-1;
+      int iend=AnEndDigiFreq*FSpecRes+1;
+      if (istart<1) istart=1;
+      if (iend>FSpecRes/2) iend=FSpecRes/2;
+      for (int i=istart; i<iend; i++)
+      {
+        if (maxv<spec[i]) maxv=spec[i];
+      }
+    }
+    oldxxd=xxd;
+  }
+  if (maxv>0) FSpecAmp=maxv_specamp/maxv;
+}
+
+
+void __fastcall TWaveView::SetAutoSpecAmp(bool AnAutoSpecAmp)
+{
+  if (FAutoSpecAmp!=AnAutoSpecAmp)
+    FAutoSpecAmp=AnAutoSpecAmp;
+}
+
+void __fastcall TWaveView::SetAxisColor(TColor AnAxisColor)
+{
+  FAxisColor=AnAxisColor;
+}
+
+void __fastcall TWaveView::SetBackColor(TColor ABackColor)
+{
+  if (FBackColor!=ABackColor)
+  {
+    FBackColor=ABackColor;
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetCaption(AnsiString ACaption)
+{
+  if (ACaption!=FCaption)
+  {
+    FCaption=ACaption;
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetClickFocus(bool AClickFocus)
+{
+  FClickFocus=AClickFocus;
+}
+
+void __fastcall TWaveView::SetContent(int index, int channel, int type)
+{                                             
+  FPanes.Content[index]=type*WV2_MAX_CHANNEL+channel;
+  if (Visible) Invalidate();
+}
+
+void __fastcall TWaveView::SetContent(int X, int Y, int channel, int type)
+{
+  FPanes.Content[Y*FPanes.FX+X]=type*WV2_MAX_CHANNEL+channel;
+  if (Visible) Invalidate();
+}
+
+void __fastcall TWaveView::SetCursorTF(int PaneIndex, int t, double digif)
+{
+  int X=FSTP(PaneIndex, t);
+  int Y=FDFTP(PaneIndex, digif);
+  TPoint P=ClientToScreen(TPoint(X, Y));
+  SetCursorPos(P.x, P.y);
+}
+
+void __fastcall TWaveView::SetData(int index, void* AData)
+{
+  if (FData[index] && FData[index]!=AData) delete[] FData[index];
+  FData[index]=AData;
+  FSpectrogram[index]->Data=AData;
+  FSpectrogram[index]->FreeBuffers();
+}
+
+void __fastcall TWaveView::SetDefaultPopupMenu(bool ADefaultPopupMenu)
+{
+  FDefaultPopupMenu=ADefaultPopupMenu;
+  if (FLength>0 && ADefaultPopupMenu) PopupMenu=FMenu;
+}
+
+void __fastcall TWaveView::SetEndPos(int AnEndPos)
+{
+  if (FEndPos==AnEndPos) return;
+  if (AnEndPos<FStartPos) throw(EWriteError("TWaveView err: EndPos must be no smaller than StartPos"));
+  bool willdozoom=true;
+  if (willdozoom)
+  {
+    FEndPos=AnEndPos;
+    Invalidate();
+    PageChange();
+  }
+}
+
+void __fastcall TWaveView::SetExtractMode(int AnExtractMode)
+{
+  FExtractMode=AnExtractMode;
+}
+
+void __fastcall TWaveView::SetForceHamming(bool AForceHamming)
+{
+  FForceHamming=AForceHamming;
+}
+
+void __fastcall TWaveView::SetMultiSelect(bool AMultiSelect)
+{
+  FMultiSelect=AMultiSelect;
+}
+
+void __fastcall TWaveView::SetPitchScalePart(int APart)
+{
+  if (APart<1) APart=1;
+  FPitchScalePart=APart;
+}
+
+void __fastcall TWaveView::SetPlaybackFilter(TWaveViewPlaybackFilter APlaybackFilter)
+{
+  FPlaybackFilter=APlaybackFilter;
+}
+
+void __fastcall TWaveView::SetRulers(int PaneIndex, int Rulers)
+{
+  if (FPanes.Rulers[PaneIndex]!=Rulers)
+  FPanes.Rulers[PaneIndex]=Rulers;
+  if (FPanes.Type[PaneIndex]==0) {Basic0Settings[FPanes.Channel[PaneIndex]].Y=0;}
+}
+
+void __fastcall TWaveView::SetRulerUnit(int UnitTime, int UnitFreq, int UnitAmp)
+{
+  if (FRulerUnitTime!=UnitTime || FRulerUnitFreq!=UnitFreq || FRulerUnitAmp!=UnitAmp)
+  {
+    FRulerUnitTime=UnitTime;
+    FRulerUnitFreq=UnitFreq;
+    FRulerUnitAmp=UnitAmp;
+  }
+}
+
+void __fastcall TWaveView::SetSamplesPerSec(int ASamplesPerSec)
+{
+  FSamplesPerSec=ASamplesPerSec;
+}
+
+void __fastcall TWaveView::SetScrollBar(TScrollBar* AScrollBar)
+{
+  if (!AScrollBar)
+    FScrollBar=0;
+  else
+  {
+    FScrollBar=AScrollBar;
+    FScrollBar->TabStop=false;
+    if (FLength>0)
+    {
+      FScrollBar->OnChange=ScrollBarChange;
+      UpdateScrollBar(this);
+    }
+  }
+}
+
+void __fastcall TWaveView::SetSelection(int Start, int End, double VStart, double VEnd)
+{
+  TWaveViewSelection sel={Start, End, VStart, VEnd};
+  if (!FMultiSelect) FSelections->Clear();
+  FSelections->Add(sel);
+  Invalidate();
+  if (FOnSelectedChange) FOnSelectedChange(this);
+}
+
+void __fastcall TWaveView::SetSelectedAreaColorX(TColor ASelectedAreaColorX)
+{
+  if (FSelectedAreaColorX!=ASelectedAreaColorX)
+  {
+    FSelectedAreaColorX=ASelectedAreaColorX;
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetSelectedFrameColorX(TColor ASelectedFrameColorX)
+{
+  if (FSelectedFrameColorX!=ASelectedFrameColorX)
+  {
+    FSelectedFrameColorX=ASelectedFrameColorX;
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetSelectingFrameColorX(TColor ASelectingFrameColorX)
+{
+  FSelectingFrameColorX=ASelectingFrameColorX;
+}
+
+void __fastcall TWaveView::SetSelectMode(int ASelectMode)
+{
+  FSelectMode=ASelectMode;
+  if (FAutoExtractMode) FExtractMode=ASelectMode;
+}
+
+void __fastcall TWaveView::SetSpecOffst(int ASpecOffst)
+{
+  if (FSpecOffst!=ASpecOffst)
+  {
+    FSpecOffst=ASpecOffst;
+    ClearSpectrograms();
+    Invalidate();
+    for (int i=0; i<FChannels; i++) FSpectrogram[i]->Offst=ASpecOffst;
+  }
+}
+
+void __fastcall TWaveView::SetSpecRes(int ASpecRes)
+{
+  if (FSpecRes!=ASpecRes)
+  {
+    FSpecOffst=FSpecOffst*ASpecRes/FSpecRes;
+    FSpecRes=ASpecRes;
+    ClearSpectrograms();
+		free8(fw); free(fhbi); free8(fwin);
+
+    fw=(cdouble*)malloc8(sizeof(cdouble)*FSpecRes*2); SetTwiddleFactors(FSpecRes, fw);
+    fx=&fw[FSpecRes/2]; famp=(double*)&fx[FSpecRes];
+
+    fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0);
+    fhbi=CreateBitInvTable(Log2(FSpecRes)-1);
+
+    for (int i=0; i<FChannels; i++) FSpectrogram[i]->Wid=ASpecRes, FSpectrogram[i]->Offst=FSpecOffst;
+
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetSpecWindowParamD(int Index, double AParamD)
+{
+  if (FSpecWindowParamD[Index]!=AParamD)
+  {
+    FSpecWindowParamD[Index]=AParamD;
+    ClearSpectrograms();
+    if (Index==0) for (int i=0; i<Channels; i++) FSpectrogram[i]->WinParam=AParamD;
+    fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, fwin);
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetSpecWindowType(WindowType ASpecWindowType)
+{
+  if (FSpecWindowType!=ASpecWindowType)
+  {
+    FSpecWindowType=ASpecWindowType;
+    ClearSpectrograms();
+    for (int i=0; i<Channels; i++) FSpectrogram[i]->WinType=ASpecWindowType;
+    fwin=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, fwin);
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetSpecAmp(double ASpecAmp)
+{
+  if (FSpecAmp!=ASpecAmp)
+  {
+    FSpecAmp=ASpecAmp;
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetStartPos(int AStartPos)
+{
+  if (FStartPos==AStartPos) return;
+  if (AStartPos>FEndPos) throw(EWriteError("TWaveView err: StartPos must be no bigger than EndPos."));
+  bool willdozoom=true;
+  if (willdozoom)
+  {
+    FStartPos=AStartPos;
+    Invalidate();
+    PageChange();
+  }
+}
+
+void __fastcall TWaveView::SetStartAndEndPos(int AStartPos, int AnEndPos)
+{
+  if (FStartPos==AStartPos && FEndPos==AnEndPos) return;
+  if (AStartPos>AnEndPos) throw (EWriteError("TWaveView err: StartPos must be no bigger than EndPos."));
+  bool willdozoom=true;
+  if (willdozoom)
+  {
+    FStartPos=AStartPos;
+    FEndPos=AnEndPos;
+    Invalidate();
+    PageChange();
+  }
+}
+
+void __fastcall TWaveView::SetTools(TWaveViewTools ATools)
+{
+  FTools=ATools;
+}
+
+void __fastcall TWaveView::SetStartAndEndDigiFreq(double AStartDigiFreq, double AnEndDigiFreq)
+{
+  if (FStartDigiFreq==AStartDigiFreq && FEndDigiFreq==AnEndDigiFreq) return;
+  if (AStartDigiFreq>AnEndDigiFreq) throw (EWriteError("TWaveView err: StartDigiFreq must be no bigger than EndDigiFreq."));
+  FStartDigiFreq=AStartDigiFreq;
+  FEndDigiFreq=AnEndDigiFreq;
+  Invalidate();
+}
+
+void __fastcall TWaveView::SetWaveAudio(TWaveAudio* AWaveAudio)
+{
+//*  tends to cause comfliction, use only when FWaveAudio!=AWaveAudio
+  if (FWaveAudio) FWaveAudio->OnAudioChange=NULL;
+
+  FWaveAudio=AWaveAudio;
+
+  if (FWaveAudio)
+  {
+    if (FStartDigiFreq<0) FStartDigiFreq=0, FEndDigiFreq=0.5;
+    FWaveAudio->OnAudioChange=WaveViewAudioChange;
+
+    FreeData(FChannels);
+    FreeInternalBitmaps(FChannels);
+    ClearSpectrograms();
+
+    FChannels=FWaveAudio->Channels;
+    FBytesPerSample=FWaveAudio->BitsPerSample/8;
+    FLength=FWaveAudio->WaveStream->Size/FChannels/FBytesPerSample;
+    FBlockSize=FWaveAudio->BlockSize;
+    SamplesPerSec=FWaveAudio->SamplesPerSec;
+
+    if (FLength)
+    {
+      for (int i=0; i<FChannels; i++)
+      {
+        FData[i]=new unsigned char[FLength*FBytesPerSample];
+        FSpectrogram[i]->Data=FData[i];
+        FSpectrogram[i]->WinType=FSpecWindowType;
+        FSpectrogram[i]->Wid=FSpecRes;
+        FSpectrogram[i]->Offst=FSpecOffst;
+        FSpectrogram[i]->WinParam=FSpecWindowParamD[0];
+        FSpectrogram[i]->BytesPerSample=FBytesPerSample;
+        FSpectrogram[i]->DataLength=FLength;
+      }
+    }
+
+    Retrieve();
+
+    FStartPos=0;
+    FEndPos=FLength;
+    FSelections->Clear();
+
+    if (FScrollBar)
+    {
+      FScrollBar->PageSize=0;
+      FScrollBar->OnChange=NULL;
+      FScrollBar->SetParams(0, 0, (FLength-1>0)?FLength-1:1);
+      FScrollBar->OnChange=ScrollBarChange;
+      FScrollBar->LargeChange=FLength/10;
+    }
+  }
+  UndoExtractSelection.EndPos=-1;
+  PageChange();
+  Invalidate();
+}
+
+void __fastcall TWaveView::SetWaveBackColor(TColor AWaveBackColor)
+{
+  if (FWaveBackColor!=AWaveBackColor)
+  {
+    FWaveBackColor=AWaveBackColor;
+    FWaveColor2=TColor((AWaveBackColor+FWaveColor)/2);
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::SetWaveColor(TColor AWaveColor)
+{
+  if (FWaveColor!=AWaveColor)
+  {
+    FWaveColor=AWaveColor;
+    FWaveColor2=TColor((AWaveColor+FWaveBackColor)/2);
+  }
+}
+
+void __fastcall TWaveView::SetYScale(int index, int yscale)
+{
+  FPanes.YScale[index]=yscale;
+  if (Visible) Invalidate();
+}
+
+void __fastcall TWaveView::SetYZoomRate(double AYZoomRate)
+{
+  FYZoomRate=AYZoomRate;
+  Invalidate();
+  if (FOnScaleChange) FOnScaleChange(this);
+}
+
+void TWaveView::StartDrag(int aX, int aY)
+{
+  FStartSelX=aX;
+  FStartSelY=aY;
+  FStartSelSel=CurrentRange;
+}
+
+void __fastcall TWaveView::StartPlayback(TObject* Sender)
+{
+  if (FBeforePlayback) FBeforePlayback(this);
+  if (FLength<1) return;
+
+  if (!FSection->Playing)
+  {
+    int PlayBytesPerSample=(FBytesPerSample<3)?FBytesPerSample:2;
+
+    loopframe0=0;
+    loopframe1=0;
+    prevk=-1;
+    
+    FSection->CustomFillBlock=FillBlock;
+    FSectionBlocks=0;
+
+    FSection->Clear(this);
+    FSection->Channels=FChannels;
+    FSection->BlockSize=FBlockSize;
+    FSection->BitsPerSample=PlayBytesPerSample*8;
+    FSection->SamplesPerSec=FSamplesPerSec;
+    if (FSamplesPerSec>0) FSection->SamplesPerSec=FSamplesPerSec;
+    if (FStereoMode==wvpLeft || FStereoMode==wvpRight) FSection->Channels=1;
+    if (FSection->Channels>2) FSection->Channels=2;
+    FSection->OnPlaybackProg=WaveViewSectionPlaybackProg;
+    FSectionProgress=-1;
+
+    //if the playback starts from outside the focused selection according to mouse pointer
+    if (FStartSelR<FSelections->StartPos||FStartSelR>=FSelections->EndPos||
+        FPanes.HasFreqAxis[FStartPane] && (FVStartSelR<FSelections->StartDigiFreq||FVStartSelR>=FSelections->EndDigiFreq))
+    {
+      if (FOnGetPlaybackStartAndEndPos) FOnGetPlaybackStartAndEndPos(this, FSectionStartPos, FSectionEndPos, false);
+      else FSectionStartPos=FStartPos, FSectionEndPos=FLength;
+      if (LoopPlay) LoopMode=1;
+    }
+    else //the playback starts from inside the focused selection
+    {
+      if (FOnGetPlaybackStartAndEndPos) FOnGetPlaybackStartAndEndPos(this, FSectionStartPos, FSectionEndPos, true);
+      else
+      {
+        FSectionStartPos=FSelections->StartPos; if (FSectionStartPos<0) FSectionStartPos=0;
+        FSectionEndPos=FSelections->EndPos; if (FSectionEndPos>FLength) FSectionEndPos=FLength;
+      }
+      if (LoopPlay) LoopMode=2;
+    }
+
+    if (FSectionEndPos>FSectionStartPos)
+    {
+      int PlayBufferSize=FSection->BlockSize/PlayBytesPerSample+FSpecRes;
+      if (FSection->Channels!=2)
+      {
+        PlayBuffer0=(double*)malloc8(sizeof(double)*PlayBufferSize); PlayBuffer1=0;
+        memset(PlayBuffer0, 0, sizeof(double)*FSpecRes);
+      }
+      else
+      {
+        PlayBuffer0=(double*)malloc8(sizeof(double)*PlayBufferSize*2); PlayBuffer1=&PlayBuffer0[PlayBufferSize];
+        memset(PlayBuffer0, 0, sizeof(double)*FSpecRes); memset(PlayBuffer1, 0, sizeof(double)*FSpecRes);
+      }
+      PBPR=FSectionStartPos, PBPA=0, PBPW=0;
+      if (FForceHamming) fw1=NewWindow8(wtHamming, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0);
+      else fw1=NewWindow8(FSpecWindowType, FSpecRes, FSpecWindowParamI, FSpecWindowParamD, 0);
+			fw2=NewWindow8(wtHann, FSpecRes, NULL, NULL, 0); fw2_fw1=(double*)malloc8(sizeof(double)*FSpecRes*2); ifw1=&fw2_fw1[FSpecRes];
+      if (fw1[0]==0) ifw1[0]=fw2_fw1[0]=0; else {ifw1[0]=1.0/fw1[0]; fw2_fw1[0]=fw2[0]*ifw1[0];}
+      for (int i=1; i<FSpecRes; i++) {ifw1[i]=1.0/fw1[i]; fw2_fw1[i]=fw2[i]*ifw1[i];}
+
+      FSection->Play(&WaveViewSectionPlaybackDone);
+      ItemPlay->Caption=WV2_STRINGS_Stop_playback;
+      if (FOnPlaybackStart) FOnPlaybackStart(this);
+    }
+  }
+  else
+  {
+    PausePlayback(this);
+  }
+}
+
+void __fastcall TWaveView::TFFilter(int channel, bool pass, bool wholelength)
+{
+  ::TFFilter(this, channel, FSelections, pass, wholelength);
+}
+
+void __fastcall TWaveView::UndoExtract(TObject* Sender)
+{
+  SetArea(UndoExtractSelection.StartPos, UndoExtractSelection.EndPos, UndoExtractSelection.StartDigiFreq, UndoExtractSelection.EndDigiFreq);
+  UndoExtractSelection.EndPos=-1;
+}
+
+void __fastcall TWaveView::UpdateScrollBar(TObject* Sender)
+{
+  TNotifyEvent SBChange=FScrollBar->OnChange;
+  FScrollBar->OnChange=NULL;
+  if (FEndPos-FStartPos>=FLength)
+  {
+    FScrollBar->PageSize=FLength;
+    FScrollBar->SetParams(FStartPos, 0, FLength);
+    ScrollBar->Visible=false;
+  }
+  else
+  {
+    FScrollBar->SetParams(FStartPos, 0, FLength);
+    FScrollBar->PageSize=FEndPos-FStartPos;
+    int change=FScrollBar->PageSize/10;
+    if (change>FSamplesPerSec/2) change=FSamplesPerSec/2;
+    FScrollBar->SmallChange=change;
+    change=FScrollBar->PageSize*0.9;
+    if (change>FSamplesPerSec) change=FSamplesPerSec;
+    FScrollBar->LargeChange=change;
+    FScrollBar->Visible=true;
+  }
+  FScrollBar->OnChange=SBChange;
+}
+
+void __fastcall TWaveView::WaveViewAudioChange(TObject* Sender)
+{
+  WaveAudio=FWaveAudio;
+  if (WaveAudio==FWaveAudio && FSection->Playing && true)
+  {
+    FSectionStartPos=FStartPos;
+    FSectionEndPos=FEndPos;
+  }
+}
+
+void __fastcall TWaveView::WaveViewHitTest(int X, int Y)
+{
+  FCurrentPane=-1;
+  for (int i=0; i<FPanes.Count; i++)
+  {
+    TRect Rect=FPanes.Rect[i];
+    if (X>=Rect.left && X<Rect.right && Y>=Rect.top && Y<Rect.bottom)
+    {
+      FCurrentPane=i;
+      FCurrentTime1=FPTS(i, X); FCurrentTime2=FPTS(i, X+1);
+      FCurrentDigiFreq2=FPTDF(i, Y); FCurrentDigiFreq1=FPTDF(i, Y+1);
+      break;
+    }
+  }
+
+  InfoRectAtPointer=-1;
+  if (FShowInfo)
+  {
+    for (int i=0; i<InfoRectCount; i++)
+    {
+      TRect Rect=InfoRect[i];
+      if (X>=Rect.left && X<Rect.right && Y>=Rect.top && Y<Rect.bottom)
+      {
+        InfoRectAtPointer=i;
+        break;
+      }
+    }
+  }
+
+  GetObjectAtPointer(X, Y);
+}
+
+void __fastcall TWaveView::WaveViewSectionPlaybackDone(TObject* Sender)
+{
+  ItemPlay->Caption=WV2_STRINGS_Play;
+
+  if (PlayBuffer0)
+  {
+    free8(PlayBuffer0);
+    PlayBuffer0=0;
+		free8(fw1); free8(fw2); free8(fw2_fw1);
+  }
+
+  FSectionProgress=-1;
+  free8(loopframe0);
+	free8(loopframe1);
+  if (FOnPlaybackDone) FOnPlaybackDone(this);
+}
+
+void __fastcall TWaveView::WaveViewSectionPlaybackProg(TObject* Sender, double Progress)
+{
+  if (FProgressCursor)
+  {
+    FSectionProgress=PBPR-FSpecRes/2;
+    if (AutoScroll && PBPR>FEndPos)
+    {
+      int len=FEndPos-FStartPos;
+      int newen=FEndPos+len;
+      if (newen>FLength) newen=FLength;
+      SetStartAndEndPos(newen-len, newen);
+    }
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::Zoom(int X, double Rate)
+{
+  int X1,X2;
+  bool pagechange=false;
+
+  if (Rate<=0){X1=0; X2=FLength;}
+  else
+  {
+    X1=FStartPos-X; X2=FEndPos-X;
+    X1=floor(X1*Rate); X2=ceil(X2*Rate);
+    X1+=X; X2+=X;
+    if (X1<0) X1=0; if (X2>Length) X2=Length;
+    if (X1>=X2) X1=X2-1;
+  }
+
+  if (FStartPos!=X1) FStartPos=X1, pagechange=true;
+  if (FEndPos!=X2) FEndPos=X2, pagechange=true;
+  if (pagechange)
+  {
+    Invalidate();
+    PageChange();
+  }
+}
+
+void __fastcall TWaveView::ZoomF(double Y, double Rate, int yscale)
+{
+  double Y1, Y2;
+
+  if (Rate<=0) {Y1=0; Y2=0.5;}
+  else
+  {
+    if (yscale==0) //linear scale
+    {
+      Y1=FStartDigiFreq-Y; Y2=FEndDigiFreq-Y;
+      Y1=Y1*Rate; Y2=Y2*Rate;
+      Y1+=Y; Y2+=Y;
+      if (Y1<0) Y1=0; if (Y2>0.5) Y2=0.5;
+    }
+    else //log scale
+    {
+      double AStartDigiFreq=(FStartDigiFreq>WV2_MIN_LOG_FREQ)?FStartDigiFreq:WV2_MIN_LOG_FREQ;
+      double AnEndDigiFreq=(FEndDigiFreq>WV2_MIN_LOG_FREQ)?FEndDigiFreq:WV2_MIN_LOG_FREQ;
+      if (Y<WV2_MIN_LOG_FREQ) Y=WV2_MIN_LOG_FREQ;
+      Y1=AStartDigiFreq/Y; Y2=AnEndDigiFreq/Y;
+      Y1=pow(Y1, Rate); Y2=pow(Y2, Rate);
+      Y1*=Y; Y2*=Y;
+      if (Y1<0) Y1=0; if (Y2>0.5) Y2=0.5;
+    }
+  }
+
+  if (FStartDigiFreq!=Y1 || FEndDigiFreq!=Y2)
+  {
+    FStartDigiFreq=Y1, FEndDigiFreq=Y2;
+    Invalidate();
+  }
+}
+
+void __fastcall TWaveView::ZoomY(double Rate)
+{
+  FYZoomRate*=Rate;
+  Invalidate();
+}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+// ValidCtrCheck is used to assure that the components created do not have
+// any pure virtual functions.
+//
+namespace Waveview
+{
+  void __fastcall PACKAGE Register()
+  {
+    TComponentClass classes[1] = {__classid(TWaveView)};
+    RegisterComponents("Samples", classes, 0);
+  }
+}
+//---------------------------------------------------------------------------
+
+#undef USE_ASM
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WaveView.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,1717 @@
+/*
+    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. 
+*/
+//---------------------------------------------------------------------------
+#ifndef WaveViewH
+#define WaveViewH
+//---------------------------------------------------------------------------
+/*
+    WaveView.cpp implements a VCL component for visualizing linear PCM
+    waveform audio contents and user interactions through this GUI.
+*/
+
+
+#include "AudioPac.h"
+#include "QuickSpec.h"
+#include "fft.h"
+
+#define C4 261.6255653005986346778499935233
+
+#define ITEMXZOOMIN_TAG   11
+#define ITEMXZOOMOUT_TAG  12
+#define ITEMXZOOMRESTORE_TAG  13
+#define ITEMYZOOMIN_TAG   14
+#define ITEMYZOOMRESTORE_TAG   15
+
+
+#define WV2_STRINGS_1   "%s\n\n%s: %d (%.3fsec)\n%s: %d (%.3fsec)\n%s: %d (%.3fsec)\n\n%s: %.1fhz\n%s: %.1fhz\n%s: %.1fhz\n\n%s: %d (%.3fsec)\n\n%s: %d\n%s: %dbit\n"
+#define WV2_STRINGS_Amplitude_rms  "Amplitude(rms)"
+#define WV2_STRINGS_Average  "Average"
+#define WV2_STRINGS_Bits_per_sample   "Bits per sample"
+#define WV2_STRINGS_Extract  "Extract"
+#define WV2_STRINGS_Frequency  "Frequency"
+#define WV2_STRINGS_From  "From"
+#define WV2_STRINGS_Maximum  "Maximum"
+#define WV2_STRINGS_Minimum  "Minimum"
+#define WV2_STRINGS_Play  "Play"
+#define WV2_STRINGS_Properties  "Properties..."
+#define WV2_STRINGS_Properties_current_audio   "Properties: current audio"
+#define WV2_STRINGS_Properties_selection   "Properties: selection"
+#define WV2_STRINGS_Samples   "Samples"
+#define WV2_STRINGS_Samples_per_second   "Samples per second"
+#define WV2_STRINGS_Size   "Size"
+#define WV2_STRINGS_Stop_playback  "Stop playback"
+#define WV2_STRINGS_Time  "Time"
+#define WV2_STRINGS_To  "To"
+#define WV2_STRINGS_Total_time   "Total time"
+#define WV2_STRINGS_X_zoom  "X zoom"
+#define WV2_STRINGS_X_zoom_all  "X zoom all"
+#define WV2_STRINGS_X_zoom_in  "X zoom in"
+#define WV2_STRINGS_X_zoom_out  "X zoom out"
+#define WV2_STRINGS_Y_zoom  "Y zoom"
+#define WV2_STRINGS_Y_zoom_all  "Y zoom all"
+#define WV2_STRINGS_Y_zoom_in  "Y zoom in"
+#define WV2_STRINGS_Y_zoom_out  "Y zoom out"
+
+#define WV2_VSELECT 1
+#define WV2_HSELECT 2
+#define WV2_AMP 4
+#define WV2_LEFT 1
+#define WV2_TOP 2
+#define WV2_RIGHT 4
+#define WV2_BOTTOM 8
+
+#define WV2_MAX_CHANNEL 16
+#define WV2_MIN_LOG_FREQ 0.0001
+#define WV2_LOG_FREQ(f) (((f)>=WV2_MIN_LOG_FREQ)?(f):WV2_MIN_LOG_FREQ)
+
+#define wopIdle -1
+#define wopDrag 0
+#define wopSelect 1
+#define wopReselect 2
+//---------------------------------------------------------------------------
+typedef void __fastcall (__closure *TWaveViewCustomPaintEvent)(TObject* Sender, bool &Done);
+typedef void __fastcall (__closure *TWaveViewCustomPropertyEvent)(TObject* Sender, bool ShowPropSel);
+typedef int __fastcall (__closure *TWaveViewCustomInfoEvent)(TObject* Sender);
+struct TWaveViewObject;
+typedef void __fastcall (__closure *TWaveViewDrawObjectEvent)(TObject* Sender, TWaveViewObject& Obj);
+typedef void __fastcall (__closure *TWaveViewMousePointerEvent)(TObject* Sender, int PaneIndex, int t, double f);
+typedef void __fastcall (__closure* TWaveViewMouseLocalDataEvent)(TObject* Sender, void* Data0, void* DataP, void* DataN, int Count, int bytespersample, int t, double f, int Down);
+typedef void __fastcall (__closure* TWaveViewGetIntervalEvent)(TObject* Sender, int& st, int& en, bool option);
+typedef void __fastcall (__closure* TWaveViewGetOpModeEvent)(TObject* Sender, TShiftState Shift, int& OpMode);
+
+struct TWaveViewRulerSetting
+{
+  TColor FrontColor;
+  TColor BackColor;
+  TColor UnitTickColor;
+  TColor TickColor;
+  TColor GridColor;
+  int UnitTickSize;
+  int TickSize;
+  TFont* UnitFont;
+  bool pre_drawing;
+};
+
+struct TWaveViewSelection
+{
+  int StartPos;
+  int EndPos;
+  double StartDigiFreq;
+  double EndDigiFreq;
+  bool __fastcall operator!=(const TWaveViewSelection& WS)
+  {
+    return StartPos!=WS.StartPos || EndPos!=WS.EndPos || StartDigiFreq!=WS.StartDigiFreq || EndDigiFreq!=WS.EndDigiFreq;
+  }
+};
+
+typedef enum
+{
+  selOuter=0,
+  selLeft=1,
+  selTopLeft=3,
+  selTop=2,
+  selTopRight=6,
+  selRight=4,
+  selBottomRight=12,
+  selBottom=8,
+  selBottomLeft=9,
+  selInner=15,
+  selNone=0
+} TWaveViewSelHitTest;
+
+typedef enum
+{
+  wvfNone,
+  wvfPass,
+  wvfStop
+} TWaveViewPlaybackFilter;
+
+typedef enum
+{
+  wvpStereo,
+  wvpSwap,
+  wvpLeft,
+  wvpRight
+} TWaveViewStereoMode;
+
+typedef enum
+{
+  wvtPitchScale,
+  wvtPlayNote
+} enumWaveViewTools;
+
+typedef Set <enumWaveViewTools, wvtPitchScale, wvtPlayNote> TWaveViewTools;
+
+/*
+  TWaveViewObject implement a class to describe visual objects (tags) drawn onto the
+  visual display of a WaveView. They can respond to keyboard and mouse events.
+
+  Rect
+  Position of object inside the WaveView. This is automatically updated each time
+  the contents of the WaveView is drawn. Keyboard and mouse events are enabled when
+  the mouse pointer falls inside the area spectifies by Rect.
+
+  Id
+  Identifier.
+
+  Tag[4], ShortTag[8]
+  Integer descriptors. By default ShortTag[0] describes the type of the tag.
+
+  Buffer
+  Assiciated binary data.
+
+  Options
+  Binary options. So far only one option wvoNoMouseFocus is available. Object
+  with this option set do not capture mouse movements or respond to events.
+
+  DrawObjects
+  Pointer to method responsible to draw the object and set Rect accordingly.
+
+  OnClick, OnDblClick, OnMouseDown, OnMouseMove, OnMouseUp, OnMouseWheel
+  Mouse event entries: pointers to methods responding to various mouse events.
+
+  OnKeyDown
+  Keyboard event entry: pointers to method responding to key-down event.
+*/
+#define wvoNoMouseFocus 1
+struct TWaveViewObject
+{
+  TRect Rect;
+  int Id;
+  union
+  {
+    int Tag[4];
+    __int16 ShortTag[8];
+  };
+  void* Buffer;
+  int Options;
+  TWaveViewDrawObjectEvent DrawObject;
+  TNotifyEvent OnClick;
+  TNotifyEvent OnDblClick;
+  TMouseEvent OnMouseDown;
+  TMouseMoveEvent OnMouseMove;
+  TMouseEvent OnMouseUp;
+  TMouseWheelEvent OnMouseWheel;
+  TKeyEvent OnKeyDown; 
+};
+
+AnsiString SemitoneToPitch(double f);
+
+/*
+  TWaveViewObjects maintains a list of TWaveViewObject pointers assicated with the
+  WaveView.
+*/
+class TWaveViewObjects
+{
+public:
+  int Capacity;
+  int Count;
+  TWaveViewObject* Items;
+  TWaveViewObjects(){Capacity=0; Count=0; Items=0;}
+  ~TWaveViewObjects(){free(Items);}
+  void Add(TWaveViewObject AnItem)
+  {
+    if (Count==Capacity)
+    {
+      Items=(TWaveViewObject*)realloc(Items, sizeof(TWaveViewObject)*(Capacity+50));
+      Capacity+=50;
+    }
+    Items[Count]=AnItem;
+    Count++;
+  }
+  void Delete(int index)
+  {
+    memmove(&Items[index], &Items[index+1], sizeof(TWaveViewObject)*(Count-index-1));
+    Count--;
+  }
+};
+
+/*
+  TWaveViewPanes mains a list of drawing panes the WaveView uses to draw waveforms,
+  spectrograms, or other contents. The drawing panes are orginized into a matrix
+  of Y rows and X columns and occupies most of the WaveView. The pane with indices
+  (x,y) in this matrix is given the pane index y*X+x.
+
+
+  public variables/properties
+
+    readwrite FX
+    Number of columns.
+
+    readonly Channel[i]
+    Channel index of the i-th pane.
+
+    readonly Count
+    Number of panes.
+
+    readonly HasFreqAxis[i]
+    True is the i-th pane has frequency axis (e.g. spectrogram pane), false if not.
+
+    readwrite Margin
+    Margin between adjacent panes, in pixels.
+
+    readwrite MarginOut
+    Margins between panes and boundary of client area, i.e. ClientRect, in pixels.
+
+    readonly Type[i]
+    Pane type (waveform, spectrogram, etc.) of the i-th pane.
+
+    readwrite Rect[i]
+    The rectangualr area of the i-th pane.
+
+    readwrite Content[i]
+    The content of the i-th pane, equals Type[i]*WV2_MAX_CHANNEL+Channel[i].
+
+    readwrite YScale[i]
+    The scale for y-axis of the i-th pane. 0 for linear scale, 1 for log scale.
+
+    readwrite Rulers[i]
+    The set of axes of the i-th pane. Set WV2_HSELECT for time axis, WV2_VSELECT for
+    frequency axis, WV2_AMP for magnitude axis.
+
+
+  public methods
+
+    WaveViewPanes, ~WaveViewPanes
+    Default constructor and destructor.
+
+    int CreatePanes(TRect ARect, int X, int Y, bool erase=true)
+    Set the number of columns to X, number of rows to Y, and client area to ARect.
+    Clear the current pane contents if erase is set. Returns X*Y is successful, 0
+    if not.
+
+    bool FreqAxis(int type)
+    Returns true if the queried pane type has frequency axis, false if not.
+
+    int ResizePanes(TRect ARect)
+    Resize to client area to ARect. Returns 0.
+*/
+class TWaveViewPanes
+{
+  int FY;
+  int FCapacity;
+  int FCount;
+  int FMargin;
+  TRect FMarginOut;
+  TRect ClientRect;
+protected:
+  void __fastcall SetMargin(int AMargin);
+  void __fastcall SetMarginOut(TRect AMarginOut);
+public:
+  int FX;
+  __property int Channel[int index]={read=GetChannel};
+  __property int Count={read=FCount};
+  __property bool HasFreqAxis[int index]={read=GetHasFreqAxis};
+  __property int Margin={read=FMargin, write=SetMargin};
+  __property TRect MarginOut={read=FMarginOut, write=FMarginOut};
+  __property int Type[int index]={read=GetType};
+  TRect* Rect;
+  int* Content;
+  int* YScale; //0:linear, 1:log
+  int* Rulers;
+  TWaveViewPanes()
+  {
+    FCapacity=50;
+    FCount=0;
+    Rect=new TRect[FCapacity];
+    Content=new int[FCapacity];
+    YScale=new int[FCapacity];
+    Rulers=new int[FCapacity];
+    memset(Content, 0xFF, sizeof(int)*FCapacity);
+    FMargin=4;
+    FMarginOut=TRect(5, 5, 5, 5);
+  }
+  ~TWaveViewPanes()
+  {
+    delete[] Rect;
+    delete[] Content;
+    delete[] YScale;
+    delete[] Rulers;
+  }
+  int CreatePanes(TRect ARect, int X, int Y, bool erase=true)
+  {
+    if (X*Y>FCapacity) return 0;
+    FCount=X*Y;
+    if (erase)
+      memset(Content, 0xFF, sizeof(int)*FCapacity),
+      memset(YScale, 0, sizeof(int)*FCapacity),
+      memset(Rulers, 0, sizeof(int)*FCapacity);
+    else
+      memset(&Content[FCount], 0xFF, sizeof(int)*(FCapacity-FCount)),
+      memset(&YScale[FCount], 0, sizeof(int)*(FCapacity-FCount)),
+      memset(&Rulers[FCount], 0, sizeof(int)*(FCapacity-FCount));
+
+    double XX=(ARect.Width()-FMarginOut.left-FMarginOut.right+FMargin)*1.0/X,
+           YY=(ARect.Height()-FMarginOut.top-FMarginOut.bottom+FMargin)*1.0/Y;
+    for (int y=0; y<Y; y++)
+    {
+      for (int x=0; x<X; x++)
+      {
+        int ind=y*X+x;
+        Rect[ind].left=ARect.left+MarginOut.left+XX*x;
+        Rect[ind].right=ARect.left+MarginOut.left+XX*(x+1)-FMargin;
+        Rect[ind].top=ARect.top+MarginOut.top+YY*y;
+        Rect[ind].bottom=ARect.top+MarginOut.top+YY*(y+1)-FMargin;
+      }
+    }
+    ClientRect=ARect;
+    FX=X, FY=Y;
+    return FCount;
+  }
+  static bool __fastcall FreqAxis(int type)
+  {
+    if (type==0) return false;
+    else return true;
+  }
+private:
+  int __fastcall GetChannel(int index)
+  {
+    return Content[index]%WV2_MAX_CHANNEL;
+  }
+  bool __fastcall GetHasFreqAxis(int index)
+  {
+    int AType=Content[index]/WV2_MAX_CHANNEL;
+    return FreqAxis(AType);
+  }
+  int __fastcall GetType(int index)
+  {
+    return Content[index]/WV2_MAX_CHANNEL;
+  }
+public:
+  int ResizePanes(TRect ARect)
+  {
+    if (FX==0 || FY==0) return 0;
+    double XX=(ARect.Width()-FMarginOut.left-FMarginOut.right+FMargin)*1.0/FX,
+           YY=(ARect.Height()-FMarginOut.top-FMarginOut.bottom+FMargin)*1.0/FY;
+    for (int y=0; y<FY; y++)
+    {
+      for (int x=0; x<FX; x++)
+      {
+        int ind=y*FX+x;
+        Rect[ind].left=ARect.left+MarginOut.left+XX*x;
+        Rect[ind].right=ARect.left+MarginOut.left+XX*(x+1)-FMargin;
+        Rect[ind].top=ARect.top+MarginOut.top+YY*y;
+        Rect[ind].bottom=ARect.top+MarginOut.top+YY*(y+1)-FMargin;
+      }
+    }
+    ClientRect=ARect;
+    return 0;
+  }
+};
+
+/*
+  TWaveViewSelections maintains a list of time-frequency selections (or a binary
+  T-F mask).
+
+
+  public variables and properties
+
+    readwrite Capacity
+    Number of selections the currently allocated buffer can hold.
+
+    readwrite FCount
+    readonly Count
+    Number of selections.
+
+    readwrite Focus
+    Index to the currently active ("focused") selection.
+
+    readonly StartPos
+    Start of the duration of the focused selection, in samples.
+
+    readonly EndPos
+    End of the duration of the focused selection, in samples.
+
+    readonly Length
+    Duration of the focused selection, in samples.
+
+    readonly StartDigiFreq
+    Lower frequency bound of the focused selection, 1=sampling frequency.
+
+    readonly EndDigiFreq
+    Upper frequency bound of the focused selection, 1=sampling frequency.
+
+    readwrite Items
+    The list of selections.
+
+
+  methods
+
+    TWaveViewSelections, ~TWaveViewSelections
+    Default constructor and destructor.
+
+    void Add(TWaveViewSelection& ASelection)
+    Adds new selection to list.
+
+    void Clear()
+    Clears list.
+
+    Delete(int Index)
+    Delete the index-th selection. Returns 1 if successful, 0 if not.
+
+    operator[i]
+    Return the i-th selection.
+
+*/
+class TWaveViewSelections
+{
+public:
+  int Capacity;
+  int FCount;
+  int Focus;
+  __property int Count={read=FCount};
+  __property int StartPos={read=GetStartPos};
+  __property int EndPos={read=GetEndPos};
+  __property int Length={read=GetLength};
+  __property double StartDigiFreq={read=GetStartDigiFreq};
+  __property double EndDigiFreq={read=GetEndDigiFreq};
+  TWaveViewSelection* Items;
+  TWaveViewSelections()
+  {
+    Capacity=100;
+    FCount=0;
+    Focus=0;
+    Items=new TWaveViewSelection[Capacity];
+  }
+  ~TWaveViewSelections()
+  {
+    delete[] Items;
+  }
+  void Add(TWaveViewSelection& ASelection)
+  {
+    if (FCount==Capacity)
+    {
+      int OldCapacity=Capacity;
+      Capacity+=50;
+      TWaveViewSelection* NewItems=new TWaveViewSelection[Capacity];
+      memcpy(NewItems, Items, sizeof(TWaveViewSelection)*OldCapacity);
+      delete[] Items;
+      Items=NewItems;
+    }
+    Items[FCount]=ASelection;
+    Focus=FCount;
+    FCount++;
+  }
+  void Clear()
+  {
+    FCount=0;
+    Focus=0;
+  }
+  Delete(int Index)
+  {
+    if (Index<0 || Index>=FCount)
+      return 0;
+    memmove(&Items[Index], &Items[Index+1], sizeof(TWaveViewSelection)*(FCount-1-Index));
+    FCount--;
+    if (Focus==Index) Focus=FCount-1;
+    else if (Focus>Index)
+      Focus--;
+    return 1;
+  }
+  int __fastcall GetStartPos()
+  {
+    if (FCount>0)
+      return Items[Focus].StartPos;
+    else return -1;
+  }
+  int __fastcall GetEndPos()
+  {
+    if (FCount>0)
+      return Items[Focus].EndPos;
+    else return -1;
+  }
+  int __fastcall GetLength()
+  {
+    if (FCount>0)
+      return Items[Focus].EndPos-Items[Focus].StartPos;
+    else return -1;
+  }
+  double __fastcall GetStartDigiFreq()
+  {
+    if (FCount>0)
+      return Items[Focus].StartDigiFreq;
+    else return -1;
+  }
+  double __fastcall GetEndDigiFreq()
+  {
+    if (FCount>0)
+      return Items[Focus].EndDigiFreq;
+    else return -1;
+  }
+  TWaveViewSelection operator[](int index)
+  {
+    if (index>=0 && index<FCount) return Items[index];
+    else
+    {
+      TWaveViewSelection wvs={0, 0, 0, 0};
+      return wvs;
+    }
+  }
+};
+
+/*
+    Component TWaveView
+
+      WaveView is a CustomControl used to display waveform audio and handling user
+      interactions with the display. Use a TWaveView object at design time or create
+      the object with new keyword.
+
+
+    Published Properties:
+
+        readwrite   Align (inherited)
+        readwrite   Anchors (inherited)
+        readwrite   AutoExtractMode
+        readwrite   AutoSpecAmp
+        readwrite   AxisColor
+        readwrite   BackColor
+        readwrite   ClickFocus
+        readwrite   DefaultPopupMenu
+        readwrite   DoubleBuffered (inherited)
+        readwrite   LocalDataTimeGrid
+        readwrite   MultiSelect
+        readwrite   PitchScalePart
+        readwrite   PlaybackFilter
+        readwrite   PopupMenu (inherited)
+        readwrite   ProgressCursor
+        readwrite   SamplesPerSec
+	      readwrite   ScrollBar
+        readwrite   SelectedAreaColorX
+        readwrite   SelectedFrameColorX
+        readwrite   SelectingFrameColorX
+        readwrite   SelectionBorderWidth
+        readwrite   Tools
+        readwrite   Visible (inherited)
+        readwrite   WaveAudio
+        readwrite   WaveBackColor
+        readwrite   WaveColor
+
+
+        AutoExtractMode
+        ExtractMode controls what type of zoom (time, frequency, time and frequency)
+        when a zoom-to-selection operation is invoked. If AutoExtractMode is set,
+        ExtractMode is automatically linked to SelectMode, i.e. if SelectMode is
+        time-select, then automatically set ExtractMode to time-zoom.
+
+        AutoSpecAmp
+        Set to automatically adjust spectrogram brightness so that the brightest
+        points in display stays at constant brightness.
+
+        AxisColor, BackColor, WaveBackColor and WaveColor
+        Use these properties to change the colors of the WaveView.
+
+        ClickFocus
+        Set to pass mouse and keyboard focus to the WaveView whenever it is clicked.
+
+        DefaultPopupMenu and PopupMenu
+        WaveView provides some basic operations with a default PopupMenu. User can
+        inspect or play the wave through these operations. Anyway, user may not want
+        the popupmenu in his design. A DefaultPopupMenu property is used for this
+        instance.  If DefaultPopupMenu is set to true, the menu is used. If it is
+        set to false, the default menu is not used, and user can assign another
+        popupmenu to the WaveView through the PopupMenu property.  The operations
+        associated with the default popupmenu are also available through a group
+        of methods that are declared public in TWaveView class.  See Public Methods
+        for details.
+
+        LocalDataTimeGrid
+        WaveView invokes MouseLocalData event as the mouse pointer is moved inside
+        the display panes, supplying the time at mouse pointer as an argument. If
+        LocalDataTimeGrid is set, the time argument provided is aligned to the
+        nearest spectrogram frame centre.
+
+        MultiSelect
+        Set to entre multiple selection mode in which the user can made multiple
+        time-frequency selections.
+
+        PitchScalePart
+        WaveView draws a set of harmonic frequency markers aligned to the position
+        of the mouse pointer if Tools contains wvtPitchScale. PitchScalePart specifies
+        the partial index associated with the frequency at mouse pointer.
+
+        PlaybackFilter
+        Specifies the type of filter (pass, stop, none) to use for playback.
+
+        ProgressCursor
+        Set to show a playback cursor during playback.
+
+        SamplesPerSec
+        Sampling rate used by the WaveView.
+
+        ScrollBar
+        WaveView doesn't implement a scrollbar. To provide a WaveView object
+        with a scrollbar, simply use a normal ScrollBar and assign it to the
+        WaveView object through the ScrollBar property. The WaveView will use
+        the scrollbar automatically.
+
+        SelectedAreaColorX, SelectedFrameColorX, SelectingFrameColorX
+        Use these properties to change the xor colour masks for drawing the
+        time-frequency selections.
+
+        Tools
+        Additional tools the WaveView comes with, including wvtPitchScale for drawing
+        a set of harmonic frequency marks aligned to the position of teh mouse pointer,
+        and wvtPlayNote for playing a note pitched at the mouse pointer when the
+        mouse is clicked with Shift key held down.
+
+        WaveAudio
+        Use this property to associate a WaveAudio object to WaveView. If 0 is
+        written to WaveAudio property, the WaveView displays nothing.
+
+
+    Public Properties
+
+        readonly    A[][]
+        readwrite   AccessFCaption
+        readonly    BytesPerSample
+        readonly    CalculateFrameCount
+        readonly    Canvas (inherited)
+        readwrite   Caption (inherited)
+        readwrite   Channels
+        readonly    CurrentAmplitude
+        readonly    CurrentChannel
+        readonly    CurrentDigiFreq
+        readonly    CurrentPane
+        readonly    CurrentRange
+        readonly    CurrentSample16
+        readonly    CurrentSampleInPixel
+        readonly    CurrentTime
+        readonly    CurrentX
+        readonly    CurrentY
+        readwrite   CursorColorBright
+        readwrite   CursorColorDim
+        readwrite   Data[]
+        readonly    Data8[]
+        readonly    Data16[]
+        readonly    Data24[]
+        readwrite   DefaultPropertyItems
+        readwrite   EndDigiFreq
+        readwrite   EndPos
+        readwrite   ExtractMode
+        readwrite   ForceHamming
+        readwrite   InfoColor0
+        readwrite   InfoColor1
+        readwrite   InfoColor2
+        readonly    LastX
+        readonly    LastY
+        readwrite   Length
+        readonly    OpMode
+        readonly    Ph[][]
+        readonly    Playing
+        readwrite   PlayNoteInSemitone
+        readwrite   RulerAlignX
+        readwrite   RulerAlignY
+        readwrite   RulerUnitAmp
+        readwrite   RulerUnitFreq
+        readwrite   RulerUnitTime
+        readwrite   SectionEndPos
+        readwrite   SectionStartPos
+        readwrite   Selections
+        readwrite   SelectMode
+        readwrite   ShowCursotText
+        readwrite   ShowInfo
+        readwrite   ShowPaneInfo
+        readonly    Spec[][]
+        readwrite   SpecAmp
+        readwrite   SpecOffst
+        readwrite   SpecRes
+        readonly    Spectrogram[]
+        readwrite   SpecWindowParamD[]
+        readwrite   SpecWindowType
+        readwrite   StartDigiFreq
+        readonly    StartPane
+        readwrite   StartPos
+        readonly    StartSel
+        readonly    StartSelX
+        readonly    StartSelY
+        readwrite   StereoMode
+        readwrite   YZoomRate
+
+
+        A[ch][fr]
+        Amplitude spectrum of channel ch and frame fr.
+
+        AccessFCaption
+        Provides direct access to FCaption without invoking SetCaption(...).
+
+        BytesPerSample
+        Bytes used for each waveform sample (8, 16 or 24).
+
+        Channels
+        Number of channels.
+
+        CurrentAmplitude
+        Reading on amplitude axis at the mouse pointer in waveform display.
+
+        CurrentChannel
+        Channel index of data displayed in CurrentPane.
+
+        CurrentDigiFreq
+        Reading on frequency axis at the mouse pointer in spectrogram display.
+
+        CurrentPane
+        Index of the display pane that currently containins the mouse pointer.
+
+        CurrentRange
+        Time-frequency scope of the current display.
+
+        CurrentSample16
+        Sample value of CurrentChannel at CurrentTime.
+
+        CurrentSampleInPixel
+        The display Y-coordinate corresponding to CurrentSample16.
+
+        CurrentTime
+        Reading on time axis at the mouse pointer.
+
+        CurrentX
+        X-coordinate of mouse pointer.
+
+        CurrentY
+        Y-coordinate of mouse pointer.
+
+        CursorColorBright
+        Colour used to draw ruler cursor in on dim background.
+
+        CursorColorDim
+        Colour used to draw ruler cursor in on bright background.
+
+        Data[ch], Data8[ch], Data16[ch], Data24[ch]
+        Data buffer of channel ch in void*, __int8*, __int16* and __pint24.
+
+        DefaultPropertyItems
+        Set to show default list of properties when Properties menu item from the
+        default popup menu is invoked.
+
+        EndDigiFreq and StartDigiFreq
+        Upper and lower bounds of the currently displayed frequency range (1=sampling
+        frequency). Write these properties to change the display range and trigger
+        an OnPageChange event.
+
+        EndPos and StartPos
+        End and starting positions of currently displayed duration, in samples.
+        Write these properties to change the  display range and trigger an OnPageChange
+        event.
+
+        ExtractMode
+        Specifies the type of zooming (time, frequency, time and frequency) to
+        perform when zoom-to-selection operation is invoked.
+
+        ForceHamming
+        Set to force Hamming windowing for audio playback via playback filter.
+
+        InfoColor0, InfoColor1, InfoColor2
+        Colours used to draw the internal (info) tags if ShowInfo is set.
+
+        LastX, LastY
+        The X and Y coordinates recorded at the last mouse down, move and up event.
+        They are identical to X and Y upon calling MouseMove() and MoveUp(), and
+        after calling MouseDown().
+
+        Length
+        Length of the audio content the WaveView currently holds, in samples.
+
+        OpMode
+        The current operation mode (idle, dragging, selecting, reselecting, or other
+        user-defined modes).
+
+        Ph[ch][fr]
+        Phase spectrum of channel ch and frame fr.
+
+        Playing
+        Set if playback is in progress, cleared if not.
+
+        PlayNoteInSemitone
+        Set to adjust note playback using wvtPlayNote tool to pitch at the nearst
+        well-tempered semitone (A4=440Hz) from CurrentDigiFreq.
+
+        RulerAlignX, RulerAlignY
+        Alignments of X and Y axes.
+
+        RulerUnitAmp
+        Display unit for amplitude axis. 0=relative(-1 to +1), 1=absolute.
+
+        RulerUnitFreq
+        Display unit for frequency axis. 0=hz, 1=bin (when using linear frequency
+        scale) or semitones (when using log frequency scale).
+
+        RulerUnitTime
+        Display unit for time axis. 0=samples, 1=seconds.
+
+        SectionEndPos, SectionStartPos
+        End and starting points of the playback duration.
+
+        Selections
+        Current time-frequency selections.
+
+        SelectMode
+        Specifies mode (time, frequency or time-and-frequency) for normal selections.
+
+        ShowCursotText
+        Set to display cursor text.
+
+        ShowInfo
+        Set to display basic info tags (number of channels, sampling rate, bytes
+        per sample, duration, display range).
+
+        ShowPaneInfo
+        Set to display pane info.
+
+        Spec[ch][fr]
+        Complex spectrum of channel ch at frame fr.
+
+        SpecAmp
+        Spectral display amplification, for adjusting the spectrogram brightness.
+
+        SpecOffst
+        Time offst between ajcent frame centres.
+
+        SpecRes
+        Window size for spectrogram computation.
+
+        Spectrogram[ch]
+        Spectrogram of channal ch.
+
+        SpecWindowParamD[], SpecWindowType
+        Window type and optional parameter list of window function.
+
+        StartPane
+        Index to display pane in which a mouse key was last pressed down in the WaveView.
+
+        StartSel
+        Reading of time axis the last time a mouse key was pressed down in the WaveView.
+
+        StartSelX, StartSelY
+        X and Y coordinates that last time a mouse key was pressed down in the WaveView.
+
+        StereoMode
+        Stereo playback mode (normal, swap-channel, left channel or right channel).
+
+        YZoomRate
+        Amplitude display amplification.
+
+
+    Public variables
+
+        PBPR
+        Playbuffer pointer. Position from which to load the next playback buffer.
+
+        DisableMouseWheelZoom
+        Set to disable time and frequency zooming by mouse wheeling.
+
+        maxv_specamp
+        Product of the maximal spectal amplitude in current display range and SpecAmp.
+        This is kept constant if AutoSpecAmp is set.
+
+        FSpectrogram[WV2_MAX_CHANNEL]
+        Spectrograms of the channels.
+
+        FPanes
+        List of display panes.
+
+        FObjects
+        List of WaveView objects.
+
+        InfoRectCount, InfoRect[]
+        Number of info tags, their display areas
+
+        InfoRectAtPointer
+        Index to the info tag at mouse pointer.
+
+        ObjectAtPointer
+        Pointer to WaveView object at mouse pointer.
+
+        StartObject
+        If a mouse key is pressed down with the mouse pointer at a WaveView object
+        whose OnMouseDown event is set, then StartObject is set to that object
+        and cleared after the next MouseUp event.
+
+        DefaultRulerSetting[4]
+        Default settings for drawing the axes.
+
+        DefaultPaneInfoFont
+        Default font for displaying pane info.
+
+        DefaultInfoFont
+        Default font for displaying info tags.
+
+        InfoLeft, InfoTop
+        Top-left coordinates to draw info tags.
+
+        AutoScroll
+        Set to enable automatic scrolling when playback proceeds beyond current
+        display range, clear to disable it.
+
+        ForceOLA
+        When filling the playback buffers, WaveView chooses whether or not using
+        overlap-add of adjacent frames according to the playback filter. If ForceOLA
+        is set then overlap-add is unconditionally enforced the next time a block
+        buffer is filled.
+
+        LoopPlay
+        Set to enable looped playback, clear to disable it.
+
+        LoopMode
+        Specifies the loop range in looped playback. 0=no looping, 1=looping the
+        current display range, 2=looping the current active selection.
+
+        Basic0[WV2_MAX_CHANNEL], Basic1[WV2_MAX_CHANNEL]
+        Internal bitmaps for storing the raw waveform and spectrogram images.
+
+
+    Public Methods
+
+        TWaveView, ~TWaveView()
+        Default constructor and destructor.
+
+        CheckWaveOutDevCaps
+        Checks if WaveOut device is ready and enable/disable playback menu accordingly.
+
+        ClearSelections
+        Empty current list of time-frequency selections.
+
+        ClearSpectrogram, ClearSpectrograms
+        Free buffered spectrogram data.
+
+        CreatePanes(X, Y)
+        Creates X columns times Y rows of display panes.
+
+        DefaultShowProperty
+        Display a message box to show basic properties of the audio content.
+
+        DoExtract, UndoExtract
+        Zoom-to-selction operation, undo the last zoom-to-selectino operation.
+
+        DrawBitmap(Sender)
+        Draws a bitmap (TBitmap*)Sender in the WaveView.
+
+        DrawCaption
+        Draws a caption on the top-right of the WaveView.
+
+        DrawCursor(PaneIndex, X, Y)
+        Draws the mouse cursors in display pane PaneIndex given pointer coordinates.
+
+        DrawInfo
+        Draws info tags and update their active areas.
+
+        DrawPane
+        Draws a display pane.
+
+        DrawPaneInfo
+        Draws the pane info.
+
+        DrawPanes
+        Draws display panes.
+
+        DrawPitchScale
+        Draws a set of harmonic frequency marks aligned to the current mouse pointer.
+
+        DrawPlaybackCursor
+        Draws the playback cursor which marks the current playback position.
+
+        DrawSelection, DrawSelections
+        Draw the current time-frequency selections.
+
+        DrawSemitones
+        Draws a set of frequency grids marking whole well-tempered semitones.
+
+        DrawSpectrogramX
+        Draws the spectrogram.
+
+        DrawWaveForm
+        Draws the waveform.
+
+        ExtDataChange
+        Invoked to notify a change to the data buffer committed by the caller so
+        that WaveView can update its display.
+
+        FocusSelection
+        Puts the focus to a specific selection in multiple selection mode.
+
+        FreeData
+        Frees internal waveform audio buffer(s).
+
+        FreeInternalBitmaps
+        Frees Basic0[] and Basic1[] which stores raw waveform and spectrogram images.
+
+        FreeSpectrograms
+        Frees internal spectrogram buffers (unlike ClearSpectrogram, which frees
+        buffer data held in the buffers).
+
+        FromAmplitudeToPixel, FromPixelToAmplitude, FromDigiFreqToPixel,
+        FromPixelToDigiFreq, FromPixelToSample, FromSampleToPixel
+        Conversion routines between screen coordinates and time-amplitude locations
+        on the displayed waveform of time-frequency locations of the spectrogram.
+
+        GetFMask
+        Obtain the frequency mask at certain time (snapshot of CurrentSelections).
+
+        GetObjectAtPointer
+        Obtain the object at given coordinates and set ObjectToPointer variable.
+
+        GetOpMode
+        Obtain OpMode given specific keyboard and mouse status and set OpMode property.
+
+        InvalidateBasic, InvalidateBasics
+        Discard stored raw waveform and/or spectrogram images.
+
+        ItemExtractClick, ItemPlayClick, ItemPropertyClick,
+        ItemXZoomClick, ItemYZoomClick
+        Calling these methods do the same as clicking on the dufault popupmenu items
+        excpet for the Sender argument. The Sender argument has its importance in
+        ItemXZoomClick and ItemYZoomClick methods. If user wishes to use his own
+        popupmenu, it is recommended to assign these methods to the menu. Before
+        assigning ItemXZoomClick and ItemYZoomClick, be sure to fill the Tag property
+        of the Sender. Valid Tag values are: ITEMXZOOMIN_TAG(11), ITEMXZOOMOUT_TAG(12),
+        ITEMXZOOMRESTORE_TAG(13), ITEMYZOOMIN_TAG(14), and ITEMYZOOMRESTORE_TAG(15).
+
+        PausePlayback, StartPlayback
+        Stops and starts audio playback.
+
+        Post
+        Sends local waveform data to the associated WaveAudio object.
+
+        RemoveSelection
+        Removes a time-frequency selection.
+
+        Retrieve
+        Read waveform data from the associated WaveAudio object into local buffer.
+
+        SelectionAtPos
+        Returns index to the time-frequency selection at specified time and frequency.
+
+        SetArea
+        Sets the four variables specifying the display range in one command.
+
+        SetContent
+        Specifies what to display in each display pane.
+
+        SetCursorTF
+        Sends mouse pointer to the position corresponding to given time and frequency.
+
+        SetRulers
+        Specifies what axes to display in each display pane.
+
+        SetRulerUnit
+        Specifies the unit used for displaying each axes.
+
+        SetSelection
+        Make a new time-frequency selection.
+
+        SetStartAndEndDigiFreq, SetStartAndEndPos
+        Sets the frequency/time range of display.
+
+        SetYScale
+        Sets the display amplification of waveform amplitude.
+
+        StartDrag
+        Simulates the start of a mouse dragging operation at specified coordinates.
+
+        TFFilter
+        Applies time-frequency filtering using a binary mask specified by CurrentSelections.
+
+        UpdateScrollBar
+        Updates the associated scrollbar.
+
+        Zoom, ZoomF, ZoomY
+        Time/magnitude/frequeny zooming operations.
+
+
+    Events
+
+        CustomCursorText
+        Triggered before drawing cursor texts for the user to fill in customized texts.
+
+        CustomItemExtractClick
+        Customized handler of the Extract menu item of the default popup menu.
+
+        CustomInfo
+        Triggered before drawing into tags for the user to fill in customized texts.
+
+        CustompaneInfo
+        Triggered before drawing pane into for the user to fill in customized texts.
+
+        CustomProperty
+        Customized handler of the Properties menu item of the default popup menu.
+
+        CustomXZoomClick, CustomYZoomClick
+        Customized handlers of the XZoom and YZoom menu items of the default popum menu.
+
+        OnCustomPaint
+        Customized painting routine of the WaveView.
+
+        OnGetPlaybackStartAndEndPos
+        Triggered before starting playback to allow user decide what duration to play.
+
+        OnGetOpMode
+        Triggered when querying operation mode to allow non-default mode settings and
+        user-defined modes.
+
+        OnInfoDblClick
+        Triggered when a info tag is double-clicked.
+
+        OnResize (inherited)
+        OnKeyDown (inherited)
+        OnKeyPress (inherited)
+        OnKeyUp (inherited)
+        OnDblClick (inherited)
+        OnMouseDown (inherited)
+        OnMousemove (inherited)
+        OnMouseUp (inherited)
+        OnMouseWheel (inherited)
+
+        OnMouseLocalData
+        Triggered when moving mouse pointer inside display pane, supplying the caller
+        with the time at mouse pointer and data buffers near the time.
+
+        OnMousePointer
+        Triggered when pressing left mouse key and when moving mouse pointer with
+        left mouse key down.
+
+        BeforePlayback
+        Triggered before playback starts.
+
+        OnPageChange
+        Triggered when the display duration is changed.
+
+        OnPaint
+        Triggered after painting the WaveView.
+
+        OnPlaybackDone
+        Triggered when playback finishes.
+
+        OnPlaybackStart
+        Triggered when playback starts.
+
+        OnSelectedChange
+        Triggered when the selection focus switches.
+
+        OnScaleChange
+        Triggered when YZoomRate changes.
+
+    Current version Wen Xue 2011/7
+    First version Wen Xue 2003/3
+*/
+class PACKAGE TWaveView : public TCustomControl
+{
+friend void FeedFFTBuffers(int Id, cdouble* &w, cdouble* &x, double* &win, int* &hbi, void* Parent);
+friend void TFFilter(TWaveView*, int, TWaveViewSelections*, bool, bool);
+private:
+  TWaveAudio* FWaveAudio;
+  TDataAudio* FSection;
+  TWaveViewSelections* FSelections;
+
+  TPopupMenu* FMenu;
+  TScrollBar* FScrollBar;
+
+  TNotifyEvent FBeforePlayback;
+  TNotifyEvent FCustomItemExtractClick;
+  TNotifyEvent FCustomXZoomClick;
+  TNotifyEvent FCustomYZoomClick;
+  TNotifyEvent FOnInfoDblClick;
+  TNotifyEvent FOnPageChange;
+  TNotifyEvent FOnPaint;
+  TNotifyEvent FOnPlaybackDone;
+  TNotifyEvent FOnPlaybackStart;
+  TNotifyEvent FOnScaleChange;
+  TNotifyEvent FOnSelectedChange;
+
+  TWaveViewGetIntervalEvent FOnGetPlaybackStartAndEndPos;
+  TWaveViewGetOpModeEvent FOnGetOpMode;
+  TWaveViewMouseLocalDataEvent FOnMouseLocalData;
+  TWaveViewMousePointerEvent FOnMousePointer;
+
+  TWaveViewCustomInfoEvent FCustomCursorText;
+  TWaveViewCustomPaintEvent FOnCustomPaint;
+  TWaveViewCustomInfoEvent FCustomPaneInfo;
+  TWaveViewCustomInfoEvent FCustomInfo;
+  TWaveViewCustomPropertyEvent FCustomProperty;
+  TWaveViewSelHitTest FSelHitTest;
+
+  TColor FAxisColor;
+  TColor FBackColor;
+  TColor FCursorColorDim;
+  TColor FCursorColorBright;
+  TColor FInfoColor0;
+  TColor FInfoColor1;
+  TColor FInfoColor2;
+  TColor FWaveBackColor;
+  TColor FWaveColor; TColor FWaveColor2;
+  TColor FSelectedAreaColorX;
+  TColor FSelectedFrameColorX;
+  TColor FSelectingFrameColorX;
+
+  AnsiString FCaption;
+
+  TAlign FRulerAlignX;
+  TAlign FRulerAlignY;
+
+#define WV2_FONT_NUMBER 6
+  TFont* FFonts[WV2_FONT_NUMBER];
+
+  bool FAutoCaption;
+  bool FAutoExtractMode;
+  bool FAutoSpecAmp;
+  bool FClickFocus;
+  bool FDefaultPopupMenu;
+  bool FDefaultPropertyItems;
+  bool FForceHamming;
+  bool FLocalDataOn;
+  bool FMultiSelect;
+  bool FPlayNoteInSemitone;
+  bool FProgressCursor;
+
+  bool FShowCursor;
+  bool FShowCursorText;
+  bool FShowInfo;
+  bool FShowPaneInfo;
+  bool FLocalDataTimeGrid;
+
+  double FCurrentDigiFreq1;
+  double FCurrentDigiFreq2;
+  double FCurrentTime1;
+  double FCurrentTime2;
+  double FSpecAmp;
+  double FEndDigiFreq;
+  double FStartDigiFreq;
+  double FVStartSel;
+  double FVStartSelR;
+  double FYZoomRate;
+  double prevk;
+  TWaveViewSelHitTest FStartSelHitTest;
+
+  double* PlayBuffer0;
+  double* PlayBuffer1;
+  int PBPA;
+  int PBPW;
+
+  int FBlockSize;
+  int FBytesPerSample;
+  int FCalculateFrameCount;
+  int FChannels;
+  int FCurrentPane;
+  int FEndPos;
+  int FExtractMode;
+  int FLength;
+  int FOpMode;
+  int FPitchScalePart;
+  int FRulerUnitAmp;
+  int FRulerUnitFreq;
+  int FRulerUnitTime;
+  int FSamplesPerSec;
+  int FSectionBlocks;
+  int FSectionProgress;
+  int FSectionStartPos;
+  int FSectionEndPos;
+  int FSelectionBorderWidth;
+  int FSelectMode;
+  int FSpecOffst;
+  int FSpecRes;
+  int FStartPane;
+  int FStartPos;
+  int FStartSel;
+  int FStartSelR;
+  int FStartSelX;
+  int FStartSelY;
+  TWaveViewSelection FStartSelSel;
+  TWaveViewStereoMode FStereoMode;
+
+  int FLastFocus;
+  int FX;
+  int FY;
+  TShiftState FLastShiftState;
+  int FLastX;
+  int FLastY;
+
+
+  int FX1;
+  int FX2;
+
+  //FFT Buffers
+  cdouble* fw;
+  cdouble* fx;
+  //playback windows
+  double* fw1;
+  double* fw2;
+  double* ifw1;
+  double* fw2_fw1;
+  //analysis window function
+  double* fwin;
+  double* famp;
+  double* loopframe0;
+  double* loopframe1;
+  int* fhbi;
+
+  void* FData[WV2_MAX_CHANNEL];
+
+  WindowType FSpecWindowType;
+  double FSpecWindowParamD[5];
+  int FSpecWindowParamI[5];
+
+  TWaveViewPlaybackFilter FPlaybackFilter;
+  TWaveViewTools FTools;
+
+public:
+  int PBPR;
+  bool DisableMouseWheelZoom;
+  double maxv_specamp;
+
+  TQuickSpectrogram* FSpectrogram[WV2_MAX_CHANNEL];
+  TWaveViewPanes FPanes;
+  TWaveViewObjects FObjects;
+  #define WV2_INFORECTCOUNT 10
+  int InfoRectCount;
+  int InfoRectAtPointer;
+  TRect InfoRect[WV2_INFORECTCOUNT];
+  TWaveViewObject* ObjectAtPointer;
+  TWaveViewObject* StartObject;
+
+  TMenuItem* ItemExtract;
+  TMenuItem* ItemPlay;
+  TMenuItem* ItemProperty;
+  TMenuItem* ItemSeparator1;
+  TMenuItem* ItemSeparator2;
+  TMenuItem* ItemXZoomRestore;
+  TMenuItem* ItemYZoomRestore;
+
+  TWaveViewSelection UndoExtractSelection;
+
+  TWaveViewRulerSetting DefaultRulerSetting[4];
+  TFont* DefaultPaneInfoFont;
+  TFont* DefaultInfoFont;
+
+  int TimeStamp1;
+  int TimeStamp2;
+  int InfoLeft;
+  int InfoTop;
+  bool AutoScroll;
+  bool ForceOLA;
+  bool LoopPlay;
+  int LoopMode;
+
+  Graphics::TBitmap* Basic0[WV2_MAX_CHANNEL];
+  struct sBasic0Settings {int X; int Y; int Start; int End; double YZR;
+    bool __fastcall operator!=(const sBasic0Settings& BS){return X!=BS.X || Y!=BS.Y || Start!=BS.Start || End!=BS.End || YZR!=BS.YZR;}
+    } Basic0Settings[WV2_MAX_CHANNEL];
+  Graphics::TBitmap* Basic1[WV2_MAX_CHANNEL];
+  struct sBasic1Settings {int X; int Y; TWaveViewSelection Sel; double amp; int yscale; int specstyle;
+    bool __fastcall operator!=(const sBasic1Settings& BS){return X!=BS.X || Y!=BS.Y || Sel!=BS.Sel || amp!=BS.amp || yscale!=BS.yscale || specstyle!=BS.specstyle;}
+    } Basic1Settings[WV2_MAX_CHANNEL];
+
+private:
+  int CalculateSpectrogramX(int channel, double* xx, int dX, bool interpolate);
+  TCursor __fastcall ControlCursorAtPos(int X, int Y);
+  int __fastcall FillBlock(void* Block);
+  void __fastcall FMenuPopup(TObject*);
+  QSPEC_FORMAT __fastcall SampleSpectrogramX(int channel, Graphics::TBitmap* ABmp, double* xx, double* yy, int dX, int dY, double amp, bool interpolate);
+  QSPEC_FORMAT __fastcall SamplePeakSpectrogramX(int yscale, int channel, double AStartDigiFreq, double AnEndDigiFreq, Graphics::TBitmap* ABmp, double* xx, int dX, int dY, double amp);
+  QSPEC_FORMAT __fastcall SampleSinuSpectrogramX(int yscale, int channel, double AStartDigiFreq, double AnEndDigiFreq, Graphics::TBitmap* ABmp, double* xx, int dX, int dY, double amp);
+  TWaveViewSelHitTest __fastcall SelHitTest(int X, int Y);
+  void __fastcall SetAutomaticSpecAmp(int channel, double* xx, double AStartDigiFreq, double AnEndDigiFreq, int dX, int dY);
+
+protected:
+  DYNAMIC void __fastcall Click(void);
+  DYNAMIC void __fastcall DblClick(void);
+  virtual QSPEC_FORMAT* __fastcall GetA(int Channel, int fr);
+  virtual double __fastcall GetCurrentAmplitude();
+  virtual int __fastcall GetCurrentChannel();
+  virtual double __fastcall GetCurrentDigiFreq();
+  virtual __int16 __fastcall GetCurrentSample16();
+  virtual int __fastcall GetCurrentSampleInPixel();
+  virtual int __fastcall GetCurrentTimeEx();
+  virtual TWaveViewSelection __fastcall GetCurrentRange();
+  virtual void* __fastcall GetData(int Channel);
+  virtual __int16* __fastcall GetData16(int Channel);
+  virtual __pint24 __fastcall GetData24(int Channel);
+  virtual char* __fastcall GetData8(int Channel);
+  virtual QSPEC_FORMAT* __fastcall GetPh(int Channel, int fr);
+	virtual cmplx<QSPEC_FORMAT>* __fastcall GetSpec(int Channel, int fr);
+	virtual TQuickSpectrogram* __fastcall GetSpectrogram(int Channel);
+	virtual double __fastcall GetSpecWindowParamD(int Index);
+	DYNAMIC void __fastcall KeyDown(Word &Key, TShiftState Shift);
+  DYNAMIC void __fastcall KeyUp(Word &Key, TShiftState Shift);
+  DYNAMIC void __fastcall MouseCursor(TShiftState Shift, int X, int Y);
+  DYNAMIC void __fastcall MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y);
+  DYNAMIC void __fastcall MouseLocalData(int X, int Y, int Down);
+  DYNAMIC void __fastcall MouseMove(TShiftState Shift, int X, int Y);
+  DYNAMIC void __fastcall MousePointer(TShiftState Shift, int X, int Y);
+  DYNAMIC void __fastcall MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y);
+  DYNAMIC void __fastcall MouseWheelHandler(TMessage& Msg);
+  virtual void __fastcall Paint();
+  DYNAMIC void __fastcall Resize();
+
+  virtual void __fastcall PageChange(bool updatescrollbar=true);
+
+  virtual void __fastcall ScrollBarChange(TObject* Sender);
+
+  virtual void __fastcall SetAutoExtractMode(bool AnAutoExtractMode);
+  virtual void __fastcall SetAutoSpecAmp(bool AnAutoSpecAmp);
+  virtual void __fastcall SetAxisColor(TColor AnAxisColor);
+  virtual void __fastcall SetBackColor(TColor ABackColor);
+  virtual void __fastcall SetCaption(AnsiString ACaption);
+  virtual void __fastcall SetClickFocus(bool AClickFocus);
+  virtual void __fastcall SetData(int index, void* AData);
+  virtual void __fastcall SetDefaultPopupMenu(bool ADefaultPopupMenu);
+  virtual void __fastcall SetEndPos(int AnEndPos);
+  virtual void __fastcall SetExtractMode(int AnExtractMode);
+  virtual void __fastcall SetForceHamming(bool AForceHamming);
+  virtual void __fastcall SetMultiSelect(bool AMultiSelect);
+  virtual void __fastcall SetPitchScalePart(int APart);
+  virtual void __fastcall SetPlaybackFilter(TWaveViewPlaybackFilter APlaybackFilter);
+  virtual void __fastcall SetSamplesPerSec(int ASamplesPerSec);
+  virtual void __fastcall SetScrollBar(TScrollBar* AScrollBar);
+  virtual void __fastcall SetSelectedAreaColorX(TColor ASelectedAreaColorX);
+  virtual void __fastcall SetSelectedFrameColorX(TColor ASelectedFrameColorX);
+  virtual void __fastcall SetSelectingFrameColorX(TColor ASelectingFrameColorX);
+  virtual void __fastcall SetSelectMode(int ASelectMode);
+  virtual void __fastcall SetSpecOffst(int ASpecOffst);
+  virtual void __fastcall SetSpecRes(int ASpecRes);
+  virtual void __fastcall SetSpecWindowParamD(int Index, double AParamD);
+  virtual void __fastcall SetSpecWindowType(WindowType ASpecWindowType);
+  virtual void __fastcall SetSpecAmp(double AnAmp);
+  virtual void __fastcall SetStartPos(int AStartPos);
+  virtual void __fastcall SetTools(TWaveViewTools ATools);
+  virtual void __fastcall SetWaveAudio(TWaveAudio* AWaveAudio);
+  virtual void __fastcall SetWaveBackColor(TColor AWaveBackColor);
+  virtual void __fastcall SetWaveColor(TColor AWaveColor);
+  virtual void __fastcall SetYZoomRate(double AYZoomRate);
+
+  virtual void __fastcall WaveViewAudioChange(TObject* Sender);
+  virtual void __fastcall WaveViewHitTest(int X, int Y);
+  virtual void __fastcall WaveViewSectionPlaybackDone(TObject* Sender);
+  virtual void __fastcall WaveViewSectionPlaybackProg(TObject* Sender, double Progress);
+
+public:
+  __property Canvas;
+
+  __property TWaveViewSelection CurrentRange={read=GetCurrentRange};
+  __property TWaveViewSelections* Selections={read=FSelections, write=FSelections};
+
+  __property AnsiString AccessFCaption={read=FCaption, write=FCaption};
+  __property AnsiString Caption={read=FCaption, write=SetCaption};
+
+  __property int CalculateFrameCount={read=FCalculateFrameCount};
+
+  __property bool DefaultPropertyItems={read=FDefaultPropertyItems, write=FDefaultPropertyItems};
+  __property bool ForceHamming={read=FForceHamming, write=SetForceHamming};
+  __property bool Playing={read=GetPlaying};
+  __property bool PlayNoteInSemitone={read=FPlayNoteInSemitone, write=FPlayNoteInSemitone};
+  __property bool ShowInfo={read=FShowInfo, write=FShowInfo};
+  __property bool ShowPaneInfo={read=FShowPaneInfo, write=FShowPaneInfo};
+
+  __property void* Data[int Channel]={read=GetData, write=SetData};
+  __property __int16* Data16[int Channel]={read=GetData16};
+  __property __pint24 Data24[int Channel]={read=GetData24};
+  __property char* Data8[int Channel]={read=GetData8};
+
+  __property double CurrentAmplitude={read=GetCurrentAmplitude};
+  __property int CurrentChannel={read=GetCurrentChannel};
+  __property double CurrentDigiFreq={read=GetCurrentDigiFreq};
+  __property int CurrentPane={read=FCurrentPane};
+  __property __int16 CurrentSample16={read=GetCurrentSample16};
+  __property int CurrentSampleInPixel={read=GetCurrentSampleInPixel};
+  __property int CurrentTime={read=GetCurrentTimeEx};
+  __property int CurrentX={read=FX};
+  __property int CurrentY={read=FY};
+  __property double EndDigiFreq={read=FEndDigiFreq, write=FEndDigiFreq};
+  __property double SpecAmp={read=FSpecAmp, write=SetSpecAmp};
+  __property double StartDigiFreq={read=FStartDigiFreq, write=FStartDigiFreq};
+  __property double YZoomRate={read=FYZoomRate,write=SetYZoomRate};
+
+  __property QSPEC_FORMAT* A[int Channel][int fr]={read=GetA};
+  __property int BytesPerSample={read=FBytesPerSample};
+  __property int Channels={read=FChannels, write=FChannels};
+  __property int EndPos={read=FEndPos, write=SetEndPos};
+  __property int ExtractMode={read=FExtractMode, write=SetExtractMode};
+  __property int LastX={read=FLastX};
+  __property int LastY={read=FLastY};
+  __property int Length={read=FLength, write=FLength};
+  __property int OpMode={read=FOpMode};
+  __property QSPEC_FORMAT* Ph[int Channel][int fr]={read=GetPh};
+  __property TAlign RulerAlignX={read=FRulerAlignX, write=FRulerAlignX};
+  __property TAlign RulerAlignY={read=FRulerAlignY, write=FRulerAlignY};
+  __property int RulerUnitAmp={read=FRulerUnitAmp, write=FRulerUnitAmp};
+  __property int RulerUnitFreq={read=FRulerUnitFreq, write=FRulerUnitFreq};
+  __property int RulerUnitTime={read=FRulerUnitTime, write=FRulerUnitTime};
+  __property int SectionEndPos={read=FSectionEndPos, write=FSectionEndPos};
+  __property int SectionStartPos={read=FSectionStartPos, write=FSectionStartPos};
+  __property int SelectMode={read=FSelectMode, write=SetSelectMode};
+  __property bool ShowCursorText={read=FShowCursorText, write=FShowCursorText};
+	__property cmplx<QSPEC_FORMAT>* Spec[int Channel][int fr]={read=GetSpec};
+	__property TQuickSpectrogram* Spectrogram[int Channel]={read=GetSpectrogram};
+	__property int SpecOffst={read=FSpecOffst, write=SetSpecOffst};
+	__property int SpecRes={read=FSpecRes, write=SetSpecRes};
+  __property double SpecWindowParamD[int Index]={read=GetSpecWindowParamD, write=SetSpecWindowParamD};
+  __property int StartPane={read=FStartPane};
+  __property int StartPos={read=FStartPos, write=SetStartPos};
+  __property int StartSel={read=FStartSel};
+  __property int StartSelX={read=FStartSelX};
+  __property int StartSelY={read=FStartSelY};
+  __property TWaveViewStereoMode StereoMode={read=FStereoMode, write=FStereoMode};
+
+  __property TColor CursorColorBright={read=FCursorColorBright, write=FCursorColorBright};
+  __property TColor CursorColorDim={read=FCursorColorDim, write=FCursorColorDim};
+  __property TColor InfoColor0={read=FInfoColor0, write=FInfoColor0};
+  __property TColor InfoColor1={read=FInfoColor1, write=FInfoColor1};
+  __property TColor InfoColor2={read=FInfoColor2, write=FInfoColor2};
+
+  __property WindowType SpecWindowType={read=FSpecWindowType, write=SetSpecWindowType};
+
+
+public:
+  __fastcall TWaveView(TComponent* Owner, bool usex=false, bool usep=false);
+  __fastcall ~TWaveView();
+
+  void ClearSpectrogram(int index);
+  void ClearSpectrograms();
+  void __fastcall DefaultShowProperty(bool selection);
+  virtual void __fastcall DoExtract(TObject* Sender);
+  virtual void __fastcall UndoExtract(TObject* Sender);
+
+  virtual void __fastcall ItemExtractClick(TObject* Sender);
+  virtual void __fastcall ItemPlayClick(TObject* Sender);
+  virtual void __fastcall ItemPropertyClick(TObject* Sender);
+  virtual void __fastcall ItemXZoomClick(TObject* Sender);
+  virtual void __fastcall ItemYZoomClick(TObject* Sender);
+
+  void __fastcall CheckWaveOutDevCaps(TObject* Sender);
+  void __fastcall ClearExtra(int AnExtra);
+  void __fastcall ClearSelections(TObject* Sender);
+  int __fastcall CreatePanes(int X, int Y);
+  void __fastcall DrawBitmap(TObject*);
+  void __fastcall DrawCaption(AnsiString ACaption);
+  void __fastcall DrawCursor(int PaneIndex, int X, int Y);
+  void __fastcall DrawInfo();
+  void __fastcall DrawPane(int Channel, int Type, int YScale, int Rulers, TCanvas* Canv, TRect& Rect);
+  void __fastcall DrawPaneInfo(int Channel, int Type, int YScale, TCanvas* Canv, TRect& Rect);
+  void __fastcall DrawPanes(int Type=-1);
+  void __fastcall DrawPitchScale(int Type, TCanvas* Canv, TRect& Rect, int yscale);
+  void __fastcall DrawPlaybackCursor(int Position, TCanvas* Canv, TRect& Rect, int PaneType);
+  void __fastcall DrawSelection(int Type, TCanvas* Canv, TRect& Rect, int yscale, int Index, TColor FrameColorX);
+  void __fastcall DrawSelections(int Type, TCanvas* Canv, TRect& Rect, int yscale);
+  void __fastcall DrawSemitones(int start, int end, TCanvas* Canv, TRect& Rect, int yscale);
+  void __fastcall DrawSpectrogramX(int channel, TWaveViewSelection Sel, int yscale, TCanvas* ACanvas, TRect ARect, double amp=1, bool forceresample=false, bool basic=false, int SpecStyle=1);
+  void __fastcall DrawWaveForm(int channel, TCanvas* ACanvas, TRect, int, int, double amp=1, bool basic=false);
+  void __fastcall ExtDataChange(TObject* Sender);
+  void __fastcall ExtDataChange(TObject* Sender, int Channel, int From, int To);
+  TRect __fastcall ExtraBounds(int AnExtra);
+  TRect __fastcall ExtraInvBounds(int AnExtra);
+  void __fastcall FocusSelection(int Index);
+  void __fastcall FreeData(int Count);
+  void __fastcall FreeInternalBitmaps(int Count);
+  void __fastcall FreeSpectrograms();
+  double __fastcall FromAmplitudeToPixel(int PaneIndex, double Amplitude);
+  double __fastcall FromPixelToAmplitude(int PaneIndex, double Y);
+  double __fastcall FromDigiFreqToPixel(int PaneIndex, double DigiFreq);
+  double __fastcall FromDigiFreqToPixel(double DigiFreq, double AStartDigiFreq, double AnEndDigiFreq, int Y1, int Y2, int YScale);
+  double __fastcall FromPixelToDigiFreq(int PaneIndex, double Y);
+  void __fastcall FromPixelToDigiFreq(int Scale, double* DigiFreq, int Count, double AStartDigiFreq, double AnEndDigiFreq);
+  double __fastcall FromPixelToSample(int PaneIndex, double X);
+  void __fastcall FromPixelToSample(double* Sample, int Count, int AStartPos, int AnEndPos);
+  double __fastcall FromPixelToSample(double X, int AStartPos, int AnEndPos, int X1, int X2);
+  double __fastcall FromSampleToPixel(int PaneIndex, double Pos);
+  double __fastcall FromSampleToPixel(double Pos, int X1, int X2);
+
+  double __fastcall GetFMask(double* mask, int t, TWaveViewPlaybackFilter Filter);
+  virtual void __fastcall GetObjectAtPointer(int X, int Y);
+  virtual void __fastcall GetOpMode(Word Key, TMouseButton Button, TShiftState Shift);
+  bool __fastcall GetPlaying();
+  bool __fastcall GetSpectroCalc(int startpos=-1, int endpos=-1, int Offst=-1, int Res=-1);
+  void __fastcall InvalidateBasic(int channel, int basic);
+  void __fastcall InvalidateBasics(int channel);
+  void __fastcall PausePlayback(TObject* Sender);
+  void __fastcall Post(int Mode=0);
+  void __fastcall RemoveSelection(int Index);
+  void __fastcall RePinExtra(int AnExtra);
+  void __fastcall Retrieve(int Mode=0, int from=0, int length=0);
+  int __fastcall SelectionAtPos(int Pos, double DigiFreq);
+  void __fastcall SetArea(int AStartPos, int AnEndPos, double AStartDigiFreq, double AnEndDigiFreq);
+  void __fastcall SetContent(int index, int channel, int type);
+  void __fastcall SetContent(int X, int Y, int channel, int type);
+  void __fastcall SetCursorTF(int PaneIndex, int t, double digif);
+  void __fastcall SetRulers(int PaneIndex, int Rulers);
+  void __fastcall SetRulerUnit(int ARulerUnitTime, int ARulerUnitFreq, int ARulerUnitAmp);
+  void __fastcall SetSelection(int Start, int End, double VStart, double VEnd);
+  void __fastcall SetStartAndEndDigiFreq(double AStartDigiFreq, double AnEndDigiFreq);
+  void __fastcall SetStartAndEndPos(int AStartPos, int AnEndPos);
+  void __fastcall SetYScale(int index, int yscale);
+  void StartDrag(int X, int Y);
+  void __fastcall StartPlayback(TObject* Sender);
+  void __fastcall TFFilter(int channel, bool pass, bool wholelength=false);
+  virtual void __fastcall UpdateScrollBar(TObject* Sender);
+  void __fastcall Zoom(int X, double Rate);
+  void __fastcall ZoomF(double Y, double Rate, int yscale);
+  void __fastcall ZoomY(double Rate);
+  
+__published:
+  __property Align;
+  __property Anchors;
+  __property bool AutoCaption={read=FAutoCaption, write=FAutoCaption};
+  __property bool AutoExtractMode={read=FAutoExtractMode, write=SetAutoExtractMode};
+  __property bool AutoSpecAmp={read=FAutoSpecAmp, write=SetAutoSpecAmp};
+  __property TColor AxisColor={read=FAxisColor,write=SetAxisColor};
+  __property TColor BackColor={read=FBackColor,write=SetBackColor};
+  __property bool ClickFocus={read=FClickFocus, write=SetClickFocus};
+  __property bool DefaultPopupMenu={read=FDefaultPopupMenu, write=SetDefaultPopupMenu, default=true};
+  __property DoubleBuffered;
+  __property bool MultiSelect={read=FMultiSelect, write=SetMultiSelect};
+  __property OnResize;
+  __property int PitchScalePart={read=FPitchScalePart, write=SetPitchScalePart};
+  __property TWaveViewPlaybackFilter PlaybackFilter={read=FPlaybackFilter, write=SetPlaybackFilter};
+  __property PopupMenu;
+  __property bool ProgressCursor={read=FProgressCursor, write=FProgressCursor, default=true};
+  __property int SamplesPerSec={read=FSamplesPerSec, write=SetSamplesPerSec};
+	__property TScrollBar* ScrollBar={read=FScrollBar,write=SetScrollBar};
+  __property TColor SelectedAreaColorX={read=FSelectedAreaColorX, write=SetSelectedAreaColorX};
+  __property TColor SelectedFrameColorX={read=FSelectedFrameColorX, write=SetSelectedFrameColorX};
+  __property TColor SelectingFrameColorX={read=FSelectingFrameColorX, write=SetSelectingFrameColorX};
+  __property int SelectionBorderWidth={read=FSelectionBorderWidth, write=FSelectionBorderWidth};
+  __property bool LocalDataTimeGrid={read=FLocalDataTimeGrid, write=FLocalDataTimeGrid, default=true};
+  __property TWaveViewTools Tools={read=FTools, write=SetTools};
+  __property Visible;
+  __property TWaveAudio* WaveAudio={read=FWaveAudio, write=SetWaveAudio};
+  __property TColor WaveBackColor={read=FWaveBackColor, write=SetWaveBackColor};
+  __property TColor WaveColor={read=FWaveColor,write=SetWaveColor};
+
+  __property TWaveViewCustomInfoEvent CustomCursorText={read=FCustomCursorText, write=FCustomCursorText};
+  __property TNotifyEvent CustomItemExtractClick={read=FCustomItemExtractClick, write=FCustomItemExtractClick};
+  __property TWaveViewCustomInfoEvent CustomInfo={read=FCustomInfo, write=FCustomInfo};
+  __property TWaveViewCustomInfoEvent CustomPaneInfo={read=FCustomPaneInfo, write=FCustomPaneInfo};
+  __property TWaveViewCustomPropertyEvent CustomProperty={read=FCustomProperty, write=FCustomProperty};
+  __property TNotifyEvent CustomXZoomClick={read=FCustomXZoomClick, write=FCustomXZoomClick};
+  __property TNotifyEvent CustomYZoomClick={read=FCustomYZoomClick, write=FCustomYZoomClick};
+  __property TWaveViewCustomPaintEvent OnCustomPaint={read=FOnCustomPaint, write=FOnCustomPaint};
+  __property TWaveViewGetIntervalEvent OnGetPlaybackStartAndEndPos={read=FOnGetPlaybackStartAndEndPos, write=FOnGetPlaybackStartAndEndPos};
+  __property TWaveViewGetOpModeEvent OnGetOpMode={read=FOnGetOpMode, write=FOnGetOpMode};
+  __property TNotifyEvent OnInfoDblClick={read=FOnInfoDblClick, write=FOnInfoDblClick};
+  __property OnKeyDown;
+  __property OnKeyPress;
+  __property OnKeyUp;
+  __property OnDblClick;
+  __property OnMouseDown;
+  __property OnMouseMove;
+  __property OnMouseWheel
+  ;
+  __property TWaveViewMouseLocalDataEvent OnMouseLocalData={read=FOnMouseLocalData, write=FOnMouseLocalData};
+  __property TWaveViewMousePointerEvent OnMousePointer={read=FOnMousePointer, write=FOnMousePointer};
+  __property OnMouseUp;
+  __property TNotifyEvent BeforePlayback={read=FBeforePlayback, write=FBeforePlayback};
+  __property TNotifyEvent OnPageChange={read=FOnPageChange,write=FOnPageChange};
+  __property TNotifyEvent OnPaint={read=FOnPaint, write=FOnPaint};
+  __property TNotifyEvent OnPlaybackDone={read=FOnPlaybackDone,write=FOnPlaybackDone};
+  __property TNotifyEvent OnPlaybackStart={read=FOnPlaybackStart, write=FOnPlaybackStart};
+  __property TNotifyEvent OnSelectedChange={read=FOnSelectedChange,write=FOnSelectedChange};
+  __property TNotifyEvent OnScaleChange={read=FOnScaleChange,write=FOnScaleChange};
+};
+//---------------------------------------------------------------------------
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bitmaps.rc	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,12 @@
+100 BITMAP "vcrplay.bmp"
+101 BITMAP "vcrstop.bmp"
+102 BITMAP "spectrogram.bmp"
+103 BITMAP "waveform.bmp"
+104 BITMAP "vcrrecrd.bmp"
+105 BITMAP "vcrrecrd2.bmp"
+106 BITMAP "timeselect.bmp"
+107 BITMAP "freqselect.bmp"
+108 BITMAP "multiselect.bmp"
+109 BITMAP "hsselect.bmp"
+110 BITMAP "cursortext.bmp"
+111 BITMAP "paneinfo.bmp"
Binary file cursortext.bmp has changed
Binary file freqselect.bmp has changed
Binary file hsselect.bmp has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hv.bdsproj	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<PersonalityInfo>
+		<Option>
+			<Option Name="Personality">CPlusPlusBuilder.Personality</Option>
+			<Option Name="ProjectType">CppVCLApplication</Option>
+			<Option Name="Version">1.0</Option>
+			<Option Name="GUID">{239CACC9-F7A7-4725-8F92-5B55AF9E72ED}</Option>
+		</Option>
+	</PersonalityInfo>
+	<CPlusPlusBuilder.Personality>
+		<Source>
+			<Source Name="MainSource">hv.cpp</Source>
+		</Source>
+		<BCBPROJECT>
+      <project version="10.0">
+        <property category="build.config" name="active" value="0"/>
+        <property category="build.config" name="count" value="1"/>
+        <property category="build.config" name="excludedefaultforzero" value="0"/>
+        <property category="build.config.0" name="builddir" value="Debug"/>
+        <property category="build.config.0" name="key" value="Debug_Build"/>
+        <property category="build.config.0" name="name" value="Debug Build"/>
+        <property category="build.config.0" name="settings.win32b" value="default"/>
+        <property category="build.config.0" name="type" value="Toolset"/>
+        <property category="build.config.0" name="win32.win32b.builddir" value="Debug_Build"/>
+        <property category="build.config.1" name="key" value="Release_Build"/>
+        <property category="build.config.1" name="name" value="Release Build"/>
+        <property category="build.config.1" name="settings.win32b" value="default"/>
+        <property category="build.config.1" name="type" value="Toolset"/>
+        <property category="build.config.1" name="win32.win32b.builddir" value="Release_Build"/>
+        <property category="build.node" name="lastconfig" value="Debug_Build"/>
+        <property category="build.node" name="name" value="hv.exe"/>
+        <property category="build.node" name="packages" value="vclx;vcl;rtl;dbrtl;vcldb;adortl;dbxcds;dbexpress;xmlrtl;vclie;inet;inetdbbde;inetdbxpress;soaprtl;dsnap;bdertl;vcldbx"/>
+        <property category="build.node" name="sparelibs" value="rtl.lib vcl.lib"/>
+        <property category="build.node" name="use_packages" value="1"/>
+        <property category="build.platform" name="active" value="win32"/>
+        <property category="build.platform" name="win32.Debug_Build.toolset" value="win32b"/>
+        <property category="build.platform" name="win32.Release_Build.toolset" value="win32b"/>
+        <property category="build.platform" name="win32.default" value="win32b"/>
+        <property category="build.platform" name="win32.enabled" value="1"/>
+        <property category="build.platform" name="win32.win32b.enabled" value="1"/>
+        <property category="win32.*.win32b.dcc32" name="param.filenames.merge" value="1"/>
+        <property category="win32.*.win32b.tasm32" name="param.listfile.merge" value="1"/>
+        <property category="win32.*.win32b.tasm32" name="param.objfile.merge" value="1"/>
+        <property category="win32.*.win32b.tasm32" name="param.xreffile.merge" value="1"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.D.arg.1" value="_DEBUG"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.D.arg.merge" value="1"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.D.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.Od.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.k.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.r.enabled" value="0"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.v.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.vi.enabled" value="0"/>
+        <property category="win32.Debug_Build.win32b.bcc32" name="option.y.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.dcc32" name="option.$D.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.dcc32" name="option.$O.enabled" value="0"/>
+        <property category="win32.Debug_Build.win32b.dcc32" name="option.D.arg.1" value="DEBUG"/>
+        <property category="win32.Debug_Build.win32b.dcc32" name="option.D.arg.merge" value="1"/>
+        <property category="win32.Debug_Build.win32b.dcc32" name="option.D.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.dcc32" name="option.V.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.ilink32" name="option.L.arg.1" value="$(BDS)\lib\debug"/>
+        <property category="win32.Debug_Build.win32b.ilink32" name="option.L.arg.merge" value="1"/>
+        <property category="win32.Debug_Build.win32b.ilink32" name="option.L.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.ilink32" name="option.dynamicrtl.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.tasm32" name="option.z.enabled" value="1"/>
+        <property category="win32.Debug_Build.win32b.tasm32" name="option.zd.enabled" value="0"/>
+        <property category="win32.Debug_Build.win32b.tasm32" name="option.zi.enabled" value="1"/>
+        <property category="win32.Release_Build.win32b.bcc32" name="option.D.arg.1" value="NDEBUG"/>
+        <property category="win32.Release_Build.win32b.bcc32" name="option.D.arg.merge" value="1"/>
+        <property category="win32.Release_Build.win32b.bcc32" name="option.D.enabled" value="1"/>
+        <property category="win32.Release_Build.win32b.bcc32" name="option.O2.enabled" value="1"/>
+        <property category="win32.Release_Build.win32b.bcc32" name="option.k.enabled" value="0"/>
+        <property category="win32.Release_Build.win32b.bcc32" name="option.r.enabled" value="1"/>
+        <property category="win32.Release_Build.win32b.bcc32" name="option.vi.enabled" value="1"/>
+        <property category="win32.Release_Build.win32b.dcc32" name="option.$D.enabled" value="0"/>
+        <property category="win32.Release_Build.win32b.dcc32" name="option.$O.enabled" value="1"/>
+        <property category="win32.Release_Build.win32b.dcc32" name="option.V.enabled" value="0"/>
+        <property category="win32.Release_Build.win32b.ilink32" name="option.L.arg.1" value="$(BDS)\lib\release"/>
+        <property category="win32.Release_Build.win32b.ilink32" name="option.L.arg.merge" value="1"/>
+        <property category="win32.Release_Build.win32b.ilink32" name="option.L.enabled" value="1"/>
+        <property category="win32.Release_Build.win32b.ilink32" name="option.dynamicrtl.enabled" value="1"/>
+        <property category="win32.Release_Build.win32b.tasm32" name="option.z.enabled" value="0"/>
+        <property category="win32.Release_Build.win32b.tasm32" name="option.zd.enabled" value="0"/>
+        <property category="win32.Release_Build.win32b.tasm32" name="option.zi.enabled" value="0"/>
+        <property category="win32.Release_Build.win32b.tasm32" name="option.zn.enabled" value="1"/>
+        <optionset name="all_configurations">
+          <property category="node" name="displayname" value="All Configurations"/>
+          <property category="win32.*.win32b.bcc32" name="option.H=.arg.1" value="$(BDS)\lib\vcl100.csm"/>
+          <property category="win32.*.win32b.bcc32" name="option.H=.arg.merge" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.H=.enabled" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.Hc.enabled" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.I.arg.1" value="..\"/>
+          <property category="win32.*.win32b.bcc32" name="option.I.arg.2" value="E:\My Projects\x\hv"/>
+          <property category="win32.*.win32b.bcc32" name="option.I.arg.3" value="$(BDS)\include"/>
+          <property category="win32.*.win32b.bcc32" name="option.I.arg.4" value="$(BDS)\include\dinkumware"/>
+          <property category="win32.*.win32b.bcc32" name="option.I.arg.5" value="$(BDS)\include\vcl"/>
+          <property category="win32.*.win32b.bcc32" name="option.I.arg.merge" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.I.enabled" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.b.enabled" value="0"/>
+          <property category="win32.*.win32b.bcc32" name="option.sysdefines.arg.1" value="_RTLDLL"/>
+          <property category="win32.*.win32b.bcc32" name="option.sysdefines.arg.2" value="NO_STRICT"/>
+          <property category="win32.*.win32b.bcc32" name="option.sysdefines.arg.3" value="USEPACKAGES"/>
+          <property category="win32.*.win32b.bcc32" name="option.sysdefines.arg.merge" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.sysdefines.enabled" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.tW.enabled" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.tWC.enabled" value="0"/>
+          <property category="win32.*.win32b.bcc32" name="option.tWD.enabled" value="0"/>
+          <property category="win32.*.win32b.bcc32" name="option.tWM.enabled" value="1"/>
+          <property category="win32.*.win32b.bcc32" name="option.vG.enabled" value="0"/>
+          <property category="win32.*.win32b.dcc32" name="option.I.arg.1" value="..\"/>
+          <property category="win32.*.win32b.dcc32" name="option.I.arg.2" value="E:\My Projects\x\hv"/>
+          <property category="win32.*.win32b.dcc32" name="option.I.arg.merge" value="1"/>
+          <property category="win32.*.win32b.dcc32" name="option.I.enabled" value="0"/>
+          <property category="win32.*.win32b.dcc32" name="option.O.arg.1" value="..\"/>
+          <property category="win32.*.win32b.dcc32" name="option.O.arg.2" value="E:\My Projects\x\hv"/>
+          <property category="win32.*.win32b.dcc32" name="option.O.arg.merge" value="1"/>
+          <property category="win32.*.win32b.dcc32" name="option.O.enabled" value="0"/>
+          <property category="win32.*.win32b.dcc32" name="option.R.arg.1" value="..\"/>
+          <property category="win32.*.win32b.dcc32" name="option.R.arg.2" value="E:\My Projects\x\hv"/>
+          <property category="win32.*.win32b.dcc32" name="option.R.arg.merge" value="1"/>
+          <property category="win32.*.win32b.dcc32" name="option.R.enabled" value="0"/>
+          <property category="win32.*.win32b.dcc32" name="option.U.arg.1" value="..\"/>
+          <property category="win32.*.win32b.dcc32" name="option.U.arg.2" value="E:\My Projects\x\hv"/>
+          <property category="win32.*.win32b.dcc32" name="option.U.arg.3" value="C:\Documents and Settings\xuew\My Documents\Borland Studio Projects"/>
+          <property category="win32.*.win32b.dcc32" name="option.U.arg.4" value="$(BDS)\lib"/>
+          <property category="win32.*.win32b.dcc32" name="option.U.arg.5" value="$(BDS)\lib\obj"/>
+          <property category="win32.*.win32b.dcc32" name="option.U.arg.merge" value="1"/>
+          <property category="win32.*.win32b.dcc32" name="option.U.enabled" value="1"/>
+          <property category="win32.*.win32b.dcc32" name="param.filenames.merge" value="1"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.1" value="..\"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.10" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.11" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.12" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.13" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.14" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.15" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.16" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.17" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.18" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.19" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.2" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.3" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.4" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.5" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.6" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.7" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.8" value="E:\My"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.9" value="Projects\x\hv"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.arg.merge" value="1"/>
+          <property category="win32.*.win32b.idl2cpp" name="option.I.enabled" value="1"/>
+          <property category="win32.*.win32b.ilink32" name="option.Gi.enabled" value="0"/>
+          <property category="win32.*.win32b.ilink32" name="option.L.arg.1" value="..\"/>
+          <property category="win32.*.win32b.ilink32" name="option.L.arg.2" value="E:\My Projects\x\hv"/>
+          <property category="win32.*.win32b.ilink32" name="option.L.arg.3" value="$(BDS)\lib"/>
+          <property category="win32.*.win32b.ilink32" name="option.L.arg.4" value="$(BDS)\lib\obj"/>
+          <property category="win32.*.win32b.ilink32" name="option.L.arg.5" value="$(BDS)\lib\psdk"/>
+          <property category="win32.*.win32b.ilink32" name="option.L.arg.merge" value="1"/>
+          <property category="win32.*.win32b.ilink32" name="option.L.enabled" value="1"/>
+          <property category="win32.*.win32b.ilink32" name="option.Tpd.enabled" value="0"/>
+          <property category="win32.*.win32b.ilink32" name="option.Tpe.enabled" value="1"/>
+          <property category="win32.*.win32b.ilink32" name="option.Tpp.enabled" value="0"/>
+          <property category="win32.*.win32b.ilink32" name="option.aa.enabled" value="1"/>
+          <property category="win32.*.win32b.ilink32" name="option.ap.enabled" value="0"/>
+          <property category="win32.*.win32b.ilink32" name="option.dynamicrtl.enabled" value="0"/>
+          <property category="win32.*.win32b.ilink32" name="option.j.arg.1" value="..\"/>
+          <property category="win32.*.win32b.ilink32" name="option.j.arg.2" value="E:\My Projects\x\hv"/>
+          <property category="win32.*.win32b.ilink32" name="option.j.arg.merge" value="1"/>
+          <property category="win32.*.win32b.ilink32" name="option.j.enabled" value="0"/>
+          <property category="win32.*.win32b.ilink32" name="param.libfiles.1" value="$(LIBRARIES)"/>
+          <property category="win32.*.win32b.ilink32" name="param.libfiles.2" value="import32.lib"/>
+          <property category="win32.*.win32b.ilink32" name="param.libfiles.3" value="cp32mti.lib"/>
+          <property category="win32.*.win32b.ilink32" name="param.libfiles.merge" value="1"/>
+          <property category="win32.*.win32b.ilink32" name="param.objfiles.1" value="c0w32.obj"/>
+          <property category="win32.*.win32b.ilink32" name="param.objfiles.2" value="$(PACKAGES)"/>
+          <property category="win32.*.win32b.ilink32" name="param.objfiles.3" value="memmgr.lib"/>
+          <property category="win32.*.win32b.ilink32" name="param.objfiles.4" value="sysinit.obj"/>
+          <property category="win32.*.win32b.ilink32" name="param.objfiles.merge" value="1"/>
+        </optionset>
+      </project>
+      <FILELIST>
+        <FILE FILENAME="hv.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="hv" FORMNAME="" DESIGNCLASS=""/>
+        <FILE FILENAME="hv.res" CONTAINERID="ResTool" LOCALCOMMAND="" UNITNAME="hv.res" FORMNAME="" DESIGNCLASS=""/>
+        <FILE FILENAME="AudioPac.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="AudioPac" FORMNAME="" DESIGNCLASS="" ADDITIONAL="AudioPac.h"/>
+        <FILE FILENAME="BackUpTool.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="BackUpTool" FORMNAME="BackupForm1" DESIGNCLASS="" ADDITIONAL="BackUpTool.h"/>
+        <FILE FILENAME="EditorPanelUnit.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="EditorPanelUnit" FORMNAME="EditorPanel" DESIGNCLASS="" ADDITIONAL="EditorPanelUnit.h"/>
+        <FILE FILENAME="EventBoxUnit.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="EventBoxUnit" FORMNAME="EventBox" DESIGNCLASS="" ADDITIONAL="EventBoxUnit.h"/>
+        <FILE FILENAME="Navigator.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="Navigator" FORMNAME="" DESIGNCLASS="" ADDITIONAL="Navigator.h"/>
+        <FILE FILENAME="RecordingUnit.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="RecordingUnit" FORMNAME="RecordingForm" DESIGNCLASS="" ADDITIONAL="RecordingUnit.h"/>
+        <FILE FILENAME="SFDemoUnit.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="SFDemoUnit" FORMNAME="SFDemoForm" DESIGNCLASS="" ADDITIONAL="SFDemoUnit.h"/>
+        <FILE FILENAME="SUThread.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="SUThread" FORMNAME="" DESIGNCLASS="" ADDITIONAL="SUThread.h"/>
+        <FILE FILENAME="Unit1.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="Unit1" FORMNAME="Form1" DESIGNCLASS="" ADDITIONAL="Unit1.h"/>
+        <FILE FILENAME="UnitRangeEdit.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="UnitRangeEdit" FORMNAME="RangeEdit" DESIGNCLASS="" ADDITIONAL="UnitRangeEdit.h"/>
+        <FILE FILENAME="VibratoDemoUnit.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="VibratoDemoUnit" FORMNAME="VibratoDemoForm" DESIGNCLASS="" ADDITIONAL="VibratoDemoUnit.h"/>
+        <FILE FILENAME="WaveView.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="WaveView" FORMNAME="" DESIGNCLASS="" ADDITIONAL="WaveView.h"/>
+        <FILE FILENAME="bitmaps.rc" CONTAINERID="RCCompiler" LOCALCOMMAND="" UNITNAME="bitmaps.rc" FORMNAME="bitmaps.res" DESIGNCLASS=""/>
+        <FILE FILENAME="..\align8.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="align8" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\align8.h"/>
+        <FILE FILENAME="..\fft.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="fft" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\fft.h"/>
+        <FILE FILENAME="..\hs.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="hs" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\hs.h"/>
+        <FILE FILENAME="..\procedures.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="procedures" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\procedures.h"/>
+        <FILE FILENAME="..\hsedit.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="hsedit" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\hsedit.h"/>
+        <FILE FILENAME="..\hssf.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="hssf" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\hssf.h"/>
+        <FILE FILENAME="..\quickspec.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="quickspec" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\quickspec.h"/>
+        <FILE FILENAME="..\sinest.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="sinest" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\sinest.h"/>
+        <FILE FILENAME="..\matrix.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="matrix" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\matrix.h"/>
+        <FILE FILENAME="..\opt.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="opt" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\opt.h"/>
+        <FILE FILENAME="..\sinsyn.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="sinsyn" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\sinsyn.h"/>
+        <FILE FILENAME="..\splines.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="splines" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\splines.h"/>
+        <FILE FILENAME="..\vibrato.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="vibrato" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\vibrato.h"/>
+        <FILE FILENAME="..\windowfunctions.cpp" CONTAINERID="CCompiler" LOCALCOMMAND="" UNITNAME="windowfunctions" FORMNAME="" DESIGNCLASS="" ADDITIONAL="..\windowfunctions.h"/>
+      </FILELIST>
+      <IDEOPTIONS>
+        <VersionInfo>
+          <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+          <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+          <VersionInfo Name="MajorVer">1</VersionInfo>
+          <VersionInfo Name="MinorVer">0</VersionInfo>
+          <VersionInfo Name="Release">0</VersionInfo>
+          <VersionInfo Name="Build">0</VersionInfo>
+          <VersionInfo Name="Debug">False</VersionInfo>
+          <VersionInfo Name="PreRelease">False</VersionInfo>
+          <VersionInfo Name="Special">False</VersionInfo>
+          <VersionInfo Name="Private">False</VersionInfo>
+          <VersionInfo Name="DLL">False</VersionInfo>
+          <VersionInfo Name="Locale">2057</VersionInfo>
+          <VersionInfo Name="CodePage">1252</VersionInfo>
+        </VersionInfo>
+        <VersionInfoKeys>
+          <VersionInfoKeys Name="CompanyName"></VersionInfoKeys>
+          <VersionInfoKeys Name="FileDescription"></VersionInfoKeys>
+          <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+          <VersionInfoKeys Name="InternalName"></VersionInfoKeys>
+          <VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys>
+          <VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys>
+          <VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys>
+          <VersionInfoKeys Name="ProductName"></VersionInfoKeys>
+          <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+          <VersionInfoKeys Name="Comments"></VersionInfoKeys>
+        </VersionInfoKeys>
+        <Debugging>
+          <Debugging Name="DebugSourceDirs"></Debugging>
+        </Debugging>
+        <Parameters>
+          <Parameters Name="RunParams"></Parameters>
+          <Parameters Name="Launcher"></Parameters>
+          <Parameters Name="UseLauncher">False</Parameters>
+          <Parameters Name="DebugCWD"></Parameters>
+          <Parameters Name="HostApplication"></Parameters>
+          <Parameters Name="RemoteHost"></Parameters>
+          <Parameters Name="RemotePath"></Parameters>
+          <Parameters Name="RemoteParams"></Parameters>
+          <Parameters Name="RemoteLauncher"></Parameters>
+          <Parameters Name="UseRemoteLauncher">False</Parameters>
+          <Parameters Name="RemoteCWD"></Parameters>
+          <Parameters Name="RemoteDebug">False</Parameters>
+          <Parameters Name="Debug Symbols Search Path"></Parameters>
+          <Parameters Name="LoadAllSymbols">True</Parameters>
+          <Parameters Name="LoadUnspecifiedSymbols">False</Parameters>
+        </Parameters>
+        <Excluded_Packages>
+          <Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\dclib100.bpl">Borland InterBase Express Components</Excluded_Packages>
+          <Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\dclIntraweb_80_100.bpl">Intraweb 8.0 Design Package for Borland Development Studio 2006</Excluded_Packages>
+          <Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\dclindy100.bpl">Internet Direct Version 9 (Indy) Property and Component Editors</Excluded_Packages>
+          <Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\bcbofficexp100.bpl">Borland C++Builder Office XP Servers Package</Excluded_Packages>
+          <Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\dclbcbsmp100.bpl">Borland Sample Controls Design Time Package</Excluded_Packages>
+          <Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\bcbie100.bpl">Borland C++Builder Internet Explorer 5 Components Package</Excluded_Packages>
+          <Excluded_Packages Name="c:\program files\borland\bds\4.0\Bin\dcltee100.bpl">TeeChart Components</Excluded_Packages>
+        </Excluded_Packages>
+        <Linker>
+          <Linker Name="LibPrefix"></Linker>
+          <Linker Name="LibSuffix"></Linker>
+          <Linker Name="LibVersion"></Linker>
+        </Linker>
+      </IDEOPTIONS>
+    </BCBPROJECT>
+		<buildevents/>
+	</CPlusPlusBuilder.Personality>
+</BorlandProject>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hv.cpp	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,59 @@
+/*
+    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
+//---------------------------------------------------------------------------
+USEFORM("BackUpTool.cpp", BackupForm1);
+USEFORM("EditorPanelUnit.cpp", EditorPanel);
+USEFORM("EventBoxUnit.cpp", EventBox);
+USEFORM("RecordingUnit.cpp", RecordingForm);
+USEFORM("SFDemoUnit.cpp", SFDemoForm);
+USEFORM("Unit1.cpp", Form1);
+USEFORM("UnitRangeEdit.cpp", RangeEdit);
+USEFORM("VibratoDemoUnit.cpp", VibratoDemoForm);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+  try
+  {
+    Application->Initialize();
+    Application->CreateForm(__classid(TForm1), &Form1);
+    Application->CreateForm(__classid(TBackupForm1), &BackupForm1);
+    Application->CreateForm(__classid(TEditorPanel), &EditorPanel);
+    Application->CreateForm(__classid(TEventBox), &EventBox);
+    Application->CreateForm(__classid(TRecordingForm), &RecordingForm);
+    Application->CreateForm(__classid(TSFDemoForm), &SFDemoForm);
+    Application->CreateForm(__classid(TRangeEdit), &RangeEdit);
+    Application->CreateForm(__classid(TVibratoDemoForm), &VibratoDemoForm);
+    Application->Run();
+  }
+  catch (Exception &exception)
+  {
+    Application->ShowException(&exception);
+  }
+  catch (...)
+  {
+    try
+    {
+       throw Exception("");
+    }
+    catch (Exception &exception)
+    {
+       Application->ShowException(&exception);
+    }
+  }
+  return 0;
+}
+//---------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hv.dfm	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,16 @@
+object Form14: TForm14
+  Left = 218
+  Top = 84
+  Caption = 'Form14'
+  ClientHeight = 470
+  ClientWidth = 862
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  PixelsPerInch = 96
+  TextHeight = 13
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hv.dsk	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,497 @@
+[Closed Files]
+File_0=TSourceModule,'E:\My Projects\x\main.cpp',0,1,1,1,1,0,0,,
+File_1=TSourceModule,'E:\My Projects\x\xcomplex.h',0,1,1,1,13,0,0,,
+File_2=TSourceModule,'E:\My Projects\x\wavelet.cpp',0,1,1,1,13,0,0,,
+File_3=TSourceModule,'E:\My Projects\x\tstream.h',0,1,1,1,13,0,0,,
+File_4=TSourceModule,'E:\My Projects\x\multires.cpp',0,1,109,1,13,0,0,,
+File_5=TSourceModule,'E:\My Projects\x\arrayalloc.h',0,1,1,1,13,0,0,,
+File_6=TSourceModule,'E:\My Projects\x\procedures.cpp',0,1,1,1,13,0,0,,
+File_7=TSourceModule,'E:\My Projects\x\hsedit.cpp',0,1,1,1,13,0,0,,
+File_8=TSourceModule,'E:\My Projects\x\hssf.cpp',0,1,1,1,13,0,0,,
+File_9=TSourceModule,'E:\My Projects\x\quickspec.cpp',0,1,1,1,13,0,0,,
+
+[Modules]
+Module0=E:\My Projects\x\hs.cpp
+Module1=E:\My Projects\x\hv\Unit1.cpp
+Module2=E:\My Projects\x\hv\hv.bdsproj
+Count=3
+EditWindowCount=1
+
+[E:\My Projects\x\hs.cpp]
+ModuleType=TSourceModule
+FormState=0
+FormOnTop=0
+
+[E:\My Projects\x\hv\Unit1.cpp]
+ModuleType=TSourceModule
+FormState=0
+FormOnTop=0
+
+[E:\My Projects\x\hv\hv.bdsproj]
+ModuleType=TBaseProject
+
+[EditWindow0]
+ViewCount=3
+CurrentEditView=E:\My Projects\x\hs.cpp
+View0=0
+View1=1
+View2=2
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=0
+State=2
+Left=11961
+Top=4932
+Width=6797
+Height=8764
+MaxLeft=-8
+MaxTop=-31
+MaxWidth=10062
+MaxHeight=14022
+ClientWidth=10000
+ClientHeight=13614
+DockedToMainForm=0
+MessageView=MessageView@EditWindow0
+BorlandEditorCodeExplorer=BorlandEditorCodeExplorer@EditWindow0
+TopPanelSize=0
+LeftPanelSize=0
+LeftPanelClients=BorlandEditorCodeExplorer@EditWindow0
+LeftPanelData=0000080001000100000019000000426F726C616E64456469746F72436F64654578706C6F726572B20C00000000000000E801000000000000FFFFFFFF
+RightPanelSize=0
+BottomPanelSize=1262
+BottomPanelClients=MessageView@EditWindow0
+BottomPanelData=0000080001000000000000000000000000000000000000000000000100000000000000000B0000004D65737361676556696577FFFFFFFF
+BottomMiddlePanelSize=0
+BottomMiddlePanelClients=DockSite0
+BottomMiddelPanelData=0000080001000100000009000000446F636B53697465300000000000000000000000000000000000FFFFFFFF
+
+[View0]
+CustomEditViewType=TEditView
+Module=E:\My Projects\x\hv\hv.cpp
+CursorX=38
+CursorY=44
+TopLine=22
+LeftCol=1
+Elisions=
+Bookmarks=
+EditViewName=E:\My Projects\x\hv\hv.cpp
+
+[View1]
+CustomEditViewType=TEditView
+Module=E:\My Projects\x\hv\Unit1.cpp
+CursorX=51
+CursorY=272
+TopLine=244
+LeftCol=1
+Elisions=
+Bookmarks=
+EditViewName=E:\My Projects\x\hv\Unit1.h
+
+[View2]
+CustomEditViewType=TEditView
+Module=E:\My Projects\x\hs.cpp
+CursorX=1
+CursorY=13
+TopLine=1
+LeftCol=1
+Elisions=
+Bookmarks=
+EditViewName=E:\My Projects\x\hs.h
+
+[Watches]
+Count=0
+
+[WatchWindow]
+WatchColumnWidth=120
+WatchShowColumnHeaders=1
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=0
+State=0
+Left=1734
+Top=1427
+Width=2625
+Height=2351
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=2562
+ClientHeight=1957
+TBDockHeight=163
+LRDockWidth=2547
+Dockable=1
+StayOnTop=0
+
+[Breakpoints]
+Count=2
+Breakpoint0='E:\My Projects\x\hv\SFDemoUnit.cpp',1162,'',0,1,'',1,0,0,'',1,'','','',0
+Breakpoint1='E:\My Projects\x\hv\WaveView.cpp',207,'fr==17',0,1,'',1,0,0,'',1,'','','',0
+
+[AddressBreakpoints]
+Count=0
+
+[Main Window]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=0
+State=0
+Left=0
+Top=0
+Width=10000
+Height=1114
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=9938
+ClientHeight=707
+BottomPanelSize=50
+
+[ProjectManager]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=1
+State=0
+Left=0
+Top=0
+Width=1320
+Height=2310
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=1320
+ClientHeight=2310
+TBDockHeight=272
+LRDockWidth=3727
+Dockable=1
+StayOnTop=0
+
+[ToolForm]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=0
+State=0
+Left=8508
+Top=4293
+Width=1477
+Height=5611
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=1414
+ClientHeight=5217
+TBDockHeight=5815
+LRDockWidth=1406
+Dockable=1
+StayOnTop=0
+
+[DebugLogView]
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=0
+State=0
+Left=70
+Top=8193
+Width=3625
+Height=3356
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=3562
+ClientHeight=2962
+TBDockHeight=299
+LRDockWidth=3625
+Dockable=1
+StayOnTop=0
+
+[ThreadStatusWindow]
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=0
+State=0
+Left=70
+Top=8193
+Width=5422
+Height=1766
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=5359
+ClientHeight=1372
+TBDockHeight=149
+LRDockWidth=5422
+Dockable=1
+StayOnTop=0
+Column0Width=145
+Column1Width=100
+Column2Width=115
+Column3Width=250
+
+[LocalVarsWindow]
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=0
+State=0
+Left=1734
+Top=1427
+Width=2625
+Height=2418
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=2562
+ClientHeight=2024
+TBDockHeight=204
+LRDockWidth=2547
+Dockable=1
+StayOnTop=0
+
+[CallStackWindow]
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=0
+State=0
+Left=117
+Top=1562
+Width=2625
+Height=2351
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=2562
+ClientHeight=1957
+TBDockHeight=163
+LRDockWidth=2547
+Dockable=1
+StayOnTop=0
+
+[FindReferencsForm]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=1
+State=0
+Left=0
+Top=0
+Width=4320
+Height=1399
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=4320
+ClientHeight=1399
+TBDockHeight=5082
+LRDockWidth=5305
+Dockable=1
+StayOnTop=0
+
+[RefactoringForm]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=1
+State=0
+Left=0
+Top=0
+Width=4320
+Height=1399
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=4320
+ClientHeight=1399
+TBDockHeight=3832
+LRDockWidth=5305
+Dockable=1
+StayOnTop=0
+
+[TemplateView]
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=0
+State=0
+Left=0
+Top=0
+Width=3438
+Height=5842
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=3375
+ClientHeight=5448
+TBDockHeight=5842
+LRDockWidth=3438
+Dockable=1
+StayOnTop=0
+Name=60
+Description=308
+filter=1
+
+[DataExplorer]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=1
+State=0
+Left=0
+Top=0
+Width=1320
+Height=2310
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=1320
+ClientHeight=2310
+TBDockHeight=4878
+LRDockWidth=7148
+Dockable=1
+StayOnTop=0
+
+[PropertyInspector]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=0
+State=0
+Left=0
+Top=4688
+Width=1688
+Height=5204
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=1625
+ClientHeight=4810
+TBDockHeight=5815
+LRDockWidth=1547
+Dockable=1
+StayOnTop=0
+SplitPos=73
+
+[BreakpointWindow]
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=0
+State=0
+Left=86
+Top=7459
+Width=6398
+Height=2283
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=6336
+ClientHeight=1889
+TBDockHeight=204
+LRDockWidth=6398
+Dockable=1
+StayOnTop=0
+Column0Width=100
+Column1Width=75
+Column2Width=200
+Column3Width=200
+Column4Width=75
+Column5Width=75
+
+[StructureView]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=0
+State=0
+Left=0
+Top=1196
+Width=1672
+Height=3465
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=1609
+ClientHeight=3071
+TBDockHeight=3465
+LRDockWidth=1672
+Dockable=1
+StayOnTop=0
+
+[MessageView@EditWindow0]
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=1
+State=0
+Left=0
+Top=23
+Width=10000
+Height=1060
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=10000
+ClientHeight=1060
+TBDockHeight=1060
+LRDockWidth=2773
+Dockable=1
+StayOnTop=0
+
+[BorlandEditorCodeExplorer@EditWindow0]
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=1
+State=0
+Left=-223
+Top=-109
+Width=1469
+Height=8261
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=1469
+ClientHeight=8261
+TBDockHeight=8261
+LRDockWidth=1469
+Dockable=1
+StayOnTop=0
+
+[DockHosts]
+DockHostCount=2
+
+[DockSite0]
+DockSiteType=1
+PercentageSizes=1
+Create=1
+Visible=0
+Docked=1
+State=0
+Left=-223
+Top=-724
+Width=4383
+Height=1875
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=4383
+ClientHeight=1875
+TBDockHeight=1875
+LRDockWidth=4383
+Dockable=1
+StayOnTop=0
+TabPosition=1
+ActiveTabID=RefactoringForm
+TabDockClients=RefactoringForm,FindReferencsForm
+
+[DockSite1]
+DockSiteType=1
+PercentageSizes=1
+Create=1
+Visible=1
+Docked=0
+State=0
+Left=8516
+Top=1128
+Width=1445
+Height=3179
+MaxLeft=-8
+MaxTop=-14
+ClientWidth=1383
+ClientHeight=2785
+TBDockHeight=3179
+LRDockWidth=1445
+Dockable=1
+StayOnTop=0
+TabPosition=1
+ActiveTabID=ProjectManager
+TabDockClients=ProjectManager,DataExplorer
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hv.h	Wed Aug 10 14:55:38 2011 +0100
@@ -0,0 +1,21 @@
+//---------------------------------------------------------------------------
+
+#ifndef hvH
+#define hvH
+//---------------------------------------------------------------------------
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+//---------------------------------------------------------------------------
+class TForm14 : public TForm
+{
+__published:	// IDE-managed Components
+private:	// User declarations
+public:		// User declarations
+  __fastcall TForm14(TComponent* Owner);
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TForm14 *Form14;
+//---------------------------------------------------------------------------
+#endif
Binary file hv.res has changed
Binary file multiselect.bmp has changed
Binary file paneinfo.bmp has changed
Binary file spectrogram.bmp has changed
Binary file timeselect.bmp has changed
Binary file timeselect.old.bmp has changed
Binary file vcrplay.bmp has changed
Binary file vcrrecrd.bmp has changed
Binary file vcrrecrd2.bmp has changed
Binary file vcrstop.bmp has changed
Binary file waveform.bmp has changed