随笔 - 2146  文章 - 19 评论 - 11846 阅读 - 1267万


装载格式信息的结构有:
TWaveFormat = packed record
  wFormatTag: Word;
  nChannels: Word;
  nSamplesPerSec: DWORD;
  nAvgBytesPerSec: DWORD;
  nBlockAlign: Word;
end;

TPCMWaveFormat = record
  wf: TWaveFormat;
  wBitsPerSample: Word;
end;

TWaveFormatEx = packed record
  wFormatTag: Word;       {格式类型; 主要使用的是 WAVE_FORMAT_PCM}
  nChannels: Word;        {声道数; 1 是单声道、2 是立体声}
  nSamplesPerSec: DWORD;  {采样频率}
  nAvgBytesPerSec: DWORD; {传输速率}
  nBlockAlign: Word;      {每次采样的大小}
  wBitsPerSample: Word;   {采样精度}
  cbSize: Word;           {附加数据的大小; PCM 编码的文件没这个字段}
end;


能看出它们是依次递增一个字段, 并且也是 Wave 文件的一个构成部分; 现在要做的就是从 Wave 文件中把它们取出来.

获取函数及测试代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses MMSystem;

//获取 Wave 中格式数据的函数; 常用的是 TWaveFormatEx, 但 PCM 缺它一个字段
function GetWaveFmt(FilePath: string; var fmt: TWaveFormatEx): Boolean;
var
  hFile: HMMIO;
  ckiRIFF,ckiFmt: TMMCKInfo;
begin
  Result := False;
  hFile := mmioOpen(PChar(FilePath), nil, MMIO_READ);
  if hFile = 0 then Exit;

  ZeroMemory(@ckiRIFF, SizeOf(TMMCKInfo));
  ZeroMemory(@ckiFmt, SizeOf(TMMCKInfo));
  ZeroMemory(@fmt, SizeOf(TWaveFormatEx));     {也先清空准备接受数据的结构体}
  ckiFmt.ckid := mmioStringToFOURCC('fmt', 0); {给查找格式块准备}

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

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

//调用测试
procedure TForm1.Button1Click(Sender: TObject);
const
  FilePath = 'C:\WINDOWS\Media\Windows XP 启动.wav';
var
  WaveFormat: TWaveFormatEx;
begin
  if GetWaveFmt(FilePath, WaveFormat) then with Memo1.Lines do
  begin
    Clear;
    Add(Format('wFormatTag: %d', [WaveFormat.wFormatTag]));
    Add(Format('nChannels: %d', [WaveFormat.nChannels]));
    Add(Format('nSamplesPerSec: %d', [WaveFormat.nSamplesPerSec]));
    Add(Format('nAvgBytesPerSec: %d', [WaveFormat.nAvgBytesPerSec]));
    Add(Format('nBlockAlign: %d', [WaveFormat.nBlockAlign]));
    Add(Format('wBitsPerSample: %d', [WaveFormat.wBitsPerSample]));
    Add(Format('cbSize: %d', [WaveFormat.cbSize]));
  end;
{ 显示结果:
  wFormatTag: 1
  nChannels: 2
  nSamplesPerSec: 22050
  nAvgBytesPerSec: 88200
  nBlockAlign: 4
  wBitsPerSample: 16
  cbSize: 0
}
end;

end.

posted on   万一  阅读(2750)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
历史上的今天:
2008-11-06 WinAPI 字符及字符串函数(15): CharNext、CharPrev
2008-11-06 WinAPI 字符及字符串函数(14): CharToOem、OemToChar
2008-11-06 WinAPI 字符及字符串函数(13): lstrcmp、lstrcmpi - 对比串
2008-11-06 获取汉字编码的几种方法 - 回复"外来天客"的问题


点击右上角即可分享
微信分享提示