or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animation.mdapplication-framework.mdasset-loading.mdaudio.mdindex.mdinput.mdmathematics.mdscene-graph.mdtask-event.mduser-interface.md

audio.mddocs/

0

# Audio and Sound

1

2

Panda3D provides a comprehensive audio system with support for 3D positional audio, sound effects, music playback, and spatial audio processing for immersive 3D environments.

3

4

## Capabilities

5

6

### Audio3DManager - 3D Positional Audio

7

8

The Audio3DManager handles 3D spatial audio with automatic distance attenuation, doppler effects, and positional sound placement.

9

10

```python { .api }

11

class Audio3DManager:

12

def __init__(self,

13

audio_manager,

14

listener_target: NodePath,

15

root: NodePath = None,

16

taskPriority: int = 51,

17

autoUpdate: bool = True) -> None:

18

"""

19

Initialize 3D audio manager.

20

21

Args:

22

audio_manager: Base audio manager instance

23

listener_target: NodePath representing listener position (usually camera)

24

root: Root node for audio coordinate system

25

taskPriority: Priority of audio update task

26

autoUpdate: Whether to automatically update audio positions

27

"""

28

29

def loadSfx(self, filename: str) -> AudioSound:

30

"""Load sound effect file."""

31

32

def loadMusic(self, filename: str) -> AudioSound:

33

"""Load music file."""

34

35

def attachSoundToObject(self, sound: AudioSound, object: NodePath) -> None:

36

"""Attach sound to 3D object for automatic positioning."""

37

38

def detachSound(self, sound: AudioSound) -> None:

39

"""Detach sound from its 3D object."""

40

41

def setListenerVelocity(self, velocity: Vec3) -> None:

42

"""Set listener velocity for doppler effects."""

43

44

def setDistanceFactor(self, factor: float) -> None:

45

"""Set distance scaling factor."""

46

47

def setDopplerFactor(self, factor: float) -> None:

48

"""Set doppler effect strength."""

49

50

def setDropOffFactor(self, factor: float) -> None:

51

"""Set audio drop-off/attenuation factor."""

52

53

def attachSoundToObject(self,

54

sound: AudioSound,

55

object: NodePath) -> None:

56

"""Attach sound to follow an object's position."""

57

58

def detachSound(self, sound: AudioSound) -> None:

59

"""Detach sound from object."""

60

61

def setSoundVelocity(self, sound: AudioSound, velocity: Vec3) -> None:

62

"""Set sound source velocity."""

63

64

def setSoundVelocityAuto(self, sound: AudioSound) -> None:

65

"""Enable automatic velocity calculation."""

66

67

def setSoundMinDistance(self, sound: AudioSound, distance: float) -> None:

68

"""Set minimum distance for audio attenuation."""

69

70

def setSoundMaxDistance(self, sound: AudioSound, distance: float) -> None:

71

"""Set maximum distance for audio attenuation."""

72

73

def update(self) -> None:

74

"""Manually update audio positions."""

75

76

def disable(self) -> None:

77

"""Disable 3D audio processing."""

78

79

def enable(self) -> None:

80

"""Enable 3D audio processing."""

81

```

82

83

### AudioSound - Individual Sound Control

84

85

AudioSound objects provide detailed control over individual audio sources.

86

87

```python { .api }

88

class AudioSound:

89

def play(self) -> None:

90

"""Play the sound."""

91

92

def stop(self) -> None:

93

"""Stop playing the sound."""

94

95

def setLoop(self, loop: bool) -> None:

96

"""Set whether sound should loop."""

97

98

def getLoop(self) -> bool:

99

"""Check if sound is set to loop."""

100

101

def setLoopStart(self, start_time: float) -> None:

102

"""Set loop start time in seconds."""

103

104

def setLoopEnd(self, end_time: float) -> None:

105

"""Set loop end time in seconds."""

106

107

def setVolume(self, volume: float) -> None:

108

"""Set sound volume (0.0 to 1.0)."""

109

110

def getVolume(self) -> float:

111

"""Get current volume."""

112

113

def setBalance(self, balance: float) -> None:

114

"""Set left/right balance (-1.0 to 1.0)."""

115

116

def getBalance(self) -> float:

117

"""Get current balance."""

118

119

def setPlayRate(self, rate: float) -> None:

120

"""Set playback speed multiplier."""

121

122

def getPlayRate(self) -> float:

123

"""Get current playback rate."""

124

125

def length(self) -> float:

126

"""Get sound duration in seconds."""

127

128

def getTime(self) -> float:

129

"""Get current playback position in seconds."""

130

131

def setTime(self, time: float) -> None:

132

"""Set playback position."""

133

134

def status(self) -> int:

135

"""Get playback status (READY, PLAYING, BAD)."""

136

137

def finished(self) -> bool:

138

"""Check if sound has finished playing."""

139

140

def ready(self) -> bool:

141

"""Check if sound is ready to play."""

142

```

