DirectX与VB.NET编程(五)3D音效实践篇 (转)

恩,这次讲DS3D实践篇,就是做一个DS3D的例子。
这次的例子是一个3D播放器,开始播放声音后不仅可以设置声源和听众的位置,还可以设置各种其它参数。

===============华丽的分割线===============

学习要点:
·掌握使用WaveFormat类;
·掌握使用Guid3DAlgorithm类;
·掌握使用主缓冲区和二级缓冲区;
·将DS3D的各项理论实践化。

===============华丽的分割线===============

首先,在讲解DS3D程序时把DS3D程序的大概流程列举出来:
1、初始化设备并绑定到窗口;
2、初始化WaveFormat(声音格式);
3、初始化主缓冲区并让其格式为实现定义的声音格式;
4、使用主缓冲区描述来初始化主缓冲区;
5、使用主缓冲区来初始化听众;
6、设定听众的属性;
7、初始化二级缓冲区描述,设定描述的Guid3DAlgorithm(声音质量)类并使用它来初始化二级缓冲区;
8、使用二级缓冲区来初始化3D音效缓冲区(声源);
9、设置3D音效缓冲区的属性;
10、播放声音;
11、调整各项参数以达到不同的播放效果。

这样说可能比较复杂,说形象点吧:
DS3D中有两个重要物体:听众和声源,声源可以有多个,但是听众却只能有一个,DS3D播放声音的原理是一个主缓冲区和多个二级缓冲区,每个二级缓冲区可以代表一个物体,它会发出自己的声音,这些声音当然就被加载在其对应的二级缓冲区里面了,而主缓冲区则只能有一个,代表听众,二级缓冲播放声音时就将它的声音灌输到主缓冲区里面,就好比各个声源的声音传播到听众耳朵里一样,这样就解释了主缓冲区和二级缓冲区的工作原理。基于这一点,二级缓冲区就必须与声源(3D音效缓冲区)对应,主缓冲区就必须与听众对应。本人在这里也是理解了很久,最终根据SDK中的C#例子看明白了(本人的SDK中不知为何找不到VB.NET的例子。。)
原理都明白了,就开始写代码了。

===============华丽的分割线===============

首先在窗口上面放置一个按钮(Button)、六个标签(Label)、六个文本框(TextBox)和一个图片框(PictureBox)。具体布局可以参考图1或者代码。

图1

===============华丽的分割线===============

程序运行时加载声音并播放。
首先声明类全局变量:
Dim Dev As Device    '设备
Dim Buff As Buffer    '主缓冲区
Dim SBuff As SecondaryBuffer    '二级缓冲区
Dim BDes As New BufferDescription    '主缓冲区描述
Dim SBDes As New BufferDescription    '二级缓冲区描述
Dim B3D As Buffer3D    '3D缓冲区
Dim B3DS As New Buffer3DSettings    '3D缓冲区描述
Dim FMT As WaveFormat    '声音格式
Dim Lis As Listener3D    '听众
Dim LisS As Listener3DSettings    '听众属性

===============华丽的分割线===============

初始化设备和声音格式:
Dev = New Device
Dev.SetCooperativeLevel(Me, CooperativeLevel.Normal)
FMT = New WaveFormat
FMT.FormatTag = WaveFormatTag.Pcm
FMT.Channels = 2
FMT.SamplesPerSecond = 22050
FMT.BitsPerSample = 16
FMT.BlockAlign = CShort(FMT.BitsPerSample / 8 * FMT.Channels)
FMT.AverageBytesPerSecond = FMT.SamplesPerSecond * FMT.BlockAlign

其中声音格式的各项参数属性:
FormatTag:音频格式。
Channels:声道数,2代表立体声。
SamplesPerSecond:音频采样级别,每秒的采样数量。
BitsPerSample:音频采样大小,每个采样的大小。
BlockAlign:每位输出率,即采样输出的比特率(根据公式猜测)。
AverageBytesPerSecond:平均每秒字节数,该数乘以把就是平均每秒比特数,即Kbps。
其实这些属性大概就是控制声音的输出品质和速率吧,本人也没有尝试过。

===============华丽的分割线===============

