play_file.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #!/usr/bin/env python3
  2. """Load an audio file into memory and play its contents.
  3. NumPy and the soundfile module (https://python-soundfile.readthedocs.io/)
  4. must be installed for this to work.
  5. This example program loads the whole file into memory before starting
  6. playback.
  7. To play very long files, you should use play_long_file.py instead.
  8. This example could simply be implemented like this::
  9. import sounddevice as sd
  10. import soundfile as sf
  11. data, fs = sf.read('my-file.wav')
  12. sd.play(data, fs)
  13. sd.wait()
  14. ... but in this example we show a more low-level implementation
  15. using a callback stream.
  16. """
  17. import argparse
  18. import threading
  19. import sounddevice as sd
  20. import soundfile as sf
  21. def int_or_str(text):
  22. """Helper function for argument parsing."""
  23. try:
  24. return int(text)
  25. except ValueError:
  26. return text
  27. parser = argparse.ArgumentParser(add_help=False)
  28. parser.add_argument(
  29. '-l', '--list-devices', action='store_true',
  30. help='show list of audio devices and exit')
  31. args, remaining = parser.parse_known_args()
  32. if args.list_devices:
  33. print(sd.query_devices())
  34. parser.exit(0)
  35. parser = argparse.ArgumentParser(
  36. description=__doc__,
  37. formatter_class=argparse.RawDescriptionHelpFormatter,
  38. parents=[parser])
  39. parser.add_argument(
  40. 'filename', metavar='FILENAME',
  41. help='audio file to be played back')
  42. parser.add_argument(
  43. '-d', '--device', type=int_or_str,
  44. help='output device (numeric ID or substring)')
  45. args = parser.parse_args(remaining)
  46. event = threading.Event()
  47. try:
  48. data, fs = sf.read(args.filename, always_2d=True)
  49. current_frame = 0
  50. def callback(outdata, frames, time, status):
  51. global current_frame
  52. if status:
  53. print(status)
  54. chunksize = min(len(data) - current_frame, frames)
  55. outdata[:chunksize] = data[current_frame:current_frame + chunksize]
  56. if chunksize < frames:
  57. outdata[chunksize:] = 0
  58. raise sd.CallbackStop()
  59. current_frame += chunksize
  60. stream = sd.OutputStream(
  61. samplerate=fs, device=args.device, channels=data.shape[1],
  62. callback=callback, finished_callback=event.set)
  63. with stream:
  64. event.wait() # Wait until playback is finished
  65. except KeyboardInterrupt:
  66. parser.exit('\nInterrupted by user')
  67. except Exception as e:
  68. parser.exit(type(e).__name__ + ': ' + str(e))