zoukankan      html  css  js  c++  java
  • 在 Delphi 下使用 DirectSound (5): 获取或设置缓冲区的格式:


    次缓冲区(或叫辅助缓冲区)尽管使用了波形文件自己的 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.
    
    
    
    

  • 相关阅读:
    缓存雪崩与缓存穿透
    读取表中最大值
    使用vscode在谷歌上运行代码
    elment 中tree组件展开所有和收缩所有节点
    深度系统商店提示无法安装软件依赖错误
    诗词,理解,品论
    《45个十分钟读懂资本论》原文、适合朗读版和个人见解
    《论持久战》全文
    OSError: [WinError 126] 找不到指定的模块。
    C++ 获取序列最大(或最小)的 N 个元素
  • 原文地址:https://www.cnblogs.com/del/p/1937823.html
Copyright © 2011-2022 走看看