Z
zgp2000
Unregistered / Unconfirmed
GUEST, unregistred user!
to 网中戏<br> 我就是那一块去文件头再重写不会啊。你将源码帖出,我调试成功就送分给你了!<br>谢谢!
<br>unit PCMWaves;<br><br>interface<br><br>uses<br> Classes, SysUtils, MMSystem;<br><br>type<br> TPCMWaveHeader = packed record<br> rID : array[0..3] of Char; //'RIFF' 标识<br> rLen : Longint;<br> wID : array[0..3] of Char; //'WAVE' 标识<br> fID : array[0..3] of Char; //'fmt ' 标识<br> fLen : Longint; //固定值, 16<br> wFormatTag : Word; //固定值, 1<br> nChannels : Word; //Mono=1, Stereo=2<br> nSamplesPerSec : Longint; //采样频率, HZ<br> nAvgBytesPerSec : Longint;<br> nBlockAlign : Word;<br> nBitsPerSample : Word; //精度, e.g. 8 or 16<br> dId : array[0..3]of Char; //'data' 标识<br> dLen : Longint; //数据长度<br> end;<br><br>type<br> EInvalidPCMWaveFormat = class(Exception);<br> <br> TPCMWave = class(TObject)<br> private<br> FStream : TMemoryStream;<br> FHeader : TPCMWaveHeader;<br><br> protected<br> function isValidFormat(aStream: TStream): Boolean; virtual;<br> function getPCMWaveHeader(aStream: TStream): TPCMWaveHeader; virtual;<br> function getData: Pointer; virtual;<br> <br> public<br> constructor Create; virtual;<br> destructor Destroy; override;<br><br> procedure LoadFromFile(const aFileName: String); virtual;<br> procedure LoadFromStream(aStream: TStream); virtual;<br> procedure SaveToFile(const aFileName: String); virtual;<br> procedure SaveToStream(aStream: TStream); virtual;<br><br> procedure Append(const aFileName: String); overload; virtual;<br> procedure Append(aStream: TStream); overload; virtual;<br><br> procedure Clear;<br><br> procedure Play;<br> procedure Stop;<br> <br> property Header: TPCMWaveHeader read FHeader;<br> property Data: Pointer read getData;<br> end;<br><br>implementation<br>uses<br> LogFiles;<br> <br>constructor TPCMWave.Create;<br>begin<br> FillChar(FHeader, SizeOf(FHeader), 0);<br> with FHeader do<br> begin<br> rID := 'RIFF'; //'RIFF' 标识<br> rLen := 36; //dLen + 36<br> wID := 'WAVE'; //'WAVE' 标识<br> fID := 'fmt '; //'fmt ' 标识<br> fLen := 16; //固定值, 16<br> wFormatTag := 1; //固定值, 1<br> nChannels := 1; //Mono=1, Stereo=2<br> nSamplesPerSec := 16000; //采样频率, HZ<br> nAvgBytesPerSec := 32000; //nSamplesPerSec*nChannels*Trunc(nBitsPerSample div 8);<br> nBlockAlign := 2; //nChannels*(nBitsPerSample div 8);<br> nBitsPerSample := 16; //精度, e.g. 8 or 16<br> dId := 'data'; //'data' 标识<br> dLen := 0;<br> end;<br><br> FStream := TMemoryStream.Create;<br> Assert(FStream <> nil);<br> <br> FStream.Write(FHeader, SizeOf(FHeader));<br>end;<br><br>destructor TPCMWave.Destroy;<br>begin<br> if Assigned(FStream) then FStream.Free;<br> inherited Destroy;<br>end;<br><br>function TPCMWave.isValidFormat(aStream: TStream): Boolean;<br>var<br> Header : TPCMWaveHeader;<br>begin<br> Header := getPCMWaveHeader(aStream);<br> with Header do<br> begin<br> Result := (rID = 'RIFF') and (wID = 'WAVE') and (wFormatTag = 1);<br> end;<br>end;<br><br>procedure TPCMWave.SaveToFile(const aFileName: String);<br>var<br> Stream: TStream;<br>begin<br> Stream := TFileStream.Create(aFileName, fmCreate);<br> Assert(Stream <> nil);<br> try<br> SaveToStream(Stream);<br> finally<br> Stream.Free;<br> end;<br>end;<br><br>procedure TPCMWave.LoadFromFile(const aFileName: String);<br>var<br> Stream: TStream;<br>begin<br> Stream := TFileStream.Create(aFileName, fmOpenRead or fmShareDenyWrite);<br> Assert(Stream <> nil);<br> try<br> LoadFromStream(Stream);<br> finally<br> Stream.Free;<br> end;<br>end;<br><br>procedure TPCMWave.SaveToStream(aStream: TStream);<br>begin<br> aStream.Seek(0, soFromBeginning);<br> FStream.Seek(0, soFromBeginning);<br> aStream.CopyFrom(FStream, FStream.Size);<br>end;<br><br>procedure TPCMWave.LoadFromStream(aStream: TStream);<br>begin<br> if not isValidFormat(aStream) then<br> raise EInvalidPCMWaveFormat.Create('Invalid PCM Wave Format');<br><br> aStream.Seek(0, soFromBeginning);<br> FStream.Seek(0, soFromBeginning);<br> FStream.CopyFrom(aStream, aStream.Size);<br> FHeader := getPCMWaveHeader(FStream);<br>end;<br><br>function TPCMWave.getPCMWaveHeader(aStream: TStream): TPCMWaveHeader;<br>var<br> Header : TPCMWaveHeader;<br>begin<br> aStream.Seek(0, soFromBeginning);<br> aStream.Read(Header, SizeOf(Header));<br> Result := Header;<br>end;<br><br>function TPCMWave.getData: Pointer;<br>begin<br> Result := FStream.Memory;<br>end;<br><br>procedure TPCMWave.Append(const aFileName: String);<br>var<br> Stream: TStream;<br>begin<br> Stream := TFileStream.Create(aFileName, fmOpenRead or fmShareDenyWrite);<br> Assert(Stream <> nil);<br> try<br> Append(Stream);<br> finally<br> Stream.Free;<br> end;<br>end;<br><br>procedure TPCMWave.Append(aStream: TStream);<br>var<br> Header : TPCMWaveHeader;<br> isSame : Boolean;<br>begin<br> if not isValidFormat(aStream) then<br> raise EInvalidPCMWaveFormat.Create('Invalid PCM Wave Format');<br><br> //数据区非空, 追加<br> if FHeader.dLen > 0 then<br> begin<br> //检测是否是相同的数据格式<br> Header := getPCMWaveHeader(aStream);<br> isSame := (Header.nChannels = FHeader.nChannels) //<br> and (Header.nSamplesPerSec = FHeader.nSamplesPerSec) //<br> and (Header.nBitsPerSample = FHeader.nBitsPerSample); //<br><br> //数据格式相同<br> if isSame then<br> begin<br> //处理非标准格式, 按规范定义, rLen不包含RIFF标志和长度共8字节<br> //因此,aStream.Size = SizeOf(TPCMWaveHeader)+Header.dLen<br> // aStream.Size = Header.rLen + 8<br> //但在实际中发现存在rLen值为包含RIFF标志和长度8字节的文件<br> if Header.dLen > aStream.Size-SizeOf(TPCMWaveHeader) then<br> begin<br> Header.dLen := aStream.Size - SizeOf(TPCMWaveHeader);<br> end;<br><br> //计算数据区长度<br> with FHeader do<br> begin<br> rLen := rLen + Header.dLen;<br> dLen := dLen + Header.dLen;<br> end;<br><br> //更新文件头<br> FStream.Seek(0, soFromBeginning);<br> FStream.Write(FHeader, SizeOf(FHeader));<br><br> //追加数据<br> FStream.Seek(0, soFromEnd);<br> aStream.Seek(SizeOf(TPCMWaveHeader), soFromBeginning); //跳过文件头<br> FStream.CopyFrom(aStream, Header.dLen);<br> end;<br> end<br> else //数据区为空, 读入新的数据<br> begin<br> LoadFromStream(aStream);<br> end;<br>end;<br><br>procedure TPCMWave.Clear;<br>begin<br> FillChar(FHeader, SizeOf(FHeader), 0);<br> with FHeader do<br> begin<br> rID := 'RIFF'; //'RIFF' 标识<br> rLen := 36; //dLen + 36<br> wID := 'WAVE'; //'WAVE' 标识<br> fID := 'fmt '; //'fmt ' 标识<br> fLen := 16; //固定值, 16<br> wFormatTag := 1; //固定值, 1<br> nChannels := 1; //Mono=1, Stereo=2<br> nSamplesPerSec := 16000; //采样频率, HZ<br> nAvgBytesPerSec := 32000; //nSamplesPerSec*nChannels*Trunc(nBitsPerSample div 8);<br> nBlockAlign := 2; //nChannels*(nBitsPerSample div 8);<br> nBitsPerSample := 16; //精度, e.g. 8 or 16<br> dId := 'data'; //'data' 标识<br> dLen := 0;<br> end;<br><br> FStream.Clear;<br> FStream.Write(FHeader, SizeOf(FHeader));<br>end;<br><br>procedure TPCMWave.Play;<br>begin<br> //声卡已安装<br> if waveOutGetNumDevs > 0 then<br> begin<br> PlaySound(Data, hInstance, SND_MEMORY or SND_ASYNC);<br> end;<br>end;<br><br>procedure TPCMWave.Stop;<br>begin<br> //声卡已安装<br> if waveOutGetNumDevs > 0 then<br> begin<br> PlaySound(nil, hInstance, 0);<br> end;<br>end;<br><br>end.<br>