3DAudio

From VRwiki
Jump to: navigation, search
Screenshot from the demo program

This tutorial will illustrate the use of XVR 3D audio capabilities, starting with some basic functionalities and then adding advanced features.

3D Audio in XVR

Setting up the audio environment: acoustic sources

In order to use 3D audio capabilities, at least an acoustical source (CVmVRAWav) object must be created.

The CVmVRAWav XVR class is documented here.

var AudioSource = CVmVRAWav();

then a wave file must be loaded inside the object (currently only WAV files are supported, MP3 and MIDI need a different approach):

AudioSource.Load("cannonball.wav", true);

setting the second parameter (is3D) to true enables 3D capabilities for this acoustic source, provided that your soundcard supports 3D audio and the basic software layer is available(although an OpenAL implementation is available, XVR natively uses DirectSound3D). is3D is false by default, as 3D audio calculations may become CPU consuming, therefore they are enabled only if needed. As for any other time-consuming loading operation (like for 3D models, images etc.), it is advisable to execute this code in the OnInit() function, i.e. before proper the real-time flow execution.

As soon as the source is filled with a sound file, it can be played:

AudioSource.Play(true);

true meaning that we want the sound to be played in a loop. Whenever we wish to stop playing this sound, it is almost straightforward to think about using:

AudioSource.Stop();

So far we have not specified any 3D property for the audio source. We can accomplish this by specifying a position and, optionally, a direction.

 
var pos_aSource = [2,2,5];
AudioSource.SetPosition(pos_aSource);

By default all the audio sources are omni-directional, but we can decide to setup a directional source. In this case, we must specify its direction and its acoustical cone:

 
AudioSource.SetConeOrientation(0,0,1);		// cone oriented along the Z axis
AudioSource.SetConeParams([90,180,-100]);	// inner angle = 90, outer angle = 180, outside volume = -100

The acoustical cone allow to specify the source directional behaviour, with respect to the listener position, in terms of sound attenuation : its axis is the specified orientation, within inner angle no attenuation is performed, beyond outer angle the maximum attenuation, specified in outside volume, is applied, in the middle the attenuation will vary between 0 and the maximum. Although all of these parameters may be dynamically altered during the real-time phase, the ones which normally need to be update are Position and Orientation in order to reflect the movements (if any) of the acoustic source.

Setting up the audio environment: listener

A listener is actually required only for 3D acoustical sources. You may consider it being the acoustic equivalent of what a camera is in a visual environment. Its basic parameters are Position and Orientation which may be set this way:

 
var listPos = [0,2,0];
var listOr = [1,0,0];
AudioSource.SetListenerPosition(listPos );
AudioSource.SetListenerOrientation(listOr );

(in the current XVR implementation, the methods related to the listener are called through any audio source interface. It is foreseen, in next implementations, to implement a stand-alone Listener class).

Very often you may desire to put the listener in the same position/orientation of the camera (for instance for first-person navigation). In this case you may use this code:

 
AudioSource.SetListenerPosition(CameraGetPosition());
AudioSource.SetListenerOrientation(-CameraGetDirection());

Why that "minus"? You must know that the XVR camera reference frame (as in OpenGL) is right-handed, while the XVR listener reference frame (as in DirectSound3D) is left-handed...this may change as well in next XVR implementation, but so far the original reference frames have been preserved. Therefore, the default camera Z-axis is oriented in the opposite direction from the listener one, and this reversal is needed.

If your camera can rotate on all axis, that's to say the camera (and the listener) are not confined to rotating on the vertical axis, you have to set the listener orientation using 2 axis, not just one (to understand why, try canting your head sidewise: your ears are not in the same place as before, and perceived sound sources change place). If your listener is supposed to move with the camera, you may use this code:

 
SetListenerOrientation(-CameraGetZaxis,-CameraGetYaxis);

Troubleshooting 3D audio: some magic

XVR automatically gets audio capabilities from the hardware in use and "should" be able to accordingly setup the corresponding software layer. It may however happen (hardware devices tend to lie, sometimes...) that an erratic behaviour may be experimented, ranging from not having any 3D effect to programs abruptly exiting. In this case, it may be worthy to try to override the XVR audio automatic setup by setting the AUDIO_MODE system constant to a specified value:

 
SET AUDIO_MODE = 0;    
// 0 = Force software 3d capabilities, 1 = Force hardware 3d capabilities, 2 = Automatically get capabilities (default)

Experimenting some of these values you may discover the one which fits better for your system.

Advanced features: environmental sound (EAX)

