# HG changeset patch # User wenx # Date 1312984538 -3600 # Node ID a6a46af64546e3348cb39b6365cdd2b160b86224 first upload diff -r 000000000000 -r a6a46af64546 AudioPac.cpp --- /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 +#pragma hdrstop + +#include "AudioPac.h" +#include + +#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; kRead(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; iRead(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; iRead(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; iRead(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; iRead(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; iRead(data, ReadSize); + IntToIntMultiChannel(C, Buffer, FBytesPerSample, FChannels, data, CountPF); + for (int c=0; cRead(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->SizeSize=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; iWrite(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 (countavailableSize=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; iWrite(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 (countavailableSize=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; iWrite(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); + } +} +//--------------------------------------------------------------------------- + + diff -r 000000000000 -r a6a46af64546 AudioPac.h --- /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 +//#include +//#include +//#include +//#include + +#include + +//--------------------------------------------------------------------------- +#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 + diff -r 000000000000 -r a6a46af64546 BackUpTool.cpp --- /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 +#include +#include +#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; + } + +} +//--------------------------------------------------------------------------- + diff -r 000000000000 -r a6a46af64546 BackUpTool.dfm --- /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 diff -r 000000000000 -r a6a46af64546 BackUpTool.h --- /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 +#include +#include +#include +#include +//--------------------------------------------------------------------------- +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 diff -r 000000000000 -r a6a46af64546 Documents/Example.doc Binary file Documents/Example.doc has changed diff -r 000000000000 -r a6a46af64546 Documents/QuickStart.1107.doc Binary file Documents/QuickStart.1107.doc has changed diff -r 000000000000 -r a6a46af64546 EditorPanelUnit.cpp --- /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 +#include +#include +#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; mM; m++) for (int fr=0; frFr; 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; iPostWaveViewData(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; iPostWaveViewData(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; iPostWaveViewData(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; iPostWaveViewData(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; iPostWaveViewData(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; mM; 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; mM; m++) memcpy(HS->Partials[m], Form1->HS->Partials[m], sizeof(atom)*HS->Fr); + Form1->PostWaveViewData(Before, Channel, From, To); +} +//--------------------------------------------------------------------------- + diff -r 000000000000 -r a6a46af64546 EditorPanelUnit.dfm --- /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 diff -r 000000000000 -r a6a46af64546 EditorPanelUnit.h --- /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 +#include +#include +#include +#include +#include +#include +#include "EventBoxUnit.h" +#include +//--------------------------------------------------------------------------- +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 diff -r 000000000000 -r a6a46af64546 EventBoxUnit.cpp --- /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 +#pragma hdrstop + +#include "EventBoxUnit.h" +#include "WaveView.h" +#include "Unit1.h" +#include "EditorPanelUnit.h" +#include +#include +//--------------------------------------------------------------------------- +#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=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 || eventenStartPos) + { + 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; iPartials[0][0].tPartials[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; iWriteToStream(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 || iReadFromStream(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; iAdd(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); +} +//--------------------------------------------------------------------------- + diff -r 000000000000 -r a6a46af64546 EventBoxUnit.dfm --- /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 diff -r 000000000000 -r a6a46af64546 EventBoxUnit.h --- /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 +#include +#include +#include +#include +#include +#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 diff -r 000000000000 -r a6a46af64546 Icon1.bmp Binary file Icon1.bmp has changed diff -r 000000000000 -r a6a46af64546 Navigator.cpp --- /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 + +#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+1Rectangle(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 (XX2+Xa) XTest=htOuter; + else if (X1-Xa<=X && X<=X1+Xb) XTest=htLeft; + else if (X1+XbY2+Ya) YTest=htOuter; + else if (Y1-Ya<=Y && Y<=Y1+Yb) YTest=htTop; + else if (Y1+YbCursors[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); + } +} +//--------------------------------------------------------------------------- diff -r 000000000000 -r a6a46af64546 Navigator.h --- /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 +#include +#include +//--------------------------------------------------------------------------- +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 diff -r 000000000000 -r a6a46af64546 RecordingUnit.cpp --- /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 +#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); +} +//--------------------------------------------------------------------------- + diff -r 000000000000 -r a6a46af64546 RecordingUnit.dfm --- /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 diff -r 000000000000 -r a6a46af64546 RecordingUnit.h --- /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 +#include +#include +#include +#include +//--------------------------------------------------------------------------- +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 diff -r 000000000000 -r a6a46af64546 SFDemoUnit.cpp --- /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 +#pragma hdrstop + +#include +#include +#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; iM<=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; imax) 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; iClear(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; i1)?0:sqrt(1-r); + for (int i=0; i=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; mPen->Color=RotateColors[m%10]; Canvas->Brush->Color=RotateColors[m%10]; + + int Sc=0; + bool visible=false; + atom* Partialsm=Partials[m]; + for (int fr=frst; fr0 && Partialsm[fr].a>0) + { + x[Sc]=Partials[m][fr].f; + y[Sc]=20*(Log10(Partialsm[fr].a)); + if (x[Sc]x[c]*0.05) fw=x[c]*0.05; + + for (int c1=0; c1xen) 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; mBrush->Color=RotateColors[m%10]; Canvas->Pen->Color=RotateColors[m%10]; + memset(XRec, 0, sizeof(int)*XX); + + for (int fr=frst; fr0 && Partialsm[fr].a>0) + { + double xx=Partialsm[fr].f; + if (xxxen) continue; + int X=floor(XXixrange*xx-xstXXixrange+0.5); + if (X>=0 && XMoveTo(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; iFont; 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 (LineCountLineTo(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; xLineTo(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; ixen) 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 (HLX1Brush->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; frF0[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; pfrColor=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; fr0) 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; pfrMoveTo(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<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; frF0C[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<TextHeight(S)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; fr0) 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; pMoveTo(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; i0) 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; frPartials[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=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=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=CX1[i] && X<=CX2[i] && Y>=CY1[i] && Y<=CY2[i]) {CurrentC=i; break;} + } + if (CurrentC>=0 && CurrentCPartials[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 (CurrentPSF.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 && CurrentBPartials[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 && CurrentPText.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; lSamplesPerSec); + 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; lSamplesPerSec); + 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; lPartials); 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; l0) for (int m=CurrentPartial+dm; m=lp0 && CurrentFrCaption=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=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) CurrentPartial=lSXc-1; + if (CurrentPartial>=1 && X-lSX[CurrentPartial-1]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])=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; pWidth*SF.L, *newlp=new double[SF.P+3]; + int newb=0; while (newbBX1[newb]) newb++; + + if (newb>0) memcpy(newlp, SF.lp, sizeof(double)*newb); + if (newbActivePage=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; kItemIndex<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; lM)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]); + double db=(sfb-SF0.avgb[m])*dbamp; + for (int l=0; lM)?sf->avgb[m]:(sf->avgb[sf->M-1]-avgbend+SF0.avgb[m]); + double db=(sfb-SF0.avgb[m])*dbamp; + for (int l=0; lM)?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; lM)?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; lSamplesPerSec); + 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; iResume(); +} + +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; imax) 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>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; nPostWaveViewData(data, Channel, StartPos, StartPos+N, Form1->FadeInCheck->Checked, Form1->FadeInCombo->Text.ToInt()); + delete[] data; + } +} +//--------------------------------------------------------------------------- + + + + diff -r 000000000000 -r a6a46af64546 SFDemoUnit.dfm --- /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 diff -r 000000000000 -r a6a46af64546 SFDemoUnit.h --- /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 +#include +#include +#include +#include +#include "AudioPac.h" +#include "WaveView.h" +#include "EventBoxUnit.h" +#include "hssf.h" +#include "SUThread.h" +#include +#include + +//--------------------------------------------------------------------------- + + + +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 diff -r 000000000000 -r a6a46af64546 SUThread.cpp --- /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 +#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); +} +//--------------------------------------------------------------------------- diff -r 000000000000 -r a6a46af64546 SUThread.h --- /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 +#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 diff -r 000000000000 -r a6a46af64546 Unit1.cpp --- /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 +#include +#include "Unit1.h" +#include "BackUpTool.h" +#include +#include +#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<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; iIndexOf(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 && XWidth && YHeight) + { + 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; iWriteString(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; iCaption=AnsiString(i+1)+". "+Names[i]; + Recents[i]->Visible=true; + } + for (int i=newi; iVisible=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; frVisible) + { + QSPEC_FORMAT* data=WaveView1->A[Channel][fr]; + for (int bin=binst; binCells[fr-frst+1][binen-bin]=AnsiString().sprintf(format, data[bin]*amp); + } + else if (ArcTab->Visible) + { + cmplx* data=WaveView1->Spec[Channel][fr]; + for (int bin=binst; binprange/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; binCells[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; cColCount; c++) + for (int r=0; rRowCount; 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; binCells[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* 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; iSpecWindowType, 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; nCells[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; iFObjects.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 (paneFPanes.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->tStartPos || par->t>=WaveView1->EndPos || par->fStartDigiFreq || 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 (X2Y-1) Y1=Y-1; if (Y2Pen->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=(Y1Y+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; evHSCount; ev++) + { + THS* hs=EventBox->HS[ev]; + if (tStartPos() || 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 (mM-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; mM; m++) for (int fr=0; frFr; 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; iFPanes.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; iFPanes.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; iFPanes.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; iFPanes.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)*10FPanes.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; iFObjects.Count; i++) + { + TWaveViewObject Obj=WaveView1->FObjects.Items[i]; + if (Obj.ShortTag[0]==stAtom && Obj.ShortTag[2]==dm && Obj.Tag[2]type=atMuted; + } + } + else + { + for (int m=0; mM; m++) for (int fr=0; frFr-dfr; fr++) + HS->Partials[m][fr]=HS->Partials[m][fr+dfr]; + HS->Fr-=dfr; + int ind=0; + for (int i=0; iFObjects.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; iFObjects.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; iFObjects.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; mM; m++) for (int fr=0; frFr; 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; mM; 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; m0 && 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; iN, 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* 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; i0) + { + if (iM) + { + 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; jM; 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; frPartials[0][0].t-hwid)/offst; + for (int fr=0; fr* 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; frM; i++) + { + atom* part=&HS->Partials[i][fr]; + if (fppfr[i]>0) + { + if (iM) + { + 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; jM; 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; m0) + { + 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; fr0) part[k++]=Partials[m][fr]; + + double ene0=0; + for (int m=0; mM; 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* spec=WaveView1->Spec[channel][fr]; + for (int i=0; i<=hwid; i++) x[i]=spec[i]; + double ene=0; + for (int m=0; mM; 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 (eneene0) ene0=ene; + } + } + else //edfr==Fr-1 + { + for (int fr=startfr+1; fr<=fren; fr++) + { + t+=dt; + cmplx* spec=WaveView1->Spec[channel][fr]; + for (int i=0; i<=hwid; i++) x[i]=spec[i]; + double ene=0; + for (int m=0; mM; 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 (eneene0) 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; m0 && Partials[m][fr1].type==atAnchor) break; if (m0 && Partials[m][fr2].type==atAnchor) break; if (mStartPos-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 (fr2Spectrogram[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; m0) 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 (fr2Spectrogram[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; m0) 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; ihW*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; ihW*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; nObjectAtPointer && 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; mM; m++) + { + atom* part=HS->Partials[m]; + bool fzero=false; + for (int fr=0; frstartamp[m][l]=tmp/tmp2; + } + } + delete[] xrec; + delete[] f1; + } + + double* xrec=SynthesisHSp(HS, dst, den); + FadeInOut(xrec, den-dst, s/2); + + for (int i=0; iChannel, 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); +} +//--------------------------------------------------------------------------- + + diff -r 000000000000 -r a6a46af64546 Unit1.dfm --- /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 diff -r 000000000000 -r a6a46af64546 Unit1.h --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AudioPac.h" +#include "WaveView.h" +#include "Navigator.h" + +#include "hs.h" +#include "EventBoxUnit.h" +#include "procedures.h" +#include + +#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 diff -r 000000000000 -r a6a46af64546 UnitRangeEdit.cpp --- /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 +#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(); +} +//--------------------------------------------------------------------------- diff -r 000000000000 -r a6a46af64546 UnitRangeEdit.dfm --- /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 diff -r 000000000000 -r a6a46af64546 UnitRangeEdit.h --- /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 +#include +#include +#include +#include +//--------------------------------------------------------------------------- +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 diff -r 000000000000 -r a6a46af64546 VibratoDemoUnit.cpp --- /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 +#pragma hdrstop + +#include +#include +#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; iM<=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; imax) 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; iClear(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; i1)?0:sqrt(1-r); + for (int i=0; i=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; mPen->Color=RotateColors[m%10]; Canvas->Brush->Color=RotateColors[m%10]; + + int Sc=0; + bool visible=false; + atom* Partialsm=Partials[m]; + for (int fr=FrStart; fr0 && Partialsm[fr].a>0) + { + x[Sc]=Partials[m][fr].f; + y[Sc]=20*Log10(Partialsm[fr].a/A0C[fr]); + if (x[Sc]x[c]*0.05) fw=x[c]*0.05; + + for (int c1=0; c1xen) 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; mBrush->Color=RotateColors[m%10]; Canvas->Pen->Color=RotateColors[m%10]; + memset(XRec, 0, sizeof(int)*XX); + + for (int fr=0; fr0 && Partialsm[fr].a>0) + { + double xx=Partialsm[fr].f; + if (xxxen) continue; + int X=floor(XXixrange*xx-xstXXixrange+0.5); + if (X>=0 && XMoveTo(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; iFont; 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 (LineCountxen) 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; xLineTo(Bdw+x, Y); + } + } + //draw source lines + for (int i=0; ixen) 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]; frF0[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; pfrColor=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; fr0) 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; pfrMoveTo(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<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; frF0C[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<TextHeight(S)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; fr0) 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; pMoveTo(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]; frF0D[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; fr0) 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; frMoveTo(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; i0) 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; frPartials[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; iPicture->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=CX1[i] && X<=CX2[i] && Y>=CY1[i] && Y<=CY2[i]) {CurrentC=i; break;} + } + if (CurrentC>=0 && CurrentCPartials[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 (tPartials[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 && CurrentModCycleSpecOffst; + 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; frf0dmax) f0dmax=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; iPicture->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; iPicture->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.F0DmaxV.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; fr0) 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; frWidth*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; lSamplesPerSec); + 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; pSamplesPerSec); + 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; pSamplesPerSec); + 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; p0) 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; pV.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=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; c2.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; cSamplesPerSec); + 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; pCaption=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) CurrentPartial=lSXc-1; + if (CurrentPartial>=1 && X-lSX[CurrentPartial-1]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=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; pP; p++) + { + double F0p=0; + int frst=V->lp[p-1], fren=V->lp[p]; + for (int fr=frst; frF0C[fr]; + F0p/=(fren-frst); + F0p*=V->afres; + int lastfp; + double lastsv; + for (int m=0; mM; m++) + { + int fp=F0p*(m+1); + double sv=V->LogASp[p][m]; + if (m==0) for (int n=0; nP-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; iResume(); +} + +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; nPostWaveViewData(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; +} +//--------------------------------------------------------------------------- + diff -r 000000000000 -r a6a46af64546 VibratoDemoUnit.dfm --- /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 diff -r 000000000000 -r a6a46af64546 VibratoDemoUnit.h --- /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 +#include +#include +#include +#include +#include "AudioPac.h" +#include "WaveView.h" +#include "EventBoxUnit.h" +#include "SUThread.h" +#include +#include +#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 diff -r 000000000000 -r a6a46af64546 WaveView.cpp --- /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 +#include +#pragma hdrstop + +#include "WaveView.h" +#include +#include +#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>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; kSamplesPerSec; + 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; iWriteSamples(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; iCount; 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; ifwin; //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; iSpecWindowType==wtHann) winrec=0; + else + { + winrec=new double[Wid]; + for (int i=0; iBytesPerSample; + char* data8=&WV->Data8[Channel][frst*Offst*bps]; + + for (int fr=0; frSpec[Channel][frst+fr]; + } + + int prefetchcount=Wid/Offst; + char** prefetch=new char*[prefetchcount]; prefetch[0]=new char[prefetchcount*bps*Wid]; for (int i=1; i* 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; ifw; + 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(Owner)) + Parent=dynamic_cast(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; iColor=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; iCapacity==0) FS->SetFrCapacity((FLength-FSpecRes)/FSpecOffst+2); + int calculatefrcount=0; + for (int x=0; x=0 && frCapacity && (interpolate || ffr-fr<=0.5)) + { + if (FS->Frame[fr]<0 || FS->Valid[fr]==0) calculatefrcount++; + } + if (fr+1>=0 && fr+1Capacity && (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; iFreeBuffers(); +} + +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 (fAdd(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 (iCount && List->Strings[i]!="") + { + TextOutline(Canvas, List->Strings[i], X-Canvas->TextWidth(List->Strings[i])/2+1, y, FC, BC); + y+=dtextheight; i++; + } + while (iCount && List->Strings[i]=="") i++; + y=Y-textheight*(List->Count-i)*0.5; + while (iCount) + { + 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; iBrush->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 (iPen->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; iCount; i++) {int AW=Canvas->TextWidth(List->Strings[i]); if (widthPen->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; iCount; 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; iBrush->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 && XPen->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; iCount; 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; iPen->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; x0); + 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; yCopyRect(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; yWidth, 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; iLineTo(Xs+i, Ys+Y0-(Data8[__int32(startpos+__int64(endpos-startpos)*i/X)]-0x80)*amp); + else + { + for (i=0; ivlocalmax) 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; iLineTo(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; i0; 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 (vlocalvlocalmax) 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+ndataen-hn) + { + if (!loop) + { + + if (readfrom>dataen-hn) + { + double* lwin=&win[n-(dataen-readfrom)]; + for (int i=0; idataen-n) + { + double* lwin=&win[n-(dataen-readfrom)]; + for (int i=dataen-hn-readfrom; idataen-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; iChannels==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 (PBPR1 && FStereoMode==wvpRight)?FData[1]:FData[0]); + + int Wid=FSpecRes, HWid=Wid/2; + while (PBPA=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; i0) + { + 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 && IndexCount && 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 || ch<0) + { + for (int i=0; i0.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; iCount; i++) + { + TWaveViewSelection sel=FSelections->Items[i]; + if (tsel.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=Rect.left && X=Rect.top && Y=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* __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=0) Basic1Settings[channel].Y=0; + else for (int i=0; i0) + { + 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 (FStartSelRStartPos ||FStartSelR>=FSelections->EndPos + ||FPanes.HasFreqAxis[FStartPane] && (FVStartSelRStartDigiFreq||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(Sender)->Tag==ITEMXZOOMIN_TAG) + Zoom(FStartSelR, 0.8); + else if (dynamic_cast(Sender)->Tag==ITEMXZOOMOUT_TAG) + Zoom(FStartSelR, 3); + else if (dynamic_cast(Sender)->Tag==ITEMXZOOMRESTORE_TAG) + Zoom(FStartSelR, 0); + } +} + +void __fastcall TWaveView::ItemYZoomClick(TObject* Sender) +{ + if (FCustomYZoomClick) FCustomYZoomClick(Sender); + else + { + if (dynamic_cast(Sender)->Tag==ITEMYZOOMIN_TAG) YZoomRate*=1.5; + else if (dynamic_cast(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=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; kSeek(writefrombytes, soFromCurrent); + char* data=&((char*)FData)[writefrom*FBytesPerSample]; + for (int k=0; kWaveStream->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; iReadSamplesMultiChannel(FChannels, FFData, readlength); + for (int i=0; iA(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; yhWid) 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 (v0Size=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=Spectrogram->Capacity) + { + for (int y=0; yCapacity) SampleImageLine(vyys1, dY, yy, Spectrogram, xxd+1); + else memset(vyys1, 0, sizeof(double)*dY); + } + else + { + if (xxd>=0 && xxdCapacity) + { + SampleImageLine(vyys0, dY, yy, Spectrogram, xxd); + for (int i=0; iCapacity) SampleImageLine(vyys1, dY, yy, Spectrogram, xxd+1); + else memset(vyys1, 0, sizeof(double)*dY); + } + + for (int y=0; y=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=Spectrogram->Capacity) + { + for (int y=0; y=0 && xxdCapacity) + { + SampleImageLine(vyys0, dY, yy, Spectrogram, xxd); + for (int i=0; i=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=Spectrogram->Capacity) + { + for (int y=0; yA(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; ispec[i-1] && spec[i]>spec[i+1]) + { + if (maxv=0 && p=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=Spectrogram->Capacity) + { + for (int y=0; yA(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; ispec[i-1] && spec[i]>spec[i+1]) + { + if (maxv=0 && p=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; iCount; i++) + { + TWaveViewSelection sel=FSelections->Items[i]; + if (Pos>=sel.StartPos && Pos=sel.StartDigiFreq && DigiFreqCount==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 (Xlright+BW) sx=sOuter; + else if (X<=lleft+BW) sx=sIBorder; + else if (Xlbottom+BW) sy=sOuter; + else if (Y<=ltop+BW) sy=sIBorder; + else if (YAnEndPos) 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=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; i0) 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 (AnEndPosTabStop=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; iOffst=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; iWid=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; iWinParam=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; iWinType=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; iData=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 (FStartSelRStartPos||FStartSelR>=FSelections->EndPos|| + FPanes.HasFreqAxis[FStartPane] && (FVStartSelRStartDigiFreq||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; iPlay(&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=Rect.left && X=Rect.top && Y=Rect.left && X=Rect.top && YCaption=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 (Y0.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 diff -r 000000000000 -r a6a46af64546 WaveView.h --- /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 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=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* __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* 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 diff -r 000000000000 -r a6a46af64546 bitmaps.rc --- /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" diff -r 000000000000 -r a6a46af64546 cursortext.bmp Binary file cursortext.bmp has changed diff -r 000000000000 -r a6a46af64546 freqselect.bmp Binary file freqselect.bmp has changed diff -r 000000000000 -r a6a46af64546 hsselect.bmp Binary file hsselect.bmp has changed diff -r 000000000000 -r a6a46af64546 hv.bdsproj --- /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 @@ + + + + + + + + + + + + hv.cpp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2057 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + False + + + + + + + False + + False + + True + False + + + Borland InterBase Express Components + Intraweb 8.0 Design Package for Borland Development Studio 2006 + Internet Direct Version 9 (Indy) Property and Component Editors + Borland C++Builder Office XP Servers Package + Borland Sample Controls Design Time Package + Borland C++Builder Internet Explorer 5 Components Package + TeeChart Components + + + + + + + + + + + diff -r 000000000000 -r a6a46af64546 hv.cpp --- /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 +#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; +} +//--------------------------------------------------------------------------- diff -r 000000000000 -r a6a46af64546 hv.dfm --- /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 diff -r 000000000000 -r a6a46af64546 hv.dsk --- /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 + diff -r 000000000000 -r a6a46af64546 hv.h --- /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 +#include +#include +#include +//--------------------------------------------------------------------------- +class TForm14 : public TForm +{ +__published: // IDE-managed Components +private: // User declarations +public: // User declarations + __fastcall TForm14(TComponent* Owner); +}; +//--------------------------------------------------------------------------- +extern PACKAGE TForm14 *Form14; +//--------------------------------------------------------------------------- +#endif diff -r 000000000000 -r a6a46af64546 hv.res Binary file hv.res has changed diff -r 000000000000 -r a6a46af64546 multiselect.bmp Binary file multiselect.bmp has changed diff -r 000000000000 -r a6a46af64546 paneinfo.bmp Binary file paneinfo.bmp has changed diff -r 000000000000 -r a6a46af64546 spectrogram.bmp Binary file spectrogram.bmp has changed diff -r 000000000000 -r a6a46af64546 timeselect.bmp Binary file timeselect.bmp has changed diff -r 000000000000 -r a6a46af64546 timeselect.old.bmp Binary file timeselect.old.bmp has changed diff -r 000000000000 -r a6a46af64546 vcrplay.bmp Binary file vcrplay.bmp has changed diff -r 000000000000 -r a6a46af64546 vcrrecrd.bmp Binary file vcrrecrd.bmp has changed diff -r 000000000000 -r a6a46af64546 vcrrecrd2.bmp Binary file vcrrecrd2.bmp has changed diff -r 000000000000 -r a6a46af64546 vcrstop.bmp Binary file vcrstop.bmp has changed diff -r 000000000000 -r a6a46af64546 waveform.bmp Binary file waveform.bmp has changed