improvemnts to fmod positional audio handling

This commit is contained in:
Philip Saltzman 2005-04-27 22:09:47 +00:00
parent cb673496b5
commit f22866dc67
9 changed files with 413 additions and 95 deletions

View File

@ -1,22 +1,198 @@
import pandac.AudioSound
import pandac.AudioManager
from pandac.VBase3 import VBase3
from direct.task import Task
class Audio3DManager:
def __init__(self, audio_manager, listener_target = None):
def __init__(self, audio_manager, listener_target = None, root = None,
taskPriority = 51):
self.audio_manager = audio_manager
self.listener_target = listener_target
self.sound_dict = {}
if (root==None):
self.root = render
else:
self.root = root
self.sound_dict = {}
self.vel_dict = {}
self.listener_vel = VBase3(0,0,0)
taskMgr.add(self.update, "Audio3DManager-updateTask", taskPriority)
def loadSfx(self, name):
"""
Use Audio3DManager.loadSfx to load a sound with 3D positioning enabled
"""
sound = None
if (name):
sound=self.audio_manager.getSound(name,1)
return sound
def setDistanceFactor(self,factor):
"""
Control the scale that sets the distance units for 3D spacialized audio.
Default is 1.0 which is adjust in panda to be feet.
"""
self.audio_manager.audio3dSetDistanceFactor(factor)
def getDistanceFactor(self):
"""
Control the scale that sets the distance units for 3D spacialized audio.
Default is 1.0 which is adjust in panda to be feet.
"""
return self.audio_manager.audio3dGetDistanceFactor()
def setDopplerFactor(self,factor):
"""
Control the presence of the Doppler effect. Default is 1.0
Exaggerated Doppler, use >1.0
Diminshed Doppler, use <1.0
"""
self.audio_manager.audio3dSetDopplerFactor(factor)
def getDopplerFactor(self):
"""
Control the presence of the Doppler effect. Default is 1.0
Exaggerated Doppler, use >1.0
Diminshed Doppler, use <1.0
"""
return self.audio_manager.audio3dGetDopplerFactor()
def setDropOffFactor(self,factor):
"""
Exaggerate or diminish the effect of distance on sound. Default is 1.0
Valid range is 0 to 10
Faster drop off, use >1.0
Slower drop off, use <1.0
"""
self.audio_manager.audio3dSetDropOffFactor(factor)
def getDropOffFactor(self):
"""
Exaggerate or diminish the effect of distance on sound. Default is 1.0
Valid range is 0 to 10
Faster drop off, use >1.0
Slower drop off, use <1.0
"""
return self.audio_manager.audio3dGetDropOffFactor()
def setSoundMinDistance(self,sound,dist):
"""
Controls the distance (in units) that this sound begins to fall off.
Also affects the rate it falls off.
Default is 1.0
Closer/Faster, <1.0
Farther/Slower, >1.0
"""
sound.set3dMinDistance(dist)
def getSoundMinDistance(self,sound):
"""
Controls the distance (in units) that this sound begins to fall off.
Also affects the rate it falls off.
Default is 1.0
Closer/Faster, <1.0
Farther/Slower, >1.0
"""
return sound.get3dMinDistance()
def setSoundMaxDistance(self,sound,dist):
"""
Controls the maximum distance (in units) that this sound stops falling off.
The sound does not stop at that point, it just doesn't get any quieter.
You should rarely need to adjust this.
Default is 1000000000.0
"""
sound.set3dMaxDistance(dist)
def getSoundMaxDistance(self,sound):
"""
Controls the maximum distance (in units) that this sound stops falling off.
The sound does not stop at that point, it just doesn't get any quieter.
You should rarely need to adjust this.
Default is 1000000000.0
"""
return sound.get3dMaxDistance()
def setSoundVelocity(self,sound,velocity):
"""
Set the velocity vector (in units/sec) of the sound, for calculating doppler shift.
This is relative to the sound root (probably render).
Default: VBase3(0,0,0)
"""
if not isinstance(velocity, VBase3):
raise TypeError, "Invalid argument 1, expected <VBase3>"
self.vel_dict[sound]=velocity
def setSoundVelocityAuto(self,sound):
"""
If velocity is set to auto, the velocity will be determined by the
previous position of the object the sound is attached to and the frame dt.
Make sure if you use this method that you remember to clear the previous
transformation between frames.
"""
self.vel_dict[sound]=None
def getSoundVelocity(self,sound):
"""
Get the velocity of the sound.
"""
if (self.vel_dict.has_key(sound)):
vel = self.vel_dict[sound]
if (vel!=None):
return vel
else:
for known_object in self.sound_dict.keys():
if self.sound_dict[known_object].count(sound):
return known_object.getPosDelta(self.root)/globalClock.getDt()
return VBase3(0,0,0)
def setListenerVelocity(self,velocity):
"""
Set the velocity vector (in units/sec) of the listener, for calculating doppler shift.
This is relative to the sound root (probably render).
Default: VBase3(0,0,0)
"""
if not isinstance(velocity, VBase3):
raise TypeError, "Invalid argument 0, expected <VBase3>"
self.listener_vel=velocity
def setListenerVelocityAuto(self):
"""
If velocity is set to auto, the velocity will be determined by the
previous position of the object the listener is attached to and the frame dt.
Make sure if you use this method that you remember to clear the previous
transformation between frames.
"""
self.listener_vel = None
def getListenerVelocity(self):
"""
Get the velocity of the listener.
"""
if (self.listener_vel!=None):
return self.listener_vel
elif (self.listener_target!=None):
return self.listener_target.getPosDelta(self.root)/globalClock.getDt()
else:
return VBase3(0,0,0)
def attachSoundToObject(self, sound, object):
"""
Sound will come from the location of the object it is attached to
"""
# sound is an AudioSound
# object is any Panda object with coordinates
for known_object in self.sound_dict.keys():
if self.sound_dict[known_object].count(sound):
# This sound is already attached to something
return 0
#return 0
# detach sound
self.sound_dict[known_object].remove(sound)
if len(self.sound_dict[known_object]) == 0:
# if there are no other sounds, don't track
# the object any more
del self.sound_dict[known_object]
if not self.sound_dict.has_key(object):
self.sound_dict[object] = []
@ -26,6 +202,9 @@ class Audio3DManager:
def detachSound(self, sound):
"""
sound will no longer have it's 3D position updated
"""
for known_object in self.sound_dict.keys():
if self.sound_dict[known_object].count(sound):
self.sound_dict[known_object].remove(sound)
@ -38,6 +217,9 @@ class Audio3DManager:
def getSoundsOnObject(self, object):
"""
returns a list of sounds attached to an object
"""
if not self.sound_dict.has_key(object):
return []
sound_list = []
@ -46,35 +228,44 @@ class Audio3DManager:
def attachListener(self, object):
"""
Sounds will be heard relative to this object. Should probably be the camera.
"""
self.listener_target = object
return 1
def detachListener(self):
"""
Sounds will be heard relative to the root, probably render.
"""
self.listener_target = None
return 1
def update(self):
def update(self,task=None):
"""
Updates position of sounds in the 3D audio system. Will be called automatically
in a task.
"""
# Update the positions of all sounds based on the objects
# to which they are attached
for known_object in self.sound_dict.keys():
tracked_sound = 0
while tracked_sound < len(self.sound_dict[known_object]):
sound = self.sound_dict[known_object][tracked_sound]
if self.listener_target:
pos = known_object.getPos(self.listener_target)
else:
pos = known_object.getPos()
sound.set3dAttributes(pos[0], pos[1], pos[2], 0,0,0)
pos = known_object.getPos(self.root)
vel = self.getSoundVelocity(sound)
sound.set3dAttributes(pos[0], pos[1], pos[2], vel[0],vel[1],vel[2])
tracked_sound += 1
# Update the position of the listener based on the object
# to which it is attached
if self.listener_target:
pos = self.listener_target.getPos()
self.audio_manager.audio3dSetListenerAttributes(pos[0], pos[1], pos[2], 0,0,0, 0,1,0, 0,0,1)
pos = self.listener_target.getPos(self.root)
vel = self.getListenerVelocity()
self.audio_manager.audio3dSetListenerAttributes(pos[0], pos[1], pos[2], vel[0],vel[1],vel[2], 0,1,0, 0,0,1)
else:
self.audio_manager.audio3dSetListenerAttributes(0,0,0, 0,0,0, 0,1,0, 0,0,1)
self.audio_manager.audio3dUpdate()
return 1
return Task.cont

