您的位置:首页 > 编程语言 > Delphi

在 Delphi 下使用 DirectSound (4): 设置音量、相位、播放频率和播放位置

2011-01-16 22:51 603 查看
通过 IDirectSoundBuffer 的 SetVolume、SetPan、SetFrequency、SetCurrentPosition 方法可以简单进行这些设置.

同时 IDirectSoundBuffer 也有对应的 GetVolume、GetPan、GetFrequency、GetCurrentPosition 方法.

关键的一点是如果能让缓冲区接受音量、相位和频率的设置, 必须在建立缓冲区时指定相应的标志.

下面的常量说明了它们的取值范围:
DSBVOLUME_MAX = 0;      //音量最大值, 保持在控制面板设置的音量
DSBVOLUME_MIN = -10000; //音量最小值

DSBPAN_LEFT   = -10000; //左声道
DSBPAN_CENTER = 0;      //均衡
DSBPAN_RIGHT  = 10000;  //右声道

DSBFREQUENCY_ORIGINAL = 0;      //使用默认
DSBFREQUENCY_MIN      = 100;    //频率最小值
DSBFREQUENCY_MAX      = 200000; //频率最大值, 在 DirectSound 9.0 之下的版本, 此值是 100000


在上一个例子中, 最占篇幅的就是那两个函数; 为了更方便使用, 把它们做在了一个 TReadWaveFile 类里:

{实现 TReadWaveFile 类的单元}
unit ReadWaveFile;

interface

uses Windows, Classes, SysUtils, MMSystem;

type
TReadWaveFile = class
private
FFileHandle: HMMIO;
FFormat: TWaveFormatEx;
FSize: DWORD;
public
constructor Create;
destructor Destroy; override;
function Open(FileName: string): Boolean;            //打开文件并读取信息
function Read(pDest: Pointer; Size: DWORD): Boolean; //读出波形数据
property Format: TWaveFormatEx read FFormat;         //读出格式数据
property Size: DWORD read FSize;                     //读出波形数据的大小
end;

implementation

{ TReadWaveFile }

constructor TReadWaveFile.Create;
begin
inherited;

end;

destructor TReadWaveFile.Destroy;
begin
if FFileHandle > 0 then mmioClose(FFileHandle, 0);
inherited;
end;

function TReadWaveFile.Open(FileName: string): Boolean;
var
ckiRIFF,ckiFmt,ckiData: TMMCKInfo;
begin
Result := False;
if not FileExists(FileName) then Exit;

FFileHandle := mmioOpen(PChar(FileName), nil, MMIO_READ);
if FFileHandle = 0 then Exit;
ZeroMemory(@ckiRIFF, SizeOf(TMMCKInfo));
mmioDescend(FFileHandle, @ckiRIFF, nil, MMIO_FINDRIFF);
if (ckiRIFF.ckid <> FOURCC_RIFF) or (ckiRIFF.fccType <> mmioStringToFOURCC('WAVE',0)) then Exit;

ZeroMemory(@FFormat, SizeOf(TWaveFormatEx));
ZeroMemory(@ckiFmt, SizeOf(TMMCKInfo));
ckiFmt.ckid := mmioStringToFOURCC('fmt', 0);

ZeroMemory(@ckiData, SizeOf(TMMCKInfo));
ckiData.ckid := mmioStringToFOURCC('data', 0);