下面设置主缓冲区描述,并使用该描述初始化主缓冲区:
BDes = New BufferDescription    '初始化描述
BDes.PrimaryBuffer = True    '设置为主缓冲区
BDes.Control3D = True    '设置为3D可调整
BDes.Format = FMT    '设置声音格式
Buff = New Buffer(BDes, Dev)    '使用描述初始化主缓冲区

说明一下,PrimaryBuffer代表设置缓冲区为主缓冲区,Control3D与ControlPan和ControlVolume的效果是相同的,即设置缓冲区是否可调整3D音效,Format即让其声音格式等于刚才设置的格式。

===============华丽的分割线===============

下面开始是初始化听众:
Lis = New Listener3D(Buff)
LisS = Lis.AllParameters
Dim LPos As Vector3
Dim LVel As Vector3
LPos.X = 0
LPos.Y = 0
LPos.Z = 0
LVel.X = 0
LVel.Y = 0
LVel.Z = 0
LisS.Position = LPos
LisS.Velocity = LVel
Lis.AllParameters = LisS

使用主缓冲区初始化听众,然后使用Lis代替修改其位置与速度,本例中听众位于中央且不动,故如此设置。需要注意的是听众的AllParamenters必须这样设置,Lis.AllParamenters.X=0等诸如此类的赋值会引起编译器报错。其实上面也很多地方也涉及到这种赋值方法。
到此为止听众已经初始化完毕了,其实前面设置主缓冲区、主缓冲区描述和声音格式等均是为了听众作铺垫。

===============华丽的分割线===============

开始设置声源(3D缓冲区),首先需要设置一个二级缓冲区及其描述:
SBDes.Guid3DAlgorithm = DSoundHelper.Guid3DAlgorithmHrtfLight    '设置品质为高
SBDes.Control3D = True    '设置为3D可调整
SBuff = New SecondaryBuffer("D:\魔兽争霸2\DRIVERS\DIGTEST.WAV", SBDes, Dev)    '使用描述初始化二级缓冲区

然后使用该二级缓冲区初始化3D缓冲区(声源):
B3D = New Buffer3D(SBuff)    '使用二级缓冲区初始化3D缓冲区
B3DS = B3D.AllParameters
B3DS.Mode = Mode3D.HeadRelative
B3D.AllParameters = B3DS

这里设置3D缓冲区的Mode属性时也使用了与上面相同的方法来设置。

===============华丽的分割线===============

最后初始化文本框并播放声音:
TextBox1.Text = B3D.MaxDistance.ToString
TextBox2.Text = B3D.MinDistance.ToString
TextBox3.Text = Lis.RolloffFactor.ToString
TextBox4.Text = Lis.DopplerFactor.ToString
TextBox5.Text = B3D.ConeAngles.Inside.ToString
TextBox6.Text = B3D.ConeAngles.Outside.ToString
SBuff.Play(0, BufferPlayFlags.Looping)    '声源开始发声

到此为止已经初始化3D声音并开始播放了。

===============华丽的分割线===============

用户应该可以调整声源的位置,以达到不同的播放效果,这里使用图片框进行调整,用户点击图片框时来调整声源的平面位置,因为这里还没有学习Direct3D因此忽略Y轴(声源与听众处于同一Y轴坐标0),同时由于没有学习DirectDraw,因此没有在所处位置绘出图形,您可以自行使用GDI绘制。修改位置的代码如下:
Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
      Dim Pos As Vector3
      Dim Vel As Vector3
      Pos.X = (e.X - PictureBox1.Width / 2) / 200
      Pos.Y = 0
      Pos.Z = (e.Y - PictureBox1.Height / 2) / 200
      Vel.X = 0
      Vel.Y = 0
      Vel.Z = 0
      B3D.Position = Pos    '设置声源的位置
      B3D.Velocity = Vel    '设置声源的速度
End Sub

===============华丽的分割线===============

如果用户需要修改参数,可以在相应文本框中输入值并点击“应用设置”即可:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      Dim TS As Buffer3DSettings    '声源属性
      Dim LS As Listener3DSettings    '
      TS = B3D.AllParameters
      LS = Lis.AllParameters
      TS.MaxDistance = Val(TextBox1.Text)    '设置最大距离
      TS.MinDistance = Val(TextBox2.Text)    '设置最小距离
      LS.RolloffFactor = Val(TextBox3.Text)    '设置衰减因子
      LS.DopplerFactor = Val(TextBox4.Text)    '设置多普勒因子
      TS.InsideConeAngle = Val(TextBox5.Text)    '设置内锥角
      TS.OutsideConeAngle = Val(TextBox6.Text)    '设置外锥角
      B3D.AllParameters = TS
      Lis.AllParameters = LS
