summaryrefslogtreecommitdiff
path: root/test/tone.py
blob: 3efeffd1a08ede858862ef459eba0affc0a33eca (plain)
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-2023 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()