View File

@ -128,9 +128,10 @@ PUBLISHED:
float *fx, float *fy, float *fz,
float *ux, float *uy, float *uz);
// Control the "relative distance factor" for 3D spacialized audio. Default is 1.0
// Control the "relative scale that sets the distance factor" units for 3D spacialized audio. Default is 1.0
// Fmod uses meters internally, so give a float in Units-per meter
// Don't know what Miles uses.
// Default is 1.0 which is adjust in panda to be feet.
virtual void audio_3d_set_distance_factor(float factor);
virtual float audio_3d_get_distance_factor() const;
@ -141,6 +142,7 @@ PUBLISHED:
virtual float audio_3d_get_doppler_factor() const;
// Exaggerate or diminish the effect of distance on sound. Default is 1.0
// Valid range is 0 to 10
// Faster drop off, use >1.0
// Slower drop off, use <1.0
virtual void audio_3d_set_drop_off_factor(float factor);

View File

@ -50,3 +50,25 @@ void AudioSound::
get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz) {
// Intentionally blank.
}
void AudioSound::
set_3d_min_distance(float dist) {
// Intentionally blank.
}
float AudioSound::
get_3d_min_distance() const {
// Intentionally blank.
return 0.0f;
}
void AudioSound::
set_3d_max_distance(float dist) {
// Intentionally blank.
}
float AudioSound::
get_3d_max_distance() const {
// Intentionally blank.
return 0.0f;
}

