git.haldean.org symrep / c73b516
lots more audio stuff Will Haldean Brown 6 years ago
5 changed file(s) with 115 addition(s) and 31 deletion(s). Raw diff Collapse all Expand all
0 import symrep
0 from symrep import *
11 import sys
22
3 n1 = symrep.product(
4 symrep.const(0.3),
5 symrep.product(
6 symrep.audio.sine(symrep.const(440)),
7 symrep.audio.sine(symrep.const(0.5)),
3 n1 = product(
4 const(0.3),
5 product(
6 audio.sine(const(440)),
7 audio.sine(const(0.5)),
88 )
99 )
10 n2 = symrep.product(
11 symrep.const(0.3),
12 symrep.product(
13 symrep.audio.sine(symrep.const(360)),
14 symrep.audio.sine(symrep.const(0.4)),
10 n2 = product(
11 const(0.2),
12 audio.sine(
13 product(
14 const(400),
15 piecewise(
16 audio.sawtooth(const(1)),
17 const(1),
18 const(1),
19 ),
20 )
1521 )
1622 )
17 n3 = symrep.product(
18 symrep.const(0.3),
19 symrep.audio.sine(symrep.const(500)),
23 n3 = product(
24 const(0.3),
25 audio.sine(const(220)),
2026 )
21 n = symrep.sum(n1, n2, n3)
27 n4 = product(
28 audio.sine(const(140)),
29 audio.square(const(2), const(0.05)),
30 )
31 n5 = product(
32 audio.sine(const(170)),
33 shift(
34 audio.square(const(2), const(0.05)),
35 const(0.25),
36 )
37 )
38 n = sum(n1, n2, n3, n4, n5)
2239
23 symrep.audio.to_wav(n, 44100, 10, sys.stdout)
40 audio.stream_pcm(n, 44100, sys.stdout)
00 import array
1 import datetime
12 import math
23 import struct
34 import symrep.base
45
56 def sine(freq):
67 return symrep.base.Node(
7 "sin", lambda t: math.sin(t * freq(t) * 2. * math.pi), [freq])
8 "sine", lambda t: math.sin(t * freq(t) * 2. * math.pi), [freq])
89
9 def square(freq):
10 pass
10 def square(freq, duty):
11 def gen(t):
12 t = t * freq(t)
13 t_frac = t - int(t)
14 if t_frac < duty(t):
15 return 1.
16 return 0.
17 return symrep.base.Node("square", gen, [freq])
18
19 def sawtooth(freq):
20 def gen(t):
21 t = t * freq(t)
22 return t - int(t)
23 return symrep.base.Node("sawtooth", gen, [freq])
1124
1225 def _to_short(val, max_amplitude=1.0):
1326 short_max = (2 ** 15) - 1
1831 return -short_max
1932 return val
2033
21 def to_wav(root, sample_rate, length, stream):
22 bits_per_sample = 16
23 data = array.array("h", map(
24 lambda x: _to_short(x[1]),
25 symrep.base.sample(root, 0., length, 1. / sample_rate)))
26
34 def _write_wav_header(stream, sample_rate, bits_per_sample, total_size):
2735 # begin file header
2836 stream.write("RIFF")
29 stream.write(struct.pack("<I",
30 # length of file is length of remaining bytes in the file header, length
31 # of the format header, length of the data header and the data itself
32 4 + 24 + 8 + len(data)))
37 stream.write(struct.pack("<I", total_size))
3338 stream.write("WAVE")
3439
3540 # begin fmt block header
4449 bits_per_sample,
4550 ))
4651
52
53 def to_wav(root, sample_rate, length, stream):
54 bits_per_sample = 16
55 data = array.array("h", map(
56 lambda x: _to_short(x[1]),
57 symrep.base.sample(root, 0., length, 1. / sample_rate)))
58
59 # length of file is length of remaining bytes in the file header, length
60 # of the format header, length of the data header and the data itself
61 file_len = 4 + 24 + 8 + len(data)
62 _write_wav_header(stream, sample_rate, 16, file_len)
63
4764 # begin data header
4865 stream.write("data")
49 stream.write(struct.pack("<I", 4 * len(data)))
66 stream.write(struct.pack("<I", (bits_per_sample / 8) * len(data)))
5067 data.tofile(stream)
68
69 def stream_pcm(root, sample_rate, stream):
70 _write_wav_header(stream, sample_rate, 16, 2 ** 32 - 1)
71 stream.write("data")
72 stream.write(struct.pack("<I", 2 ** 32 - 1))
73 t = 0.
74 while True:
75 stream.write(struct.pack("<h", _to_short(root(t))))
76 t += 1. / sample_rate
1414 "product",
1515 lambda t: reduce(operator.mul, (n(t) for n in nodes), 1),
1616 nodes)
17
18 def piecewise(pre, post, split):
19 return Node(
20 "piecewise",
21 lambda t: pre(t) if t < split(t) else post(t - split(t)),
22 [pre, post, split])
23
24 def shift(n, shift):
25 return Node("shift", lambda t: n(t + shift(t)), [n, shift])
1726
1827 class Node(object):
1928 _next_id = 0
4857 def to_dot(root, stream, name="symrep"):
4958 stream.write("digraph {name} {{\n".format(name=name))
5059 for node in collect_nodes(root):
51 stream.write("{id} [label=\"{name}\"];\n".format(
60 stream.write("{id} [label=\"{name}\\n{id}\"];\n".format(
5261 id=node.id, name=node.name))
5362 for n1, n2 in collect_edges(root):
5463 stream.write("{n2} -> {n1};\n".format(n1=n1, n2=n2))
5564 stream.write("}\n")
65
66 def dump_samples(root, min_t, max_t, delta_t, f):
67 nodes = list(collect_nodes(root))
68 nodes.sort(key=lambda n: n.id)
69 f.write("t," + ",".join(str(n.id) for n in nodes) + "\n")
70 t = min_t
71 while t < max_t:
72 f.write("{},".format(t))
73 f.write(",".join(repr(n(t)) for n in nodes))
74 f.write("\n")
75 t += delta_t
3535 self.assertAlmostEqual(n(0.75), -1)
3636 self.assertAlmostEqual(n(1), 0)
3737
38 def test_sine_modulation(self):
39 n = symrep.audio.sine(
40 symrep.audio.sawtooth(symrep.const(1)))
41 self.assertAlmostEqual(n(0), 0)
42 self.assertAlmostEqual(n(1), 0)
43
3844 def test_collect_nodes(self):
3945 n1 = symrep.const(1)
4046 n2 = symrep.audio.sine(n1)
0 import matplotlib.pyplot as plt
1 import numpy
2 import sys
3
4 dat = numpy.genfromtxt(
5 sys.stdin,
6 delimiter=",",
7 names=True)
8 cols = dat.dtype.names
9 for col in cols:
10 if col in ["t"] + sys.argv:
11 continue
12 plt.plot(dat["t"], dat[col], label=col)
13 plt.legend()
14 plt.show()