0
# Audio System
1
2
Comprehensive audio playback, recording, and mixing capabilities through SDL2 audio and SDL2_mixer integration. PySDL2 provides both low-level audio device control and high-level audio mixing functions.
3
4
## Capabilities
5
6
### Core Audio Device Management
7
8
Low-level audio device functions for playback and recording.
9
10
```python { .api }
11
def SDL_GetNumAudioDevices(iscapture: int) -> int:
12
"""
13
Get number of available audio devices.
14
15
Parameters:
16
- iscapture: 0 for playback devices, 1 for recording devices
17
18
Returns:
19
Number of available devices
20
"""
21
22
def SDL_GetAudioDeviceName(index: int, iscapture: int) -> bytes:
23
"""
24
Get name of audio device.
25
26
Parameters:
27
- index: device index
28
- iscapture: 0 for playback, 1 for recording
29
30
Returns:
31
Device name as bytes
32
"""
33
34
def SDL_OpenAudioDevice(device: bytes, iscapture: int, desired: SDL_AudioSpec,
35
obtained: SDL_AudioSpec, allowed_changes: int) -> int:
36
"""
37
Open audio device for playback or recording.
38
39
Parameters:
40
- device: device name (None for default)
41
- iscapture: 0 for playback, 1 for recording
42
- desired: desired audio specification
43
- obtained: actual audio specification (may differ from desired)
44
- allowed_changes: allowed changes to audio spec
45
46
Returns:
47
Audio device ID (>= 2) on success, 0 on failure
48
"""
49
50
def SDL_CloseAudioDevice(dev: int) -> None:
51
"""Close audio device."""
52
53
def SDL_PauseAudioDevice(dev: int, pause_on: int) -> None:
54
"""Pause or unpause audio device."""
55
56
def SDL_GetAudioDeviceStatus(dev: int) -> int:
57
"""Get audio device status."""
58
```
59
60
### Audio Specification and Format
61
62
Audio format constants and specification structure.
63
64
```python { .api }
65
# Audio format constants
66
SDL_AUDIO_MASK_BITSIZE: int = 0xFF
67
SDL_AUDIO_MASK_DATATYPE: int = (1 << 8)
68
SDL_AUDIO_MASK_ENDIAN: int = (1 << 12)
69
SDL_AUDIO_MASK_SIGNED: int = (1 << 15)
70
71
# Specific audio formats
72
AUDIO_U8: int = 0x0008 # Unsigned 8-bit
73
AUDIO_S8: int = 0x8008 # Signed 8-bit
74
AUDIO_U16LSB: int = 0x0010 # Unsigned 16-bit little-endian
75
AUDIO_S16LSB: int = 0x8010 # Signed 16-bit little-endian
76
AUDIO_U16MSB: int = 0x1010 # Unsigned 16-bit big-endian
77
AUDIO_S16MSB: int = 0x9010 # Signed 16-bit big-endian
78
AUDIO_U16: int = AUDIO_U16LSB
79
AUDIO_S16: int = AUDIO_S16LSB
80
AUDIO_S32LSB: int = 0x8020 # Signed 32-bit little-endian
81
AUDIO_S32MSB: int = 0x9020 # Signed 32-bit big-endian
82
AUDIO_S32: int = AUDIO_S32LSB
83
AUDIO_F32LSB: int = 0x8120 # 32-bit floating point little-endian
84
AUDIO_F32MSB: int = 0x9120 # 32-bit floating point big-endian
85
AUDIO_F32: int = AUDIO_F32LSB
86
87
class SDL_AudioSpec:
88
"""Audio specification structure."""
89
freq: int # Sample rate (samples per second)
90
format: int # Audio format (AUDIO_S16, etc.)
91
channels: int # Number of channels (1=mono, 2=stereo)
92
silence: int # Silence value for audio format
93
samples: int # Audio buffer size in samples (power of 2)
94
padding: int # Padding
95
size: int # Audio buffer size in bytes
96
callback: ctypes.CFUNCTYPE # Audio callback function
97
userdata: ctypes.c_void_p # User data for callback
98
```
99
100
### Audio Conversion
101
102
Functions for converting between audio formats.
103
104
```python { .api }
105
def SDL_BuildAudioCVT(cvt: SDL_AudioCVT, src_format: int, src_channels: int, src_rate: int,
106
dst_format: int, dst_channels: int, dst_rate: int) -> int:
107
"""Build audio conversion structure."""
108
109
def SDL_ConvertAudio(cvt: SDL_AudioCVT) -> int:
110
"""Convert audio data using conversion structure."""
111
112
class SDL_AudioCVT:
113
"""Audio conversion structure."""
114
needed: int # Set to 1 if conversion needed
115
src_format: int # Source audio format
116
dst_format: int # Destination audio format
117
rate_incr: float # Rate conversion increment
118
buf: ctypes.POINTER(ctypes.c_uint8) # Audio buffer
119
len: int # Original audio buffer length
120
len_cvt: int # Converted audio buffer length
121
len_mult: int # Buffer length multiplier
122
len_ratio: float # Length ratio
123
```
124
125
### SDL2_mixer Integration
126
127
High-level audio mixing functions through SDL2_mixer.
128
129
```python { .api }
130
def Mix_OpenAudio(frequency: int, format: int, channels: int, chunksize: int) -> int:
131
"""
132
Initialize audio mixer.
133
134
Parameters:
135
- frequency: sample rate (22050, 44100, etc.)
136
- format: audio format (MIX_DEFAULT_FORMAT recommended)
137
- channels: number of output channels (1=mono, 2=stereo)
138
- chunksize: audio buffer size in samples
139
140
Returns:
141
0 on success, -1 on failure
142
"""
143
144
def Mix_CloseAudio() -> None:
145
"""Close audio mixer."""
146
147
def Mix_QuerySpec(frequency: ctypes.POINTER(ctypes.c_int), format: ctypes.POINTER(ctypes.c_uint16),
148
channels: ctypes.POINTER(ctypes.c_int)) -> int:
149
"""Query mixer audio format."""
150
151
def Mix_AllocateChannels(numchans: int) -> int:
152
"""Set number of mixing channels."""
153
```
154
155
### Sound Loading and Playback
156
157
Functions for loading and playing sound effects.
158
159
```python { .api }
160
def Mix_LoadWAV(file: bytes) -> Mix_Chunk:
161
"""
162
Load WAV audio file.
163
164
Parameters:
165
- file: path to WAV file as bytes
166
167
Returns:
168
Mix_Chunk object or None on failure
169
"""
170
171
def Mix_LoadWAV_RW(src: SDL_RWops, freesrc: int) -> Mix_Chunk:
172
"""Load WAV from SDL_RWops."""
173
174
def Mix_FreeChunk(chunk: Mix_Chunk) -> None:
175
"""Free audio chunk."""
176
177
def Mix_PlayChannel(channel: int, chunk: Mix_Chunk, loops: int) -> int:
178
"""
179
Play audio chunk on channel.
180
181
Parameters:
182
- channel: channel to play on (-1 for first available)
183
- chunk: audio chunk to play
184
- loops: number of loops (-1 for infinite)
185
186
Returns:
187
Channel number playing on, -1 on error
188
"""
189
190
def Mix_PlayChannelTimed(channel: int, chunk: Mix_Chunk, loops: int, ticks: int) -> int:
191
"""Play audio chunk with time limit."""
192
193
def Mix_Volume(channel: int, volume: int) -> int:
194
"""
195
Set channel volume.
196
197
Parameters:
198
- channel: channel number (-1 for all channels)
199
- volume: volume level (0-128)
200
201
Returns:
202
Previous volume level
203
"""
204
205
def Mix_Pause(channel: int) -> None:
206
"""Pause channel."""
207
208
def Mix_Resume(channel: int) -> None:
209
"""Resume channel."""
210
211
def Mix_HaltChannel(channel: int) -> int:
212
"""Stop playing on channel."""
213
214
def Mix_Playing(channel: int) -> int:
215
"""Check if channel is playing."""
216
217
def Mix_Paused(channel: int) -> int:
218
"""Check if channel is paused."""
219
```
220
221
### Music Loading and Playback
222
223
Functions for loading and playing background music.
224
225
```python { .api }
226
def Mix_LoadMUS(file: bytes) -> Mix_Music:
227
"""
228
Load music file.
229
230
Parameters:
231
- file: path to music file as bytes
232
233
Returns:
234
Mix_Music object or None on failure
235
"""
236
237
def Mix_LoadMUS_RW(src: SDL_RWops, freesrc: int) -> Mix_Music:
238
"""Load music from SDL_RWops."""
239
240
def Mix_FreeMusic(music: Mix_Music) -> None:
241
"""Free music."""
242
243
def Mix_PlayMusic(music: Mix_Music, loops: int) -> int:
244
"""
245
Play music.
246
247
Parameters:
248
- music: music to play
249
- loops: number of loops (-1 for infinite)
250
251
Returns:
252
0 on success, -1 on error
253
"""
254
255
def Mix_FadeInMusic(music: Mix_Music, loops: int, ms: int) -> int:
256
"""Play music with fade-in effect."""
257
258
def Mix_VolumeMusic(volume: int) -> int:
259
"""
260
Set music volume.
261
262
Parameters:
263
- volume: volume level (0-128)
264
265
Returns:
266
Previous volume level
267
"""
268
269
def Mix_PauseMusic() -> None:
270
"""Pause music."""
271
272
def Mix_ResumeMusic() -> None:
273
"""Resume music."""
274
275
def Mix_HaltMusic() -> int:
276
"""Stop music."""
277
278
def Mix_FadeOutMusic(ms: int) -> int:
279
"""Fade out music over time."""
280
281
def Mix_PlayingMusic() -> int:
282
"""Check if music is playing."""
283
284
def Mix_PausedMusic() -> int:
285
"""Check if music is paused."""
286
287
def Mix_GetMusicType(music: Mix_Music) -> int:
288
"""Get music type."""
289
```
290
291
### Mixer Constants and Types
292
293
Constants and types for SDL2_mixer.
294
295
```python { .api }
296
# Mixer format constants
297
MIX_DEFAULT_FREQUENCY: int = 22050
298
MIX_DEFAULT_FORMAT: int = AUDIO_S16LSB
299
MIX_DEFAULT_CHANNELS: int = 2
300
MIX_MAX_VOLUME: int = 128
301
302
# Mixer initialization flags
303
MIX_INIT_FLAC: int = 0x00000001
304
MIX_INIT_MOD: int = 0x00000002
305
MIX_INIT_MP3: int = 0x00000008
306
MIX_INIT_OGG: int = 0x00000010
307
MIX_INIT_MID: int = 0x00000020
308
MIX_INIT_OPUS: int = 0x00000040
309
310
# Music types
311
MUS_NONE: int = 0
312
MUS_CMD: int = 1
313
MUS_WAV: int = 2
314
MUS_MOD: int = 3
315
MUS_MID: int = 4
316
MUS_OGG: int = 5
317
MUS_MP3: int = 6
318
MUS_MP3_MAD_UNUSED: int = 7
319
MUS_FLAC: int = 8
320
MUS_MODPLUG_UNUSED: int = 9
321
MUS_OPUS: int = 10
322
323
class Mix_Chunk:
324
"""Audio chunk structure."""
325
allocated: int # 1 if allocated, 0 if not
326
abuf: ctypes.POINTER(ctypes.c_uint8) # Audio buffer
327
alen: int # Audio buffer length
328
volume: int # Volume (0-128)
329
330
class Mix_Music:
331
"""Opaque music structure."""
332
```
333
334
### Audio Callbacks and Effects
335
336
Advanced audio processing functions.
337
338
```python { .api }
339
def Mix_RegisterEffect(chan: int, f: ctypes.CFUNCTYPE, d: ctypes.CFUNCTYPE, arg: ctypes.c_void_p) -> int:
340
"""Register audio effect function."""
341
342
def Mix_UnregisterEffect(channel: int, f: ctypes.CFUNCTYPE) -> int:
343
"""Unregister audio effect function."""
344
345
def Mix_UnregisterAllEffects(channel: int) -> int:
346
"""Unregister all effects on channel."""
347
348
def Mix_SetPostMix(mix_func: ctypes.CFUNCTYPE, arg: ctypes.c_void_p) -> None:
349
"""Set post-mix callback function."""
350
351
def Mix_HookMusic(mix_func: ctypes.CFUNCTYPE, arg: ctypes.c_void_p) -> None:
352
"""Set music hook callback function."""
353
354
def Mix_HookMusicFinished(music_finished: ctypes.CFUNCTYPE) -> None:
355
"""Set callback for when music finishes."""
356
357
def Mix_ChannelFinished(channel_finished: ctypes.CFUNCTYPE) -> None:
358
"""Set callback for when channel finishes."""
359
```
360
361
## Usage Examples
362
363
### Basic Sound Playback
364
365
```python
366
import sdl2
367
import sdl2.sdlmixer
368
369
# Initialize SDL2 with audio
370
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
371
372
# Initialize mixer
373
if sdl2.sdlmixer.Mix_OpenAudio(22050, sdl2.sdlmixer.MIX_DEFAULT_FORMAT, 2, 1024) == -1:
374
print("Failed to initialize mixer")
375
exit(1)
376
377
# Load sound effect
378
sound = sdl2.sdlmixer.Mix_LoadWAV(b"sound.wav")
379
if not sound:
380
print("Failed to load sound")
381
exit(1)
382
383
# Load background music
384
music = sdl2.sdlmixer.Mix_LoadMUS(b"music.ogg")
385
if not music:
386
print("Failed to load music")
387
exit(1)
388
389
# Play background music
390
sdl2.sdlmixer.Mix_PlayMusic(music, -1) # Loop forever
391
392
# Main loop
393
running = True
394
event = sdl2.SDL_Event()
395
396
while running:
397
while sdl2.SDL_PollEvent(event):
398
if event.type == sdl2.SDL_QUIT:
399
running = False
400
elif event.type == sdl2.SDL_KEYDOWN:
401
if event.key.keysym.sym == sdl2.SDLK_SPACE:
402
# Play sound effect
403
sdl2.sdlmixer.Mix_PlayChannel(-1, sound, 0)
404
405
# Cleanup
406
sdl2.sdlmixer.Mix_FreeChunk(sound)
407
sdl2.sdlmixer.Mix_FreeMusic(music)
408
sdl2.sdlmixer.Mix_CloseAudio()
409
sdl2.SDL_Quit()
410
```
411
412
### Low-Level Audio Device Control
413
414
```python
415
import sdl2
416
import ctypes
417
418
def audio_callback(userdata, stream, length):
419
"""Audio callback function."""
420
# Fill stream with audio data
421
# This example just fills with silence
422
ctypes.memset(stream, 0, length)
423
424
# Initialize SDL2
425
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
426
427
# Set up audio specification
428
audio_spec = sdl2.SDL_AudioSpec()
429
audio_spec.freq = 44100
430
audio_spec.format = sdl2.AUDIO_S16LSB
431
audio_spec.channels = 2
432
audio_spec.samples = 1024
433
audio_spec.callback = audio_callback
434
audio_spec.userdata = None
435
436
# Open audio device
437
obtained = sdl2.SDL_AudioSpec()
438
device_id = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, obtained, 0)
439
440
if device_id == 0:
441
print("Failed to open audio device")
442
exit(1)
443
444
print(f"Opened audio device {device_id}")
445
print(f"Format: {obtained.format}, Freq: {obtained.freq}, Channels: {obtained.channels}")
446
447
# Start audio playback
448
sdl2.SDL_PauseAudioDevice(device_id, 0)
449
450
# Run for a while
451
sdl2.SDL_Delay(5000)
452
453
# Stop and close
454
sdl2.SDL_PauseAudioDevice(device_id, 1)
455
sdl2.SDL_CloseAudioDevice(device_id)
456
sdl2.SDL_Quit()
457
```
458
459
### Audio Format Conversion
460
461
```python
462
import sdl2
463
import ctypes
464
465
# Initialize SDL2
466
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
467
468
# Set up conversion from 16-bit stereo to 8-bit mono
469
cvt = sdl2.SDL_AudioCVT()
470
result = sdl2.SDL_BuildAudioCVT(
471
cvt,
472
sdl2.AUDIO_S16LSB, 2, 44100, # Source: 16-bit stereo 44.1kHz
473
sdl2.AUDIO_U8, 1, 22050 # Dest: 8-bit mono 22.05kHz
474
)
475
476
if result == -1:
477
print("Audio conversion not possible")
478
exit(1)
479
elif result == 0:
480
print("No conversion needed")
481
exit(0)
482
483
# Allocate buffer for conversion (example with 1024 samples)
484
original_len = 1024 * 2 * 2 # 1024 samples * 2 channels * 2 bytes per sample
485
cvt.len = original_len
486
cvt.buf = (ctypes.c_uint8 * (original_len * cvt.len_mult))()
487
488
# Fill buffer with sample data (normally you'd load from file)
489
# ... fill cvt.buf with audio data ...
490
491
# Perform conversion
492
if sdl2.SDL_ConvertAudio(cvt) == 0:
493
print(f"Conversion successful. New length: {cvt.len_cvt}")
494
else:
495
print("Conversion failed")
496
497
sdl2.SDL_Quit()
498
```
499
500
### Volume and Effects Control
501
502
```python
503
import sdl2
504
import sdl2.sdlmixer
505
506
# Initialize SDL2 and mixer
507
sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO)
508
sdl2.sdlmixer.Mix_OpenAudio(44100, sdl2.sdlmixer.MIX_DEFAULT_FORMAT, 2, 1024)
509
510
# Load sound
511
sound = sdl2.sdlmixer.Mix_LoadWAV(b"sound.wav")
512
513
# Set channel volume to 50%
514
sdl2.sdlmixer.Mix_Volume(0, sdl2.sdlmixer.MIX_MAX_VOLUME // 2)
515
516
# Play sound on channel 0
517
channel = sdl2.sdlmixer.Mix_PlayChannel(0, sound, 0)
518
519
# Wait for sound to finish
520
while sdl2.sdlmixer.Mix_Playing(channel):
521
sdl2.SDL_Delay(100)
522
523
# Play with fade-in effect
524
sdl2.sdlmixer.Mix_FadeInChannelTimed(0, sound, 0, 1000, 5000) # 1s fade-in, 5s total
525
526
# Cleanup
527
sdl2.sdlmixer.Mix_FreeChunk(sound)
528
sdl2.sdlmixer.Mix_CloseAudio()
529
sdl2.SDL_Quit()
530
```