把两个简单的wav文件合并起来

[提出]因为近来需要把数据库中涉及到同一事项的多个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.

This entry was posted in 学习历程. Bookmark the permalink.

One Response to 把两个简单的wav文件合并起来

  1. a_gui says:

    其实语音格式就是一个特定格式的记录,对不?

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word