Click here to Skip to main content
15,883,558 members
Articles / Multimedia / DirectX

The Ultimate Managed DirectSound 9 Tutorial Part 2: managing 3D Sounds

Rate me:
Please Sign up or sign in to vote.
4.71/5 (10 votes)
2 Aug 2005CPOL5 min read 104.1K   1.3K   54  
How to playback sounds with 3D audio management.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
using System.Threading;

namespace DirectSound3DDemo {
	
	public class FrmMain : System.Windows.Forms.Form {
		
		private System.ComponentModel.Container components = null;

		public FrmMain() {
			InitializeComponent();

			pnlMain.MouseDown += new MouseEventHandler(pnlMain_MouseDown);
			pnlMain.MouseMove += new MouseEventHandler(pnlMain_MouseMove);
			pnlMain.MouseUp += new MouseEventHandler(pnlMain_MouseUp);

			prepareSound(currFile);
		}

		protected override void Dispose(bool disposing) {
			if(disposing) {
				if(components != null) {
					components.Dispose();
				}
			}
			base.Dispose(disposing);
		}

		#region Windows Forms Design Tools generated code
		private void InitializeComponent()
		{
			this.pnlMain = new DirectSound3DDemo.FlickerFreePanel();
			this.label1 = new System.Windows.Forms.Label();
			this.label2 = new System.Windows.Forms.Label();
			this.lblSoundPos = new System.Windows.Forms.Label();
			this.btnRotate = new System.Windows.Forms.Button();
			this.label3 = new System.Windows.Forms.Label();
			this.trkHeight = new System.Windows.Forms.TrackBar();
			this.label4 = new System.Windows.Forms.Label();
			((System.ComponentModel.ISupportInitialize)(this.trkHeight)).BeginInit();
			this.SuspendLayout();
			// 
			// pnlMain
			// 
			this.pnlMain.BackColor = System.Drawing.Color.Black;
			this.pnlMain.Location = new System.Drawing.Point(8, 8);
			this.pnlMain.Name = "pnlMain";
			this.pnlMain.Size = new System.Drawing.Size(312, 312);
			this.pnlMain.TabIndex = 0;
			this.pnlMain.Paint += new System.Windows.Forms.PaintEventHandler(this.pnlMain_Paint);
			// 
			// label1
			// 
			this.label1.Location = new System.Drawing.Point(328, 8);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(232, 32);
			this.label1.TabIndex = 1;
			this.label1.Text = "Red dot is the sound source, Green dot is the listener.";
			// 
			// label2
			// 
			this.label2.Location = new System.Drawing.Point(328, 48);
			this.label2.Name = "label2";
			this.label2.Size = new System.Drawing.Size(96, 16);
			this.label2.TabIndex = 2;
			this.label2.Text = "Sound Position";
			this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			// 
			// lblSoundPos
			// 
			this.lblSoundPos.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblSoundPos.Location = new System.Drawing.Point(432, 48);
			this.lblSoundPos.Name = "lblSoundPos";
			this.lblSoundPos.Size = new System.Drawing.Size(104, 16);
			this.lblSoundPos.TabIndex = 3;
			this.lblSoundPos.Text = "10, 10, 0";
			this.lblSoundPos.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
			// 
			// btnRotate
			// 
			this.btnRotate.FlatStyle = System.Windows.Forms.FlatStyle.System;
			this.btnRotate.Location = new System.Drawing.Point(336, 72);
			this.btnRotate.Name = "btnRotate";
			this.btnRotate.Size = new System.Drawing.Size(216, 24);
			this.btnRotate.TabIndex = 4;
			this.btnRotate.Text = "Rotate Source";
			this.btnRotate.Click += new System.EventHandler(this.btnRotate_Click);
			// 
			// label3
			// 
			this.label3.Location = new System.Drawing.Point(336, 112);
			this.label3.Name = "label3";
			this.label3.Size = new System.Drawing.Size(72, 32);
			this.label3.TabIndex = 5;
			this.label3.Text = "Height of the sound source";
			this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// trkHeight
			// 
			this.trkHeight.Location = new System.Drawing.Point(352, 152);
			this.trkHeight.Maximum = 50;
			this.trkHeight.Minimum = -50;
			this.trkHeight.Name = "trkHeight";
			this.trkHeight.Orientation = System.Windows.Forms.Orientation.Vertical;
			this.trkHeight.Size = new System.Drawing.Size(45, 168);
			this.trkHeight.TabIndex = 6;
			this.trkHeight.TickFrequency = 10;
			this.trkHeight.TickStyle = System.Windows.Forms.TickStyle.Both;
			this.trkHeight.Scroll += new System.EventHandler(this.trkHeight_Scroll);
			// 
			// label4
			// 
			this.label4.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.label4.Location = new System.Drawing.Point(416, 112);
			this.label4.Name = "label4";
			this.label4.Size = new System.Drawing.Size(136, 200);
			this.label4.TabIndex = 7;
			this.label4.Text = @"Instructions: click and drag on the black panel to move the sound source. Hit on 'Rotate Source' to make the source rotating around the center. Scroll the trackbar to move up and down the source in the 3D space (effects may be noticeable only on surround systems).";
			this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// FrmMain
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(570, 328);
			this.Controls.Add(this.label4);
			this.Controls.Add(this.trkHeight);
			this.Controls.Add(this.label3);
			this.Controls.Add(this.btnRotate);
			this.Controls.Add(this.lblSoundPos);
			this.Controls.Add(this.label2);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.pnlMain);
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
			this.MaximizeBox = false;
			this.Name = "FrmMain";
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
			this.Text = "DirectSound3D";
			((System.ComponentModel.ISupportInitialize)(this.trkHeight)).EndInit();
			this.ResumeLayout(false);

		}
		#endregion