Starting from engine version 144, XVR supports also Creative EAX 2.0 environmental effects. This feature is still under testing, but it already offers a lot of very interesting functionalities. In order to use EAX features you must:

  • have an EAX compatible soundcard (Creative SoundBlaster, Audigy, X-FI, but also many thirdy-part soundcards)
  • own the eax.dll file (which may be downloaded from the Creative developer website, together with the whole SDK,

or from other thirdy party sites (only the dll file) like: this, or this one, and many others) that must be copied in the [WINDOWS]/System or [WINDOWS]/System32 folder, depending on your Windows version.

  • enable EAX capabilities by setting:
 
SET AUDIO_EAX = 1;

To verify that your system complies to these requirements, you might want to call, at the very beginning of your code (OnInit() is a good place):

 
var eaxOn = EAXIsActive();

In order to have a code compatible with any soundcard, it's a good practice to "protect" every other EAX-related method call with an appropriate if statement:

 
if (eaxOn)
{
  AudioSource.EAXInitEnvironmentFromFile("4environment.env");
  AudioSource.EAXInitMaterialFromFile("materialf.mat");
}

so that, if EAX is not present, 3D sound will work anyway, even if without environmental effects.

Examples of the most common EAX commands are:

  • EAXSetEnvironment
 
var id = 0;
if (eaxOn)
  AudioSource.EAXSetEnvironment(id);

where id is one of the EAX presents (see XVR documentation here).

  • EAXSetOcclusion, EAXSetObstruction
 
if (eaxOn) 
  AudioSource.EAXSetOcclusion(-10000,1,1);    // s_attenuation, LFRatio, RoomRatio
  AudioSource.EAXSetObstruction(-10000,1);    // s_attenuation, LFRatio

Occlusion may be used if an obstacle causing occlusion (like a wall - this means that the sound arrives through the obstacle) is in the path between the listener and the sound source. Obstruction if the object (e.g. a column) stops the direct path, but allows some "indirect" path (the sound arrives around the object). For a detailed description of parameters and their meaning you can have a look here, however shortly:

  • s_attenuation is the amount of "muffling" you want to apply, in hundredths of dB. 0 means no attenuation, -10000 (max) means -100dB.
  • LFRatio specifies if the attenuation must be applied also to Low Frequences. It ranges between 0.0 and 1.0. LFRatio = 0.0 means no attenuation at low frequencies, 1.0 means that the same attenuation applied to high frequencies is applied also to low frequencies. a good default is equal to 0.25.
  • RoomRatio controls the attenuation applied to the reverberation (indirect sound).It ranges between 0.0 and 10.0, 0.0 meaning that the same attenuation is applied to direct sound and reverberation and 10.0 meaning that reverberation will be attenuated an additional ten times the amount (specified in s_attenuation) applied to direct sound.

The "need" to apply Occlusion and Obstruction effects may be verified with the IsColliding method. Let:

  • o_env be the CVmObj whose mesh (m_env) represents the virtual environment we are navigating
  • L_Pos be the position of the listener
  • S_Pos be the position of the sound source we want to check occlusion/obstruction
  • Wall the name of the AAM mesh subset representing a wall
  • Column the name of the AAM mesh subset representing a column
 
var triangleID = -1;
var objname = "";
if o_env.isColliding( L_Pos, S_Pos,,,&triangleID)) 
{
   m_env.GetSubsetFromTriIndex(triangleIDO,&objname);		
   if (objname == "Wall")
     AudioSource.SetOcclusion(-5000,1,1);						
   else if (objname == "Column")
     AudioSource.SetObstruction(-1000,1);						
}

Of course, in case no intersection happens in the path between the listener and the sound source, you should remove obstruction/occlusion effects you may have applied, by simply specifying 0 attenuation:

  • to remove occlusion
 
AudioSource.SetOcclusion(0,0,0);	// 2nd and 3rd parameter will be ignored					
  • to remove obstruction
 
AudioSource.SetObstruction(0,0);	// 2nd parameter will be ignored				

Unfortunately, this procedure has a limitation: currently IsColliding() returns ONLY the closest intersecting object, therefore in case of multiple sources and many objects in the environment, it may lead to mistakes in applying/removing effects. It is foreseen the possibility for the IsColliding, by specifying a flag, to return ALL the intersecting objects: stay tuned for next versions!

Next step: using a 3D modeler

A future version of this tutorial will deal with the integration with 3DStudioMax to export also audio properties to be used inside XVR.

Demo program

A demo tutorial program with commented source code is available.

  • you can see it here
  • you can download it here (7.8 MB)

External links