View File

@ -104,6 +104,21 @@ PUBLISHED:
float *vx, float *vy, float *vz);
// Controls the distance (in units) that this sound begins to fall off.
// Also affects the rate it falls off.
// Default is 1.0
// Closer/Faster, <1.0
// Farther/Slower, >1.0
virtual void set_3d_min_distance(float dist);
virtual float get_3d_min_distance() const;
// Controls the maximum distance (in units) that this sound stops falling off.
// The sound does not stop at that point, it just doesn't get any quieter.
// You should rarely need to adjust this.
// Default is 1000000000.0
virtual void set_3d_max_distance(float dist);
virtual float get_3d_max_distance() const;
enum SoundStatus { BAD, READY, PLAYING };
virtual SoundStatus status() const = 0;

View File

@ -118,6 +118,24 @@ void NullAudioSound::get_3d_attributes(float *px, float *py, float *pz, float *v
// Intentionally blank.
}
void NullAudioSound::set_3d_min_distance(float dist) {
// Intentionally blank.
}
float NullAudioSound::get_3d_min_distance() const {
// Intentionally blank.
return 0.0f;
}
void NullAudioSound::set_3d_max_distance(float dist) {
// Intentionally blank.
}
float NullAudioSound::get_3d_max_distance() const {
// Intentionally blank.
return 0.0f;
}
AudioSound::SoundStatus NullAudioSound::status() const {
return AudioSound::READY;
}

View File

@ -64,6 +64,10 @@ public:
void set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz);
void get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *vz);
void set_3d_min_distance(float dist);
float get_3d_min_distance() const;
void set_3d_max_distance(float dist);
float get_3d_max_distance() const;
AudioSound::SoundStatus status() const;

View File

