Ei vielä käännetty
Tätä sivua ei ole vielä käännetty suomeksi, joten se näytetään englanniksi. Auta kääntämään
winsound Module Complexity¶
The winsound module is a thin layer over three Windows calls: PlaySound() for WAV audio,
Beep() for a tone, and MessageBeep() for the system alert sounds. What a call costs is
mostly how long it blocks, and for PlaySound() also what Windows reads and keeps in memory
on the way.
It is Windows-only. On other platforms import winsound raises ModuleNotFoundError.
d is how long a sound plays: a synchronous call blocks for all of it, and the work of
streaming the audio to the device is counted in it. f is the bytes of the WAV file a sound
comes from, the whole file rather than just its audio data. A WAV image passed from memory has
no size term: it is read in place, so a larger image with the same audio costs the same.
Complexity Reference¶
PlaySound¶
| Operation | Time | Space | Notes |
|---|---|---|---|
winsound.PlaySound(sound, SND_MEMORY) |
O(d) | O(1) | sound is a bytes-like WAV image, read in place rather than copied; blocks until the sound ends |
winsound.PlaySound(sound, SND_FILENAME) |
O(f + d) | O(f) | Windows reads the whole file and keeps it until the next PlaySound() call; accepts os.PathLike on Python 3.12+ |
winsound.PlaySound(sound, SND_ALIAS) |
O(f + d) | O(f) | Looks up the event's file in the registry, then plays it as SND_FILENAME does |
winsound.PlaySound(sound, flags \| SND_ASYNC) |
O(1) | O(f) | Returns without waiting for the file to be read, which Windows does in the background; with SND_MEMORY it raises RuntimeError instead |
winsound.PlaySound(None, flags) |
O(1) | O(1) | Stops an asynchronous sound and releases the kept file, whatever the flags; a synchronous play in another thread runs to its end |
Tones and alerts¶
| Operation | Time | Space | Notes |
|---|---|---|---|
winsound.Beep(frequency, duration) |
O(d) | O(1) | d = duration in milliseconds, for which the call blocks; a frequency outside 37 to 32,767 raises ValueError before anything plays |
winsound.MessageBeep(type=MB_OK) |
O(1) | O(1) | Queues the system sound for type and returns without waiting for it |
Constants¶
| Operation | Time | Space | Notes |
|---|---|---|---|
winsound.SND_FILENAME, winsound.SND_ALIAS, winsound.SND_MEMORY |
O(1) | O(1) | Integer flags saying what sound is: a path, a registry event name, or a WAV image |
winsound.SND_APPLICATION |
O(1) | O(1) | With SND_ALIAS, looks the name up among the running program's own events |
winsound.SND_ASYNC |
O(1) | O(1) | Return without waiting for the sound; not allowed with SND_MEMORY |
winsound.SND_SYNC |
O(1) | O(1) | 0, the default: wait for the sound to end. Python 3.14+ |
winsound.SND_LOOP |
O(1) | O(1) | Repeat until the next PlaySound() call; needs SND_ASYNC, so a sound from memory cannot loop |
winsound.SND_NODEFAULT |
O(1) | O(1) | A sound that cannot be found or played raises RuntimeError instead of playing the default sound |
winsound.SND_NOSTOP |
O(1) | O(1) | While an earlier asynchronous sound still plays, PlaySound() raises RuntimeError instead of stopping it |
winsound.SND_NOWAIT, winsound.SND_PURGE |
O(1) | O(1) | Accepted, but on Windows 11 a sound played with either while another plays is neither refused nor cut short |
winsound.SND_SENTRY, winsound.SND_SYSTEM |
O(1) | O(1) | A SoundSentry visual cue, and the system notification audio session. Python 3.14+ |
winsound.MB_OK, winsound.MB_ICONASTERISK, winsound.MB_ICONEXCLAMATION, winsound.MB_ICONHAND, winsound.MB_ICONQUESTION |
O(1) | O(1) | The alert a MessageBeep() call plays |
winsound.MB_ICONERROR, winsound.MB_ICONINFORMATION, winsound.MB_ICONSTOP, winsound.MB_ICONWARNING |
O(1) | O(1) | Other names for MB_ICONHAND, MB_ICONASTERISK, MB_ICONHAND and MB_ICONEXCLAMATION. Python 3.14+ |
Playing From Memory¶
SND_MEMORY plays a WAV image you already hold, bytes or any other bytes-like object, without
copying it. The call blocks for the whole sound, and there is no asynchronous form: combining it
with SND_ASYNC raises before anything plays.
import io
import wave
import winsound
buffer = io.BytesIO()
with wave.open(buffer, "wb") as w:
w.setnchannels(1)
w.setsampwidth(1)
w.setframerate(8000)
w.writeframes(b"\x80" * 800) # 0.1 s of silence
data = buffer.getvalue()
flags = winsound.SND_MEMORY | winsound.SND_NODEFAULT
winsound.PlaySound(data, flags) # O(d) - returns when the sound ends
winsound.PlaySound(bytearray(data), flags) # any bytes-like object
try:
winsound.PlaySound(data, flags | winsound.SND_ASYNC)
except RuntimeError as error:
assert "asynchronously from memory" in str(error)
else:
raise AssertionError("an asynchronous play from memory was accepted")
Playing a File¶
A file is not streamed. Windows reads the whole of it, including any chunks around the audio,
and keeps it after the call returns until the next PlaySound() call. PlaySound(None, 0)
releases it, and also stops a sound started with SND_ASYNC.
import os
import tempfile
import wave
import winsound
with tempfile.TemporaryDirectory() as tmp:
path = os.path.join(tmp, "silence.wav")
with wave.open(path, "wb") as w:
w.setnchannels(1)
w.setsampwidth(1)
w.setframerate(8000)
w.writeframes(b"\x80" * 8000) # 1 s of silence
flags = winsound.SND_FILENAME | winsound.SND_NODEFAULT
winsound.PlaySound(path, flags) # O(f + d) - reads the file, then plays it to the end
winsound.PlaySound(path, flags | winsound.SND_ASYNC) # O(1) - does not wait for the read
winsound.PlaySound(None, 0) # O(1) - stops it and releases the file's bytes
Missing Sounds¶
A file or alias that cannot be found is not an error by default: Windows plays the default
system sound instead. SND_NODEFAULT turns that into a RuntimeError.
import os
import tempfile
import winsound
with tempfile.TemporaryDirectory() as tmp:
missing = os.path.join(tmp, "missing.wav")
try:
winsound.PlaySound(missing, winsound.SND_FILENAME | winsound.SND_NODEFAULT)
except RuntimeError as error:
assert str(error) == "Failed to play sound"
else:
raise AssertionError("a missing file played")
Looping¶
SND_LOOP repeats the sound until the next PlaySound() call, and Windows loops only a sound
played with SND_ASYNC. Memory cannot play asynchronously, so a loop needs a file or an alias.
import os
import tempfile
import wave
import winsound
with tempfile.TemporaryDirectory() as tmp:
path = os.path.join(tmp, "silence.wav")
with wave.open(path, "wb") as w:
w.setnchannels(1)
w.setsampwidth(1)
w.setframerate(8000)
w.writeframes(b"\x80" * 800)
flags = winsound.SND_FILENAME | winsound.SND_NODEFAULT
winsound.PlaySound(path, flags | winsound.SND_ASYNC | winsound.SND_LOOP) # O(1) - loops
winsound.PlaySound(None, 0) # O(1) - ends the loop
with open(path, "rb") as f:
data = f.read()
try:
winsound.PlaySound(data, winsound.SND_MEMORY | winsound.SND_ASYNC | winsound.SND_LOOP)
except RuntimeError as error:
assert "asynchronously from memory" in str(error)
else:
raise AssertionError("a loop from memory was accepted")
Tones and System Sounds¶
Beep() blocks for its duration. MessageBeep() hands the alert to Windows and returns at
once. Both make a sound, so this example is not run by the test suite.
import winsound
winsound.Beep(440, 500) # O(d) - blocks for 500 ms
winsound.MessageBeep(winsound.MB_ICONEXCLAMATION) # O(1) - returns without waiting
Common Patterns¶
Playing Generated Audio Without Blocking¶
A WAV image built in memory cannot play asynchronously. Write it to a file and play that, then stop it and remove the file when it is no longer needed.
import io
import os
import tempfile
import wave
import winsound
buffer = io.BytesIO()
with wave.open(buffer, "wb") as w:
w.setnchannels(1)
w.setsampwidth(1)
w.setframerate(8000)
w.writeframes(b"\x80" * 4000)
fd, path = tempfile.mkstemp(suffix=".wav")
with os.fdopen(fd, "wb") as f:
f.write(buffer.getvalue()) # O(f)
flags = winsound.SND_FILENAME | winsound.SND_NODEFAULT | winsound.SND_ASYNC
winsound.PlaySound(path, flags) # O(1)
# ... carry on while it plays ...
winsound.PlaySound(None, 0) # O(1)
os.remove(path)
Performance Best Practices¶
✅ Do:
- Pass
SND_ASYNCfrom a thread that must stay responsive; the default blocks for the sound - Use
SND_MEMORYfor a sound you already hold: it is read in place, not copied - Add
SND_NODEFAULTwhen a file or alias may be missing, so the failure raises instead of playing the default sound - Call
PlaySound(None, 0)after a large file, which releases the copy Windows kept
❌ Avoid:
SND_ASYNCwithSND_MEMORY- it raisesRuntimeErroron every version- Playing a short sound from a large file - Windows reads the whole file, not just the audio
- Relying on
SND_PURGEorSND_NOWAIT; stop a sound withPlaySound(None, 0) - Stopping a synchronous play from another thread -
PlaySound(None, 0)does not reach it
Version Notes¶
- Python 3.12+:
PlaySound()accepts anos.PathLikepath; earlier versions accept onlystr - Python 3.14+: Added
SND_SYNC,SND_SENTRY,SND_SYSTEM,MB_ICONERROR,MB_ICONINFORMATION,MB_ICONSTOPandMB_ICONWARNING - All Python 3: Windows only, and
SND_MEMORYcannot be combined withSND_ASYNC