0
# Sound System
1
2
Audio playback capabilities with support for multiple formats, volume control, spatial audio, and sound effect management for creating immersive game experiences with music and sound effects.
3
4
## Capabilities
5
6
### Core Sound Classes
7
8
Base sound classes for loading, playing, and controlling audio in games.
9
10
```python { .api }
11
class Sound:
12
"""
13
Audio sound class for loading and playing sound effects and music.
14
Supports various audio formats including WAV, OGG, and MP3.
15
"""
16
def __init__(self, file_path: str, streaming: bool = False):
17
"""
18
Create a sound object from an audio file.
19
20
Args:
21
file_path: Path to audio file or resource handle (e.g., ":resources:sounds/...")
22
streaming: Whether to stream the audio (for large files like music)
23
"""
24
25
# Properties
26
file_path: str
27
streaming: bool
28
29
def play(self, volume: float = 1.0, pan: float = 0.0, loop: bool = False, speed: float = 1.0) -> object:
30
"""
31
Play the sound with specified parameters.
32
33
Args:
34
volume: Volume level (0.0 = silent, 1.0 = full volume, >1.0 = amplified)
35
pan: Stereo panning (-1.0 = full left, 0.0 = center, 1.0 = full right)
36
loop: Whether to loop the sound continuously
37
speed: Playback speed (1.0 = normal, 2.0 = double speed, 0.5 = half speed)
38
39
Returns:
40
Media player object for controlling playback
41
"""
42
43
def stop(self) -> None:
44
"""Stop all instances of this sound."""
45
46
def get_length(self) -> float:
47
"""
48
Get the duration of the sound in seconds.
49
50
Returns:
51
Duration in seconds
52
"""
53
54
def get_volume(self) -> float:
55
"""
56
Get the current volume level.
57
58
Returns:
59
Volume level (0.0 to 1.0+)
60
"""
61
62
def set_volume(self, volume: float) -> None:
63
"""
64
Set the volume level for new playback instances.
65
66
Args:
67
volume: Volume level (0.0 = silent, 1.0 = full volume)
68
"""
69
```
70
71
### Sound Loading and Management Functions
72
73
Utility functions for loading sounds and managing audio playback.
74
75
```python { .api }
76
def load_sound(file_path: str, streaming: bool = False) -> arcade.Sound:
77
"""
78
Load a sound file and return a Sound object.
79
80
Args:
81
file_path: Path to audio file or resource handle
82
streaming: Whether to stream the audio (recommended for music)
83
84
Returns:
85
Sound object ready for playback
86
"""
87
88
def play_sound(sound: arcade.Sound, volume: float = 1.0, pan: float = 0.0,
89
loop: bool = False, speed: float = 1.0) -> object:
90
"""
91
Play a sound with specified parameters.
92
93
Args:
94
sound: Sound object to play
95
volume: Volume level (0.0 to 1.0+)
96
pan: Stereo panning (-1.0 to 1.0)
97
loop: Whether to loop the sound
98
speed: Playback speed multiplier
99
100
Returns:
101
Media player object for controlling playback
102
"""
103
104
def stop_sound(player: object) -> None:
105
"""
106
Stop a specific sound instance.
107
108
Args:
109
player: Media player object returned from play_sound()
110
"""
111
```
112
113
### Audio Control and Effects
114
115
Advanced audio control functions for managing playback and applying effects.
116
117
```python { .api }
118
def set_background_music(sound: arcade.Sound, volume: float = 0.5) -> None:
119
"""
120
Set and start playing background music.
121
122
Args:
123
sound: Sound object to use as background music
124
volume: Music volume level
125
"""
126
127
def stop_background_music() -> None:
128
"""Stop the currently playing background music."""
129
130
def pause_background_music() -> None:
131
"""Pause the background music (can be resumed)."""
132
133
def resume_background_music() -> None:
134
"""Resume paused background music."""
135
136
def get_background_music_volume() -> float:
137
"""
138
Get the current background music volume.
139
140
Returns:
141
Volume level (0.0 to 1.0+)
142
"""
143
144
def set_background_music_volume(volume: float) -> None:
145
"""
146
Set the background music volume.
147
148
Args:
149
volume: New volume level (0.0 to 1.0+)
150
"""
151
```
152
153
### Spatial Audio
154
155
Functions for creating positional and directional audio effects.
156
157
```python { .api }
158
def play_sound_3d(sound: arcade.Sound, listener_position: tuple[float, float],
159
sound_position: tuple[float, float], max_distance: float = 1000.0,
160
volume: float = 1.0) -> object:
161
"""
162
Play a sound with 3D spatial positioning.
163
164
Args:
165
sound: Sound object to play
166
listener_position: (x, y) position of the listener
167
sound_position: (x, y) position of the sound source
168
max_distance: Maximum audible distance
169
volume: Base volume level
170
171
Returns:
172
Media player object for controlling playback
173
"""
174
175
def update_sound_3d(player: object, listener_position: tuple[float, float],
176
sound_position: tuple[float, float], max_distance: float = 1000.0) -> None:
177
"""
178
Update the 3D position of a playing sound.
179
180
Args:
181
player: Media player object from play_sound_3d()
182
listener_position: New listener position
183
sound_position: New sound source position
184
max_distance: Maximum audible distance
185
"""
186
```
187
188
### Audio Streaming
189
190
Classes and functions for handling streaming audio, particularly useful for music and large audio files.
191
192
```python { .api }
193
class StreamingSound(arcade.Sound):
194
"""
195
Specialized sound class for streaming large audio files from disk.
196
More memory efficient for long audio tracks like background music.
197
"""
198
def __init__(self, file_path: str, buffer_size: int = 65536):
199
"""
200
Create a streaming sound.
201
202
Args:
203
file_path: Path to audio file
204
buffer_size: Size of streaming buffer in bytes
205
"""
206
207
buffer_size: int
208
209
def preload_streaming(self, seconds: float = 2.0) -> None:
210
"""
211
Preload a portion of the streaming audio to reduce latency.
212
213
Args:
214
seconds: Amount of audio to preload in seconds
215
"""
216
217
def create_sound_stream(file_path: str, buffer_size: int = 65536) -> arcade.StreamingSound:
218
"""
219
Create a streaming sound object for large audio files.
220
221
Args:
222
file_path: Path to audio file
223
buffer_size: Streaming buffer size
224
225
Returns:
226
StreamingSound object
227
"""
228
```
229
230
### Audio Format Support
231
232
Information about supported audio formats and codec capabilities.
233
234
```python { .api }
235
# Supported audio formats
236
SUPPORTED_FORMATS: list[str] = [
237
".wav", # Waveform Audio File Format (uncompressed)
238
".ogg", # Ogg Vorbis (compressed, open source)
239
".mp3", # MPEG Audio Layer 3 (compressed)
240
".flac", # Free Lossless Audio Codec
241
".aiff", # Audio Interchange File Format
242
".au", # Sun/Unix audio format
243
]
244
245
def is_audio_format_supported(file_path: str) -> bool:
246
"""
247
Check if an audio file format is supported.
248
249
Args:
250
file_path: Path to audio file
251
252
Returns:
253
True if format is supported, False otherwise
254
"""
255
256
def get_audio_info(file_path: str) -> dict:
257
"""
258
Get information about an audio file.
259
260
Args:
261
file_path: Path to audio file
262
263
Returns:
264
Dictionary with audio properties (duration, sample_rate, channels, etc.)
265
"""
266
```
267
268
## Usage Examples
269
270
### Basic Sound Effects
271
272
```python
273
import arcade
274
275
class SoundEffectsGame(arcade.Window):
276
def __init__(self):
277
super().__init__(800, 600, "Sound Effects Example")
278
279
self.sound_list = {}
280
self.background_music = None
281
282
def setup(self):
283
# Load sound effects
284
self.sound_list["jump"] = arcade.load_sound(":resources:sounds/jump1.wav")
285
self.sound_list["coin"] = arcade.load_sound(":resources:sounds/coin1.wav")
286
self.sound_list["hit"] = arcade.load_sound(":resources:sounds/hit1.wav")
287
self.sound_list["explosion"] = arcade.load_sound(":resources:sounds/explosion1.wav")
288
289
# Load and start background music
290
self.background_music = arcade.load_sound(":resources:music/1918.mp3", streaming=True)
291
arcade.play_sound(self.background_music, volume=0.3, loop=True)
292
293
# Create some sprites for interaction
294
self.player_list = arcade.SpriteList()
295
self.coin_list = arcade.SpriteList()
296
297
# Player sprite
298
self.player = arcade.Sprite(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png", 0.5)
299
self.player.center_x = 400
300
self.player.center_y = 300
301
self.player_list.append(self.player)
302
303
# Create coins
304
for i in range(5):
305
coin = arcade.Sprite(":resources:images/items/coinGold.png", 0.3)
306
coin.center_x = 150 + i * 100
307
coin.center_y = 200
308
self.coin_list.append(coin)
309
310
def on_draw(self):
311
self.clear()
312
self.player_list.draw()
313
self.coin_list.draw()
314
315
# Draw instructions
316
arcade.draw_text("SPACE = Jump sound", 10, 550, arcade.color.WHITE, 16)
317
arcade.draw_text("Move player to collect coins", 10, 525, arcade.color.WHITE, 16)
318
arcade.draw_text("X = Explosion sound", 10, 500, arcade.color.WHITE, 16)
319
arcade.draw_text("M = Toggle music", 10, 475, arcade.color.WHITE, 16)
320
321
def on_update(self, delta_time):
322
self.player_list.update()
323
324
# Check for coin collisions
325
coins_hit = arcade.check_for_collision_with_list(self.player, self.coin_list)
326
for coin in coins_hit:
327
# Play coin sound with slight volume variation
328
arcade.play_sound(self.sound_list["coin"], volume=0.8 + (0.4 * random.random()))
329
coin.remove_from_sprite_lists()
330
331
def on_key_press(self, key, modifiers):
332
if key == arcade.key.SPACE:
333
# Play jump sound
334
arcade.play_sound(self.sound_list["jump"], volume=0.5)
335
336
elif key == arcade.key.X:
337
# Play explosion with random pan
338
pan = (random.random() - 0.5) * 2 # Random pan from -1.0 to 1.0
339
arcade.play_sound(self.sound_list["explosion"], volume=0.7, pan=pan)
340
341
elif key == arcade.key.M:
342
# Toggle background music
343
if self.background_music_playing:
344
arcade.stop_sound(self.background_music)
345
self.background_music_playing = False
346
else:
347
arcade.play_sound(self.background_music, volume=0.3, loop=True)
348
self.background_music_playing = True
349
350
# Movement controls
351
elif key == arcade.key.LEFT:
352
self.player.change_x = -5
353
elif key == arcade.key.RIGHT:
354
self.player.change_x = 5
355
elif key == arcade.key.UP:
356
self.player.change_y = 5
357
elif key == arcade.key.DOWN:
358
self.player.change_y = -5
359
360
def on_key_release(self, key, modifiers):
361
if key in (arcade.key.LEFT, arcade.key.RIGHT):
362
self.player.change_x = 0
363
elif key in (arcade.key.UP, arcade.key.DOWN):
364
self.player.change_y = 0
365
366
def main():
367
game = SoundEffectsGame()
368
game.setup()
369
arcade.run()
370
371
if __name__ == "__main__":
372
main()
373
```
374
375
### 3D Spatial Audio Example
376
377
```python
378
import arcade
379
import math
380
381
class SpatialAudioGame(arcade.Window):
382
def __init__(self):
383
super().__init__(800, 600, "3D Spatial Audio")
384
385
self.player_list = arcade.SpriteList()
386
self.sound_source_list = arcade.SpriteList()
387
self.ambient_sound = None
388
self.sound_players = []
389
390
def setup(self):
391
# Create player (listener)
392
self.player = arcade.Sprite(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png", 0.4)
393
self.player.center_x = 400
394
self.player.center_y = 300
395
self.player_list.append(self.player)
396
397
# Create sound sources around the map
398
self.sound_sources = []
399
400
# Campfire sound source
401
campfire = arcade.Sprite(":resources:images/tiles/torch1.png", 0.5)
402
campfire.center_x = 200
403
campfire.center_y = 200
404
campfire.sound = arcade.load_sound(":resources:sounds/fire.wav")
405
self.sound_source_list.append(campfire)
406
self.sound_sources.append(campfire)
407
408
# Water sound source
409
water = arcade.Sprite(":resources:images/tiles/water.png", 0.5)
410
water.center_x = 600
411
water.center_y = 400
412
water.sound = arcade.load_sound(":resources:sounds/water.wav")
413
self.sound_source_list.append(water)
414
self.sound_sources.append(water)
415
416
# Start playing spatial sounds
417
self.start_spatial_sounds()
418
419
def start_spatial_sounds(self):
420
"""Start playing all spatial sound sources."""
421
for source in self.sound_sources:
422
player = arcade.play_sound_3d(
423
source.sound,
424
listener_position=(self.player.center_x, self.player.center_y),
425
sound_position=(source.center_x, source.center_y),
426
max_distance=300.0,
427
volume=0.5
428
)
429
source.player = player
430
self.sound_players.append(player)
431
432
def update_spatial_audio(self):
433
"""Update 3D audio based on player position."""
434
listener_pos = (self.player.center_x, self.player.center_y)
435
436
for source in self.sound_sources:
437
source_pos = (source.center_x, source.center_y)
438
439
# Update 3D position
440
arcade.update_sound_3d(
441
source.player,
442
listener_position=listener_pos,
443
sound_position=source_pos,
444
max_distance=300.0
445
)
446
447
def on_draw(self):
448
self.clear()
449
450
# Draw sound source ranges
451
for source in self.sound_sources:
452
# Draw audible range circle
453
arcade.draw_circle_outline(source.center_x, source.center_y, 300, arcade.color.YELLOW, 2)
454
455
self.sound_source_list.draw()
456
self.player_list.draw()
457
458
# Draw instructions and info
459
arcade.draw_text("Move with arrow keys", 10, 570, arcade.color.WHITE, 16)
460
arcade.draw_text("Listen to spatial audio effects", 10, 545, arcade.color.WHITE, 16)
461
462
# Draw distance to nearest sound source
463
if self.sound_sources:
464
nearest = min(self.sound_sources,
465
key=lambda s: arcade.get_distance_between_sprites(self.player, s))
466
distance = arcade.get_distance_between_sprites(self.player, nearest)
467
arcade.draw_text(f"Distance to nearest source: {distance:.1f}", 10, 520, arcade.color.WHITE, 16)
468
469
def on_update(self, delta_time):
470
self.player_list.update()
471
self.update_spatial_audio()
472
473
def on_key_press(self, key, modifiers):
474
if key == arcade.key.LEFT:
475
self.player.change_x = -5
476
elif key == arcade.key.RIGHT:
477
self.player.change_x = 5
478
elif key == arcade.key.UP:
479
self.player.change_y = 5
480
elif key == arcade.key.DOWN:
481
self.player.change_y = -5
482
483
def on_key_release(self, key, modifiers):
484
if key in (arcade.key.LEFT, arcade.key.RIGHT):
485
self.player.change_x = 0
486
elif key in (arcade.key.UP, arcade.key.DOWN):
487
self.player.change_y = 0
488
489
def main():
490
game = SpatialAudioGame()
491
game.setup()
492
arcade.run()
493
494
if __name__ == "__main__":
495
main()
496
```
497
498
### Music Player with Controls
499
500
```python
501
import arcade
502
503
class MusicPlayerExample(arcade.Window):
504
def __init__(self):
505
super().__init__(800, 600, "Music Player")
506
507
self.music_list = []
508
self.current_track = 0
509
self.current_player = None
510
self.is_playing = False
511
self.volume = 0.7
512
513
def setup(self):
514
# Load music tracks
515
self.music_list = [
516
arcade.load_sound(":resources:music/1918.mp3", streaming=True),
517
arcade.load_sound(":resources:music/funkyrobot.mp3", streaming=True),
518
]
519
520
# Start with first track
521
self.play_current_track()
522
523
def play_current_track(self):
524
"""Start playing the current track."""
525
if self.current_player:
526
arcade.stop_sound(self.current_player)
527
528
if self.music_list:
529
music = self.music_list[self.current_track]
530
self.current_player = arcade.play_sound(music, volume=self.volume, loop=True)
531
self.is_playing = True
532
533
def next_track(self):
534
"""Switch to the next track."""
535
if self.music_list:
536
self.current_track = (self.current_track + 1) % len(self.music_list)
537
self.play_current_track()
538
539
def previous_track(self):
540
"""Switch to the previous track."""
541
if self.music_list:
542
self.current_track = (self.current_track - 1) % len(self.music_list)
543
self.play_current_track()
544
545
def toggle_playback(self):
546
"""Toggle play/pause."""
547
if self.is_playing:
548
arcade.pause_background_music()
549
self.is_playing = False
550
else:
551
arcade.resume_background_music()
552
self.is_playing = True
553
554
def adjust_volume(self, change: float):
555
"""Adjust the volume up or down."""
556
self.volume = max(0.0, min(1.0, self.volume + change))
557
if self.current_player:
558
arcade.set_background_music_volume(self.volume)
559
560
def on_draw(self):
561
self.clear()
562
563
# Draw music player interface
564
arcade.draw_text("Music Player", 400, 500, arcade.color.WHITE, 36, anchor_x="center")
565
566
if self.music_list:
567
track_name = f"Track {self.current_track + 1}/{len(self.music_list)}"
568
arcade.draw_text(track_name, 400, 450, arcade.color.WHITE, 24, anchor_x="center")
569
570
status = "Playing" if self.is_playing else "Paused"
571
arcade.draw_text(f"Status: {status}", 400, 400, arcade.color.WHITE, 20, anchor_x="center")
572
573
arcade.draw_text(f"Volume: {self.volume:.1f}", 400, 350, arcade.color.WHITE, 20, anchor_x="center")
574
575
# Draw controls
576
controls = [
577
"SPACE = Play/Pause",
578
"N = Next Track",
579
"P = Previous Track",
580
"+ = Volume Up",
581
"- = Volume Down"
582
]
583
584
for i, control in enumerate(controls):
585
arcade.draw_text(control, 400, 280 - i * 30, arcade.color.LIGHT_GRAY, 16, anchor_x="center")
586
587
def on_key_press(self, key, modifiers):
588
if key == arcade.key.SPACE:
589
self.toggle_playback()
590
elif key == arcade.key.N:
591
self.next_track()
592
elif key == arcade.key.P:
593
self.previous_track()
594
elif key == arcade.key.PLUS or key == arcade.key.EQUAL:
595
self.adjust_volume(0.1)
596
elif key == arcade.key.MINUS:
597
self.adjust_volume(-0.1)
598
599
def main():
600
game = MusicPlayerExample()
601
game.setup()
602
arcade.run()
603
604
if __name__ == "__main__":
605
main()
606
```