Subversion Repositories spacemission

Compare Revisions

Problem with comparison.

Regard whitespace Rev HEAD → Rev 1

/VCL_DELPHIX_D6/Wave.pas
0,0 → 1,726
unit Wave;
 
interface
 
{$INCLUDE DelphiXcfg.inc}
 
uses
Windows, SysUtils, Classes, MMSystem;
 
type
 
{ EWaveError }
 
EWaveError = class(Exception);
 
{ TWave }
 
TWave = class(TPersistent)
private
FData: Pointer;
FFormat: PWaveFormatEx;
FFormatSize: Integer;
FSize: Integer;
procedure SetFormatSize(Value: Integer);
procedure SetSize(Value: Integer);
protected
procedure DefineProperties(Filer: TFiler); override;
procedure ReadData(Stream: TStream); virtual;
procedure WriteData(Stream: TStream); virtual;
public
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
procedure Clear;
procedure LoadFromFile(const FileName : string);
procedure LoadFromStream(Stream: TStream);
procedure SaveToFile(const FileName : string);
procedure SaveToStream(Stream: TStream);
procedure SetPCMFormat(SamplesPerSec, BitsPerSample, Channels: Integer);
property Data: Pointer read FData;
property Format: PWaveFormatEx read FFormat;
property FormatSize: Integer read FFormatSize write SetFormatSize;
property Size: Integer read FSize write SetSize;
end;
 
{ TCustomDXWave }
 
TCustomDXWave = class(TComponent)
private
FWave: TWave;
procedure SetWave(Value: TWave);
public
constructor Create(AOnwer: TComponent); override;
destructor Destroy; override;
property Wave: TWave read FWave write SetWave;
end;
 
{ TDXWave }
 
TDXWave = class(TCustomDXWave)
published
property Wave;
end;
 
{ EWaveStreamError }
 
EWaveStreamError = class(Exception);
 
{ TCustomWaveStream }
 
TCustomWaveStream = class(TStream)
private
FPosition: Integer;
protected
function GetFilledSize: Integer; virtual;
function GetFormat: PWaveFormatEx; virtual; abstract;
function GetFormatSize: Integer; virtual;
function GetSize: Integer; virtual;
function ReadWave(var Buffer; Count: Integer): Integer; virtual;
procedure SetFormatSize(Value: Integer); virtual; abstract;
procedure SetSize(Value: Integer); override;
function WriteWave(const Buffer; Count: Integer): Integer; virtual;
public
function Read(var Buffer; Count: Longint): Longint; override;
function Seek(Offset: Longint; Origin: Word): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
procedure SetPCMFormat(SamplesPerSec, BitsPerSample, Channels: Integer);
property FilledSize: Integer read GetFilledSize;
property Format: PWaveFormatEx read GetFormat;
property FormatSize: Integer read GetFormatSize write SetFormatSize;
property Size: Integer read GetSize write SetSize;
end;
 
{ TCustomWaveStream2 }
 
TCustomWaveStream2 = class(TCustomWaveStream)
private
FFormat: PWaveFormatEx;
FFormatSize: Integer;
protected
function GetFormat: PWaveFormatEx; override;
function GetFormatSize: Integer; override;
procedure SetFormatSize(Value: Integer); override;
public
destructor Destroy; override;
end;
 
{ TWaveObjectStream }
 
TWaveObjectStream = class(TCustomWaveStream)
private
FWave: TWave;
protected
function GetFormat: PWaveFormatEx; override;
function GetFormatSize: Integer; override;
function GetSize: Integer; override;
function ReadWave(var Buffer; Count: Integer): Integer; override;
procedure SetFormatSize(Value: Integer); override;
procedure SetSize(Value: Integer); override;
function WriteWave(const Buffer; Count: Integer): Integer; override;
public
constructor Create(AWave: TWave);
end;
 
{ TWaveStream }
 
TWaveStream = class(TCustomWaveStream2)
private
FDataPosition: Integer;
FDataHeaderPosition: Integer;
FOpened: Boolean;
FOriPosition: Integer;
FReadMode: Boolean;
FSize: Integer;
FStream: TStream;
procedure CloseWriteMode;
procedure OpenReadMode;
procedure OpenWriteMode;
protected
function GetSize: Integer; override;
function ReadWave(var Buffer; Count: Integer): Integer; override;
function WriteWave(const Buffer; Count: Integer): Integer; override;
public
constructor Create(AStream: TStream);
destructor Destroy; override;
procedure Open(WriteMode: Boolean);
end;
 
{ TWaveFileStream }
 
TWaveFileStream = class(TWaveStream)
private
FFileStream: TFileStream;
public
constructor Create(const FileName: string; FileMode: Integer);
destructor Destroy; override;
end;
 
procedure MakePCMWaveFormatEx(var Format: TWaveFormatEx;
SamplesPerSec, BitsPerSample, Channels: Integer);
 
implementation
 
uses DXConsts;
 
procedure MakePCMWaveFormatEx(var Format: TWaveFormatEx;
SamplesPerSec, BitsPerSample, Channels: Integer);
begin
with Format do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := Channels;
nSamplesPerSec := SamplesPerSec;
wBitsPerSample := BitsPerSample;
nBlockAlign := nChannels*(wBitsPerSample div 8);
nAvgBytesPerSec := nBlockAlign*nSamplesPerSec;
cbSize := 0;
end;
end;
 
{ TWave }
 
const
WavePoolSize = 8096;
 
destructor TWave.Destroy;
begin
Clear;
inherited Destroy;
end;
 
procedure TWave.Assign(Source: TPersistent);
var
AWave: TWave;
begin
if Source=nil then
begin
Clear;
end else if Source is TWave then
begin
if Source<>Self then
begin
AWave := TWave(Source);
Size := AWave.Size;
FormatSize := AWave.FormatSize;
Move(AWave.Data^, FData^, FSize);
Move(AWave.Format^, FFormat^, FFormatSize);
end;
end else
inherited Assign(Source);
end;
 
procedure TWave.Clear;
begin
FreeMem(FData, 0); FData := nil;
FreeMem(FFormat, 0); FFormat := nil;
 
FSize := 0;
FFormatSize := 0;
end;
 
procedure TWave.DefineProperties(Filer: TFiler);
begin
inherited DefineProperties(Filer);
Filer.DefineBinaryProperty('WAVE', ReadData, WriteData, True);
end;
 
procedure TWave.LoadFromFile(const FileName : string);
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
 
procedure TWave.LoadFromStream(Stream: TStream);
var
WaveStream: TWaveStream;
begin
Clear;
 
WaveStream := TWaveStream.Create(Stream);
try
WaveStream.Open(False);
 
FormatSize := WaveStream.FormatSize;
Move(WaveStream.Format^, Format^, FormatSize);
Size := WaveStream.Size;
WaveStream.ReadBuffer(FData^, Size);
finally
WaveStream.Free;
end;
end;
 
procedure TWave.ReadData(Stream: TStream);
begin
LoadFromStream(Stream);
end;
 
procedure TWave.SaveToFile(const FileName : string);
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream);
finally
Stream.Free;
end;
end;
 
procedure TWave.SaveToStream(Stream: TStream);
var
WaveStream: TWaveStream;
begin
if (FFormatSize<=0) or (FSize<=0) then Exit;
 
WaveStream := TWaveStream.Create(Stream);
try
WaveStream.FormatSize := FormatSize;
Move(Format^, WaveStream.Format^, FormatSize);
 
WaveStream.Open(True);
WaveStream.WriteBuffer(FData^, Size);
finally
WaveStream.Free;
end;
end;
 
procedure TWave.SetFormatSize(Value: Integer);
begin
if Value<=0 then Value := 0;
ReAllocMem(FFormat, Value);
FFormatSize := Value;
end;
 
procedure TWave.SetPCMFormat(SamplesPerSec, BitsPerSample, Channels: Integer);
begin
FormatSize := SizeOf(TWaveFormatEx);
MakePCMWaveFormatEx(Format^, SamplesPerSec, BitsPerSample, Channels);
end;
 
procedure TWave.SetSize(Value: Integer);
var
i: Integer;
begin
if Value<=0 then Value := 0;
 
i := (Value+WavePoolSize-1) div WavePoolSize;
if i<>(FSize+WavePoolSize-1) div WavePoolSize then
ReAllocMem(FData, i*WavePoolSize);
 
FSize := Value;
end;
 
procedure TWave.WriteData(Stream: TStream);
begin
SaveToStream(Stream);
end;
 
{ TCustomDXWave }
 
constructor TCustomDXWave.Create(AOnwer: TComponent);
begin
inherited Create(AOnwer);
FWave := TWave.Create;
end;
 
destructor TCustomDXWave.Destroy;
begin
FWave.Free;
inherited Destroy;
end;
 
procedure TCustomDXWave.SetWave(Value: TWave);
begin
FWave.Assign(Value);
end;
 
{ TCustomWaveStream }
 
function TCustomWaveStream.GetFilledSize: Longint;
begin
Result := -1;
end;
 
function TCustomWaveStream.GetFormatSize: Integer;
begin
Result := 0;
end;
 
function TCustomWaveStream.GetSize: Integer;
begin
Result := -1;
end;
 
