Mercurial > hg > hv
diff AudioPac.cpp @ 0:a6a46af64546
first upload
author | wenx <xue.wen@eecs.qmul.ac.uk> |
---|---|
date | Wed, 10 Aug 2011 14:55:38 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AudioPac.cpp Wed Aug 10 14:55:38 2011 +0100 @@ -0,0 +1,1534 @@ +/* + Harmonic Visualiser + + An audio file viewer and editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2011 Wen Xue. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. +*/ +//--------------------------------------------------------------------------- +#include <vcl.h> +#pragma hdrstop + +#include "AudioPac.h" +#include <math.h> + +#pragma package(smart_init) +//--------------------------------------------------------------------------- +void DoubleToInt(void* out, int BytesPerSample, double* in, int Count) +{ + if (BytesPerSample==1){unsigned char* out8=(unsigned char*)out; for (int k=0; k<Count; k++) *(out8++)=*(in++)+128.5;} + else if (BytesPerSample==2) {__int16* out16=(__int16*)out; for (int k=0; k<Count; k++) *(out16++)=floor(*(in++)+0.5);} + else {__pint24 out24=(__pint24)out; for (int k=0; k<Count; k++) {*(out24++)=floor(*(in++)+0.5);}} +} + +void IntToDouble(double* out, void* in, int BytesPerSample, int Count) +{ + if (BytesPerSample==1){unsigned char* in8=(unsigned char*)in; for (int k=0; k<Count; k++) *(out++)=*(in8++)-128.0;} + else if (BytesPerSample==2) {__int16* in16=(__int16*)in; for (int k=0; k<Count; k++) *(out++)=*(in16++);} + else {__pint24 in24=(__pint24)in; for (int k=0; k<Count; k++) {*(out++)=*(in24++);}} +} + +void DoubleToIntInterleave(void* out, int BytesPerSample, double* in1, double* in2, int Count) +{ + if (BytesPerSample==1) + { + unsigned char* out8=(unsigned char*)out; + for (int k=0; k<Count; k++) {*(out8++)=*(in1++)+128; *(out8++)=*(in2++)+128;} + } + else if (BytesPerSample==2) + { + __int16* out16=(__int16*)out; + for (int k=0; k<Count; k++) {*(out16++)=*(in1++); *(out16++)=*(in2++);} + } + else if (BytesPerSample==3) + { + __pint24 out24=(__pint24)out; + for (int k=0; k<Count; k++) {*(out24++)=*(in1++); *(out24++)=*(in2++); } + } +} + +void IntToDoubleInterleave(double* out1, double* out2, void* in, int BytesPerSample, int Count) +{ + if (BytesPerSample==1) + { + unsigned char* in8=(unsigned char*)in; + for (int k=0; k<Count; k++) {*(out1++)=*(in8++)-128.0; *(out2++)=*(in8++)-128.0;} + } + else if (BytesPerSample==2) + { + __int16* in16=(__int16*)in; + for (int k=0; k<Count; k++) {*(out1++)=*(in16++); *(out2++)=*(in16++);} + } + else if (BytesPerSample==3) + { + __pint24 in24=(__pint24)in; + for (int k=0; k<Count; k++) {*(out1++)=*(in24++); *(out2++)=*(in24++);} + } +} + +int IntToIntInterleave(void* dest, int bytesperunit, void* block1, void* block2, int Count) +{ + if (bytesperunit==1) + { + char* Dest=(char*)dest; + char* Block1=(char*)block1; + char* Block2=(char*)block2; + for (int i=0; i<Count; i++) + { + *(Dest++)=*(Block1++); + *(Dest++)=*(Block2++); + } + return 2*Count; + } + else if (bytesperunit==2) + { + __int16* Dest=(__int16*)dest; + __int16* Block1=(__int16*)block1; + __int16* Block2=(__int16*)block2; + for (int i=0; i<Count; i++) + { + *(Dest++)=*(Block1++); + *(Dest++)=*(Block2++); + } + return 4*Count; + } + else if (bytesperunit==3) + { + __pint24 Dest=(__pint24)dest; + __pint24 Block1=(__pint24)block1; + __pint24 Block2=(__pint24)block2; + for (int i=0; i<Count; i++) + { + *(Dest++)=*(Block1++); + *(Dest++)=*(Block2++); + } + return 6*Count; + } + else + return 0; +} + +int IntToIntInterleave(void* dest1, void* dest2, int bytesperunit, void* block, int Count) +{ + if (bytesperunit==1) + { + char* Dest1=(char*)dest1; + char* Dest2=(char*)dest2; + char* Block=(char*)block; + for (int i=0; i<Count; i++) + { + *(Dest1++)=*(Block++); + *(Dest2++)=*(Block++); + } + return 2*Count; + } + else if (bytesperunit==2) + { + __int16* Dest1=(__int16*)dest1; + __int16* Dest2=(__int16*)dest2; + __int16* Block=(__int16*)block; + for (int i=0; i<Count; i++) + { + *(Dest1++)=*(Block++); + *(Dest2++)=*(Block++); + } + return 4*Count; + } + else if (bytesperunit==2) + { + __pint24 Dest1=(__pint24)dest1; + __pint24 Dest2=(__pint24)dest2; + __pint24 Block=(__pint24)block; + for (int i=0; i<Count; i++) + { + *(Dest1++)=*(Block++); + *(Dest2++)=*(Block++); + } + return 6*Count; + } + else + return 0; +} + +int IntToIntMultiSingle(void* dest, int bytesperunit, int channels, int offset, void* block, int Count) +{ + if (channels==1) + { + memcpy(dest, &((char*)block)[offset*bytesperunit], bytesperunit*Count); + return Count; + } + else if (channels==2) + { + if (bytesperunit==1) + { + char* Dest=(char*)dest; + char* Block=&((char*)block)[offset]; + for (int i=0; i<Count; i++) + { + *(Dest++)=*Block; + Block+=2; + } + return Count; + } + else if (bytesperunit==2) + { + __int16* Dest=(__int16*)dest; + __int16* Block=(__int16*)(&((char*)block)[offset*2]); + for (int i=0; i<Count; i++) + { + *(Dest++)=*Block; + Block+=2; + } + return Count*2; + } + else if (bytesperunit==3) + { + __pint24 Dest=(__pint24)dest; + __pint24 Block=(__pint24)(&((char*)block)[offset*3]); + for (int i=0; i<Count; i++) + { + *(Dest++)=*Block; + Block+=2; + } + return Count*3; + } + else + return 0; + } + else + { + if (bytesperunit==1) + { + char* Dest=(char*)dest; + char* Block=&((char*)block)[offset]; + for (int i=0; i<Count; i++) + { + *(Dest++)=*Block; + Block+=channels; + } + return Count; + } + else if (bytesperunit==2) + { + __int16* Dest=(__int16*)dest; + __int16* Block=(__int16*)(&((char*)block)[offset*2]); + for (int i=0; i<Count; i++) + { + *(Dest++)=*Block; + Block+=channels; + } + return Count*2; + } + else if (bytesperunit==3) + { + __pint24 Dest=(__pint24)dest; + __pint24 Block=(__pint24)(&((char*)block)[offset*3]); + for (int i=0; i<Count; i++) + { + *(Dest++)=*Block; + Block+=channels; + } + return Count*3; + } + else return 0; + } +} + +int IntToIntMultiChannel(int C, void** dest, int bytesperunit, int channels, void* block, int count) +{ + int tail=channels-C; + if (bytesperunit==1) + { + char* data=(char*)block; + for (int i=0; i<count; i++) + { + for (int c=0; c<C; c++) *(((char*)dest[c])++)=*(data++); + data=&data[tail]; + } + return count; + } + else if (bytesperunit==2) + { + __int16* data=(__int16*)block; + for (int i=0; i<count; i++) + { + for (int c=0; c<C; c++) *(((__int16*)dest[c])++)=*(data++); + data=&data[tail]; + } + return count*2; + } + else if (bytesperunit==3) + { + __pint24 data=(__pint24)block; + for (int i=0; i<count; i++) + { + for (int c=0; c<C; c++) {*(((__pint24)dest[c])++)=*(data++); } + data=&data[tail]; + } + return count*3; + } + else + return 0; +} + +__fastcall TAttachFileStream::TAttachFileStream(TFileStream* AFile) + : TStream() +{ + File=AFile; + StartOffset=0; + EndOffset=0; +} + +__fastcall TAttachFileStream::~TAttachFileStream() +{ + delete File; +} + +int __fastcall TAttachFileStream::Read(void *Buffer, int Count) +{ + return File->Read(Buffer, Count); +} + +int __fastcall TAttachFileStream::Seek(int AnOffset, Word Origin) +{ + if (!File) return 0; + if (Origin==soFromBeginning) + return File->Seek(AnOffset+StartOffset, soFromBeginning)-StartOffset; + else if (Origin==soFromCurrent) + return File->Seek(AnOffset, soFromCurrent)-StartOffset; + else + return File->Seek(AnOffset+EndOffset, soFromEnd)-StartOffset; +} + +__int64 __fastcall TAttachFileStream::Seek(const __int64 AnOffset, TSeekOrigin Origin) +{ + return Seek((int)AnOffset, (Word)Origin); +} + +int __fastcall TAttachFileStream::Write(const void *Buffer, int Count) +{ + return File->Write(Buffer, Count); +} + +//--------------------------------------------------------------------------- +// ValidCtrCheck is used to assure that the components created do not have +// any pure virtual functions. +// + +static inline void ValidCtrCheck(TWaveAudio *) +{ + new TWaveAudio(NULL); +} +//--------------------------------------------------------------------------- +__fastcall TWaveAudio::~TWaveAudio() +{ + delete FMemoryStream; + delete FFileStream; + DeallocateHWnd(HWndOut); + DeallocateHWnd(HWndIn); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::Clear(TObject* Sender) +{ + if (!FUseMemoryStream) + { + FUseMemoryStream=true; + delete FFileStream->File; + FFileStream->File=0; + FFileName=""; + } + FMemoryStream->Position=0; + FMemoryStream->Size=0; + if (FOnAudioChange) FOnAudioChange(this); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::CloseFile(bool Close) +{ + if (UseMemoryStream) return; + int Position=FFileStream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenWrite); + SaveHeader(FFileStream->File); + delete FFileStream->File; + FFileStream->File=0; + if (!Close) + { + FFileStream->File=new TFileStream(FFileName, fmOpenRead); + FFileStream->Position=Position; + } +} + +//--------------------------------------------------------------------------- +void TWaveAudio::CopyFrom(TStream* AStream, int Count) +{ + WaveStream->CopyFrom(AStream, Count); + if (FOnAudioChange) FOnAudioChange(this); +} + +void TWaveAudio::CopyFrom(TWaveAudio* AWaveAudio, int Count) +{ + WaveStream->CopyFrom(AWaveAudio->WaveStream, Count); + if (FOnAudioChange) FOnAudioChange(this); +} + +//--------------------------------------------------------------------------- +void TWaveAudio::CopySamplesFrom(TStream* AStream, int Count) +{ + WaveStream->CopyFrom(AStream, Count*FChannels*(BitsPerSample/8)); + if (FOnAudioChange) FOnAudioChange(this); +} + +void TWaveAudio::CopySamplesFrom(TWaveAudio* AWaveAudio, int Count) +{ + WaveStream->CopyFrom(AWaveAudio->WaveStream, Count*FChannels*(BitsPerSample/8)); + if (FOnAudioChange) FOnAudioChange(this); +} + +//--------------------------------------------------------------------------- +void TWaveAudio::CreateFile(AnsiString FileName) +{ + UseMemoryStream=false; + + TFileStream* OpenFile=new TFileStream(FileName, fmCreate); + SaveHeader(OpenFile); + delete OpenFile; + + delete FFileStream->File; + FFileStream->File=new TFileStream(FileName, fmOpenReadWrite); + FFileStream->StartOffset=FFileStream->File->Size; + FFileStream->Position=0; + FFileName=FileName; +} + +//--------------------------------------------------------------------------- +int __fastcall TWaveAudio::FillBlock(void* Block) +{ + return Stream->Read(Block, FBlockSize); +} + +//--------------------------------------------------------------------------- +int __fastcall TWaveAudio::GetBytesPerSample() +{ + return FBitsPerSample/8; +} + +//--------------------------------------------------------------------------- +__int32 __fastcall TWaveAudio::GetLength() +{ + return Stream->Size/FBlockAlign; +} + +//--------------------------------------------------------------------------- +TStream* __fastcall TWaveAudio::GetStream() +{ + if (FUseMemoryStream) return FMemoryStream; + else return FFileStream; +} + +//--------------------------------------------------------------------------- +void TWaveAudio::GetWaveProperties(TWaveAudio* WaveAudio1) +{ + FFormatTag=WaveAudio1->FormatTag; + SamplesPerSec=WaveAudio1->SamplesPerSec; + BitsPerSample=WaveAudio1->BitsPerSample; + Channels=WaveAudio1->Channels; + BlockSize=WaveAudio1->BlockSize; +} + +//--------------------------------------------------------------------------- +bool __fastcall TWaveAudio::ReadHeader(TStream* AStream, __int32& length, bool allowunfinisheddata) +{ + bool success=true; + char s[10]; + __int32 headerlen; + __int32 headerstart; + + __int16 formattag; + __int16 channels; + __int32 samplespersec; + __int32 avgbytespersec; + __int16 blockalign; + __int16 bitspersample; + + int rc=AStream->Read(s, 4); s[4]=0; + success=success&&(rc==4)&&!strcmp(s, "RIFF"); + if (!success) return success; + + rc=AStream->Read(&length, 4); + success=success&&(rc==4); + + rc=AStream->Read(s, 4); if (rc!=4) return false; + s[4]=0; + success=success&&(rc==4)&&!strcmp(s, "WAVE"); + if (!success) return success; + + rc=AStream->Read(s, 4); s[4]=0; + while(rc==4 && strcmp(s, "fmt ")) + { + AStream->Read(&length, 4); + AStream->Seek(length, soFromCurrent); + rc=AStream->Read(s, 4); s[4]=0; + } + success=success&&(rc==4); + if (!success) return success; + + rc=AStream->Read(&headerlen, 4); + headerstart=AStream->Position; + + AStream->Read(&formattag, 2); + AStream->Read(&channels, 2); + AStream->Read(&samplespersec, 4); + AStream->Read(&avgbytespersec, 4); + AStream->Read(&blockalign, 2); + AStream->Read(&bitspersample, 2); + success=success&&(formattag==1); + success=success&&(rc==4)&&(blockalign*8==channels*bitspersample); + success=success&&(avgbytespersec==samplespersec*blockalign); + + if (!success) return success; + AStream->Seek(headerlen+headerstart, soFromBeginning); + + rc=AStream->Read(s, 4); s[4]=0; + while(rc==4 && strcmp(s, "data")) + { + AStream->Read(&length, 4); + AStream->Seek(length, soFromCurrent); + rc=AStream->Read(s, 4); s[4]=0; + } + success=success&&(rc==4); + if (!success) return success; + + rc=AStream->Read(&length, 4); + success=success&&(rc==4); + if (!success) return success; + + if (AStream->Position+length>AStream->Size) + { + if (allowunfinisheddata) length=(AStream->Size-AStream->Position)/blockalign*blockalign; + else success=false; + } + if (!success) return success; + + FFormatTag=formattag; + FChannels=channels; + FSamplesPerSec=samplespersec; + FAvgBytesPerSec=avgbytespersec; + FBlockAlign=blockalign; + FBitsPerSample=bitspersample; + + return success; +} + +void TWaveAudio::InsertFromFile(AnsiString FileName) +{ + TFileStream* OpenFile=new TFileStream(FileName, fmOpenRead|fmShareDenyNone); + + __int32 length; + bool success=ReadHeader(OpenFile, length); + + if (success) + { + FFileName=FileName; + if (FUseMemoryStream) + { + if (length>0) + { + FMemoryStream->Size=length; + OpenFile->Read(FMemoryStream->Memory, length); + } + delete OpenFile; + } + else + { + delete FFileStream->File; + FFileStream->File=OpenFile; + FFileStream->StartOffset=OpenFile->Position; + FFileStream->EndOffset=OpenFile->Position+length-OpenFile->Size; + } + + if (FStreamLimit>0 && Stream->Size>=FStreamLimit && OnStreamFull) OnStreamFull(this); + if (FOnAudioChange) FOnAudioChange(this); + } + else + { + delete OpenFile; + throw EReadError("PCM error ecountered reading "+FileName); + } +} + +//--------------------------------------------------------------------------- +bool TWaveAudio::IsValidWave(AnsiString FileName) +{ + bool success=true; + char s[10]; + __int32 headerlen; + __int32 headerstart; + + __int16 formattag; + __int16 channels; + __int32 samplespersec; + __int32 avgbytespersec; + __int16 blockalign; + __int16 bitspersample; + __int32 length; + + + TFileStream* OpenFile=new TFileStream(FileName,fmOpenRead|fmShareDenyNone); + + OpenFile->Read(s, 4); + s[4]=0; + success=success&&!strcmp(s, "RIFF"); + + OpenFile->Read(&length, 4); + success=success&&(length+OpenFile->Position==OpenFile->Size); + + OpenFile->Read(s, 8); + s[8]=0; + success=success&&!strcmp(s, "WAVEfmt "); + + OpenFile->Read(&headerlen, 4); + headerstart=OpenFile->Position; + + OpenFile->Read(&formattag, 2); + success=success&&(formattag==1); + + OpenFile->Read(&channels, 2); + OpenFile->Read(&samplespersec, 4); + OpenFile->Read(&avgbytespersec, 4); + OpenFile->Read(&blockalign, 2); + OpenFile->Read(&bitspersample, 2); + success=success&&(blockalign*8==channels*bitspersample); + success=success&&(avgbytespersec==samplespersec*blockalign); + + OpenFile->Seek(headerlen+headerstart, soFromBeginning); + OpenFile->Read(s, 4); + s[4]=0; + success=success&&!strcmp(s, "data"); + + OpenFile->Read(&length, 4); + success=success&&(length+OpenFile->Position==OpenFile->Size); + + delete OpenFile; + return success; +} + +//--------------------------------------------------------------------------- +void TWaveAudio::LoadFromFile(AnsiString FileName) +{ + if (FOnBeforeLoad) FOnBeforeLoad(this); + if (FAutoUseMemoryStream) UseMemoryStream=false; + if (FUseMemoryStream) FMemoryStream->Clear(); + InsertFromFile(FileName); + if (FOnLoad) FOnLoad(this); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::OnWimClose(TMessage& Message) +{ + waveInUnprepareHeader(WaveIn,WaveHdr1,sizeof(WAVEHDR)); + waveInUnprepareHeader(WaveIn,WaveHdr2,sizeof(WAVEHDR)); + delete WaveHdr1; + delete WaveHdr2; + delete[] Buffer1; + delete[] Buffer2; + FRecording=false; + if (ResetInStream && FOnStreamFull) + FOnStreamFull(this); + ResetInStream=false; + ResetInUser=false; + if (FOnRecordingDone) FOnRecordingDone(this); + if (FOnAudioChange) FOnAudioChange(this); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::OnWimData(TMessage& Message) +{ + WAVEHDR* WaveHdr=(WAVEHDR*)Message.LParam; + if (!FRecording) return; + + if (!ResetInStream) + { + ReleaseBlock(WaveHdr->lpData,WaveHdr->dwBytesRecorded); + if (FStreamLimit>0 && Stream->Size>=FStreamLimit) + ResetInStream=true; + waveInAddBuffer(WaveIn,WaveHdr,sizeof(WAVEHDR)); + if (FOnInAddBuffer) FOnInAddBuffer(this); + if (ResetInUser) + { + waveInReset(WaveIn); + waveInClose(WaveIn); + } + } + else + { + waveInReset(WaveIn); + waveInClose(WaveIn); + } +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::OnWimOpen(TMessage& Message) +{ +// +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::OnWomClose(TMessage& Message) +{ + waveOutUnprepareHeader(WaveOut,WaveHdr1,sizeof(WAVEHDR)); + waveOutUnprepareHeader(WaveOut,WaveHdr2,sizeof(WAVEHDR)); + delete WaveHdr1; + delete WaveHdr2; + delete[] Buffer1; + delete[] Buffer2; + WaveHdr1=WaveHdr2=0; + Buffer1=Buffer2=0; + FPlaying=false; + FPaused=false; + ResetOut=false; + ResetOutUser=false; + if (FOnPlaybackProgress) FOnPlaybackProgress(this, 1); + if (FOnPlaybackProg) FOnPlaybackProg(this, -2); + + if (OnPlaybackDone) OnPlaybackDone(this); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::OnWomDone(TMessage& Message) +{ + WAVEHDR* WaveHdr=(WAVEHDR*)Message.LParam; + + if (ResetOut) + { + if (WaveHdr->dwBufferLength!=(unsigned)FBlockSize) + { + waveOutClose(WaveOut); + } + } + else + { + int rc; + + if (ResetOutUser) rc=0; + else rc=FillBlock(WaveHdr->lpData); + + if (rc!=FBlockSize) + { + ResetOut=true; + WaveHdr->dwBufferLength=rc; + if (BitsPerSample==8) memset(&WaveHdr->lpData[rc],0x80,FBlockSize-rc); + else memset(&WaveHdr->lpData[rc],0,FBlockSize-rc); + waveOutUnprepareHeader(WaveOut, WaveHdr, sizeof(WAVEHDR)); + waveOutPrepareHeader(WaveOut, WaveHdr, sizeof(WAVEHDR)); + } + waveOutWrite(WaveOut,WaveHdr,sizeof(WAVEHDR)); + if (FOnPlaybackProgress) + FOnPlaybackProgress(this, (Stream->Position-FBlockSize)*1.0/Stream->Size); + if (FOnPlaybackProg) + FOnPlaybackProg(this, Stream->Position-FBlockSize); + if (FOnOutWrite) FOnOutWrite(this); + } +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::OnWomOpen(TMessage& Message) +{ +// +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::Pause(TObject* Sender) +{ + if (FPlaying) + { + waveOutPause(WaveOut); + FPaused=true; + } +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::PausePlayback(TObject* Sender) +{ + if (Playing) ResetOutUser=true; +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::PauseRecording(TObject* Sender) +{ + if (Recording) ResetInUser=true; +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::Play(TObject* Sender) +{ + Rewind(this); + StartPlayback(this); +} + +void __fastcall TWaveAudio::Play(TNotifyEvent AnOnPlaybackDone) +{ + Rewind(this); + OnPlaybackDone=AnOnPlaybackDone; + StartPlayback(this); +} + +//--------------------------------------------------------------------------- +int __fastcall TWaveAudio::Read(void* Buffer, int Count) +{ + return Stream->Read(Buffer, Count); +} + +int __fastcall TWaveAudio::ReadSamples(void* Buffer, int Count) +{ + return Stream->Read(Buffer, Count*FChannels*(BitsPerSample/8)); +} + +int __fastcall TWaveAudio::ReadSamples(double* Buffer, int Count) +{ + int FBytesPerSample=FBitsPerSample/8; + int countavailable=(Stream->Size-Stream->Position)/FBytesPerSample; + if (Count>countavailable) Count=countavailable; + if (FUseMemoryStream) + { + int Position=FMemoryStream->Position; + IntToDouble(Buffer, &((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Count); + FMemoryStream->Position=Position+Count*FBytesPerSample; + } + else + { + void *data=new char[FBlockSize]; + double *Data=Buffer; + int CountPF=FBlockSize/FBytesPerSample; + int Fr=(Count/CountPF); + for (int i=0; i<Fr; i++) + { + Stream->Read(data, FBlockSize); + IntToDouble(Data, data, FBytesPerSample, CountPF); + Data=&Data[CountPF]; + } + int CountLastF=Count%CountPF; + int lastblocksize=CountLastF*FBytesPerSample; + Stream->Read(data, lastblocksize); + IntToDouble(Data, data, FBytesPerSample, CountLastF); + delete[] data; + } + + return Count*FBytesPerSample; +} + +int __fastcall TWaveAudio::ReadSamplesInterleave(void* Buffer1, void* Buffer2, int Count) +{ + int FBytesPerSample=FBitsPerSample/8; + int SampleSize=FBytesPerSample*2; + int countavailable=(Stream->Size-Stream->Position)/SampleSize; + if (Count>countavailable) Count=countavailable; + if (FUseMemoryStream) + { + int Position=FMemoryStream->Position; + IntToIntInterleave(Buffer1, Buffer2, FBytesPerSample, &((char*)FMemoryStream->Memory)[Position], Count); + FMemoryStream->Position=Position+Count*SampleSize; + } + else + { + void *Data1=Buffer1, *Data2=Buffer2, *data=new char[FBlockSize]; + int HBlockSize=FBlockSize/2, CountPF=FBlockSize/SampleSize; + int Fr=Count/CountPF; + for (int i=0; i<Fr; i++) + { + Stream->Read(data, FBlockSize); + IntToIntInterleave(Data1, Data2, FBytesPerSample, data, CountPF); + Data1=&((char*)Data1)[HBlockSize], Data2=&((char*)Data2)[HBlockSize]; + } + int CountLastF=Count%CountPF; + int lastblocksize=CountLastF*SampleSize; + Stream->Read(data, lastblocksize); + IntToIntInterleave(Data1, Data2, FBytesPerSample, data, CountLastF); + delete[] data; + } + return Count*SampleSize; +} + +int __fastcall TWaveAudio::ReadSamplesInterleave(double* Buffer1, double* Buffer2, int Count) +{ + int FBytesPerSample=FBitsPerSample/8; + int SampleSize=FBytesPerSample*2; + int countavailable=(Stream->Size-Stream->Position)/SampleSize; + if (Count>countavailable) Count=countavailable; + if (FUseMemoryStream) + { + int Position=FMemoryStream->Position; + IntToDoubleInterleave(Buffer1, Buffer2, &((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Count); + FMemoryStream->Position=Position+Count*SampleSize; + } + else + { + double *Data1=Buffer1, *Data2=Buffer2; + void *data=new char[FBlockSize]; + int CountPF=FBlockSize/SampleSize; + int Fr=Count/CountPF; + for (int i=0; i<Fr; i++) + { + Stream->Read(data, FBlockSize); + IntToDoubleInterleave(Data1, Data2, data, FBytesPerSample, CountPF); + Data1=&Data1[CountPF], Data2=&Data2[CountPF]; + } + int CountLastF=Count%CountPF; + int lastblocksize=CountLastF*SampleSize; + Stream->Read(data, lastblocksize); + IntToDoubleInterleave(Data1, Data2, data, FBytesPerSample, CountLastF); + delete[] data; + } + return Count*SampleSize; +} + +int __fastcall TWaveAudio::ReadSamplesMultiSingle(void* Buffer, int Channel, int Count) +{ + int FBytesPerSample=FBitsPerSample/8; + int SampleSize=FBytesPerSample*FChannels; + int countavailable=(Stream->Size-Stream->Position)/SampleSize; + if (Count>countavailable) Count=countavailable; + if (FUseMemoryStream) + { + int Position=FMemoryStream->Position; + IntToIntMultiSingle(Buffer, FBytesPerSample, FChannels, Channel, &((char*)FMemoryStream->Memory)[Position], Count); + FMemoryStream->Position=Position+Count*SampleSize; + } + else + { + int CountPF=FBlockSize/SampleSize; + int ReadSize=CountPF*SampleSize, WriteSize=CountPF*FBytesPerSample; + int Fr=Count/CountPF; + void *Data=Buffer, *data=new char[ReadSize]; + for (int i=0; i<Fr; i++) + { + Stream->Read(data, ReadSize); + IntToIntMultiSingle(Data, FBytesPerSample, FChannels, Channel, data, CountPF); + Data=&((char*)Data)[WriteSize]; + } + int CountLastF=Count%CountPF; + ReadSize=CountLastF*SampleSize; + Stream->Read(data, ReadSize); + IntToIntMultiSingle(Data, FBytesPerSample, FChannels, Channel, data, CountLastF); + delete[] data; + } + return Count*FBytesPerSample; +} + +int __fastcall TWaveAudio::ReadSamplesMultiChannel(int C, void** Buffer, int Count) +{ + if (C>FChannels) C=FChannels; + int FBytesPerSample=FBitsPerSample/8; + int SampleSize=FBytesPerSample*FChannels; + int countavailable=(Stream->Size-Stream->Position)/SampleSize; + if (Count>countavailable) Count=countavailable; + if (FUseMemoryStream) + { + int Position=FMemoryStream->Position; + IntToIntMultiChannel(C, Buffer, FBytesPerSample, FChannels, &((char*)FMemoryStream->Memory)[Position], Count); + FMemoryStream->Position=Position+Count*SampleSize; + } + else + { + int CountPF=FBlockSize/SampleSize; + int ReadSize=CountPF*SampleSize, WriteSize=CountPF*FBytesPerSample; + int Fr=Count/CountPF; + void* data=new char[ReadSize]; + for (int i=0; i<Fr; i++) + { + Stream->Read(data, ReadSize); + IntToIntMultiChannel(C, Buffer, FBytesPerSample, FChannels, data, CountPF); + for (int c=0; c<C; c++) Buffer[c]=&((char*)Buffer[c])[WriteSize]; + } + int CountLastF=Count*CountPF; + ReadSize=CountLastF*SampleSize; + Stream->Read(data, ReadSize); + IntToIntMultiChannel(C, Buffer, FBytesPerSample, FChannels, data, CountLastF); + } + return Count*SampleSize; +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::ReleaseBlock(void* Block, int BytesRecorded) +{ + Stream->Write(Block, BytesRecorded); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::Restart(TObject* Sender) +{ + if (FPlaying) + { + waveOutRestart(WaveOut); + FPaused=false; + } +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::Rewind(TObject* Sender) +{ + Stream->Seek(0,soFromBeginning); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::SaveHeader(TStream* AStream) +{ + __int32 s32; + __int16 s16; + + AStream->Write("RIFF",4); + s32=Stream->Size+38; + AStream->Write(&s32,4); + AStream->Write("WAVEfmt ",8); + s32=0x12; + AStream->Write(&s32,4); + s16=FFormatTag; + AStream->Write(&s16,2); + s16=FChannels; + AStream->Write(&s16,2); + s32=FSamplesPerSec; + AStream->Write(&s32,4); + s32=FAvgBytesPerSec; + AStream->Write(&s32,4); + s16=FBlockAlign; + AStream->Write(&s16,2); + s16=FBitsPerSample; + AStream->Write(&s16,2); + s16=0; + AStream->Write(&s16,2); + AStream->Write("data",4); + s32=Stream->Size; + AStream->Write(&s32,4); +} + +void __fastcall TWaveAudio::SaveToFile(AnsiString FileName) +{ + TFileStream& SaveFile=*new TFileStream(FileName, fmCreate); + SaveHeader(&SaveFile); + + if (FUseMemoryStream) + ((TMemoryStream*)Stream)->SaveToStream(&SaveFile); + else + SaveFile.CopyFrom(Stream, 0); + delete &SaveFile; +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::Seek(int Offset, WORD Origin) +{ + WaveStream->Seek(Offset, Origin); +} + +void __fastcall TWaveAudio::SeekSamples(int Offset, WORD Origin) +{ + WaveStream->Seek(Offset*FChannels*(BitsPerSample/8), Origin); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::SetBitsPerSample(__int16 ABitsPerSample) +{ + if (ABitsPerSample!=8 && ABitsPerSample!=16 && ABitsPerSample!=24) return; + FBitsPerSample=ABitsPerSample; + FAvgBytesPerSec=FSamplesPerSec*FBitsPerSample*FChannels/8; + FBlockAlign=FBitsPerSample*FChannels/8; +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::SetBlockSize(int ABlockSize) +{ + FBlockSize=ABlockSize; +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::SetChannels(__int16 AChannels) +{ + if (AChannels!=1 && AChannels!=2) return; + FChannels=AChannels; + FAvgBytesPerSec=FSamplesPerSec*FBitsPerSample*FChannels/8; + FBlockAlign=FBitsPerSample*FChannels/8; +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::SetLVolume(unsigned __int16 ALVolume) +{ + if (ALVolume!=FLVolume) + { + FLVolume=ALVolume; + if (FPlaying) SetVolume(); + } +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::SetRVolume(unsigned __int16 ARVolume) +{ + if (ARVolume!=FRVolume) + { + FRVolume=ARVolume; + if (FPlaying) SetVolume(); + } +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::SetSamplesPerSec(__int32 ASamplesPerSec) +{ + FSamplesPerSec=ASamplesPerSec; + FAvgBytesPerSec=FSamplesPerSec*FBitsPerSample*FChannels/8; +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::SetStreamLimit(int AStreamLimit) +{ + if (AStreamLimit>0 && Stream->Size>AStreamLimit) + { + if (OnStreamLimitFailure) OnStreamLimitFailure(this); + return; + } + FStreamLimit=AStreamLimit; +} + +void __fastcall TWaveAudio::SetUseMemoryStream(bool AUseMemoryStream) +{ + if (FUseMemoryStream!=AUseMemoryStream) + { + FUseMemoryStream=AUseMemoryStream; + } +} + +//--------------------------------------------------------------------------- +MMRESULT __fastcall TWaveAudio::SetVolume(void) +{ + unsigned __int32 Volume=FRVolume; + Volume=Volume<<16; + Volume+=FLVolume; + return waveOutSetVolume(WaveOut, Volume); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::StartPlayback(TObject* Sender) +{ + if (FPlaying) return; + + WAVEFORMATEX wfx; + wfx.wFormatTag=FFormatTag; + wfx.nChannels=FChannels; + wfx.nSamplesPerSec=FSamplesPerSec; + wfx.nAvgBytesPerSec=FAvgBytesPerSec; + wfx.nBlockAlign=FBlockAlign; + wfx.wBitsPerSample=FBitsPerSample; + wfx.cbSize=FcbSize; + + if (waveOutOpen(&WaveOut,WAVE_MAPPER,&wfx,(DWORD)HWndOut, NULL, + CALLBACK_WINDOW)!=MMSYSERR_NOERROR) + { + throw EWriteError("TWaveAudio Err: Failed opening device WaveOut"); + } + + SetVolume(); + + Buffer1=new char[FBlockSize]; + Buffer2=new char[FBlockSize]; + WaveHdr1=new WAVEHDR; + WaveHdr2=new WAVEHDR; + + WaveHdr1->lpData=(char*)Buffer1; + WaveHdr1->dwBufferLength=FBlockSize; + WaveHdr1->dwBytesRecorded=0; + WaveHdr1->dwUser=0; + WaveHdr1->dwFlags=0; + WaveHdr1->dwLoops=1; + WaveHdr1->lpNext=NULL; + WaveHdr1->reserved=0; + + WaveHdr2->lpData=(char*)Buffer2; + WaveHdr2->dwBufferLength=FBlockSize; + WaveHdr2->dwBytesRecorded=0; + WaveHdr2->dwUser=0; + WaveHdr2->dwFlags=0; + WaveHdr2->dwLoops=1; + WaveHdr2->lpNext=NULL; + WaveHdr2->reserved=0; + + int rc; + + ResetOut=false; + ResetOutUser=false; + + rc=(FillBlock(WaveHdr1->lpData)); + if (rc!=FBlockSize) + { + if (BitsPerSample==8) memset(&WaveHdr1->lpData[rc],0x80,FBlockSize-rc); + else memset(&WaveHdr1->lpData[rc],0,FBlockSize-rc); + WaveHdr1->dwBufferLength=rc; + ResetOut=true; + } + waveOutPrepareHeader(WaveOut,WaveHdr1,sizeof(WAVEHDR)); + waveOutWrite(WaveOut,WaveHdr1,sizeof(WAVEHDR)); + + if (FOnPlaybackProgress) + FOnPlaybackProgress(this, 0); + if (FOnPlaybackProg) + FOnPlaybackProg(this, 0); + + if (rc==BlockSize) + { + rc=(FillBlock(WaveHdr2->lpData)); + if (rc!=FBlockSize) + { + if (BitsPerSample==8) memset(&WaveHdr2->lpData[rc],0x80,FBlockSize-rc); + else memset(&WaveHdr2->lpData[rc],0,FBlockSize-rc); + WaveHdr2->dwBufferLength=rc; + ResetOut=true; + } + + waveOutPrepareHeader(WaveOut,WaveHdr2,sizeof(WAVEHDR)); + waveOutWrite(WaveOut,WaveHdr2,sizeof(WAVEHDR)); + + if (FOnPlaybackProgress) + FOnPlaybackProgress(this, (Stream->Position-FBlockSize)*1.0/Stream->Size); + if (FOnPlaybackProg) + FOnPlaybackProg(this, Stream->Position-FBlockSize); + + } + FPlaying=true; + if (FOnStartPlayback) FOnStartPlayback(this); +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::StartRecording(TObject* Sender) +{ + if (FRecording) return; + + WAVEFORMATEX wfx; + wfx.wFormatTag=FFormatTag; + wfx.nChannels=FChannels; + wfx.nSamplesPerSec=FSamplesPerSec; + wfx.nAvgBytesPerSec=FAvgBytesPerSec; + wfx.nBlockAlign=FBlockAlign; + wfx.wBitsPerSample=FBitsPerSample; + wfx.cbSize=FcbSize; + + MMRESULT tr=waveInOpen(&WaveIn, WAVE_MAPPER, &wfx, (unsigned long)HWndIn, NULL, + CALLBACK_WINDOW); + if (tr!=MMSYSERR_NOERROR && tr!=MMSYSERR_ALLOCATED) + { + throw EReadError("TWaveAudio err: Failed opening device WaveIn"); + } + + Buffer1=new char[FBlockSize]; + Buffer2=new char[FBlockSize]; + WaveHdr1=new WAVEHDR; + WaveHdr2=new WAVEHDR; + + WaveHdr1->lpData=(char*)Buffer1; + WaveHdr1->dwBufferLength=FBlockSize; + WaveHdr1->dwBytesRecorded=0; + WaveHdr1->dwUser=0; + WaveHdr1->dwFlags=0; + WaveHdr1->dwLoops=1; + WaveHdr1->lpNext=NULL; + WaveHdr1->reserved=0; + + waveInPrepareHeader(WaveIn,WaveHdr1,sizeof(WAVEHDR)); + + WaveHdr2->lpData=(char*)Buffer2; + WaveHdr2->dwBufferLength=FBlockSize; + WaveHdr2->dwBytesRecorded=0; + WaveHdr2->dwUser=0; + WaveHdr2->dwFlags=0; + WaveHdr2->dwLoops=1; + WaveHdr2->lpNext=NULL; + WaveHdr2->reserved=0; + + waveInPrepareHeader(WaveIn,WaveHdr2,sizeof(WAVEHDR)); + + waveInAddBuffer(WaveIn,WaveHdr1,sizeof(WAVEHDR)); + waveInAddBuffer(WaveIn,WaveHdr2,sizeof(WAVEHDR)); + + ResetInStream=false; + ResetInUser=false; + FRecording=true; + + waveInStart(WaveIn); + + if (FOnStartRecording) FOnStartRecording(this); +} + +//--------------------------------------------------------------------------- +__fastcall TWaveAudio::TWaveAudio(TComponent* Owner) + : TComponent(Owner) +{ + FBlockSize=12288; + FStreamLimit=0; + FUseMemoryStream=true; + FAutoUseMemoryStream=true; + FMemoryStream=new TMemoryStream; + FFileStream=new TAttachFileStream(NULL); + + FPlaying=false; + FRecording=false; + FPaused=false; + + FOnAudioChange=0; + FOnStartPlayback=0; + FOnStartRecording=0; + FOnPlaybackDone=0; + FOnRecordingDone=0; + FOnStreamLimitFailure=0; + FOnStreamFull=0; + FOnPlaybackProgress=0; + FOnPlaybackProg=0; + FOnInAddBuffer=0; + FOnOutWrite=0; + + FSamplesPerSec=44100; + FBitsPerSample=16; + FChannels=1; + FFileName=""; + + FFormatTag=WAVE_FORMAT_PCM; + FcbSize=0; //ignored for PCM + FAvgBytesPerSec=FSamplesPerSec*FBitsPerSample*FChannels/8; + FBlockAlign=FBitsPerSample*FChannels/8; + + HWndOut=AllocateHWnd(WaveOutProc); + HWndIn=AllocateHWnd(WaveInProc); + + unsigned long Volume; + waveOutGetVolume((void *)WAVE_MAPPER, &Volume); + FLVolume=Volume&0x0000FFFF; + FRVolume=Volume>>16; +} + + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::WaveInProc(TMessage& Message) +{ + switch(Message.Msg) + { + case MM_WIM_OPEN: OnWimOpen(Message); break; + case MM_WIM_DATA: OnWimData(Message); break; + case MM_WIM_CLOSE: OnWimClose(Message); break; + } +} + +//--------------------------------------------------------------------------- +void __fastcall TWaveAudio::WaveOutProc(TMessage& Message) +{ + switch(Message.Msg) + { + case MM_WOM_OPEN: OnWomOpen(Message); break; + case MM_WOM_DONE: OnWomDone(Message); break; + case MM_WOM_CLOSE: OnWomClose(Message); break; + } +} + +//--------------------------------------------------------------------------- +int __fastcall TWaveAudio::Write(void* Buffer, int Count) +{ + if (!FUseMemoryStream) + { + int Position=FFileStream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenWrite); + FFileStream->Position=Position; + } + int result=Stream->Write(Buffer, Count); + if (!FUseMemoryStream) + { + int Position=FFileStream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenRead); + FFileStream->Position=Position; + } + if (FOnAudioChange) FOnAudioChange(this); + return result; +} + +int __fastcall TWaveAudio::WriteSamples(void* Buffer, int Count) +{ + if (!FUseMemoryStream) + { + int Position=FFileStream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenWrite); + FFileStream->Position=Position; + } + int result=Stream->Write(Buffer, Count*FChannels*FBitsPerSample/8); + if (!FUseMemoryStream) + { + int Position=FFileStream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenRead); + FFileStream->Position=Position; + } + if (FOnAudioChange) FOnAudioChange(this); + return result; +} + +int __fastcall TWaveAudio::WriteSamples(double* Buffer, int Count) +{ + int result=0; + if (!FUseMemoryStream) + { + int Position=FFileStream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenWrite); + FFileStream->Position=Position; + } + + int FBytesPerSample=FBitsPerSample/8; + if (FUseMemoryStream) + { + int Position=FMemoryStream->Position; + result=Count*FBytesPerSample; + if (FMemoryStream->Size<Position+result) FMemoryStream->Size=Position+result; + DoubleToInt(&((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Buffer, Count); + FMemoryStream->Position=Position+result; + } + else + { + void *data=new char[FBlockSize]; + double *Data=Buffer; + int CountPF=FBlockSize/FBytesPerSample; + int Fr=(Count/CountPF); + for (int i=0; i<Fr; i++) + { + DoubleToInt(data, FBytesPerSample, Data, CountPF); + result+=Stream->Write(data, FBlockSize); + Data=&Data[CountPF]; + } + int CountLastF=Count%CountPF; + int lastblocksize=CountLastF*FBytesPerSample; + DoubleToInt(data, FBytesPerSample, Data, CountLastF); + result+=Stream->Write(data, lastblocksize); + delete[] data; + } + + if (!FUseMemoryStream) + { + int Position=FFileStream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenRead); + FFileStream->Position=Position; + } + if (FOnAudioChange) FOnAudioChange(this); + return result; +} + +int __fastcall TWaveAudio::WriteSamplesInterleave(void* Buffer1, void* Buffer2, int Count) +{ + int FBytesPerSample=FBitsPerSample/8; + int SampleSize=FBytesPerSample*2; + if (FUseMemoryStream) + { + int Position=FMemoryStream->Position; + int countavailable=(FMemoryStream->Size-Position)/SampleSize; + if (countavailable<Count) FMemoryStream->Size=Position+SampleSize*Count; + IntToIntInterleave(&((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Buffer1, Buffer2, Count); + FMemoryStream->Position=Position+SampleSize*Count; + } + else + { + int Position=Stream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenWrite); + FFileStream->Position=Position; + + int CountPF=FBlockSize/SampleSize, HBlockSize=FBlockSize/2; + int Fr=Count/CountPF; + void *Data1=Buffer1, *Data2=Buffer2, *data=new char[FBlockSize]; + for (int i=0; i<Fr; i++) + { + IntToIntInterleave(data, FBytesPerSample, Data1, Data2, CountPF); + Stream->Write(data, FBlockSize); + Data1=&((char*)Data1)[HBlockSize], Data2=&((char*)Data2)[HBlockSize]; + } + int CountLastF=Count%CountPF; + int lastblocksize=CountLastF*SampleSize; + IntToIntInterleave(data, FBytesPerSample, Data1, Data2, CountLastF); + Stream->Write(data, lastblocksize); + + Position=Stream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenRead); + FFileStream->Position=Position; + } + if (FOnAudioChange) FOnAudioChange(this); + return Count*SampleSize; +} + +int __fastcall TWaveAudio::WriteSamplesInterleave(double* Buffer1, double* Buffer2, int Count) +{ + int FBytesPerSample=FBitsPerSample/8; + int SampleSize=FBytesPerSample*2; + if (FUseMemoryStream) + { + int Position=FMemoryStream->Position; + int countavailable=(FMemoryStream->Size-Position)/SampleSize; + if (countavailable<Count) FMemoryStream->Size=Position+SampleSize*Count; + DoubleToIntInterleave(&((char*)FMemoryStream->Memory)[Position], FBytesPerSample, Buffer1, Buffer2, Count); + FMemoryStream->Position=Position+SampleSize*Count; + } + else + { + int Position=Stream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenWrite); + FFileStream->Position=Position; + + int CountPF=FBlockSize/SampleSize; + int Fr=Count/CountPF; + double *Data1=Buffer1, *Data2=Buffer2; + void *data=new char[FBlockSize]; + for (int i=0; i<Fr; i++) + { + DoubleToIntInterleave(data, FBytesPerSample, Data1, Data2, CountPF); + Stream->Write(data, FBlockSize); + Data1=&Data1[CountPF], Data2=&Data2[CountPF]; + } + int CountLastF=Count%CountPF; + int lastblocksize=CountLastF*SampleSize; + DoubleToIntInterleave(data, FBytesPerSample, Data1, Data2, CountLastF); + Stream->Write(data, lastblocksize); + + Position=Stream->Position; + delete FFileStream->File; + FFileStream->File=new TFileStream(FFileName, fmOpenRead); + FFileStream->Position=Position; + } + if (FOnAudioChange) FOnAudioChange(this); + return Count*SampleSize; +} +//--------------------------------------------------------------------------- +__fastcall TDataAudio::TDataAudio(TComponent* Owner) + : TWaveAudio(Owner) +{ + FCustomFillBlock=0; +} + +int __fastcall TDataAudio::FillBlock(void* Block) +{ + if (FCustomFillBlock) + return FCustomFillBlock(Block); + else + return TWaveAudio::FillBlock(Block); +} + +//--------------------------------------------------------------------------- +namespace Audiopac +{ + void __fastcall PACKAGE Register() + { + TComponentClass classes[1] = {__classid(TWaveAudio)}; + RegisterComponents("Samples", classes, 0); + } +} +//--------------------------------------------------------------------------- + +