3d sound in Panda3D

I created a simple test and found that the sound source is at position 0, 0, 0 when it was attached to an object that is in a different place.

from direct.showbase.ShowBase import ShowBase
from direct.showbase import Audio3DManager

class MyApp(ShowBase):
 
    def __init__(self):
        ShowBase.__init__(self)

        self.audio3d = Audio3DManager.Audio3DManager(base.sfxManagerList[0], camera)

        model = loader.loadModel('panda')
        model.reparentTo(render)

        sound = self.audio3d.loadSfx('audio/sfx/GUI_click.wav')
        sound.setLoop(True)
        sound.play()

        self.audio3d.attachSoundToObject(sound, model)
        model.setPos(-40, 0, 0)
        
        taskMgr.add(self.loop, 'loop')

    def loop(self, task):
        self.audio3d.update()
        return task.cont

app = MyApp()
app.run()

I wonder if this is a mistake or I’m missing something.

ADD: Checked in Panda3D 1.8.1 and this code works as expected.

For other people coming upon this thread: as remarked in the GitHub issue, the workaround is to keep a reference around to the model NodePath:

However, this is not an option; if I wrap it with a function, the reference to NodePath is not saved. With multiple function calls.

        self.create_point3D(sound = 'Res/sound/fx.wav', pos = (0, 50, 0))
        self.create_point3D(sound = 'Res/sound/fx1.wav', pos = (0, 25, 0))
        self.create_point3D(sound = 'Res/sound/fx2.wav', pos = (0, 0, 0))
        
    def create_point3D(self, sound, pos):
    
        sound = self.audio3d.loadSfx(sound)
        
        self.model = loader.loadModel('Res/models/sound')
        self.model.setPos(pos)
        self.model.reparentTo(render)
        
        self.audio3d.attachSoundToObject(sound, self.model)
        
        sound.play()

All sounds are located in one place, which sets the last call.

You could keep the references in a list, perhaps. Something like this:

 # In your initialisation:
        self.modelList = []
 # /initialisation

 def create_point3D(self, sound, pos):
    
        sound = self.audio3d.loadSfx(sound)
        
        model = loader.loadModel('Res/models/sound')
        self.modelList.append(model)
        
        # The rest of your logic follows...

It seems the time has come when the obvious things are not working. However, I need to add different links to the 3D audio manager, and not to the list.

Perhaps a small wrapper-class? That might store a variety of bits of information, including a reference to the audio manager. (I think that I did something similar for certain “positioned sounds” in one of my own projects.)

[edit] (You could then store instances of that wrapper-class in the list, rather than just node-paths.)

I wonder why not leave everything as it was in the old versions of panda3D? In the end, these changes were supposed to remove unnecessary links. However, the picture is the opposite, we now have to hide links in the corners and under the pillow :slight_smile:

Hmm, yeah, I suppose that with this issue, the old way was a bit better, even though it required explicitly unregistering the sound when destroying the node.

I’ll try to think of a solution.