function TCustomWaveStream.Read(var Buffer; Count: Longint): Longint;
begin
if GetSize<0 then
Result := ReadWave(Buffer, Count)
else
begin
if FPosition>Size then
FPosition := Size;
if FPosition+Count>Size then
Result := Size-FPosition
else
Result := Count;
 
Result := ReadWave(Buffer, Result);
end;
 
Inc(FPosition, Result);
end;
 
function TCustomWaveStream.ReadWave(var Buffer; Count: Integer): Integer;
begin
Result := 0;
end;
 
function TCustomWaveStream.Seek(Offset: Longint; Origin: Word): Longint;
begin
case Origin of
soFromBeginning: FPosition := Offset;
soFromCurrent : FPosition := FPosition + Offset;
soFromEnd : FPosition := GetSize + Offset;
end;
if FPosition<0 then FPosition := 0;
if FPosition>GetSize then FPosition := GetSize;
 
Result := FPosition;
end;
 
procedure TCustomWaveStream.SetPCMFormat(SamplesPerSec, BitsPerSample, Channels: Integer);
begin
FormatSize := SizeOf(TWaveFormatEx);
MakePCMWaveFormatEx(Format^, SamplesPerSec, BitsPerSample, Channels);
end;
 
procedure TCustomWaveStream.SetSize(Value: Integer);
begin
end;
 
function TCustomWaveStream.Write(const Buffer; Count: Longint): Longint;
begin
if FPosition>Size then
FPosition := Size;
Result := WriteWave(Buffer, Count);
Inc(FPosition, Result);
end;
 
function TCustomWaveStream.WriteWave(const Buffer; Count: Integer): Integer;
begin
Result := 0;
end;
 
{ TCustomWaveStream2 }
 
destructor TCustomWaveStream2.Destroy;
begin
FormatSize := 0;
inherited Destroy;
end;
 
function TCustomWaveStream2.GetFormat: PWaveFormatEx;
begin
Result := FFormat;
end;
 
function TCustomWaveStream2.GetFormatSize: Integer;
begin
Result := FFormatSize;
end;
 
procedure TCustomWaveStream2.SetFormatSize(Value: Integer);
begin
ReAllocMem(FFormat, Value);
FFormatSize := Value;
end;
 
{ TWaveObjectStream }
 
constructor TWaveObjectStream.Create(AWave: TWave);
begin
inherited Create;
FWave := AWave;
 
FormatSize := FWave.FormatSize;
Move(FWave.Format^, Format^, FormatSize);
end;
 
function TWaveObjectStream.GetFormat: PWaveFormatEx;
begin
Result := FWave.Format;
end;
 
function TWaveObjectStream.GetFormatSize: Integer;
begin
Result := FWave.FormatSize;
end;
 
function TWaveObjectStream.GetSize: Integer;
begin
Result := FWave.Size;
end;
 
function TWaveObjectStream.ReadWave(var Buffer; Count: Integer): Integer;
begin
Result := Count;
Move(Pointer(Integer(FWave.Data)+Position)^, Buffer, Count);
end;
 
procedure TWaveObjectStream.SetFormatSize(Value: Integer);
begin
FWave.FormatSize := Value;
end;
 
procedure TWaveObjectStream.SetSize(Value: Integer);
begin
FWave.Size := Value;
end;
 
function TWaveObjectStream.WriteWave(const Buffer; Count: Integer): Integer;
begin
Result := Count;
if Position+Count>Size then
SetSize(Size+(Position+Count+Size));
Move(Buffer, Pointer(Integer(FWave.Data)+Position)^, Count);
end;
 
{ TWaveStream }
 
const
ID_RIFF = Ord('R') + Ord('I')*$100 + Ord('F')*$10000 + Ord('F')*$1000000;
ID_WAVE = Ord('W') + Ord('A')*$100 + Ord('V')*$10000 + Ord('E')*$1000000;
ID_FMT = Ord('f') + Ord('m')*$100 + Ord('t')*$10000 + Ord(' ')*$1000000;
ID_FACT = Ord('f') + Ord('a')*$100 + Ord('c')*$10000 + Ord('t')*$1000000;
ID_DATA = Ord('d') + Ord('a')*$100 + Ord('t')*$10000 + Ord('a')*$1000000;
 
type
TWaveFileHeader = packed record
FType: Integer;
Size: Longint;
RType: Integer;
end;
 
TWaveChunkHeader = packed record
CType: Longint;
Size: Longint;
end;
 
constructor TWaveStream.Create(AStream: TStream);
begin
inherited Create;
FStream := AStream;
 
FOriPosition := FStream.Position;
end;
 
destructor TWaveStream.Destroy;
begin
if FOpened and (not FReadMode) then
CloseWriteMode;
inherited Destroy;
end;
 