143

144

### Basic Audio Management

145

146

Simple audio playback without 3D positioning for music and UI sounds.

147

148

```python { .api }

149

class AudioManager:

150

def getSound(self, filename: str, positional: bool = False) -> AudioSound:

151

"""Load audio file and return AudioSound object."""

152

153

def playSound(self,

154

sound: AudioSound,

155

looping: bool = False,

156

interrupt: bool = True,

157

volume: float = 1.0,

158

node: NodePath = None) -> None:

159

"""Play sound with optional 3D positioning."""

160

161

def stopSound(self, sound: AudioSound) -> None:

162

"""Stop playing sound."""

163

164

def setVolume(self, volume: float) -> None:

165

"""Set global volume."""

166

167

def getVolume(self) -> float:

168

"""Get global volume."""

169

170

def setSfxVolume(self, volume: float) -> None:

171

"""Set sound effects volume."""

172

173

def getSfxVolume(self) -> float:

174

"""Get sound effects volume."""

175

176

def setMusicVolume(self, volume: float) -> None:

177

"""Set music volume."""

178

179

def getMusicVolume(self) -> float:

180

"""Get music volume."""

181

182

def stopAllSounds(self) -> None:

183

"""Stop all currently playing sounds."""

184

185

def setSoundsActive(self, active: bool) -> None:

186

"""Enable or disable all sound playback."""

187

188

def getSoundsActive(self) -> bool:

189

"""Check if sounds are active."""

190

```

191

192

## Usage Examples

193

194

### 3D Positional Audio

195

196

