You've already forked lazarus-ccr
335 lines
7.1 KiB
ObjectPascal
335 lines
7.1 KiB
ObjectPascal
![]() |
(*
|
||
|
this file is a part of audio components suite v 2.3 (delphi version).
|
||
|
copyright (c) 2002-2005 andrei borovsky. all rights reserved.
|
||
|
see the license file for more details.
|
||
|
you can contact me at acs@compiler4.net
|
||
|
this is the acs for delphi (windows) version of the unit.
|
||
|
*)
|
||
|
|
||
|
{
|
||
|
$Log: waveconverter.pas,v $
|
||
|
Revision 1.1 2005/12/19 18:36:49 z0m3ie
|
||
|
*** empty log message ***
|
||
|
|
||
|
Revision 1.1 2005/09/12 22:04:53 z0m3ie
|
||
|
modified structure again, fileformats are now in an sperat folder.
|
||
|
all File In/Out classes are capsulated from TFileIn and TFileOut
|
||
|
|
||
|
Revision 1.1 2005/08/25 20:18:00 z0m3ie
|
||
|
Version 2.4 restructure
|
||
|
TCDPlayer removed (fits not in component structure)
|
||
|
TMP3ToWavConverter removed (fits not in component structure)
|
||
|
|
||
|
Revision 1.2 2005/08/22 20:17:02 z0m3ie
|
||
|
changed Headers to log
|
||
|
changed mail adress
|
||
|
|
||
|
}
|
||
|
|
||
|
unit waveconverter;
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
SysUtils,
|
||
|
Windows, Classes, MMSystem, MSAcm;
|
||
|
|
||
|
type
|
||
|
{$IFDEF FPC}
|
||
|
TWaveFormat = WAVEFORMAT;
|
||
|
{$ENDIF}
|
||
|
|
||
|
TRiffID = array[0..3] of char;
|
||
|
TRiffHeader = packed record
|
||
|
ID: TRiffID;
|
||
|
BytesFollowing: DWord;
|
||
|
end;
|
||
|
|
||
|
|
||
|
TACMWaveFormat = packed record
|
||
|
case integer of
|
||
|
0 : (Format : TWaveFormatEx);
|
||
|
1 : (RawData : Array[0..128] of byte);
|
||
|
end;
|
||
|
|
||
|
TWaveConverter = class(TMemoryStream)
|
||
|
private
|
||
|
FMaxFmtSize: DWord;
|
||
|
public
|
||
|
CurrentFormat: TACMWaveFormat;
|
||
|
NewFormat: TACMWaveFormat;
|
||
|
function LoadStream(Stream : TStream): integer;
|
||
|
function Convert: integer;
|
||
|
function SaveWavToStream(MS: TStream): Integer;
|
||
|
constructor Create;
|
||
|
destructor Destroy; override;
|
||
|
end;
|
||
|
|
||
|
implementation
|
||
|
|
||
|
{ TWaveConverter }
|
||
|
|
||
|
function TWaveConverter.Convert: integer;
|
||
|
var
|
||
|
FStreamHandle: HACMStream;
|
||
|
OutputBufferSize: DWord;
|
||
|
FStreamHeader: TACMStreamHeader;
|
||
|
OutPut: Pointer;
|
||
|
begin
|
||
|
FStreamHandle := nil;
|
||
|
|
||
|
//
|
||
|
// Open the stream we're going to use to convert from the current to the
|
||
|
// new format
|
||
|
//
|
||
|
Result := acmStreamOpen(FStreamhandle, nil, CurrentFormat.Format,
|
||
|
NewFormat.Format, nil, 0, 0, ACM_STREAMOPENF_NONREALTIME);
|
||
|
if Result <> 0 then
|
||
|
begin
|
||
|
//SetError('acmStreamOpen', Result);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
//
|
||
|
// Calculate the size of the converted data
|
||
|
//
|
||
|
Result := acmStreamSize(FStreamHandle, self. Size, OutputBufferSize,
|
||
|
ACM_STREAMSIZEF_SOURCE);
|
||
|
|
||
|
if Result <> 0 then
|
||
|
begin
|
||
|
// SetError('acmStreamSize', Result);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
//
|
||
|
// Allocate memory for the converted data
|
||
|
//
|
||
|
GetMem(OutPut, OutputBufferSize);
|
||
|
FillChar(OutPut^,OutputBufferSize,#0);
|
||
|
|
||
|
Self.Seek(0,0);
|
||
|
|
||
|
//
|
||
|
// Initialize and prepare a header
|
||
|
//
|
||
|
with FStreamHeader do
|
||
|
begin
|
||
|
cbStruct := SizeOf(TACMStreamHeader);
|
||
|
fdwStatus := 0;
|
||
|
dwUser := 0;
|
||
|
pbSrc := self.Memory;
|
||
|
cbSrcLength := self.Size;
|
||
|
cbSrcLengthUsed := 0;
|
||
|
dwSrcUser := 0;
|
||
|
pbDst := OutPut;
|
||
|
cbDstLength := OutputBufferSize;
|
||
|
cbDstLengthUsed := 0;
|
||
|
dwDstUser := 0;
|
||
|
end;
|
||
|
Result := acmStreamPrepareHeader(FStreamHandle,FStreamHeader, 0);
|
||
|
if Result <> 0 then
|
||
|
begin
|
||
|
// SetError('acmStreamPrepareHeader', Result);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
//
|
||
|
// Tell acm to convert the stream
|
||
|
//
|
||
|
Result := acmStreamConvert(FStreamHandle,FStreamHeader,
|
||
|
ACM_STREAMCONVERTF_BLOCKALIGN);
|
||
|
if Result <> 0 then
|
||
|
begin
|
||
|
// SetError('acmStreamConvert', Result);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
//
|
||
|
// Set the format eqaul to the newformat and copy the
|
||
|
// data over to the streams memory
|
||
|
//
|
||
|
Move(NewFormat.RawData, CurrentFormat.RawData, FMaxFmtSize);
|
||
|
Self.SetSize(OutputBufferSize);
|
||
|
Self.Seek(0,0);
|
||
|
Self.Write(Output^, OutputBufferSize);
|
||
|
|
||
|
//
|
||
|
// Unprepeare the header
|
||
|
//
|
||
|
Result := acmStreamUnprepareHeader(FStreamHandle,FStreamHeader, 0);
|
||
|
if Result <> 0 then
|
||
|
begin
|
||
|
// SetError('acmStreamUnprepareHeader', Result);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
//
|
||
|
// Close the stream
|
||
|
//
|
||
|
Result := acmStreamClose(FStreamHandle, 0);
|
||
|
if Result <> 0 then
|
||
|
begin
|
||
|
// SetError('acmStreamClose', Result);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
FreeMem(OutPut);
|
||
|
end;
|
||
|
|
||
|
constructor TWaveConverter.Create;
|
||
|
begin
|
||
|
inherited;
|
||
|
|
||
|
acmMetrics(nil, ACM_METRIC_MAX_SIZE_FORMAT, FMaxFmtSize);
|
||
|
|
||
|
FillChar(CurrentFormat.Format, FMaxFmtSize, 0);
|
||
|
FillChar(NewFormat.Format, FMaxFmtSize, 0);
|
||
|
end;
|
||
|
|
||
|
destructor TWaveConverter.Destroy;
|
||
|
begin
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
function TWaveConverter.LoadStream(Stream : TStream): integer;
|
||
|
var
|
||
|
Header: TRiffHeader;
|
||
|
ID: TRiffID;
|
||
|
Mem: Pointer;
|
||
|
Data: PByteArray;
|
||
|
|
||
|
|
||
|
NumRead: Integer;
|
||
|
Pos: Integer;
|
||
|
|
||
|
begin
|
||
|
Result := 0;
|
||
|
try
|
||
|
//read the header
|
||
|
NumRead := Stream.Read(Header, SizeOf(Header));
|
||
|
Pos := NumRead;
|
||
|
|
||
|
NumRead := Stream.Read(ID, SizeOf(ID));
|
||
|
Pos := Pos + NumRead;
|
||
|
|
||
|
if (Header.ID <> 'RIFF') or (ID <> 'WAVE') then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
while Pos < Stream.Size -1 do
|
||
|
begin
|
||
|
Dec(Pos,7);
|
||
|
Stream.Seek(Pos, soFromBeginning);
|
||
|
|
||
|
NumRead := Stream.Read(Header, SizeOf(Header));
|
||
|
Pos := Pos + NumRead;
|
||
|
|
||
|
|
||
|
if Header.ID = 'fmt ' then
|
||
|
begin
|
||
|
GetMem(Mem, Header.BytesFollowing);
|
||
|
try
|
||
|
NumRead := Stream.Read(Mem^, Header.BytesFollowing);
|
||
|
Pos := Pos + NumRead;
|
||
|
|
||
|
if Header.BytesFollowing < SizeOf(TWaveFormatEx) then
|
||
|
Move(Mem^, CurrentFormat.Format , SizeOf(TWaveFormatEx))
|
||
|
else
|
||
|
Move(Mem^, CurrentFormat.Format, Header.BytesFollowing);
|
||
|
finally
|
||
|
FreeMem(Mem);
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
if Header.ID = 'fact' then
|
||
|
begin
|
||
|
GetMem(Data, Header.BytesFollowing);
|
||
|
try
|
||
|
NumRead := Stream.Read(Data^, Header.BytesFollowing);
|
||
|
Pos := Pos + NumRead;
|
||
|
finally
|
||
|
FreeMem(Data);
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
if Header.ID = 'data' then
|
||
|
begin
|
||
|
if Header.BytesFollowing > 0 then
|
||
|
begin
|
||
|
GetMem(Data, Header.BytesFollowing);
|
||
|
try
|
||
|
NumRead := Stream.Read(Data^, Header.BytesFollowing);
|
||
|
Pos := Pos + NumRead;
|
||
|
|
||
|
Self.SetSize(Header.BytesFollowing);
|
||
|
Self.Seek(0,0);
|
||
|
Self.Write(Data^, (*Header.BytesFollowing*)self.Size);
|
||
|
finally
|
||
|
FreeMem(Data);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
Seek(0,0);
|
||
|
finally
|
||
|
// FileStream.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
function TWaveConverter.SaveWavToStream(MS: TStream): Integer;
|
||
|
var
|
||
|
CurrentPos : Integer;
|
||
|
H : TRiffHeader;
|
||
|
ID : TRiffID;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
try
|
||
|
CurrentPos := Position;
|
||
|
|
||
|
H.ID := 'RIFF';
|
||
|
H.BytesFollowing := 0;
|
||
|
MS.Write(H, SizeOf(H));
|
||
|
|
||
|
ID := 'WAVE';
|
||
|
MS.Write(ID, SizeOf(ID));
|
||
|
|
||
|
H.ID := 'fmt ';
|
||
|
H.BytesFollowing := SizeOf(TWaveFormat) + 2;
|
||
|
MS.Write(H, SizeOf(H));
|
||
|
MS.Write(CurrentFormat.Format, SizeOf(TWaveFormat) + 2);
|
||
|
|
||
|
H.ID := 'data';
|
||
|
H.BytesFollowing := Size;
|
||
|
MS.Write(H, SizeOf(H));
|
||
|
Seek(0,0);
|
||
|
// MS.CopyFrom(Self, Size);
|
||
|
// ms.Write( Self, Size);
|
||
|
self.SaveToStream(MS);
|
||
|
|
||
|
|
||
|
MS.Seek(0,0);
|
||
|
H.ID := 'RIFF';
|
||
|
H.BytesFollowing := MS.Size - SizeOf(H) +1;
|
||
|
MS.Write(H,SizeOf(H));
|
||
|
|
||
|
Position := CurrentPos;
|
||
|
// MS.Free;
|
||
|
except
|
||
|
on E: Exception do
|
||
|
begin
|
||
|
Result := MCIERR_FILE_NOT_SAVED;
|
||
|
// SetError('SaveFile', MCIERR_FILE_NOT_SAVED);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
end.
|
||
|
|
||
|
|
||
|
|
||
|
|