if (mmioDescend(FFileHandle, @ckiFmt, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then
mmioRead(FFileHandle, @FFormat, SizeOf(TWaveFormatEx));

mmioAscend(FFileHandle, @ckiFmt, 0);

if (mmioDescend(FFileHandle, @ckiData, @ckiRIFF, MMIO_FINDCHUNK) = MMSYSERR_NOERROR) then
FSize := ckiData.cksize;

Result := FFormat.wFormatTag = WAVE_FORMAT_PCM;
end;

function TReadWaveFile.Read(pDest: Pointer; Size: DWORD): Boolean;
begin
Result := mmioRead(FFileHandle, pDest, Size) = Size;
end;

end.


测试程序用到了四个 Button 和三个 TrackBar 还有它们的默认事件:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;

type
TForm1 = class(TForm)
Button1: TButton;     //打开并播放
Button2: TButton;     //反复播放
Button3: TButton;     //暂停
Button4: TButton;     //从头播放
TrackBar1: TTrackBar; //用于音量调节
TrackBar2: TTrackBar; //用于相位调节
TrackBar3: TTrackBar; //用于频率调节
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
procedure TrackBar2Change(Sender: TObject);
procedure TrackBar3Change(Sender: TObject);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

uses DirectSound, ReadWaveFile; // ReadWaveFile 是 TReadWaveFile 类所在的单元

var
myDSound: IDirectSound8;
buf: IDirectSoundBuffer;

procedure TForm1.FormCreate(Sender: TObject);
begin
TrackBar1.Min := DSBVOLUME_MIN;
TrackBar1.Max := DSBVOLUME_MAX;

TrackBar2.Min := DSBPAN_LEFT;
TrackBar2.Max := DSBPAN_RIGHT;

TrackBar3.Min := 100;
TrackBar3.Max := 100000;

Button1.Caption := '打开并播放';
Button2.Caption := '反复播放';
Button3.Caption := '暂停';
Button4.Caption := '从头播放';
System.ReportMemoryLeaksOnShutdown := true;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
bufDesc: TDSBufferDesc;
p1: Pointer;
n1: DWORD;
wavPath: string;
wav: TReadWaveFile; //
begin
buf := nil;
myDSound := nil;
with TOpenDialog.Create(nil) do begin
Filter := 'Wave File(*.wav)|*.wav';
if Execute then wavPath := FileName;
Free;
end;

wav := TReadWaveFile.Create;
if not wav.Open(wavPath) then
begin
ShowMessage('只能是 PCM 格式的 WAVE 文件');
wav.Free;
Exit;
end;

DirectSoundCreate8(nil, myDSound, nil);
myDSound.SetCooperativeLevel(Self.Handle, DSSCL_NORMAL);

ZeroMemory(@bufDesc, SizeOf(TDSBufferDesc));
bufDesc.dwSize := SizeOf(TDSBufferDesc);
{指定缓冲区允许音量、相位和频率调节}
bufDesc.dwFlags := DSBCAPS_STATIC or DSBCAPS_CTRLVOLUME or DSBCAPS_CTRLPAN or DSBCAPS_CTRLFREQUENCY;
bufDesc.dwBufferBytes := wav.Size;
bufDesc.lpwfxFormat := @wav.Format;

myDSound.CreateSoundBuffer(bufDesc, buf, nil);
buf.Lock(0, 0, @p1, @n1, nil, nil, DSBLOCK_ENTIREBUFFER);
wav.Read(p1, n1);

buf.Unlock(p1, n1, nil, 0);
buf.Play(0, 0, 0);

TrackBar1.Position := 0;
TrackBar2.Position := 0;
TrackBar3.Position := wav.Format.nSamplesPerSec;
wav.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
if buf <> nil then buf.Play(0, 0, DSBPLAY_LOOPING);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
if buf <> nil then buf.Stop;
end;

{从头播放}
procedure TForm1.Button4Click(Sender: TObject);
begin
if buf = nil then Exit;
buf.Stop;
buf.SetCurrentPosition(0);
buf.Play(0, 0, 0);
end;

{音量调节}
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if buf <> nil then buf.SetVolume(TTrackBar(Sender).Position);
end;

{相位调节}
procedure TForm1.TrackBar2Change(Sender: TObject);
begin
if buf <> nil then buf.SetPan(TTrackBar(Sender).Position);
end;

{频率调节}
procedure TForm1.TrackBar3Change(Sender: TObject);
begin
if buf <> nil then buf.SetFrequency(TTrackBar(Sender).Position);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
buf := nil;
myDSound := nil;
end;

end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