```python

197

from direct.showbase.ShowBase import ShowBase

198

from direct.showbase.Audio3DManager import Audio3DManager

199

from panda3d.core import Vec3

200

from direct.task import Task

201

202

class Audio3DDemo(ShowBase):

203

def __init__(self):

204

ShowBase.__init__(self)

205

206

# Initialize 3D audio manager

207

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

208

209

# Load sounds

210

self.engine_sound = self.audio3d.loadSfx("sounds/engine.wav")

211

self.footsteps = self.audio3d.loadSfx("sounds/footsteps.wav")

212

self.ambient = self.audio3d.loadMusic("sounds/ambient.ogg")

213

214

# Create moving objects

215

self.createMovingObjects()

216

217

# Setup audio properties

218

self.setupAudioProperties()

219

220

# Start background music

221

self.audio3d.play(self.ambient, looping=True, volume=0.3)

222

223

# Setup controls

224

self.setupControls()

225

226

def createMovingObjects(self):

227

"""Create objects that will have attached sounds."""

228

# Car with engine sound

229

self.car = self.loader.loadModel("models/car")

230

self.car.reparentTo(self.render)

231

self.car.setPos(-10, 20, 0)

232

233

# Attach engine sound to car

234

self.audio3d.attachSoundToObject(self.engine_sound, self.car)

235

self.audio3d.play(self.engine_sound, looping=True)

236

237

# Set up car movement

238

self.taskMgr.add(self.moveCar, "move-car")

239

240

# Walking character

241

self.character = self.loader.loadModel("models/character")

242

self.character.reparentTo(self.render)

243

self.character.setPos(5, 15, 0)

244

245

# Attach footstep sound

246

self.audio3d.attachSoundToObject(self.footsteps, self.character)

247

248

def setupAudioProperties(self):

249

"""Configure 3D audio properties."""

250

# Set distance factors

251

self.audio3d.setDistanceFactor(1.0)

252

self.audio3d.setDopplerFactor(1.0)

253

self.audio3d.setDropOffFactor(0.1)

254

255

# Configure individual sounds

256

self.audio3d.setSoundMinDistance(self.engine_sound, 5.0)

257

self.audio3d.setSoundMaxDistance(self.engine_sound, 50.0)

258

259

self.audio3d.setSoundMinDistance(self.footsteps, 2.0)

260

self.audio3d.setSoundMaxDistance(self.footsteps, 20.0)

261

262

def moveCar(self, task):

263

"""Move car in circle for doppler demonstration."""

264

angle = task.time * 30 # 30 degrees per second

265

radius = 15

266

267

x = radius * math.cos(math.radians(angle))

268

y = 20 + radius * math.sin(math.radians(angle))

269

270

self.car.setPos(x, y, 0)

271

self.car.setH(angle + 90) # Face movement direction

272

273

return task.cont

274

275

def setupControls(self):

276

"""Setup keyboard controls."""

277

self.accept("1", self.toggleEngine)

278

self.accept("2", self.playFootsteps)

279

self.accept("3", self.adjustVolume, [0.1])

280

self.accept("4", self.adjustVolume, [-0.1])

281

282

# Movement controls for listener

283

self.accept("arrow_left", self.moveListener, [Vec3(-1, 0, 0)])

284

self.accept("arrow_right", self.moveListener, [Vec3(1, 0, 0)])

285

self.accept("arrow_up", self.moveListener, [Vec3(0, 1, 0)])

286

self.accept("arrow_down", self.moveListener, [Vec3(0, -1, 0)])

287

288

def toggleEngine(self):

289

"""Toggle engine sound."""

290

if self.engine_sound.status() == AudioSound.PLAYING:

291

self.audio3d.stop(self.engine_sound)

292

else:

293

self.audio3d.play(self.engine_sound, looping=True)

294

295

def playFootsteps(self):

296

"""Play footstep sound."""

297

self.audio3d.play(self.footsteps)

298

299

def adjustVolume(self, change):

300

"""Adjust global volume."""

301

current = base.musicManager.getVolume()

302

new_volume = max(0.0, min(1.0, current + change))

303

base.musicManager.setVolume(new_volume)

304

print(f"Volume: {new_volume:.1f}")

305

306

def moveListener(self, direction):

307

"""Move audio listener (camera)."""

308

current_pos = self.camera.getPos()

309

new_pos = current_pos + direction * 2

310

self.camera.setPos(new_pos)

311

print(f"Listener position: {new_pos}")

312

313

import math

314

app = Audio3DDemo()

315

app.run()

316

```

317

318

### Sound Manager Class

319

320