		[STAThread] static void Main() {
			Application.Run(new FrmMain());
		}

		private string currFile = Application.StartupPath + "\\AudioMono.wav";
		private Device dSound;
		private SecondaryBuffer sound;
		private Buffer3D sound3D;
		private DirectSound3DDemo.FlickerFreePanel pnlMain;
		private System.Windows.Forms.Label label1;
		private Listener3D listener;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.Label lblSoundPos;
		private bool mouseDown = false;
		private System.Windows.Forms.Button btnRotate;
		private bool rotating = false;
		private int ray = 0;
		private int angle = 0;
		private System.Windows.Forms.Label label3;
		private System.Windows.Forms.TrackBar trkHeight;
		private System.Windows.Forms.Label label4;
		private int h = 0;

		private void prepareSound(string file) {
			dSound = new Device();
			dSound.SetCooperativeLevel(this.Handle, CooperativeLevel.Priority);

			BufferDescription d = new BufferDescription();
			d.Control3D = true;
			d.ControlVolume = true;
			d.ControlFrequency = true;
			d.Guid3DAlgorithm = DSoundHelper.Guid3DAlgorithmHrtfFull; // High quality algorithms

			sound = new SecondaryBuffer(currFile, d, dSound);

			sound3D = new Buffer3D(sound);
			sound3D.Mode = Mode3D.HeadRelative; // Enable possibility to move sound's source and listener positons

			Microsoft.DirectX.DirectSound.Buffer b; // A primary buffer is needed
			BufferDescription dp = new BufferDescription();
			dp.PrimaryBuffer = true;
			dp.Control3D = true;
			b = new Microsoft.DirectX.DirectSound.Buffer(dp, dSound);

			listener = new Listener3D(b);

			// Setup initial positions
			listener.Position = new Vector3(0, 0, 0);
			sound3D.Position = new Vector3(10, 10, 0);

			Listener3DOrientation o = new Listener3DOrientation();
			// Set the orientation's data: the listener looks forward
			o.Front = new Vector3(1, 0, 0);
			o.Top = new Vector3(0, 1, 0);
			listener.Orientation = o;

			// Set attenuation
			sound3D.MinDistance = 50;
			listener.DopplerFactor = 10;

			sound.Play(0, BufferPlayFlags.Looping);
		}