End Sub

===============华丽的分割线===============

下面是程序的全部代码:
Imports Microsoft.DirectX.DirectSound
Imports Microsoft.DirectX

Public Class Form1
      Inherits System.Windows.Forms.Form
      Dim Dev As Device    '设备
      Dim Buff As Buffer    '主缓冲区
      Dim SBuff As SecondaryBuffer    '二级缓冲区
      Dim BDes As New BufferDescription    '主缓冲区描述
      Dim SBDes As New BufferDescription    '二级缓冲区描述
      Dim B3D As Buffer3D    '3D缓冲区
      Dim B3DS As New Buffer3DSettings    '3D缓冲区描述
      Dim FMT As WaveFormat    '声音格式
      Dim Lis As Listener3D    '听众
      Dim LisS As Listener3DSettings    '听众属性


#Region " Windows 窗体设计器生成的代码 "

      Public Sub New()
          MyBase.New()

          '该调用是 Windows 窗体设计器所必需的。
          InitializeComponent()

          '在 InitializeComponent() 调用之后添加任何初始化

      End Sub

      '窗体重写 dispose 以清理组件列表。
      Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
          If disposing Then
              If Not (components Is Nothing) Then
                  components.Dispose()
              End If
          End If
          MyBase.Dispose(disposing)
      End Sub

      'Windows 窗体设计器所必需的
      Private components As System.ComponentModel.IContainer

      '注意: 以下过程是 Windows 窗体设计器所必需的
      '可以使用 Windows 窗体设计器修改此过程。
      '不要使用代码编辑器修改它。
      Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
      Friend WithEvents Label1 As System.Windows.Forms.Label
      Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
      Friend WithEvents Label2 As System.Windows.Forms.Label
      Friend WithEvents TextBox2 As System.Windows.Forms.TextBox
      Friend WithEvents Label3 As System.Windows.Forms.Label
      Friend WithEvents TextBox3 As System.Windows.Forms.TextBox
      Friend WithEvents Label4 As System.Windows.Forms.Label
      Friend WithEvents TextBox4 As System.Windows.Forms.TextBox
      Friend WithEvents Button1 As System.Windows.Forms.Button
      Friend WithEvents Label5 As System.Windows.Forms.Label
      Friend WithEvents TextBox5 As System.Windows.Forms.TextBox
      Friend WithEvents Label6 As System.Windows.Forms.Label
      Friend WithEvents TextBox6 As System.Windows.Forms.TextBox
      <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
          Me.PictureBox1 = New System.Windows.Forms.PictureBox
          Me.Label1 = New System.Windows.Forms.Label
          Me.TextBox1 = New System.Windows.Forms.TextBox
          Me.Label2 = New System.Windows.Forms.Label
          Me.TextBox2 = New System.Windows.Forms.TextBox
          Me.Label3 = New System.Windows.Forms.Label
          Me.TextBox3 = New System.Windows.Forms.TextBox
          Me.Label4 = New System.Windows.Forms.Label
          Me.TextBox4 = New System.Windows.Forms.TextBox
          Me.Button1 = New System.Windows.Forms.Button
          Me.Label5 = New System.Windows.Forms.Label
          Me.TextBox5 = New System.Windows.Forms.TextBox
          Me.Label6 = New System.Windows.Forms.Label
          Me.TextBox6 = New System.Windows.Forms.TextBox
          Me.SuspendLayout()
          '
          'PictureBox1
          '
          Me.PictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
          Me.PictureBox1.Location = New System.Drawing.Point(8, 8)
          Me.PictureBox1.Name = "PictureBox1"
          Me.PictureBox1.Size = New System.Drawing.Size(320, 320)
          Me.PictureBox1.TabIndex = 0
          Me.PictureBox1.TabStop = False
          '
          'Label1
          '
          Me.Label1.Location = New System.Drawing.Point(336, 8)
          Me.Label1.Name = "Label1"
          Me.Label1.Size = New System.Drawing.Size(56, 16)
          Me.Label1.TabIndex = 1
          Me.Label1.Text = "最大距离"
          '
          'TextBox1
          '
          Me.TextBox1.Location = New System.Drawing.Point(336, 24)
          Me.TextBox1.Name = "TextBox1"
          Me.TextBox1.Size = New System.Drawing.Size(144, 21)
          Me.TextBox1.TabIndex = 2
          Me.TextBox1.Text = ""
          '
          'Label2
          '
          Me.Label2.Location = New System.Drawing.Point(336, 56)
          Me.Label2.Name = "Label2"
          Me.Label2.Size = New System.Drawing.Size(64, 16)
          Me.Label2.TabIndex = 3
          Me.Label2.Text = "最小距离"
          '
          'TextBox2
          '
          Me.TextBox2.Location = New System.Drawing.Point(336, 72)
          Me.TextBox2.Name = "TextBox2"
          Me.TextBox2.Size = New System.Drawing.Size(144, 21)
          Me.TextBox2.TabIndex = 4
          Me.TextBox2.Text = ""
          '
          'Label3
          '
          Me.Label3.Location = New System.Drawing.Point(336, 104)
          Me.Label3.Name = "Label3"
          Me.Label3.Size = New System.Drawing.Size(56, 16)
          Me.Label3.TabIndex = 5
          Me.Label3.Text = "衰减因子"
          '
          'TextBox3
          '
          Me.TextBox3.Location = New System.Drawing.Point(336, 120)
          Me.TextBox3.Name = "TextBox3"
          Me.TextBox3.Size = New System.Drawing.Size(144, 21)
          Me.TextBox3.TabIndex = 6
          Me.TextBox3.Text = ""
          '
          'Label4
          '
          Me.Label4.Location = New System.Drawing.Point(336, 152)
          Me.Label4.Name = "Label4"
          Me.Label4.Size = New System.Drawing.Size(72, 16)
          Me.Label4.TabIndex = 7
          Me.Label4.Text = "多普勒因子"
          '
          'TextBox4
          '
          Me.TextBox4.Location = New System.Drawing.Point(336, 168)
          Me.TextBox4.Name = "TextBox4"
          Me.TextBox4.Size = New System.Drawing.Size(144, 21)
          Me.TextBox4.TabIndex = 8
          Me.TextBox4.Text = ""
          '
          'Button1
          '
          Me.Button1.Location = New System.Drawing.Point(400, 296)
          Me.Button1.Name = "Button1"
          Me.Button1.Size = New System.Drawing.Size(80, 24)
          Me.Button1.TabIndex = 13
          Me.Button1.Text = "应用设置"
          '
          'Label5
          '
          Me.Label5.Location = New System.Drawing.Point(336, 200)
          Me.Label5.Name = "Label5"
          Me.Label5.Size = New System.Drawing.Size(72, 16)
          Me.Label5.TabIndex = 14
          Me.Label5.Text = "内锥角"
          '
          'TextBox5
          '
          Me.TextBox5.Location = New System.Drawing.Point(336, 216)
          Me.TextBox5.Name = "TextBox5"
          Me.TextBox5.Size = New System.Drawing.Size(144, 21)
          Me.TextBox5.TabIndex = 15
          Me.TextBox5.Text = ""
          '
          'Label6
          '
          Me.Label6.Location = New System.Drawing.Point(336, 248)
          Me.Label6.Name = "Label6"
          Me.Label6.Size = New System.Drawing.Size(64, 16)
          Me.Label6.TabIndex = 16
          Me.Label6.Text = "外锥角"
          '
          'TextBox6
          '
          Me.TextBox6.Location = New System.Drawing.Point(336, 264)
          Me.TextBox6.Name = "TextBox6"
          Me.TextBox6.Size = New System.Drawing.Size(144, 21)
          Me.TextBox6.TabIndex = 17
          Me.TextBox6.Text = ""
          '
          'Form1
          '
          Me.AutoScaleBaseSize = New System.Drawing.Size(6, 14)
          Me.ClientSize = New System.Drawing.Size(488, 334)
          Me.Controls.Add(Me.TextBox6)
          Me.Controls.Add(Me.Label6)
          Me.Controls.Add(Me.TextBox5)
          Me.Controls.Add(Me.Label5)
          Me.Controls.Add(Me.Button1)
          Me.Controls.Add(Me.TextBox4)
          Me.Controls.Add(Me.Label4)
          Me.Controls.Add(Me.TextBox3)
          Me.Controls.Add(Me.Label3)
          Me.Controls.Add(Me.TextBox2)
          Me.Controls.Add(Me.Label2)
          Me.Controls.Add(Me.TextBox1)
          Me.Controls.Add(Me.Label1)
          Me.Controls.Add(Me.PictureBox1)
          Me.MaximizeBox = False
          Me.Name = "Form1"
          Me.Text = "DS3D演示"
          Me.ResumeLayout(False)

      End Sub

