• delphi 多媒体 操作 wave(1)


    Wave 文件的文件格式

    微软的多媒体文件(wav、avi、tif 等)都有一个 RIFF 头, Wave 文件基本是这个样子:

    RIFF 头
      fmt 子块
    data 子块



    Wave 文件的编码方式有好多, 最常用最简单的就是 PCM 编码.
    其他编码会包含更多的"块", 但至少会包含上面的块, PCM 编码只包含上面的块

    2.判断一个文件是否是 Wave 文件

    Wave 文件的前 12 个字节可以这样描述:

    TRiff = record
      ckId    : DWORD; {'RIFF'}
      ckSize  : DWORD; {文件大小, 不包括前 8 个字节}
      fccType : DWORD; {'WAVE'}
    end;

    3.mmio 系列函数用于 Wave 等多媒体文件的 I/O 操作

    mmio 系列函数比一般的 I/O 函数更适合操作 RIFF 格式的多媒体文件, 主要是能更方便地操作 RIFF 的文件块, 官方还说它们更优化.

    和其他 I/O 函数一样, 它们也是要 Open 获取句柄, 然后读写, 最后关闭; 但它们文件句柄和其他 I/O 函数的句柄并不兼容, 不过部分函数(上面前 7 个)也可以用于一般文件的操作.

    uses MMSystem;

    procedure TForm1.FormCreate(Sender: TObject);

    const 

       FilePath = 'C:\Temp\mm.txt';

    var 

      hFile: HMMIO;  str: RawByteString;

    begin

       hFile := mmioOpen(PChar(FilePath),  {要打开的文件} nil{接受 TMMIOInfo 结构信息的指针, 暂时没用到}  

                                            MMIO_CREATE or MMIO_READWRITE {打开选项; 这是建立并以读写权限打开}     ); 

      mmioWrite(hFile, 'Delphi', 6);      {写入 6 个字符} 

       mmioSeek(hFile, 0, SEEK_SET);      {把读写指针移动到文件头}

       SetLength(str, 6);  mmioRead(hFile, PAnsiChar(str), 6); {读出 6 个字符}

      ShowMessage(str);                  {Delphi}

      mmioClose(hFile, 0);                {关闭文件; 第二个参数还可以是 MMIO_FHOPEN, 另有它用}  {最后再删除这个文件, 既然已删除就无需 Close 了}

      mmioOpen(PChar(FilePath), nil, MMIO_DELETE);

    end;

    4.有两个相关的结构体: TMMIOInfo、TMMCKInfo.

    TMMIOInfo 是多媒体文件打开后的状态信息, mmioOpen 函数的第二个参数就是这个结构的指针.现在先用到了 TMMCKInfo, 这是文件内部 "块" 的信息, 构成如下

    TMMCKInfo = record
      ckid: FOURCC;        {块标识}
      cksize: DWORD;       {块大小}
      fccType: FOURCC;     {格式类型标识}
      dwDataOffset: DWORD; {偏移地址}
      dwFlags: DWORD;      {附加信息}
    end;

    查找 "块" 需要通过 mmioDescend、mmioAscend 两个函数.

    mmioAscend 是从子块跳出;

    mmioDescend 是进入到子块; 进入子块是需要指定子块的 ckid 和父块信息;
    mmioDescend 也用来查找主块(RIFF), 此时需要很少的信息就可以找到主块.

    5.获取 Wave 文件的波形数据

    uses MMSystem;

    function GetWaveData(FilePath: string; var stream: TMemoryStream): Boolean;
    var
      hFile: HMMIO;
      ckiRIFF,ckiData: TMMCKInfo;
    begin
      Result := False;
      hFile := mmioOpen(PChar(FilePath), nil, MMIO_READ);
      if hFile = 0 then Exit;

      ZeroMemory(@ckiRIFF, SizeOf(TMMCKInfo));
      ZeroMemory(@ckiData, SizeOf(TMMCKInfo));
      ckiData.ckid := mmioStringToFOURCC('data', 0);

      //先获取主块的信息
      mmioDescend(hFile, @ckiRIFF, nil, MMIO_FINDRIFF);

      //再获取 data 块的信息后, 指针将自动指向 data 数据的起点; 然后读出数据
      if (ckiRIFF.ckid = FOURCC_RIFF) and
         (ckiRIFF.fccType = mmioStringToFOURCC('WAVE',0)) and
         (mmioDescend(hFile, @ckiData, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then
        begin
          stream.Size := ckiData.cksize;
          Result := (mmioRead(hFile, stream.Memory, ckiData.cksize) = ckiData.cksize);
        end;
      mmioClose(hFile, 0);
    end;

    //调用测试
    procedure TForm1.Button1Click(Sender: TObject);
    const
      FilePath = 'C:\WINDOWS\Media\Windows XP 启动.wav';
    var
      stream: TMemoryStream;
    begin
      stream := TMemoryStream.Create;

      if GetWaveData(FilePath, stream) then
        ShowMessageFmt('读出的数据大小是: %d', [stream.Size]); {424600}

      stream.Free;
    end;

     6.使用 TMediaPlayer 录制 wav 文件

    TMediaPlayer 录音是基于一个已存在的 wav 文件, 上次建立空白 wav 的函数可派上用场了.TMediaPlayer 的功能是基于 MCI 的, 都是该淘汰的东西了, 只是简单了解下.
    接下来还要学习用 waveIn...系列函数录音、用 DirectSound 录音.

    7.多媒体函数库Bass.dll

    http://www.cnblogs.com/del/category/150851.html

    最近要写个小程序, 用到 mp3 播放; 因为需要非常复杂的控制与功能, 想到了 Bass.dll.

    以前我曾以为 Bass.dll 是 Windows 系统自带的库, 后来才知道原来是第三方的:
    http://www.un4seen.com/.

    Bass.dll 一直在更新, 现在最新版本是 2.411, 下载地址:
    http://us2.un4seen.com/files/bass24.zip


    在 Delphi 中使用前, 有三步工作要做:
    1、复制 Bass.dll 到系统可以识别的文件夹, 譬如: Windows\System32、Windows、Windows\System, 也可以是系统或用户的环境变量 Path 指定的任何目录, 还可以在做程序时放在当前目录, 随便放一个文件夹然后在程序中指定路径也可以.
    2、把专为 Delphi 写的头文件 bass.pas 放在某个目录(譬如: C:\Program Files\CodeGear\RAD Studio\6.0\Imports\Bass24).
    3、然后从 Delphi 菜单 -> Tools -> Options -> Library-Win32 -> Library path -> 然后 Add 这个目录 (
    例子).

  • 相关阅读:
    [小技巧] micropython 如何执行 *.mpy 文件
    从零开始深入 Linux 底层(软件工程)
    从嵌套结构中取值时如何编写兜底逻辑
    学习JUC源码(2)——自定义同步组件
    学习JUC源码(1)——AQS同步队列(源码分析结合图文理解)
    Java多线程中的wait/notify通信模式
    详解Java锁的升级与对比(1)——锁的分类与细节(结合部分源码)
    认识Redis集群——Redis Cluster
    工作三年多的感慨与总结(二)
    工作三年多的感慨与总结(一)
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3019695.html
Copyright © 2020-2023  润新知