1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
#
# Copyright (c) 2020-2021 Vasile Vilvoiu <vasi@vilvoiu.ro>
#
# specgram is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
import argparse
import numpy as np
import time
import sys
def main():
# Argument parsing
parser = argparse.ArgumentParser(description='Generate a tone on stdout.')
parser.add_argument('freq', type=float, help='frequency of tone')
parser.add_argument('rate', type=float, help='sampling rate')
parser.add_argument('dtype', type=str, help='data type')
parser.add_argument('--bs', type=int, default=512, help='block size')
parser.add_argument('--pp', type=float, default=2.0, help='peak to peak amplitude')
#parser.add_argument('--rl', action='store_true', help='rate limit output')
args = parser.parse_args()
# Parse datatype
if args.dtype[0] == 'c':
is_complex = True
args.dtype = args.dtype[1:]
else:
is_complex = False
if args.dtype == 'u8':
dtype = np.uint8
elif args.dtype == 's8':
dtype = np.int8
elif args.dtype == 'u16':
dtype = np.uint16
elif args.dtype == 's16':
dtype = np.int16
elif args.dtype == 'u32':
dtype = np.uint32
elif args.dtype == 's32':
dtype = np.int32
elif args.dtype == 'u64':
dtype = np.uint64
elif args.dtype == 's64':
dtype = np.int64
elif args.dtype == 'f32':
dtype = np.float32
elif args.dtype == 'f64':
dtype = np.float64
else:
raise Exception('bad datatype')
index = 0
while True:
# Generate complex tone
t = np.linspace(index, index + args.bs - 1, args.bs, dtype=np.float128) / args.rate
c = np.exp(2j * np.pi * args.freq * t) / 2.0 # -0.5 .. 0.5
# Convert to output data type
if args.dtype[0] == 's':
dr = (np.real(c) * args.pp * np.iinfo(dtype).max).astype(dtype)
di = (np.imag(c) * args.pp * np.iinfo(dtype).max).astype(dtype)
elif args.dtype[0] == 'u':
dr = (np.real((c + 0.5) / 2.0) * args.pp * np.iinfo(dtype).max).astype(dtype)
di = (np.imag((c + 0.5) / 2.0) * args.pp * np.iinfo(dtype).max).astype(dtype)
else:
dr = np.real(c * args.pp).astype(dtype)
di = np.imag(c * args.pp).astype(dtype)
# Output block
if (is_complex):
dc = np.ravel(np.column_stack((dr, di)))
sys.stdout.buffer.write(dc.tobytes())
else:
sys.stdout.buffer.write(dr.tobytes())
sys.stdout.buffer.flush()
# Advance
index += args.bs
if __name__ == '__main__':
main()
|