		private void pnlMain_Paint(object sender, System.Windows.Forms.PaintEventArgs e) {
			try {
				Vector3 listPos = listener.Position;
				Vector3 sndPos = sound3D.Position;

				Graphics gr = e.Graphics;
				//gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

				gr.DrawLine(Pens.Blue, pnlMain.Width / 2, 0, pnlMain.Width / 2, pnlMain.Height);
				gr.DrawLine(Pens.Blue, 0, pnlMain.Height / 2, pnlMain.Width, pnlMain.Height / 2);

				gr.DrawEllipse(Pens.Green, pnlMain.Width / 2 + (listPos.X - 4), pnlMain.Height / 2 - (listPos.Y + 4), 8, 8);
				gr.FillEllipse(Brushes.Green, pnlMain.Width / 2 + (listPos.X - 4), pnlMain.Height / 2 - (listPos.Y + 4), 8, 8);

				gr.DrawEllipse(Pens.Red, pnlMain.Width / 2 + (sndPos.X - 4), pnlMain.Height / 2 - (sndPos.Y + 4), 8, 8);
				gr.FillEllipse(Brushes.Red, pnlMain.Width / 2 + (sndPos.X - 4), pnlMain.Height / 2 - (sndPos.Y + 4), 8, 8);
			}
			catch {}
		}

		private void pnlMain_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
			mouseDown = true;
			if(!rotating) {
				Vector3 p = new Vector3(-pnlMain.Width / 2 + e.X, pnlMain.Height / 2 - e.Y, h);
				sound3D.Position = p;
				lblSoundPos.Text = p.X.ToString() + ", " + p.Y.ToString() + ", " + h.ToString();
				pnlMain.Refresh();
			}
		}
		private void pnlMain_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
			if(mouseDown && !rotating) {
				Vector3 p = new Vector3(-pnlMain.Width / 2 + e.X, pnlMain.Height / 2 - e.Y, h);
				sound3D.Position = p;
				lblSoundPos.Text = p.X.ToString() + ", " + p.Y.ToString() + ", " + h.ToString();
				pnlMain.Refresh();
			}
		}
		private void pnlMain_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
			mouseDown = false;
		}

		private void btnRotate_Click(object sender, System.EventArgs e) {
			if(rotating) {
				rotating = false;
				btnRotate.Text = "Rotate Source";
			}
			else {
				btnRotate.Text = "Stop Rotation";
				ray = (int)Math.Round(Math.Sqrt(Math.Pow(sound3D.Position.X, 2) + Math.Pow(sound3D.Position.Y, 2)));
				angle = (int)Math.Round(Math.Atan(sound3D.Position.Y / sound3D.Position.Y) * 180 / Math.PI);
				Thread t = new Thread(new ThreadStart(rotator));
				rotating = true;
				t.Start();
			}
		}

		private void rotator() {
			int r = ray;
			int a = angle;
			if(a % 2 != 0)
				a++;
			Vector3 pos;
			while(rotating) {

				pos = new Vector3((float)Math.Cos(a * Math.PI / 180) * r, (float)Math.Sin(a * Math.PI / 180) * r, h);
				sound3D.Position = pos;
				lblSoundPos.Text = string.Format("{0:N0}", pos.X) + ", " + string.Format("{0:N0}", pos.Y) + ", " + h.ToString();
				pnlMain.Refresh();

				a += 2;
				if(a == 360)
					a = 0;
				Thread.Sleep(50);
			}
		}

		private void trkHeight_Scroll(object sender, System.EventArgs e) {
			h = trkHeight.Value;
			Vector3 pos = sound3D.Position;
			lblSoundPos.Text = string.Format("{0:N0}", pos.X) + ", " + string.Format("{0:N0}", pos.Y) + ", " + h.ToString();
		}

		protected override void OnClosed(EventArgs e) {
			// Terminate thread!!!
			rotating = false;
			base.OnClosed (e);
		}

	}

	// A flicker free panel
	public class FlickerFreePanel : System.Windows.Forms.Panel {

		public FlickerFreePanel() {
			SetStyle(ControlStyles.DoubleBuffer, true);
			SetStyle(ControlStyles.UserPaint, true);
			SetStyle(ControlStyles.AllPaintingInWmPaint, true);
		}

	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Italy Italy
Software Development Manager working on IaaS cloud computing. Cloud believer, (former) entrepreneur, F1 addict.

Follow me at dariosolera.it or on Twitter.

Comments and Discussions