function TWaveStream.GetSize: Integer;
begin
if FOpened then
begin
if not FReadMode then
Result := FStream.Size-FDataPosition
else
Result := FSize;
end else
Result := 0;
end;
 
function TWaveStream.ReadWave(var Buffer; Count: Integer): Integer;
begin
if not FOpened then
raise EWaveStreamError.Create(SStreamNotOpend);
 
FStream.Position := FDataPosition+Position;
Result := FStream.Read(Buffer, Count);
end;
 
function TWaveStream.WriteWave(const Buffer; Count: Integer): Integer;
begin
if not FOpened then
raise EWaveStreamError.Create(SStreamNotOpend);
 
if FReadMode then
begin
if Position+Count>FSize then
Count := FSize-Position;
end;
 
FStream.Position := FDataPosition+Position;
Result := FStream.Write(Buffer, Count);
end;
 
procedure TWaveStream.Open(WriteMode: Boolean);
begin
if WriteMode then
OpenWriteMode
else
OpenReadMode;
end;
 
procedure TWaveStream.OpenReadMode;
var
WF: TWaveFileHeader;
WC: TWaveChunkHeader;
 
procedure Readfmt; { fmt }
begin
FormatSize := WC.Size;
FStream.ReadBuffer(Format^, WC.Size);
end;
 
procedure Readdata; { data }
begin
FSize := WC.Size;
FDataPosition := FStream.Position;
FStream.Seek(FSize, 1);
end;
 
begin
if FOpened then
raise EWaveStreamError.Create(SStreamOpend);
 
FOpened := True;
FReadMode := True;
 
FStream.Position := FOriPosition;
 
//if FStream.Size-FStream.Position<=0 then Exit;
 
{ File header reading. }
FStream.ReadBuffer(WF, SizeOf(TWaveFileHeader));
 
{ Is it Wave file of the file? }
if (WF.FType<>ID_RIFF) or (WF.RType<>ID_WAVE) then
raise EWaveStreamError.Create(SInvalidWave);
 
{ Chunk reading. }
FillChar(WC, SizeOf(WC), 0);
FStream.Read(WC, SizeOf(TWaveChunkHeader));
while WC.CType<>0 do
begin
case WC.CType of
ID_FMT : Readfmt;
ID_DATA: Readdata;
else
{ Chunk which does not correspond is disregarded. }
FStream.Seek(WC.Size, 1);
end;
 
FillChar(WC, SizeOf(WC), 0);
FStream.Read(WC, SizeOf(TWaveChunkHeader));
end;
end;
 
procedure TWaveStream.OpenWriteMode;
 
procedure WriteFmt; { fmt }
var
WC: TWaveChunkHeader;
begin
with WC do
begin
CType := ID_FMT;
Size := FFormatSize;
end;
 
FStream.WriteBuffer(WC, SizeOf(WC));
FStream.WriteBuffer(FFormat^, FFormatSize);
end;
 
procedure WriteData; { data }
var
WC: TWaveChunkHeader;
begin
FDataHeaderPosition := FStream.Position;
 
with WC do
begin
CType := ID_DATA;
Size := 0;
end;
 
FStream.WriteBuffer(WC, SizeOf(WC));
 
FDataPosition := FStream.Position;
end;
 
var
WF: TWaveFileHeader;
begin
if FOpened then
raise EWaveStreamError.Create(SStreamOpend);
 
if FormatSize=0 then
raise EWaveStreamError.Create(SInvalidWaveFormat);
 
FOpened := True;
FStream.Position := FOriPosition;
 
FStream.WriteBuffer(WF, SizeOf(TWaveFileHeader));
 
{ Chunk writing. }
WriteFmt;
WriteData;
end;
 
procedure TWaveStream.CloseWriteMode;
 
procedure WriteDataHeader; { data }
var
WC: TWaveChunkHeader;
begin
FStream.Position := FDataHeaderPosition;
 
with WC do
begin
CType := ID_DATA;
Size := Self.Size;
end;
 
FStream.WriteBuffer(WC, SizeOf(WC));
end;
 
var
WF: TWaveFileHeader;
begin
with WF do
begin
FType := ID_RIFF;
Size := (FStream.Size-FOriPosition)-SizeOf(TWaveChunkHeader);
RType := ID_WAVE;
end;
FStream.Position := FOriPosition;
FStream.WriteBuffer(WF, SizeOf(TWaveFileHeader));
WriteDataHeader;
FStream.Position := FStream.Size;
end;
 
{ TWaveFileStream }
 
constructor TWaveFileStream.Create(const FileName: string; FileMode: Integer);
begin
FFileStream := TFileStream.Create(FileName, FileMode);
inherited Create(FFileStream);
end;
 
destructor TWaveFileStream.Destroy;
begin
inherited Destroy;
FFileStream.Free;
end;
 
end.