RawWaveData = packed record
chunkID: FOURCC; // fmt chunk id-'DATA'
chunkSize: LongInt; //
//waveformData: array[0..0] of byte;
end;
WaveFmtHeader =packed record
fmtid: FOURCC; // fmt chunk id-'fmt '
chunkSize: LongInt; // size of the chunk not include <id and size>
end;
PWaveFormatE = ^TWaveFormat;
TWaveFormatE = packed record
wFormatTag: Word; //format type-- PCM = 1
nChannels: Word; // number of channels (i.e. mono, stereo, etc.)
nSamplesPerSec: DWORD; // sample rate (11025,22050,44010)
nAvgBytesPerSec: DWORD; // for buffer estimation
nBlockAlign: Word; // block size of data
wBitsPerSample: Word; // number of bits per sample of mono data
//cbSize: Word; // the count in bytes of the size of extra
//extra data format
end;
{ Predictors for ADPCM }
TADPCMCoef = packed record
Coef1, Coef2: SmallInt;
end;
TADPCMCoefSet = Array[0..MSADPCM_NUM_COEF-1] of TADPCMCoef;
PADPCMCoefSet = ^TADPCMCoefSet;
TWaveFormatEx = packed record
wFormatTag: Word; { format type }
nChannels: Word; { number of channels (i.e. mono, stereo, etc.) }
nSamplesPerSec: Longint; { sample rate }
nAvgBytesPerSec: Longint; { for buffer estimation }
nBlockAlign: Word; { block size of data }
wBitsPerSample: Word;
cbSize: Word; { SizeOf(wSamplesPerBlock..Predictors. Optional with PCM
extra size}
wSamplesPerBlock: SmallInt;
wNumCoef: SmallInt; { const 7 }
CoefSet: TADPCMCoefSet;
end;
PWaveFormatEx = ^TWaveFormatEx;
TWaveFile = Class (TObject)
FMMioHandle :Integer;
FFileName :String;
FWaveFormat : TWaveFormatEx;
FDataBytes,FDataOffset: Integer;
FFileSize:Integer;
SampleCount: LongInt;
public
constructor Create;
destructor Destory;
function OpenWaveFile(FileName: string):Boolean;
function GetDataBuffer(Buffer:PChar):Integer;
function ReadData(Buffer:PChar;dataPos,readbytes:Integer):Integer;
function WriteData(Buffer:PChar;dataPos,readbytes:Integer):Integer;
procedure CloseWaveFile;
function GetDataSecs:Integer;
function IsFileOpen:Boolean;
published
property WaveFormat: TWaveFormatEx read FWaveFormat;
property FileSize:Integer read FFileSize;
property DataBytes:Integer read FDataBytes;
property DataSecs:Integer read GetDataSecs;
end;
function CreateWaveFile(FileName:String;SampleRate,BitsNum:Integer;Stereo:Boolean):Integer;
function PlayWaveFile(FileName:String):Integer;
function StripeWaveFile(FileName:String):Integer;
function writeWaveFileFromBuf(tmpBuffer:PChar;VocLen:Integer;TripSilence:Boolean):String;
//Used for 变换语音文件放大因子,由于输入Microphone声音太小或太大可以
//按比例进行放缩
function getBufferPeak(ptrBuf:PSmallInt;BufSize,FrameSize:Integer):Single;
function getWaveFileLen(fileName:String;var lSecs,lBytes:Integer):Bool;
function getWaveFileFormat(fileName:String;var Sample,BitsNum:Integer;var Stereo:Boolean):Bool;
function getWaveFileLen(fileName:String;var lSecs,lBytes:Integer):Bool;
begin
result:=False;
with TWaveFile.Create do
begin
if OpenWaveFile(fileName) then
begin
lSecs:=DataSecs;
lBytes:=DataBytes;
CloseWaveFile;
result:=True;
end;
Free;
end; // with
end;
function getWaveFileFormat(fileName:String;var Sample,BitsNum:Integer;var Stereo:Boolean):Bool;
begin
result:=False;
with TWaveFile.Create do
begin
if OpenWaveFile(fileName) then
begin
Sample:=FWaveFormat.nSamplesPerSec;
BitsNum:=FWaveFormat.wBitsPerSample;
if FWaveFormat.nChannels = 1 then
Stereo:=False
else
Stereo:=True;
CloseWaveFile;
result:=True;
end;
Free;
end; // with
end;
function PlayWaveFile(FileName:String):Integer;
begin
SndPlaySound(PChar(FileName),SND_SYNC or SND_NODEFAULT);
end;
procedure Error(Text: string);
var
StackTop: record end;
Stack: record
EBP: Integer;
ReturnAddress: Pointer;
end absolute StackTop;
begin
raise Exception.Create(Text) at Stack.ReturnAddress;
end;
constructor TWaveFile.Create;
begin
inherited Create;
FMMioHandle:=0;
FDataBytes:=0;
FDataOffset:=0;
FFileSize:=0;
end;
destructor TWaveFile.Destory;
begin
inherited;
if FMMioHandle <> 0 then
CloseWaveFile;
end;
//打开Wave文件,得到Wave的数据格式FWaveFormat
function TWaveFile.OpenWaveFile(FileName: string):Boolean;
var
ckRIFF, ck: TMMCKINFO;
procedure ErrExit(Msg: String);
begin
Error(FileName+': '+Msg);
end;
begin
result:=False;
if (FileName = '') or not FileExists(FileName)
then Error('File '+FileName+' not found.');
Assert(FMMioHandle=0);
FMMioHandle := mmioOpen(PChar(FileName), nil, MMIO_READ or MMIO_ALLOCBUF);
if FMMioHandle = 0 then ErrExit('mmioOpen failed');
try
FFileName:=FileName;
ckRIFF.fccType := mmioStringToFourCC('WAVE',0);
if mmioDescend(FMMioHandle, @ckRIFF, nil, MMIO_FINDRIFF) <> 0
then ErrExit('WAVE chunk not found');
while mmioDescend(FMMioHandle, @ck, @ckRIFF, 0) = MMSYSERR_NOERROR do
begin
if (ck.dwDataOffset + ck.cksize) > (ckRIFF.dwDataOffset + ckRIFF.cksize)
then ErrExit('Chunk size mismatch');
if ck.ckid = mmioStringToFourCC('fmt ',0) then
begin
if FWaveFormat.wFormatTag = 0 then
begin
if ck.ckSize > SizeOf(TWaveFormatEx) then
ErrExit('ADPCM, unexpected number of coefficients');
if mmioRead(FMMioHandle, @FWaveFormat, ck.ckSize) <> ck.ckSize then
ErrExit('Error reading ''fmt '' chunk');
end;
end
else
if ck.ckid = mmioStringToFourCC('fact',0) then
begin
if (SampleCount = 0) and (FWaveFormat.wFormatTag = Wave_Format_ADPCM) then
begin
mmioRead(FMMioHandle, @SampleCount, SizeOf(LongInt));
end; { else multiple fact chunks - ignore }
end
else if ck.ckid = mmioStringToFourCC('data',0) then
begin
FDataBytes := ck.cksize;
case FWaveFormat.wFormatTag of
0:
ErrExit('No ''fmt '' chunk');
Wave_Format_PCM:
with FWaveFormat do
{ not documented: Avg div SamplesPerSec always integer }
SampleCount := FDataBytes div (nAvgBytesPerSec div nSamplesPerSec);
Wave_Format_ADPCM:
;
else
ErrExit('''fmt '' chunk exists, but unknown format');
end;
FDataOffset:=mmioSeek(FMmioHandle,0,1);//from cur
{
if bReadBuffer then
begin
GetMem(Buf, DataBytes);
mmioRead(FMMioHandle, PChar(Buf), DataBytes);
end;
}
end;
{ else leave subchunk }
mmioAscend(FMMioHandle, @ck, 0);
end; { while mmioDescend }
finally
//mmioClose(FMMioHandle,0);
FFileSize:=mmioSeek(FMMioHandle,0,2);
end;
result:=True;
end;
//返回Wave数据的总秒数
function TWaveFile.GetDataSecs:Integer;
begin
result:=DataBytes div FWaveFormat.nAvgBytesPerSec;
end;
//读出整个Wave数据区
function TWaveFile.GetDataBuffer(Buffer:PChar):Integer;
begin
result:=0;
if (FDataBytes > 0) and (FDataOffset>=44) then
begin
mmioSeek(FMMioHandle,FDataoffset,0);//from beginning
result:=mmioRead(FMmioHandle,Buffer,FDataBytes);
end;
end;
function TWaveFile.WriteData(Buffer:PChar;dataPos,readbytes:Integer):Integer;
begin
if FMMiohandle <> 0 then
begin
mmioSeek(FMMioHandle,FDataOffset+dataPos,0);
result:=mmioWrite(FMMioHandle,buffer,readBytes);
//可能有错
//应重新修改FWaveFormat的相关数据
end;
end;
function TWaveFile.ReadData(Buffer:PChar;dataPos,readbytes:Integer):Integer;
begin
if FMMiohandle <> 0 then
begin
mmioSeek(FMMioHandle,FDataOffset+dataPos,0);
result:=mmioRead(FMMioHandle,buffer,readBytes);
end;
end;
procedure TWaveFile.CloseWaveFile;
begin
if FMMioHandle <> 0 then
mmioClose(FMMioHandle,0);
FMMioHandle:=0;
end;
function TWaveFile.IsFileOpen:Boolean;
begin
result := (FMMioHandle <> 0);
end;
//功能:创建Wave文件
//参数:FileName-----文件名
//返回:其他:成功
// -1: 错误
function CreateWaveFile(FileName:String;SampleRate,BitsNum:Integer;Stereo:Boolean):Integer;
var
aHDr :WaveFileHeader;
aData :RawWaveData;
aFmt : WaveFmtHeader;
aWaveFormat:TWaveFormatEx;
begin
result:=FileCreate(FileName);
if result = -1 then
//ShowMessage('Create File Error');
Error('无法创建文件');
if result > 0 then
begin
with aHdr do
begin
ckid:=FOURCC_RIFF;
cksize:=44;
rifftype:=FOURCC_WAVE;
end;
FileWrite(result,aHDr,SizeOf(WaveFileHeader));
with aFmt do
begin
fmtid:=FOURCC_FMT;
chunksize:=$10; //for standard format
end;
FileWrite(result,aFmt,SizeOf(WaveFmtHeader));
with aWaveFormat do
begin
aWaveFormat.wFormatTag:=1; //pcm
{
aWaveFormat.nChannels:=1;
aWaveFormat.nSamplesPerSec:=11025;
aWaveFormat.wBitsPerSample:=16;
aWaveFormat.nAvgBytesPerSec:=22050;
}
if Stereo then
aWaveFormat.nChannels:=2
else
aWaveFormat.nChannels:=1;
aWaveFormat.nSamplesPerSec:=SampleRate;
aWaveFormat.wBitsPerSample:=BitsNum;
aWaveFormat.nBlockAlign:=(BitsNum div 8)*aWaveFormat.nChannels;
aWaveFormat.nAvgBytesPerSec:=SampleRate*aWaveFormat.nBlockAlign;
end;
FileWrite(result,aWaveFormat,SizeOf(TWaveFormatE));
with aData do
begin
chunkID:=FOURCC_DATA;
chunkSize:=0;
end;
FileWrite(result,aData,SizeOf(RawWaveData));
end;
end;