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);
  }
}
//---------------------------------------------------------------------------