Right parameters for 3D Audio


#1

Hey there, I’m quite new to Panda3D and just playing around with sounds.
I used the following code to attach a sound to the pandamodel from the Hello World tutorial but it wont work for me. I hear sound and the volume definitly changes but not the way I expected it :smiley: Sometimes its loud when the model is in front of the camera and then it suddenly softens without the camera moving that far away.
Here’s the code responsible for changes in the listener and 3d-sound-attributes:

AsyncTask::DoneStatus ContSoundTask(GenericAsyncTask* task, void* data){
	bgsound->set_3d_attributes(pandaActor.get_x(), pandaActor.get_y(), pandaActor.get_z(),0,0,0);
	LVecBase3f view = camera.get_hpr();
	AM->audio_3d_set_listener_attributes(camera.get_x(),camera.get_y(), camera.get_z(),0,0,0, view.get_x(), view.get_y(), view.get_z(), 0,0,1);
	AM->update();
 return AsyncTask::DS_cont;

Anybody got any idea what’s wrong?
Thanks in advance


#2

Hi

For your AM->audio_3d_set_listener_attributes try this:

  LMatrix4f mat = camera.get_mat();
  LVecBase3f lv = mat.get_row3(1);
  LVecBase3f uv = mat.get_row3(2);
  LVecBase3f pos = mat.get_row3(3);
  AM->audio_3d_set_listener_attributes(pos.get_x(),pos.get_y(),pos.get_z(),                                                                         0,0,0,
                                       lv.get_x(),lv.get_y(),lv.get_z(),
                                       uv.get_x(),uv.get_y(),uv.get_z());

#3

Hey, thanks for the quick reply.
It works definitly better than my code but when the panda gets really close to the camera (but is still in front of it) the volume softens again…
I made a picture of what it looks like:

The black circle represents the cameramovement whereas the blue arrow represents the way, the panda walks back and forth. The lookat of the camera is always set to the red circle. This is the spot where the sound is the loudest whereas at the green circles the most quiet.

What do the parameters of the function audio_3d_set_listener_attributes mean at all?
px, py and pz are obviously the position of the listener.
vx, py and pz is the velocityvector in wich the listener moves but since we’re adjusting the cameraposition each frame manually we don’t need this one, right? so 0,0,0
fx, fy and fz is the lookAt-vector and
ux, uy and uz is the up-vector.
Is this assumption correct? Coulnd find any detailed information for this function.
Regards
NoMonkey

Edit: damn this image is huge, sorry for that


#4

Hi

after creating the AM do a AM->set_3d_min_distance(1.);
if you haven’t already and see if that helps.

the description for the listener looks right


#5

Hey,
you mean setting the min distance for the used sound to 1? Because the AudioManager doent have a function set_3d_min_diestance()
I applied it to the sound i’m using but it had no effect.

Here’s my full code if it is helpful:

#include "pandaFramework.h"
#include "pandaSystem.h"
 
#include "genericAsyncTask.h"
#include "asyncTaskManager.h"
 
#include "cIntervalManager.h"
#include "cLerpNodePathInterval.h"
#include "cMetaInterval.h"

#include "audiomanager.h"
#include "audiosound.h"
 
// Global stuff
PandaFramework framework;
PT(AsyncTaskManager) taskMgr = AsyncTaskManager::get_global_ptr(); 
PT(ClockObject) globalClock = ClockObject::get_global_clock();
NodePath camera;
PT(AudioManager) AM = AudioManager::create_AudioManager();
  PT(AudioSound) bgsound;
   NodePath pandaActor;
 
// Task to move the camera
AsyncTask::DoneStatus SpinCameraTask(GenericAsyncTask* task, void* data) {
  double time = globalClock->get_real_time();
  double angledegrees = time * 6.0;
  double angleradians = angledegrees * (3.14 / 180.0);
  camera.set_pos(20*sin(angleradians),-20.0*cos(angleradians),3);
  camera.set_hpr(angledegrees, 0, 0);
  //camera.look_at(pandaActor);
  return AsyncTask::DS_cont;
}
AsyncTask::DoneStatus ContSoundTask(GenericAsyncTask* task, void* data){
	//My second attempt
	LPoint3f pandapos = pandaActor.get_pos();
	bgsound->set_3d_attributes(pandapos.get_x(),pandapos.get_y(),pandapos.get_z(),0,0,0);
	LPoint3f camerapos = camera.get_pos();
	AM->audio_3d_set_listener_attributes(camerapos.get_x(),camerapos.get_y(),camerapos.get_z(),
										0,0,0,
										pandapos.get_x(), pandapos.get_y(), pandapos.get_z(),
										0,0,1);



/*	// My first attempt
	LVecBase3f view = camera.get_hpr();
	AM->audio_3d_set_listener_attributes(camera.get_x(),camera.get_y(), camera.get_z(),
										0,0,0, 
										view.get_x(), view.get_y(), view.get_z(), 
										0,0,1);
	// tah's attempt
	 LMatrix4f mat = camera.get_mat(); 
	 LVecBase3f lv = mat.get_row3(1); 
	 LVecBase3f uv = mat.get_row3(2); 
	 LVecBase3f pos = mat.get_row3(3); 
	 AM->audio_3d_set_listener_attributes(pos.get_x(),pos.get_y(),pos.get_z(),
										0,0,0, 
		                                   lv.get_x(),lv.get_y(),lv.get_z(), 
			                                uv.get_x(),uv.get_y(),uv.get_z()); 
	*/
	AM->update();

 return AsyncTask::DS_cont;
}	
 
int main(int argc, char *argv[]) {
  // Open a new window framework and set the title
  framework.open_framework(argc, argv);
  framework.set_window_title("My Panda3D Window");
 
  // Open the window
  WindowFramework *window = framework.open_window();
  camera = window->get_camera_group(); // Get the camera and store it

  //Sound
  bgsound = AM->get_sound("KirbyMono.mp3");
 bgsound->set_3d_min_distance(1);
 // AM->set_3d_min_distance(1.); doesnt exist
  bgsound->set_loop(true);
  bgsound->play();
 
  // Load the environment model
  NodePath environ = window->load_model(framework.get_models(),
    "models/environment");
  environ.reparent_to(window->get_render());
  environ.set_scale(0.25 , 0.25, 0.25);
  environ.set_pos(-8, 42, 0);
 
  // Load our panda
  pandaActor = window->load_model(framework.get_models(),
    "panda-model");
  pandaActor.set_scale(0.005);
  pandaActor.reparent_to(window->get_render());
 
  // Load the walk animation
  window->load_model(pandaActor, "panda-walk4");
  window->loop_animations(0);
 
  // Create the lerp intervals needed to walk back and forth
  PT(CLerpNodePathInterval) pandaPosInterval1, pandaPosInterval2,
    pandaHprInterval1, pandaHprInterval2;
  pandaPosInterval1 = new CLerpNodePathInterval("pandaPosInterval1",
    13.0, CLerpInterval::BT_no_blend,
    true, false, pandaActor, NodePath());
  pandaPosInterval1->set_start_pos(LPoint3f(0, 10, 0));
  pandaPosInterval1->set_end_pos(LPoint3f(0, -10, 0));
 
  pandaPosInterval2 = new CLerpNodePathInterval("pandaPosInterval2",
    13.0, CLerpInterval::BT_no_blend,
    true, false, pandaActor, NodePath());
  pandaPosInterval2->set_start_pos(LPoint3f(0, -10, 0));
  pandaPosInterval2->set_end_pos(LPoint3f(0, 10, 0));
 
  pandaHprInterval1 = new CLerpNodePathInterval("pandaHprInterval1", 3.0,
    CLerpInterval::BT_no_blend,
    true, false, pandaActor, NodePath());
  pandaHprInterval1->set_start_hpr(LPoint3f(0, 0, 0));
  pandaHprInterval1->set_end_hpr(LPoint3f(180, 0, 0));
 
  pandaHprInterval2 = new CLerpNodePathInterval("pandaHprInterval2", 3.0,
    CLerpInterval::BT_no_blend,
    true, false, pandaActor, NodePath());
  pandaHprInterval2->set_start_hpr(LPoint3f(180, 0, 0));
  pandaHprInterval2->set_end_hpr(LPoint3f(0, 0, 0));
 
  // Create and play the sequence that coordinates the intervals
  PT(CMetaInterval) pandaPace;
  pandaPace = new CMetaInterval("pandaPace");
  pandaPace->add_c_interval(pandaPosInterval1, 0,
    CMetaInterval::RS_previous_end);
  pandaPace->add_c_interval(pandaHprInterval1, 0,
    CMetaInterval::RS_previous_end);
  pandaPace->add_c_interval(pandaPosInterval2, 0,
    CMetaInterval::RS_previous_end);
  pandaPace->add_c_interval(pandaHprInterval2, 0,
    CMetaInterval::RS_previous_end);
  pandaPace->loop();
 
  // Add our task.
  taskMgr->add(new GenericAsyncTask("Spins the camera",
    &SpinCameraTask, (void*) NULL));
  taskMgr->add(new GenericAsyncTask("Continues Sound", &ContSoundTask, (void*) NULL));
 
  // This is a simpler way to do stuff every frame,
  // if you're too lazy to create a task.
  Thread *current_thread = Thread::get_current_thread();
  while(framework.do_frame(current_thread)) {
    // Step the interval manager
    CIntervalManager::get_global_ptr()->step();
  }
 
  framework.close_framework();
  return (0);
}

#6

oops,sorry, it’s part of AudioSound.
like this:

        bgsound->set_3d_min_distance(1.);

I’ll take a look at the code


#7

Interesting…
sound shuts off when pandapos y value is positive; the panda only moves along the y direction, back and forth.

I’ve worked with 3d sound a little bit. Made a fountain that had splashing fountain sounds, and camera was free to move (user control) and all that works fine. Got to look at this some more a little later.


#8

Thank you for that, I don’t realy have a starting point for my research because I can’t find any sample-programms in c++ using 3D-Audio.

When in try it, it isn’t a positive y-coordinate that makes the sound fall off. Any direction away form the zero point makes the sound quieter…

I appreciate your help!


#9

Looks like you’ve got your settings for the listener wrong. Here is the equivalent Python code which should be pretty straightforward to convert to C++.

forward = render.getRelativeVector(camera, Vec3.forward())
up = render.getRelativeVector(camera, Vec3.up())
vel = (0, 0, 0)
audiomanager.audio3dSetListenerAttributes(pos[0], pos[1], pos[2], vel[0], vel[1], vel[2], forward[0], forward[1], forward[2], up[0], up[1], up[2])

The important difference is that this command is expecting vectors, not rotations.


#10

Thanks for your reply.
So I translated the code to c++. This is the result:

	LVector3f fw = window->get_render().get_relative_vector(camera, LVector3f::forward());  
	LVector3f up = window->get_render().get_relative_vector(camera, LVector3f::up());
	LVector3f vel = (0,0,0);
	LVector3f pos = camera.get_pos();

	AM->audio_3d_set_listener_attributes(pos[0],pos[1],pos[2],
								  		 vel[0],vel[1],vel[2],
								 		  fw[0], fw[1], fw[2],
										  up[0], up[1], up[2]);
	LPoint3f pandapos = pandaActor.get_pos();
	bgsound->set_3d_attributes(pandapos[0],pandapos[1],pandapos[2],0,0,0);
AM->update();

Unfortunately it has no effect on the program whatsoever. The sound is still loud when the panda is at zero point and softens as it moves away. Altough the values I’m getting for the forward, up and positionvector seem to be correct.

Edit:
It’s like none of my actions do anything. Even when I type in nonsene for the positionvalue of the listener, it has no effect.
I printed out the listener_attributes of the Audiomanager via AM->audio_3d_get_listener_attributes(…) because i thought maybe the set-function doesnt work properly but the values I got correspond with the actual values of the cameras position, lookat, etc.


#11

Ah, I missed the line that gets you the position. The sound system is expecting all positions to be in the same relative coordinates, so you must get the camera position relative to the root of the scene. The same goes for getting the position of the panda. If you use get_pos with no argument it is just giving you the transform of that node, but you need it to take into consideration any parent nodes that might also have a transform on them.

In C++ I think that would be something like:

LPoint3f pos = camera.get_pos(window->get_render());

#12

Hi there,
you’re correct but in this case it shouln’t matter because camera and panda are directly paranted to the render-node, so there are no other transformations. (But you’re suggestion is definitly the “cleaner” one)

As a matter of fact the coordinates are correct (i printed them out to the console and they match with what you would expect from the cameramovement (circling around the zeropoint with a radius of twenty) and the pandamovement (walking back an forth between 0,-10,0 and 0,10,0). The upvector is always 0,0,1 as it should be and the forward-vector is always a unit vector pointing towards the zero point.

Nevertheless i tried it with:

LPoint3f pandapos = pandaActor.get_pos(window->get_render());

and

LVector3f pos = camera.get_pos(window->get_render());

but the result was the same. Loud at the zero point and quiter in any dircetion away from it.

I’m realy getting desperate…

@tah
Is it possible for you to post the part of your code where you define the listener and 3d_attributes of your fountain-project?

Regards,
Kilian


#13

Just had another look through your code. The problem might be the way the sound is created. By default, get_sound gives you a non-positional sound. This is from audioManager.h:

virtual PT(AudioSound) get_sound(const string& file_name, bool positional = false, int mode=SM_heuristic) = 0;

You need to set this positional argument to true, so:

bgsound = AM->get_sound("KirbyMono.mp3", true);

#14

Wow, that seems to fix it =) I’m happy. Thanks a lot. I wondered if there is a flag that you have to set to true to enable positional sound but i coulndt find a function that would do that.

So thanks again for all your help.


#15

Good catch teedee !

I have that in my code, but missed it when looking at NoMonkey’s code.

As for how I set up set_3d_attributes is the same as you do, it’s just my fountain doesn’t pace back and forth… ha, and the listener is like I showed before.

Sorry I didn’t catch it, I was starting to question if I would be having the same problem if I moved the fountain around, but teedee found the reason it wasn’t working for you.

But this is great for someone down the road that might have the same or similar problem and come to the forum, do a search and find this post, and problem solved. The forums have helped me many times like this :smiley: