次緩衝區(或叫輔助緩衝區)儘管使用了波形檔案自己的 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;interfaceuses 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.