Mercurial > hg > hv
view AudioPac.cpp @ 1:f3fd4e19cec0 tip
first binary upload
author | wenx <xue.wen@eecs.qmul.ac.uk> |
---|---|
date | Wed, 10 Aug 2011 14:56:28 +0100 |
parents | a6a46af64546 |
children |
line wrap: on
line source
/* Harmonic Visualiser An audio file viewer and editor. Centre for Digital Music, Queen Mary, University of London. This file copyright 2011 Wen Xue. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ //--------------------------------------------------------------------------- #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); } } //---------------------------------------------------------------------------