@ -59,9 +59,9 @@ FmodAudioManager() {
_listener_vel[0] = 0.0f; _listener_vel[1] = 0.0f; _listener_vel[2] = 0.0f;
_listener_forward[0] = 0.0f; _listener_forward[1] = 1.0f; _listener_forward[2] = 0.0f;
_listener_up[0] = 0.0f; _listener_up[1] = 0.0f; _listener_up[2] = 1.0f;
_distance_factor = audio_distance_factor;
_doppler_factor = audio_doppler_factor;
_drop_off_factor = audio_drop_off_factor;
_distance_factor = .3048f;
_doppler_factor = 1.0f;
_drop_off_factor = 1.0f;
_cache_limit = audio_cache_limit;
_concurrent_sound_limit = 0;
@ -642,15 +642,6 @@ stop_all_sounds() {
void FmodAudioManager::
audio_3d_update() {
audio_debug("FmodAudioManager::audio_3d_update()");
//convert panda coordinates to fmod coordinates
float fmod_pos [] = {_listener_pos[0], _listener_pos[2], _listener_pos[1]};
float fmod_vel [] = {_listener_vel[0], _listener_vel[2], _listener_vel[1]};
float fmod_forward [] = {_listener_forward[0], _listener_forward[2], _listener_forward[1]};
float fmod_up [] = {_listener_up[0], _listener_up[2], _listener_up[1]};
FSOUND_3D_Listener_SetAttributes(fmod_pos, fmod_vel,
fmod_forward[0], fmod_forward[1], fmod_forward[2],
fmod_up[0], fmod_up[1], fmod_up[2]);
FSOUND_Update();
}
@ -668,7 +659,15 @@ audio_3d_set_listener_attributes(float px, float py, float pz, float vx, float v
_listener_forward[0] = fx; _listener_forward[1] = fy; _listener_forward[2] = fz;
_listener_up[0] = ux; _listener_up[1] = uy; _listener_up[2] = uz;
//FSOUND_3D_Listener_SetAttributes(_listener_pos, _listener_vel, fx, fz, fy, ux, uz, uy);
//convert panda coordinates to fmod coordinates
float fmod_pos [] = {_listener_pos[0], _listener_pos[2], _listener_pos[1]};
float fmod_vel [] = {_listener_vel[0], _listener_vel[2], _listener_vel[1]};
float fmod_forward [] = {_listener_forward[0], _listener_forward[2], _listener_forward[1]};
float fmod_up [] = {_listener_up[0], _listener_up[2], _listener_up[1]};
FSOUND_3D_Listener_SetAttributes(fmod_pos, fmod_vel,
fmod_forward[0], fmod_forward[1], fmod_forward[2],
fmod_up[0], fmod_up[1], fmod_up[2]);
}
////////////////////////////////////////////////////////////////////
@ -715,7 +714,7 @@ audio_3d_set_distance_factor(float factor) {
}
if (_distance_factor != factor){
_distance_factor = factor;
FSOUND_3D_SetDistanceFactor(_distance_factor);
FSOUND_3D_SetDistanceFactor(_distance_factor*3.28f); // convert from feet to meters
}
}

View File

@ -79,6 +79,7 @@ FmodAudioSound(FmodAudioManager* manager, FSOUND_STREAM *audio_data,
_active(true), _paused(false), _bExclusive(false),_channel(-1) {
_pos[0] = 0.0f; _pos[1] = 0.0f; _pos[2] = 0.0f;
_vel[0] = 0.0f; _vel[1] = 0.0f; _vel[2] = 0.0f;
_min_dist = 1.0f; _max_dist = 1000000000.0f;
nassertv(!file_name.empty());
nassertv(audio_data != NULL);
@ -143,6 +144,12 @@ if (_bExclusive) {
if(!FSOUND_3D_SetAttributes(_channel, fmod_pos, fmod_vel)) {
audio_error("Unable to set 3d attributes for "<<_file_name<<"!");
}
if(!FSOUND_3D_SetMinMaxDistance(_channel, _min_dist, _max_dist)) {
//Seems like the return value is documented incorrectly, so this error gets
//needlessly spammed
//audio_error("Unable to set 3d min/max distance for "<<_file_name<<"!");
}
}
// Set looping -- unimplemented
@ -424,6 +431,13 @@ set_3d_attributes(float px, float py, float pz, float vx, float vy, float vz) {
fmod_audio_debug("Set 3d position and velocity (px="<<px<<", py="<<py<<", pz="<<pz<<", vx="<<vx<<", vy="<<vy<<", vz="<<vz<<")");
_pos[0] = px; _pos[1] = py; _pos[2] = pz;
_vel[0] = vx; _vel[1] = vy; _vel[2] = vz;
if (FSOUND_Stream_GetMode(_audio) & FSOUND_HW3D) {
// Convert from Panda coordinates to Fmod coordinates
float fmod_pos [] = {_pos[0], _pos[2], _pos[1]};
float fmod_vel [] = {_vel[0], _vel[2], _vel[1]};
FSOUND_3D_SetAttributes(_channel, fmod_pos, fmod_vel);
}
}
////////////////////////////////////////////////////////////////////
@ -450,6 +464,53 @@ get_3d_attributes(float *px, float *py, float *pz, float *vx, float *vy, float *
//FSOUND_3D_GetAttributes(_channel, pos, vel);
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::set_3d_min_distance
// Access: public
// Description: Set the distance that this sound begins to fall off. Also
// affects the rate it falls off.
////////////////////////////////////////////////////////////////////
void FmodAudioSound::set_3d_min_distance(float dist) {
fmod_audio_debug("Set 3d min distance (min="<<dist<<")");
_min_dist = dist;
if (FSOUND_Stream_GetMode(_audio) & FSOUND_HW3D) {
FSOUND_3D_SetMinMaxDistance(_channel, _min_dist,_max_dist);
}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::get_3d_min_distance
// Access: public
// Description: Get the distance that this sound begins to fall off
////////////////////////////////////////////////////////////////////
float FmodAudioSound::get_3d_min_distance() const {
return _min_dist;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::set_3d_max_distance
// Access: public
// Description: Set the distance that this sound stops falling off
////////////////////////////////////////////////////////////////////
void FmodAudioSound::set_3d_max_distance(float dist) {
fmod_audio_debug("Set 3d max distance (max="<<dist<<")");
_max_dist = dist;
if (FSOUND_Stream_GetMode(_audio) & FSOUND_HW3D) {
FSOUND_3D_SetMinMaxDistance(_channel, _min_dist,_max_dist);
}
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::get_3d_max_distance
// Access: public
// Description: Get the distance that this sound stops falling off
////////////////////////////////////////////////////////////////////
float FmodAudioSound::get_3d_max_distance() const {
return _max_dist;
}
////////////////////////////////////////////////////////////////////
// Function: FmodAudioSound::status
// Access: public

View File

@ -85,6 +85,10 @@ public:
float vx, float vy, float vz);
void get_3d_attributes(float *px, float *py, float *pz,
float *vx, float *vy, float *vz);
void set_3d_min_distance(float dist);
float get_3d_min_distance() const;
void set_3d_max_distance(float dist);
float get_3d_max_distance() const;
AudioSound::SoundStatus status() const;
@ -101,6 +105,8 @@ private:
float _balance; // -1..1
float _pos [3];
float _vel [3];
float _min_dist;
float _max_dist;
unsigned long _loop_count;
mutable float _length; // in seconds.
bool _active;