```python

321

from direct.showbase.DirectObject import DirectObject

322

from direct.showbase.Audio3DManager import Audio3DManager

323

324

class SoundManager(DirectObject):

325

"""Centralized sound management system."""

326

327

def __init__(self, listener_target):

328

DirectObject.__init__(self)

329

330

# Initialize audio systems

331

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

332

333

# Sound libraries

334

self.sounds = {}

335

self.music = {}

336

self.current_music = None

337

338

# Volume settings

339

self.master_volume = 1.0

340

self.sfx_volume = 1.0

341

self.music_volume = 0.7

342

343

# Load sound libraries

344

self.loadSounds()

345

346

def loadSounds(self):

347

"""Load all game sounds."""

348

# Sound effects

349

sound_files = {

350

"button_click": "sounds/ui/button_click.wav",

351

"explosion": "sounds/fx/explosion.wav",

352

"pickup": "sounds/fx/pickup.wav",

353

"footstep": "sounds/character/footstep.wav",

354

"jump": "sounds/character/jump.wav"

355

}

356

357

for name, filename in sound_files.items():

358

try:

359

self.sounds[name] = self.audio3d.loadSfx(filename)

360

except:

361

print(f"Failed to load sound: {filename}")

362

363

# Music tracks

364

music_files = {

365

"menu": "music/menu_theme.ogg",

366

"level1": "music/level1_bg.ogg",

367

"victory": "music/victory.ogg"

368

}

369

370

for name, filename in music_files.items():

371

try:

372

self.music[name] = self.audio3d.loadMusic(filename)

373

except:

374

print(f"Failed to load music: {filename}")

375

376

def playSfx(self, name, volume=None, position=None, looping=False):

377

"""Play sound effect."""

378

if name not in self.sounds:

379

print(f"Sound not found: {name}")

380

return

381

382

sound = self.sounds[name]

383

384

# Set volume

385

if volume is None:

386

volume = self.sfx_volume

387

sound.setVolume(volume * self.master_volume)

388

389

# Set position if specified

390

if position:

391

self.audio3d.attachSoundToObject(sound, position)

392

393

# Play sound

394

self.audio3d.play(sound, looping=looping)

395

396

def playMusic(self, name, fade_in=False, fade_out_current=False):

397

"""Play background music."""

398

if name not in self.music:

399

print(f"Music not found: {name}")

400

return

401

402

# Stop current music

403

if self.current_music:

404

if fade_out_current:

405

self.fadeOutMusic(self.current_music, 1.0)

406

else:

407

self.audio3d.stop(self.current_music)

408

409

# Start new music

410

music = self.music[name]

411

music.setVolume(self.music_volume * self.master_volume)

412

413

if fade_in:

414

self.fadeInMusic(music, 2.0)

415

else:

416

self.audio3d.play(music, looping=True)

417

418

self.current_music = music

419

420

def stopMusic(self):

421

"""Stop current music."""

422

if self.current_music:

423

self.audio3d.stop(self.current_music)

424

self.current_music = None

425

426

def fadeInMusic(self, music, duration):

427

"""Fade in music over time."""

428

target_volume = self.music_volume * self.master_volume

429

music.setVolume(0.0)

430

self.audio3d.play(music, looping=True)

431

432

# Create fade task

433

def fadeTask(task):

434

progress = task.time / duration

435

if progress >= 1.0:

436

music.setVolume(target_volume)

437

return task.done

438

439

volume = target_volume * progress

440

music.setVolume(volume)

441

return task.cont

442

443

taskMgr.add(fadeTask, f"fade-in-{id(music)}")

444

445

def fadeOutMusic(self, music, duration):

446

"""Fade out music over time."""

447

start_volume = music.getVolume()

448

449

def fadeTask(task):

450

progress = task.time / duration

451

if progress >= 1.0:

452

self.audio3d.stop(music)

453

return task.done

454

455

volume = start_volume * (1.0 - progress)

456

music.setVolume(volume)

457

return task.cont

458

459

taskMgr.add(fadeTask, f"fade-out-{id(music)}")

460

461

def setMasterVolume(self, volume):

462

"""Set master volume level."""

463

self.master_volume = max(0.0, min(1.0, volume))

464

465

# Update current music volume

466

if self.current_music:

467

self.current_music.setVolume(self.music_volume * self.master_volume)

468

469

def setSfxVolume(self, volume):

470

"""Set sound effects volume."""

471

self.sfx_volume = max(0.0, min(1.0, volume))

472

473

def setMusicVolume(self, volume):

474

"""Set music volume."""

475

self.music_volume = max(0.0, min(1.0, volume))

476

477

# Update current music

478

if self.current_music:

479

self.current_music.setVolume(self.music_volume * self.master_volume)

480

481

def cleanup(self):

482

"""Clean up audio resources."""

483

self.stopMusic()

484

self.audio3d.disable()

485

self.ignoreAll()

486

```

487

488

## Types

489

490

```python { .api }

491

# Audio status constants

492

class AudioSound:

493

READY = 2 # Sound loaded and ready

494

PLAYING = 3 # Sound currently playing

495

BAD = 4 # Sound failed to load

496

497

# Audio file format support

498

SUPPORTED_AUDIO_FORMATS = [

499

".wav", # WAV (uncompressed)

500

".ogg", # Ogg Vorbis (compressed)

501

".mp3", # MP3 (compressed, if available)

502

".flac" # FLAC (lossless, if available)

503

]

504

```