#End Region

      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
          '初始化缓冲区

          Dev = New Device
          Dev.SetCooperativeLevel(Me, CooperativeLevel.Normal)
          FMT = New WaveFormat
          FMT.FormatTag = WaveFormatTag.Pcm
          FMT.Channels = 2
          FMT.SamplesPerSecond = 22050
          FMT.BitsPerSample = 16
          FMT.BlockAlign = CShort(FMT.BitsPerSample / 8 * FMT.Channels)
          FMT.AverageBytesPerSecond = FMT.SamplesPerSecond * FMT.BlockAlign

          BDes = New BufferDescription    '初始化描述
          BDes.PrimaryBuffer = True    '设置为主缓冲区
          BDes.Control3D = True    '设置为3D可调整
          BDes.Format = FMT    '设置声音格式
          Buff = New Buffer(BDes, Dev)    '使用描述初始化主缓冲区

          Lis = New Listener3D(Buff)
          LisS = Lis.AllParameters
          Dim LPos As Vector3
          Dim LVel As Vector3
          LPos.X = 0
          LPos.Y = 0
          LPos.Z = 0
          LVel.X = 0
          LVel.Y = 0
          LVel.Z = 0
          LisS.Position = LPos
          LisS.Velocity = LVel
          Lis.AllParameters = LisS

          '加载声音

          SBDes.Guid3DAlgorithm = DSoundHelper.Guid3DAlgorithmHrtfLight    '设置品质为高
          SBDes.Control3D = True    '设置为3D可调整
          SBuff = New SecondaryBuffer("D:\魔兽争霸2\DRIVERS\DIGTEST.WAV", SBDes, Dev)    '使用描述初始化二级缓冲区

          B3D = New Buffer3D(SBuff)    '使用二级缓冲区初始化3D缓冲区
          B3DS = B3D.AllParameters
          B3DS.Mode = Mode3D.HeadRelative
          B3D.AllParameters = B3DS

          TextBox1.Text = B3D.MaxDistance.ToString
          TextBox2.Text = B3D.MinDistance.ToString
          TextBox3.Text = Lis.RolloffFactor.ToString
          TextBox4.Text = Lis.DopplerFactor.ToString
          TextBox5.Text = B3D.ConeAngles.Inside.ToString
          TextBox6.Text = B3D.ConeAngles.Outside.ToString
          SBuff.Play(0, BufferPlayFlags.Looping)    '声源开始发声
      End Sub

      Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click

      End Sub

      Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
          Dim Pos As Vector3
          Dim Vel As Vector3
          Pos.X = (e.X - PictureBox1.Width / 2) / 200
          Pos.Y = 0
          Pos.Z = (e.Y - PictureBox1.Height / 2) / 200
          Vel.X = 0
          Vel.Y = 0
          Vel.Z = 0
          B3D.Position = Pos    '设置声源的位置
          B3D.Velocity = Vel    '设置声源的速度
      End Sub

      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
          Dim TS As Buffer3DSettings
          Dim LS As Listener3DSettings
          TS = B3D.AllParameters
          LS = Lis.AllParameters
          TS.MaxDistance = Val(TextBox1.Text)    '设置最大距离
          TS.MinDistance = Val(TextBox2.Text)    '设置最小距离
          LS.RolloffFactor = Val(TextBox3.Text)    '设置衰减因子
          LS.DopplerFactor = Val(TextBox4.Text)    '设置多普勒因子
          TS.InsideConeAngle = Val(TextBox5.Text)    '设置内锥角
          TS.OutsideConeAngle = Val(TextBox6.Text)    '设置外锥角
          B3D.AllParameters = TS
          Lis.AllParameters = LS
      End Sub
End Class

好了~~可以体验下3D的魅力了,注意,一定要是单声道声音!

恩,下次是传说中的声音特效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值