| 
 DirectSound: 
  3D Sound 
By: Jack Hoxley 
Written: June 2000 
  Download: 
  DS_3D.Zip 
  (14kb)     
 
DirectSound3D is a fairly new 
  addition to DirectX, and is possibly one of the fastest developing areas of 
  technology (behind 3D). New 3D soundcards are coming out all the time, with 
  incredible sound quality. Sound has moved on from just squeaks and beeps. I 
  happen to own one of each of the main competitors (Aureal Vortex 2 and Creative 
  EAX) - playing games that support 3D and using 4 speakers is amazing; it adds 
  something to the game. 
Anyway; Using DirectSound3D is 
  fairly easy; as most of it is automated - you set up the sound parameters, and 
  set where it's coming from in 3D space and it'll do the rest. Bare in mind that 
  it is hardware dependent - Although you dont need to enumerate for it's presence, 
  it wont really be in full effect unless the computer either has 2 speaker 3D 
  emulation or a full 4 (or more) speaker surround sound system. Also bare in 
  mind that setting a buffer to be 3D has performance costs; because of this you 
  should limit the number of 3D sounds, and give users the option of turning it 
  off - It could well make a difference, especially if the 3D calculations are 
  done by the processor (rather than hardware). 
DirectSound3D can be combined 
  with Direct3D; which is often the case. Because they both use the same unit/coordinate 
  scheme it is easy to set a sound to come from a given place in your 3D world; 
  which adds to the atmosphere greatly. You will need to bare the following things 
  in mind when setting up your application 
Coordinates 
  The coordinate system is the same for DirectSound as it is for Direct3D - X, 
  Y, Z. It is easily shown with this diagram: 
   
 In Directsound 
  3D, unless set otherwise, you (the listener) is positioned at 0,0,0 This means 
  that to get a sound in front of you it must have a +Z value; for it to be behind 
  you it must have -Z value. For it to be to the left it must be -X, to the right 
  it must be +X. To be above it must be +Y and below -Y. Of course, this all changes 
  when you start moving around... 
Distances 
  The distance from the sound to the listener needs to be very small to be heard 
  properly. To be heard at a reasonable volume (when the normal volume is at Max) 
  it must be within 0.5 units of the listener. Anything more than 5 will be almost 
  silent. If the sound you are playing doesn't appear to be playing, it is quite 
  likely to be that it is too far away. If this system does not fit into your 
  3D world, you can quite easily add a multiplier or divider to increase/decrease 
  the value that you use. 
And you will need to know what 
  these are: 
DirectSound3DListener 
  This class represents you - the listener; and how the sounds are played. 
  In a typical 3D game, the position of the DirectSound3DListener would need to 
  be the same position as the player. This object also controls the amount of 
  Roll Off and Doppler effects of sound heard by the user, and other effects and 
  settings related to the environment. More on this in another Tutorial. 
DirectSound3DBuffer 
  This object does all the 3D calculations for a sound. It attaches itself 
  to a normal sound buffer (with a normal wave file) and then modifies it. You 
  can use this object to set the sounds properties; including orientation, direction, 
  Velocity and position. The changes made here affect only this sound; whereas 
  changes in Directsound3DListener affect everything on a global scale. 
Step1: Initialising Everything 
  This is very similiar to intialising a normal DirectSound program; except for 
  a few different variables and flags. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        'We must always have the 
      root DirectX object 
      Dim Dx As New DirectX7 
      'DirectSound will be created by DirectX 
      Dim Ds As DirectSound  
      'This is where the sound is; and what we play 
      'to hear it  
      Dim DsBuffer As DirectSoundBuffer 
      'This does all the 3D calculations  
      Dim DsBuffer3D As DirectSound3DBuffer  
      'The primary sound buffer  
      Dim DsPrimary As DirectSoundBuffer 
      'This represents you. 
      Dim DsListener As DirectSound3DListener  
      'Although this says D3D at the beginning  
      'it is only used because it has all the right 
      'properties for us: X, Y, Z  
      Dim SoundPos As D3DVECTOR | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        On Local Error Resume Next 
       
      Set Ds = Dx.DirectSoundCreate("")  
      'Tell the user we've got a problem  
      If Err.Number <> 0 Then 
      MsgBox "Unable to initialise; Either bad soundcard or bad drivers. Quiting" 
       
      End 
      End If 
       
      'Priority gives us greater control.  
      Ds.SetCooperativeLevel Me.hWnd, DSSCL_PRIORITY 
      'These two describe what our sound buffer will be 
      like  
      Dim primDesc As DSBUFFERDESC, format As WAVEFORMATEX  
      'Using the CTRL3D flag has speed penalties; dont use 
      it unless 
      'you have to - but you have to use it for 3D sounds...  
      primDesc.lFlags = DSBCAPS_CTRL3D Or DSBCAPS_PRIMARYBUFFER 
      'You can set the Stereo/Mono and Frequency settings 
      here 
      'and they will be applied to the primary buffer.  
      Set DsPrimary = Ds.CreateSoundBuffer(primDesc, format) 
       
      'Get a 3D listener device  
      Set DsListener = DsPrimary.GetDirectSound3DListener() 
      'The listener is at the 3D coordinate 0,0,0 
       
      'We set the sound to be front-left 
      'of the listener  
      SoundPos.X = -0.5: SoundPos.Z = 0.5  
       
      '0 is the loudest volume  
      DsBuffer.SetVolume 0 | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Step2: Loading and Setting 
  up 
  Now that we have everything initialised we can load some data into our buffer; 
  and set the options of our buffer. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                         Dim bufferDesc1 As DSBUFFERDESC 
       
      Dim waveFormat1 As WAVEFORMATEX  
       
      file = App.Path & "\tester.wav"  
      bufferDesc1.lFlags = (DSBCAPS_CTRL3D Or DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLPAN 
      Or DSBCAPS_CTRLVOLUME) Or DSBCAPS_STATIC  
      Set DsBuffer = Ds.CreateSoundBufferFromFile(file, bufferDesc1, waveFormat1) 
       
      'The original buffer (above) must be created before this 
      'line; and the original buffer must have the CTRL3D flag present  
      Set DsBuffer3D = DsBuffer.GetDirectSound3DBuffer 
       
      'The angles define how sensitive the sound buffer 
      will be. A  
      'narrower cone will result in more sensitive. 
      'You can have 0 degrees for no cone 
      'You can have 360 degrees for a full sphere  
      'Or you can use any of these constants  
      'DS3D_MINCONEANGLE 
      'DS3D_MAXCONEANGLE 
      'DS3D_DEFAULTCONEANGLE - the default is 360 degrees 
      DsBuffer3D.SetConeAngles DS3D_MINCONEANGLE, 100, DS3D_IMMEDIATE 
      'the DS3D_IMMEDIATE makes Directsound stop and recalculate 
      ALL  
      'Directsound3D Buffers, coordinates and positions. If you use 
      'DS3D_DEFFERED flag, you can make several parameter changes before 
      'allowing DirectSound to recalculate everything. You have to call; 
      'DirectSound3DListener.CommitDefferedSettings before they take effect. 
      DsBuffer3D.SetConeOutsideVolume -400, DS3D_IMMEDIATE  
       
      DsBuffer3D.SetPosition SoundPos.X / 50, 0, SoundPos.Z / 50, DS3D_IMMEDIATE | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Now; If we play our DsBuffer 
  object we will be getting a 3D sound. Cones are quite important, and are discussed 
  in a later tutorial. 
Step3: Positioning the sound. 
  Before this code is executed; you should set the sound to play looping. The 
  code is very simple; and is included in the example project. This next piece 
  of code will rotate the sound in a square about your position. If you listen 
  closely you will hear the sound go past you, behind you and to either side of 
  you. 
                                        
                                          
                                          
                                            
                                              
                                                
                                                  
                                                    
                                                      
                                                        
                                                          
                                                            
                                                              
                                                                
                                                                  
                                                                    
                                                                      
                                                                        | 
       Select Case CurrStage 
        Case 0 'Left  
        SoundPos.Z = SoundPos.Z - 0.1  
        If SoundPos.Z <= -0.5 Then  
        CurrStage = 1  
        End If  
        Case 1 'behind  
        SoundPos.X = SoundPos.X + 0.1  
        If SoundPos.X >= 0.5 Then  
        CurrStage = 2  
        End If  
        Case 2 'right  
        SoundPos.Z = SoundPos.Z + 0.1 
        If SoundPos.Z >= 0.5 Then  
        CurrStage = 3  
        End If  
        Case 3 'in front  
        SoundPos.X = SoundPos.X - 0.1  
        If SoundPos.X <= -0.5 Then  
        CurrStage = 0  
        End If  
        End Select 
      'The next line is a safety 
        net; to stop us changing stuff at the wrong times.  
        If DsBuffer3D Is Nothing Then Exit Sub 
        DsBuffer3D.SetPosition SoundPos.X, SoundPos.Y, SoundPos.Z, DS3D_IMMEDIATE 
                                                                         | 
                                                                       
                                                                    
                                                                   
                                                                 | 
                                                               
                                                            
                                                           
                                                         | 
                                                       
                                                    
                                                   
                                                 | 
                                               
                                            
                                           
                                          
                                         
Although this tutorial has shown 
  you all the code needed, it is advisable to look at the demonstration program 
  - which will give you a better idea of how this works. You can get it from the 
  top of the page; or from my downloads page. 
                                       |