下面是使用低级音频函数播放 wav 的两个方法, 对这个感兴趣的人恐怕很少, 免注释了.
使用窗口接受音频输出设备的消息:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private protected procedure WndProc(var Message: TMessage); override; public end; var Form1: TForm1; implementation {$R *.dfm} uses MMSystem; //获取文件格式和波形数据的函数 function GetWaveFmtData(path: string; var fmt: TWaveFormatEx; var buf: TBytes): Boolean; var hFile: HMMIO; ckiRIFF,ckiFmt,ckiData: TMMCKInfo; begin Result := False; hFile := mmioOpen(PChar(path), nil, MMIO_READ); if hFile = 0 then Exit; ZeroMemory(@ckiRIFF, SizeOf(TMMCKInfo)); ZeroMemory(@ckiFmt, SizeOf(TMMCKInfo)); ZeroMemory(@ckiData, SizeOf(TMMCKInfo)); ckiRIFF.fccType := mmioStringToFOURCC('WAVE', 0); ckiFmt.ckid := mmioStringToFOURCC('fmt', 0); ckiData.ckid := mmioStringToFOURCC('data', 0); ZeroMemory(@fmt, SizeOf(TWaveFormatEx)); mmioDescend(hFile, @ckiRIFF, nil, MMIO_FINDRIFF); if (ckiRIFF.ckid = FOURCC_RIFF) and (ckiRIFF.fccType = mmioStringToFOURCC('WAVE',0)) and (mmioDescend(hFile, @ckiFmt, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) and (mmioRead(hFile, @fmt, ckiFmt.cksize) = ckiFmt.cksize) and (mmioAscend(hFile, @ckiFmt, 0) = MMSYSERR_NOERROR) and (mmioDescend(hFile, @ckiData, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then begin SetLength(buf, ckiData.cksize); Result := (mmioRead(hFile, PAnsiChar(buf), ckiData.cksize) = ckiData.cksize); end; mmioClose(hFile, 0); end; //------------------------------------------------------------------------------ var wh: TWaveHdr; hOut: HWAVEOUT; fmt: TWaveFormatEx; buf: TBytes; procedure TForm1.Button1Click(Sender: TObject); const path = 'C:\WINDOWS\Media\Windows XP 启动.wav'; begin GetWaveFmtData(path, fmt, buf); wh.lpData := PAnsiChar(buf); wh.dwBufferLength := Length(buf); wh.dwBytesRecorded := 0; wh.dwUser := 0; wh.dwFlags := 0; wh.dwLoops := 1; wh.lpNext := nil; wh.reserved := 0; waveOutOpen(@hOut, WAVE_MAPPER, @fmt, Handle, 0, CALLBACK_WINDOW); waveOutPrepareHeader(hOut, @wh, SizeOf(TWaveHdr)); waveOutWrite(hOut, @wh, SizeOf(TWaveHdr)); end; procedure TForm1.WndProc(var Message: TMessage); begin inherited; case Message.Msg of MM_WOM_OPEN: ; MM_WOM_CLOSE: ; MM_WOM_DONE: begin waveOutUnprepareHeader(hOut, @wh, SizeOf(TWaveHdr)); waveOutClose(hOut); end; end; end; end.
使用回调函数:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} uses MMSystem; function GetWaveFmtData(path: string; var fmt: TWaveFormatEx; var buf: TBytes): Boolean; var hFile: HMMIO; ckiRIFF,ckiFmt,ckiData: TMMCKInfo; begin Result := False; hFile := mmioOpen(PChar(path), nil, MMIO_READ); if hFile = 0 then Exit; ZeroMemory(@ckiRIFF, SizeOf(TMMCKInfo)); ZeroMemory(@ckiFmt, SizeOf(TMMCKInfo)); ZeroMemory(@ckiData, SizeOf(TMMCKInfo)); ckiRIFF.fccType := mmioStringToFOURCC('WAVE', 0); ckiFmt.ckid := mmioStringToFOURCC('fmt', 0); ckiData.ckid := mmioStringToFOURCC('data', 0); ZeroMemory(@fmt, SizeOf(TWaveFormatEx)); mmioDescend(hFile, @ckiRIFF, nil, MMIO_FINDRIFF); if (ckiRIFF.ckid = FOURCC_RIFF) and (ckiRIFF.fccType = mmioStringToFOURCC('WAVE',0)) and (mmioDescend(hFile, @ckiFmt, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) and (mmioRead(hFile, @fmt, ckiFmt.cksize) = ckiFmt.cksize) and (mmioAscend(hFile, @ckiFmt, 0) = MMSYSERR_NOERROR) and (mmioDescend(hFile, @ckiData, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then begin SetLength(buf, ckiData.cksize); Result := (mmioRead(hFile, PAnsiChar(buf), ckiData.cksize) = ckiData.cksize); end; mmioClose(hFile, 0); end; //------------------------------------------------------------------------------ var wh: TWaveHdr; hOut: HWAVEOUT; fmt: TWaveFormatEx; buf: TBytes; procedure WaveProc(hWave: HWAVE; uMsg, dwInstance, dwParam1, dwParam2: DWORD); stdcall; begin case uMsg of MM_WOM_OPEN: ; MM_WOM_CLOSE: ; MM_WOM_DONE: begin waveOutUnprepareHeader(hWave, PWaveHdr(dwParam1), SizeOf(TWaveHdr)); waveOutClose(hWave); end; end; end; procedure TForm1.Button1Click(Sender: TObject); const path = 'C:\WINDOWS\Media\Windows XP 启动.wav'; begin GetWaveFmtData(path, fmt, buf); wh.lpData := PAnsiChar(buf); wh.dwBufferLength := Length(buf); wh.dwBytesRecorded := 0; wh.dwUser := 0; wh.dwFlags := 0; wh.dwLoops := 1; wh.lpNext := nil; wh.reserved := 0; waveOutOpen(@hOut, WAVE_MAPPER, @fmt, DWORD(@WaveProc), 0, CALLBACK_FUNCTION); waveOutPrepareHeader(hOut, @wh, SizeOf(TWaveHdr)); waveOutWrite(hOut, @wh, SizeOf(TWaveHdr)); end; //暂停 procedure TForm1.Button2Click(Sender: TObject); begin waveOutPause(hOut); end; //继续 procedure TForm1.Button3Click(Sender: TObject); begin waveOutRestart(hOut); end; end.