[提出]因为近来需要把数据库中涉及到同一事项的多个wav录音同时播放,因为条件限制无法使用播放列表,只能在客户端将这几个wav文件合并起来。
[资料]上网查阅了相关的帖子,思路比较清晰,
1、将每个wav的数据部分相加
2、将文件头中包含的文件大小相加
3、重新写入一个文件,然后更新一下文件头
[实现] 恰好在盒子里翻的时候,发现了一个现成的unit,呵呵,省却了俺好多功夫啊,真是万分感谢原作者。
因为使用的8位单声道8khz的录音文件,因此对其中的一些小项重新添加了一下,用integer代替了cardinal。
关于wav文件头部分的说明,俺前面已经引用了一份资料地。
下面是unit的内容:
unit ConcatWaveU;
interface
uses SysUtils, Classes, Dialogs;
//Déclaration des différents headers contenus dans un fichier WAV...
//Allez faire une recherche sur www.wotsit.org pour des informations précises
//sur le format WAV ! (ou sur google : "WAVE file Format specification" !)
//本单元中的ConcatWave函数用于将相同格式的Wave文件合成一个Wave文件
type
THeaderRIFF = packed record
ID: array[1..4] of Char; // 总为 'RIFF'
Size: Integer; // 大小
Format: array[1..4] of Char; // 总为 'WAVE'
end;
THeaderFormat = packed record
ID: array[1..4] of Char; //总为 'fmt '注意后面一个空格
Size: integer;
Format: word;
Mode: word;
SRate: Integer; //=Sample Rate
BRate: Integer; //=Byte Rate
Align: word;
BPS: word; //Bits Per Sample
Extra:word; //Extra Format Information, 2字节(非8k采样则无此字段,仅对PCM,Alaw,Ulaw而言)
Face:array[1..4]of char; //face字符
SizeExtra: Integer; //4 face后的数据长度.(到字符data之前的长度4)
Extras: Integer;//Total Samples 表示共有多少采样点.等于55-58的数据。(在其他格式中此子块可扩展)
end;
THeaderData = packed record
ID: array[1..4] of Char; //总为'data'
Size: Integer; //在这之后的音频数据(Datas)的大小
//Datas: array of Byte; //音频数据,在这里不需要
end;
//这个Wave类型记录实际上只包含了Wave文件的头信息
//因为Datas并没有定义,在这里并不需要
TWAVE = packed record
RIFF: THeaderRIFF; //à ignorer les fichiers dont le format diffère
Fmt: THeaderFormat;
Data: THeaderData;
end;
function ConcatWave(AWaveList: TStringList; ADestFile: string): string;
implementation
function WAV_Valid(Fichier: string): Boolean; //判断是否为合法的wav文件格式
var
WAV: TFileStream;
RIFF: array[1..4] of Char;
WAVEfmt: array[1..8] of Char;
PCM: WORD;
begin
Result := False;
try
WAV := TFileStream.Create(Fichier, fmOpenRead); //原来为fmOpenRead
WAV.Read(RIFF, 4);
if RIFF <> 'RIFF' then
begin
Wav.Free;
Exit;
end;
WAV.Seek(8, soFromBeginning); //从memory开始移动8个字节
WAV.Read(WAVEfmt, 8); //Lecture de "WAVE" et "fmt " en même temps
if WAVEfmt <> 'WAVEfmt ' then
begin
WAV.Free;
Exit;
end;
WAV.Seek(20, soFromBeginning);
WAV.Read(PCM, 2);
if PCM <> 1 then
begin
WAV.Free;
Exit;
end;
except
on Exception do
Exit;
end;
WAV.Free;
Result := True;
end;
function FormatOK(Ref, Fich: TWAVE): Boolean;
begin
Result := (Ref.Fmt.Format = Fich.Fmt.Format)
and (Ref.Fmt.Mode = Fich.Fmt.Mode)
and (Ref.Fmt.SRate = Fich.Fmt.SRate)
and (Ref.Fmt.BRate = Fich.Fmt.BRate)
and (Ref.Fmt.Align = Fich.Fmt.Align)
and (Ref.Fmt.BPS = Fich.Fmt.BPS);
end;
function ConcatWave(AWaveList: TStringList; ADestFile: string): string;
var
Source, Dest: TFileStream;
Temp: TMemoryStream;
I,K: Integer;
Fichier, Ref: TWAVE;
CopyCount:Integer;
begin
Result := ADestFile;
try
try
Temp := TMemoryStream.Create;
Dest := TFileStream.Create(ADestFile, fmCreate);
for I := 0 to AWaveList.Count - 1 do
begin
if WAV_Valid(AWaveList[I]) then //验证格式正确
begin
try
Source := TFileStream.Create(AWaveList[i], fmOpenRead);
Source.Read(Fichier.RIFF, SizeOf(THeaderRIFF));
Source.Read(Fichier.Fmt, SizeOf(THeaderFormat));
Source.Read(Fichier.Data, SizeOf(THeaderData));
if I = 0 then
begin
Ref.RIFF := Fichier.RIFF;
Ref.Fmt := Fichier.Fmt;
Ref.Data := Fichier.Data;
end;
if FormatOK(Ref, Fichier) then
Temp.CopyFrom(Source,Fichier.Data.Size); //Fichier.Data.Size
finally
Source.Free;
end;
end;
end;
Ref.RIFF.Size := 36 + Temp.Size;
Ref.Data.Size := Temp.Size;
Dest.Write(Ref.RIFF, SizeOf(Ref.RIFF));
Dest.Write(Ref.Fmt, SizeOf(Ref.Fmt));
Dest.Write(Ref.Data, SizeOf(Ref.Data));
Dest.CopyFrom(Temp, 0);
except on Exception do
begin
Result := 'Error';
Exit;
end;
end;
finally
temp.Free;
Dest.Free;
end;
end;
end.