1#!/usr/bin/env python3 2"""Play a sine signal.""" 3import argparse 4import sys 5 6import numpy as np 7import sounddevice as sd 8 9 10def int_or_str(text): 11 """Helper function for argument parsing.""" 12 try: 13 return int(text) 14 except ValueError: 15 return text 16 17 18parser = argparse.ArgumentParser(add_help=False) 19parser.add_argument( 20 '-l', '--list-devices', action='store_true', 21 help='show list of audio devices and exit') 22args, remaining = parser.parse_known_args() 23if args.list_devices: 24 print(sd.query_devices()) 25 parser.exit(0) 26parser = argparse.ArgumentParser( 27 description=__doc__, 28 formatter_class=argparse.RawDescriptionHelpFormatter, 29 parents=[parser]) 30parser.add_argument( 31 'frequency', nargs='?', metavar='FREQUENCY', type=float, default=500, 32 help='frequency in Hz (default: %(default)s)') 33parser.add_argument( 34 '-d', '--device', type=int_or_str, 35 help='output device (numeric ID or substring)') 36parser.add_argument( 37 '-a', '--amplitude', type=float, default=0.2, 38 help='amplitude (default: %(default)s)') 39args = parser.parse_args(remaining) 40 41start_idx = 0 42 43try: 44 samplerate = sd.query_devices(args.device, 'output')['default_samplerate'] 45 46 def callback(outdata, frames, time, status): 47 if status: 48 print(status, file=sys.stderr) 49 global start_idx 50 t = (start_idx + np.arange(frames)) / samplerate 51 t = t.reshape(-1, 1) 52 outdata[:] = args.amplitude * np.sin(2 * np.pi * args.frequency * t) 53 start_idx += frames 54 55 with sd.OutputStream(device=args.device, channels=1, callback=callback, 56 samplerate=samplerate): 57 print('#' * 80) 58 print('press Return to quit') 59 print('#' * 80) 60 input() 61except KeyboardInterrupt: 62 parser.exit('') 63except Exception as e: 64 parser.exit(type(e).__name__ + ': ' + str(e)) 65