次緩沖區(或叫輔助緩沖區)盡管使用了波形文件自己的 TWaveFormatEx, 但最終播放的卻只是 22050HZ 的 8 位立體聲.
因為次緩沖區最終要混入主緩沖區才播放, 可主緩沖區的缺省格式是 22050HZ 的 8 位立體聲(這利於在不同應用程序之間的平滑切換).
次緩沖區一旦建立, 其格式就無法修改了(無法使用緩沖區對象的 SetFormat() 方法); 好在主緩沖區可以重置格式.
也就是說, 播放 44100HZ、16 位的 Wave 時, 如果不通過主緩沖修改格式則無法原聲播放.
要修改格式只能手動建立主緩沖區(我們無法使 DirectSound 自動建立的主緩沖區, 沒有入口).
手動建立主緩沖區的注意事項:
1、SetCoOperativeLevel(Handle, DSSCL_PRIORITY); 因為主緩沖應該是硬緩沖, 這會影響到其它應用程序.
2、為緩沖區指定 TDSBufferDesc 結構時須 TDSBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER.
3、同時 TDSBufferDesc.dwBufferBytes = 0; 主緩沖使用的應該是硬緩沖, 其大小是固定的, 不能設置, 指定 0 即可
4、同時 TDSBufferDesc.lpwfxFormat = nil; 因為主緩沖區的格式已有默認, 重新設置必須使用 SetFormat() 方法.
另外, 主緩沖不支持 IDirectSoundBuffer8 接口(IDirectSoundBuffer8 比 IDirectSoundBuffer 多出一些功能);
在次緩沖中可以使用 IDirectSoundBuffer8,但不存在像 CreateSoundBuffer8 這樣的函數, 可通過 IDirectSoundBuffer.QueryInterface() 方法方便獲取.
測試程序:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses DirectSound, MMSystem;
var
myDSound: IDirectSound8; //設備對象
bufPrimary: IDirectSoundBuffer; //主緩沖
buf: IDirectSoundBuffer; //次緩沖
buf8: IDirectSoundBuffer8; //次緩沖的 IDirectSoundBuffer8 接口
{初始化設備}
procedure TForm1.FormCreate(Sender: TObject);
begin
DirectSoundCreate8(nil, myDSound, nil);
{若手動建立主緩沖, 設備的優先級至少要指定為 DSSCL_PRIORITY}
myDSound.SetCoOperativeLevel(Handle, DSSCL_PRIORITY);
end;
{建立主緩沖, 並修改其格式}
procedure TForm1.Button1Click(Sender: TObject);
var
wavFormat,fmt2: TWaveFormatEx;
bufDesc: TDSBufferDesc;
begin
ZeroMemory(@bufDesc, SizeOf(TDSBufferDesc));
bufDesc.dwSize := SizeOf(TDSBufferDesc);
bufDesc.dwFlags := DSBCAPS_PRIMARYBUFFER; //指明建立的是主緩沖
bufDesc.dwBufferBytes := 0; //主緩沖有固定的大小, 無需指定, 須是 0
bufDesc.lpwfxFormat := nil; //主緩沖有自己的格式, 修改它須通過 SetFormat() 方法
myDSound.CreateSoundBuffer(bufDesc, bufPrimary, nil);
{顯示修改前主緩沖格式}
bufPrimary.GetFormat(@fmt2, SizeOf(TWaveFormatEx), nil);
ShowMessageFmt('主緩沖默認: %dHZ %d 位 %d 聲道', [fmt2.nSamplesPerSec, fmt2.wBitsPerSample, fmt2.nChannels]);
{修改主緩沖的格式}
ZeroMemory(@wavFormat, SizeOf(TWaveFormatEx));
with wavFormat do begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := 2;
nSamplesPerSec := 44100;
wBitsPerSample := 16;
nBlockAlign := wBitsPerSample * nChannels div 8;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
end;
bufPrimary.SetFormat(@wavFormat);
{顯示修改後主緩沖格式}
bufPrimary.GetFormat(@fmt2, SizeOf(TWaveFormatEx), nil);
ShowMessageFmt('主緩沖改後: %dHZ %d 位 %d 聲道', [fmt2.nSamplesPerSec, fmt2.wBitsPerSample, fmt2.nChannels]);
end;
{建立次緩沖, 同時獲取個 IDirectSoundBuffer8 接口}
procedure TForm1.Button2Click(Sender: TObject);
var
wavFormat,fmt2: TWaveFormatEx;
bufDesc: TDSBufferDesc;
begin
{為建立次緩沖准備格式}
ZeroMemory(@wavFormat, SizeOf(TWaveFormatEx));
with wavFormat do begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := 2;
nSamplesPerSec := 44100;
wBitsPerSample := 16;
nBlockAlign := wBitsPerSample * nChannels div 8;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
end;
ZeroMemory(@bufDesc, SizeOf(TDSBufferDesc));
bufDesc.dwSize := SizeOf(TDSBufferDesc);
bufDesc.dwFlags := DSBCAPS_STATIC;
bufDesc.dwBufferBytes := 3 * wavFormat.nAvgBytesPerSec; //指定容納 3 秒鐘的波形數據
bufDesc.lpwfxFormat := @wavFormat;
{建立 IDirectSoundBuffer, 並查看其格式}
myDSound.CreateSoundBuffer(bufDesc, buf, nil);
buf.GetFormat(@fmt2, SizeOf(TWaveFormatEx), nil);
ShowMessageFmt('buf: %dHZ %d 位 %d 聲道', [fmt2.nSamplesPerSec, fmt2.wBitsPerSample, fmt2.nChannels]);
{從 IDirectSoundBuffer 獲取 IDirectSoundBuffer8, 並查看其格式}
buf.QueryInterface(IID_IDirectSoundBuffer8, buf8); //
ZeroMemory(@fmt2, SizeOf(TWaveFormatEx));
buf.GetFormat(@fmt2, SizeOf(TWaveFormatEx), nil);
ShowMessageFmt('buf8: %dHZ %d 位 %d 聲道', [fmt2.nSamplesPerSec, fmt2.wBitsPerSample, fmt2.nChannels]);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
bufPrimary := nil;
buf := nil;
buf8 := nil;
myDSound := nil;
end;
end.