|
1 | 1 | #!/usr/bin/env python3
|
2 | 2 | """Load an audio file into memory and play its contents.
|
3 | 3 |
|
4 |
| -NumPy and the soundfile module (https://PySoundFile.readthedocs.io/) |
| 4 | +NumPy and the soundfile module (https://python-soundfile.readthedocs.io/) |
5 | 5 | must be installed for this to work.
|
6 | 6 |
|
7 | 7 | This example program loads the whole file into memory before starting
|
8 | 8 | playback.
|
9 | 9 | To play very long files, you should use play_long_file.py instead.
|
10 | 10 |
|
| 11 | +This example could simply be implemented like this:: |
| 12 | +
|
| 13 | + import sounddevice as sd |
| 14 | + import soundfile as sf |
| 15 | +
|
| 16 | + data, fs = sf.read('my-file.wav') |
| 17 | + sd.play(data, fs) |
| 18 | + sd.wait() |
| 19 | +
|
| 20 | +... but in this example we show a more low-level implementation |
| 21 | +using a callback stream. |
| 22 | +
|
11 | 23 | """
|
12 | 24 | import argparse
|
| 25 | +import threading |
13 | 26 |
|
14 | 27 | import sounddevice as sd
|
15 | 28 | import soundfile as sf
|
@@ -43,13 +56,30 @@ def int_or_str(text):
|
43 | 56 | help='output device (numeric ID or substring)')
|
44 | 57 | args = parser.parse_args(remaining)
|
45 | 58 |
|
| 59 | +event = threading.Event() |
| 60 | + |
46 | 61 | try:
|
47 |
| - data, fs = sf.read(args.filename, dtype='float32') |
48 |
| - sd.play(data, fs, device=args.device) |
49 |
| - status = sd.wait() |
| 62 | + data, fs = sf.read(args.filename, always_2d=True) |
| 63 | + |
| 64 | + current_frame = 0 |
| 65 | + |
| 66 | + def callback(outdata, frames, time, status): |
| 67 | + global current_frame |
| 68 | + if status: |
| 69 | + print(status) |
| 70 | + chunksize = min(len(data) - current_frame, frames) |
| 71 | + outdata[:chunksize] = data[current_frame:current_frame + chunksize] |
| 72 | + if chunksize < frames: |
| 73 | + outdata[chunksize:] = 0 |
| 74 | + raise sd.CallbackStop() |
| 75 | + current_frame += chunksize |
| 76 | + |
| 77 | + stream = sd.OutputStream( |
| 78 | + samplerate=fs, device=args.device, channels=data.shape[1], |
| 79 | + callback=callback, finished_callback=event.set) |
| 80 | + with stream: |
| 81 | + event.wait() # Wait until playback is finished |
50 | 82 | except KeyboardInterrupt:
|
51 | 83 | parser.exit('\nInterrupted by user')
|
52 | 84 | except Exception as e:
|
53 | 85 | parser.exit(type(e).__name__ + ': ' + str(e))
|
54 |
| -if status: |
55 |
| - parser.exit('Error during playback: ' + str(status)) |
|
0 commit comments