关键字: VB .NET DirectX DirectSound 3D 作者:董含君
经过一下午的奋战,走了若干弯路,终于可以播放3D声音效果了
感动 ~ ~
大体按照下列的步骤来:
1 关联设备 SetCooperativeLevel
2 设置3D硬件效果 DSoundHelper.Guid3DAlgorithmHrtfFull
3 格式要求 SoundFormat 必须是单声道,不能是立体声
4 主要缓冲区描述
5 创建Listenner
6 辅助缓冲区读取wav
7 创建3D缓冲区
8 播放
9 控制空间位置,以及设置多普勒效应因子,衰减因子
10 停止播放
以下代码注释比较全,顺序比微软的例子简单不少
由于CSDN的Blog不能上传贴图以及RAR,只能帖代码了,有两个Button 一个Picturebox,还有若干Label
==================================================================================
Imports Microsoft.DirectX
Imports Microsoft.DirectX.DirectSound
Imports System.Drawing
Imports System.Drawing.Graphics
Public Class Form1
Inherits System.Windows.Forms.Form
Dim Dev As Device '设备
Dim Buff As Buffer '主要缓冲
Dim SBuff As SecondaryBuffer '二级缓冲
Dim Buff3D As Buffer3D '3D缓冲
Dim descBuff As BufferDescription '缓冲区描述
Dim Buff3DSet As Buffer3DSettings '3D缓冲设置
Dim Listenner As Listener3D '听众
Dim ListennerSet As Listener3DSettings '听众设置
Dim Pic As Graphics
Dim BMP As Bitmap
Const FN = "g:\media\wav\rod2m.wav" '要播放的文件,必须是单声道
#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 Button1 As System.Windows.Forms.Button
Friend WithEvents Button2 As System.Windows.Forms.Button
Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
Friend WithEvents Label1 As System.Windows.Forms.Label
Friend WithEvents Label2 As System.Windows.Forms.Label
Friend WithEvents Label3 As System.Windows.Forms.Label
Friend WithEvents Label4 As System.Windows.Forms.Label
Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
Friend WithEvents TextBox2 As System.Windows.Forms.TextBox
Friend WithEvents TextBox3 As System.Windows.Forms.TextBox
Friend WithEvents TextBox4 As System.Windows.Forms.TextBox
Friend WithEvents Label5 As System.Windows.Forms.Label
Friend WithEvents TextBox5 As System.Windows.Forms.TextBox
Friend WithEvents Label6 As System.Windows.Forms.Label
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button
Me.Button2 = New System.Windows.Forms.Button
Me.PictureBox1 = New System.Windows.Forms.PictureBox
Me.Label1 = New System.Windows.Forms.Label
Me.Label2 = New System.Windows.Forms.Label
Me.Label3 = New System.Windows.Forms.Label
Me.Label4 = New System.Windows.Forms.Label
Me.TextBox1 = New System.Windows.Forms.TextBox
Me.TextBox2 = New System.Windows.Forms.TextBox
Me.TextBox3 = New System.Windows.Forms.TextBox
Me.TextBox4 = New System.Windows.Forms.TextBox
Me.Label5 = New System.Windows.Forms.Label
Me.TextBox5 = New System.Windows.Forms.TextBox
Me.Label6 = New System.Windows.Forms.Label
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(24, 8)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(88, 32)
Me.Button1.TabIndex = 0
Me.Button1.Text = "初始化"
'
'Button2
'
Me.Button2.Location = New System.Drawing.Point(24, 48)
Me.Button2.Name = "Button2"
Me.Button2.Size = New System.Drawing.Size(88, 32)
Me.Button2.TabIndex = 1
Me.Button2.Text = "播放"
'
'PictureBox1
'
Me.PictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
Me.PictureBox1.Location = New System.Drawing.Point(152, 48)
Me.PictureBox1.Name = "PictureBox1"
Me.PictureBox1.Size = New System.Drawing.Size(552, 432)
Me.PictureBox1.TabIndex = 2
Me.PictureBox1.TabStop = False
'
'Label1
'
Me.Label1.Location = New System.Drawing.Point(8, 104)
Me.Label1.Name = "Label1"
Me.Label1.TabIndex = 3
Me.Label1.Text = "多普勒效应0~10"
'
'Label2
'
Me.Label2.Location = New System.Drawing.Point(8, 160)
Me.Label2.Name = "Label2"
Me.Label2.TabIndex = 4
Me.Label2.Text = "衰减因子 0~10"
'
'Label3
'
Me.Label3.Location = New System.Drawing.Point(8, 216)
Me.Label3.Name = "Label3"
Me.Label3.TabIndex = 5
Me.Label3.Text = "最大距离 0~100"
'
'Label4
'
Me.Label4.Location = New System.Drawing.Point(8, 272)
Me.Label4.Name = "Label4"
Me.Label4.TabIndex = 6
Me.Label4.Text = "最小距离 0~100"
'
'TextBox1
'
Me.TextBox1.Location = New System.Drawing.Point(24, 128)
Me.TextBox1.Name = "TextBox1"
Me.TextBox1.TabIndex = 7
Me.TextBox1.Text = "0.0"
'
'TextBox2
'
Me.TextBox2.Location = New System.Drawing.Point(24, 184)
Me.TextBox2.Name = "TextBox2"
Me.TextBox2.TabIndex = 8
Me.TextBox2.Text = "0.0"
'
'TextBox3
'
Me.TextBox3.Location = New System.Drawing.Point(24, 240)
Me.TextBox3.Name = "TextBox3"
Me.TextBox3.TabIndex = 9
Me.TextBox3.Text = "0.9"
'
'TextBox4
'
Me.TextBox4.Location = New System.Drawing.Point(24, 296)
Me.TextBox4.Name = "TextBox4"
Me.TextBox4.TabIndex = 10
Me.TextBox4.Text = "20.0"
'
'Label5
'
Me.Label5.Location = New System.Drawing.Point(8, 328)
Me.Label5.Name = "Label5"
Me.Label5.TabIndex = 11
Me.Label5.Text = "Y轴"
'
'TextBox5
'
Me.TextBox5.Location = New System.Drawing.Point(24, 352)
Me.TextBox5.Name = "TextBox5"
Me.TextBox5.TabIndex = 12
Me.TextBox5.Text = "0.0"
'
'Label6
'
Me.Label6.Location = New System.Drawing.Point(152, 16)
Me.Label6.Name = "Label6"
Me.Label6.Size = New System.Drawing.Size(424, 24)
Me.Label6.TabIndex = 13
Me.Label6.Text = "Label6"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(6, 14)
Me.ClientSize = New System.Drawing.Size(720, 501)
Me.Controls.Add(Me.Label6)
Me.Controls.Add(Me.TextBox5)
Me.Controls.Add(Me.Label5)
Me.Controls.Add(Me.TextBox4)
Me.Controls.Add(Me.TextBox3)
Me.Controls.Add(Me.TextBox2)
Me.Controls.Add(Me.TextBox1)
Me.Controls.Add(Me.Label4)
Me.Controls.Add(Me.Label3)
Me.Controls.Add(Me.Label2)
Me.Controls.Add(Me.Label1)
Me.Controls.Add(Me.PictureBox1)
Me.Controls.Add(Me.Button2)
Me.Controls.Add(Me.Button1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
#End Region
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'''加载的时候初始化一下PictureBox,把它变成黑色(没有颜色)
PictureBox1_DoubleClick(0, Nothing)
End Sub
Sub initDirectSound()
''加载DirectSound设备以及读取wav文件
'设置3D模式
Dim DSMode As Guid
DSMode = DSoundHelper.Guid3DAlgorithmHrtfFull '由于为了演示3D效果,所以用最高模式
'关联窗体
Dev = New Device
Dev.SetCooperativeLevel(Me.Handle, CooperativeLevel.Priority)
''加载wav '''注释掉了,原来测试用的
'Dim TmpDesc As New BufferDescription
'TmpDesc.Guid3DAlgorithm = DSMode
'TmpDesc.Control3D = True
'SBuff = New SecondaryBuffer(FN, TmpDesc, Dev)
'格式有比较严格的限制
Dim fmt As 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
'创建描述
descBuff = New BufferDescription
'descBuff.ControlVolume = True
descBuff.Control3D = True
'descBuff.GlobalFocus = True
'descBuff.StaticBuffer = True
'descBuff.LocateInHardware = True
descBuff.PrimaryBuffer = True
descBuff.Format = fmt
'descBuff.Guid3DAlgorithm = DSMode
'''以上可以自己去掉注释尝试一下,某些时候当Primary打开的时候,其他的不能用,有冲突,尤其是后面几个
'创建主缓冲
Try
'''捕获一下,防止descript的描述不正确(就是参数设置的不对)
Buff = New Buffer(descBuff, Dev)
Catch ex As Exception
MsgBox(ex.Message)
End '不对的话,就没有必要继续了
End Try
'创建听众
Listenner = New Listener3D(Buff)
ListennerSet = Listenner.AllParameters '使用主缓冲听众的设置
''WAV
Dim tmpDesc2 As New BufferDescription
tmpDesc2.Guid3DAlgorithm = DSMode
tmpDesc2.Control3D = True
''' 这里必须借助辅助缓冲给主缓冲提供实例,不知道微软怎么想的,也可能是我学艺不精,怎么尝试都要这样用
Buff = New SecondaryBuffer(FN, tmpDesc2, Dev)
'创建3D缓冲区
Buff3D = New Buffer3D(Buff)
Buff3DSet = Buff3D.AllParameters '使用默认的设置
Buff3DSet.Mode = Mode3D.HeadRelative '改变一个参数
Buff3D.AllParameters = Buff3DSet '应用新的设置
MsgBox("已经读取" + FN)
'ok,初始化完成
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Buff.Play(0, BufferPlayFlags.Looping)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
initDirectSound()
End Sub
Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
''' 当鼠标左键按下去的时候有效,我可不希望鼠标经过就改变
If e.Button <> MouseButtons.Left Then Exit Sub
Dim r = New Rectangle(e.X, e.Y, 3, 3)
Pic = PictureBox1.CreateGraphics()
Me.Text = e.X.ToString + "," + e.Y.ToString
Pic.DrawImage(BMP, 1, 1)
Pic.DrawEllipse(New Pen(Color.Red), r)
SetSoundPos(Convert.ToSingle(e.X), Convert.ToSingle(TextBox5.Text), Convert.ToSingle(e.Y))
'''这里坐标变换一下,因为y轴向上,我们需要的是远近,所以负值给Z轴(从上面俯视)
End Sub
Private Sub PictureBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureBox1.DoubleClick
''' 清除画板,只需双击一下,免得太乱
BMP = New Bitmap(400, 300)
PictureBox1.BackgroundImage = BMP
End Sub
Sub SetSoundPos(ByVal x As Single, ByVal y As Single, ByVal z As Single)
'''''''''用户改变位置以及速度之后,对Buff进行调整的代码
''' 很简单,就是更改参数而已
''' 定义域在-1 到 1 之间
Dim POS As Vector3
Dim Speed As Vector3
POS.X = (x - PictureBox1.Width / 2) / 100
POS.Y = y / 100
POS.Z = (z - PictureBox1.Height / 2) / 100
Speed.X = 1
Speed.Y = 1
Speed.Z = 1
Buff3D.Position = POS
Buff3D.Velocity = Speed
Label6.Text = "相对坐标:(x,y)=" + x.ToString + "," + z.ToString
End Sub
End Class
================================================================================
这里对y轴的操作不多,我无法用Picturebox描述3D的效果,也许学会了D3D就可以比较形象的描述了
而且对于多普勒也没有过多的使用(我的音箱很难分辨),最好用那种汽车的单一的声音最好
还有速度的改变需要检测鼠标两次的位置判断(需要研究公式的,懒)否则多普勒不够真实
对于表现DirectSound3D的性能,这个例子是不够完善的,但是对于介绍使用DS3D的步骤,我想还是
说得过去的.其他的部分大家自己完善就可以了.
下次就是最后的部分了,利用DirectSound进行混音,实现特效.
倒是想过自己做一个封装,用于声音引擎,但是似乎牵扯到3D的地方必须了解D3D,所以DS一般都包含在游戏引擎里面
单独拿出来就没有太大的意义了(除非不使用3D)