piip's home

----piip咯吱窝[lyb826@chinaren.com]

首页 CNDEV 网志 联络 (RSS 2.0) (Atom) 登录
  随笔 330 :: 收藏 4 :: 评论 0 :: 寻迹: 0

News

现在时刻

江城子.密州出猎
    老夫聊发少年狂,左牵黄,右擎苍。 锦帽貂裘,千骑卷平冈。 欲报倾城随太守,亲射虎,看孙郎。

    酒酣胸胆尚开张,鬓微霜,又何妨! 持节云中,何日遣冯唐? 会挽雕弓如满月,西北望,射天狼。

随笔

随笔归档

跟着学习

好友链接

日常应用

新闻与军事

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

posted on 2006-09-29 15:16

Feedback

# 回复: 把两个简单的wav文件合并起来 2006-10-01 08:50:00 a_gui
其实语音格式就是一个特定格式的记录,对不?

发表评论

标题:  
署名:  
链接:
内容:
验证码: