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 这个目录 (例子).