-
Notifications
You must be signed in to change notification settings - Fork 0
/
staticbit.py
executable file
·166 lines (132 loc) · 3.6 KB
/
staticbit.py
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env python
"""staticbit.py - encode a bitstream as static noise
Usage:
python staticbit.py (-e | -d) <FILE> [-s <N>]
python staticbit.py -h
Options:
-s Set the chip size (default: 1024)
-h Print this help
"""
from __future__ import print_function
import numpy
import os
import sys
import wave
__author__ = 'Mansour Moufid'
__email__ = 'mansourmoufid@gmail.com'
__license__ = 'ISC'
__status__ = 'Development'
__version__ = '0.1'
PCM_DTYPE = numpy.int16
PCM_MAX = 2.0 ** (16 - 1) - 1.0
def readbytes(f):
while True:
char = f.read(1)
if char == '':
break
byte = ord(char)
yield byte
def tobits(bytes):
for byte in bytes:
for i in range(8):
yield (byte >> i) & 1
def tobyte(bits):
return sum(2 ** i * bit for i, bit in enumerate(bits))
def xcor(x, y):
x = numpy.copy(x)
y = numpy.copy(y[::-1])
n = x.size + y.size
x.resize(n)
y.resize(n)
X = numpy.fft.rfft(x)
Y = numpy.fft.rfft(y)
Z = X * Y
z = numpy.fft.irfft(Z, n=n)
return z
def modxcor(x, y):
z = xcor(x, y)
n = y.size
return z[(n // 2):-(n // 2)]
class Chip(object):
def __init__(self, size, seed=None):
self.size = size
numpy.random.seed(seed)
def code(self):
return numpy.float32(numpy.random.normal(0.0, 0.2, self.size))
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '-h':
print(__doc__)
sys.exit(0)
try:
encode = '-e' in sys.argv
i = sys.argv.index('-e' if encode else '-d')
filename = sys.argv[i + 1]
if '-s' in sys.argv:
i = sys.argv.index('-s')
size = int(sys.argv[i + 1])
else:
size = 2 ** 10
except:
print(__doc__)
sys.exit(os.EX_USAGE)
tty = os.ctermid()
prompt = '\xF0\x9F\x94\x91 '
with open(tty, 'w') as f:
f.write(prompt)
with open(tty, 'r') as f:
line = f.readline()
key = line.rstrip('\n')
key = int(key)
chip = Chip(size, seed=key)
FS = 44100
SAMPWIDTH = 2
NCHANNELS = 1
if encode:
wav = wave.open(filename, 'wb')
wav.setframerate(FS)
wav.setsampwidth(SAMPWIDTH)
wav.setnchannels(NCHANNELS)
else:
wav = wave.open(filename, 'rb')
sampwidth = wav.getsampwidth()
nchannels = wav.getnchannels()
nframes = wav.getnframes()
fs = wav.getframerate()
assert fs == FS
assert sampwidth == SAMPWIDTH
assert nchannels == NCHANNELS
if encode:
for bit in tobits(readbytes(sys.stdin)):
code = chip.code()
one = PCM_DTYPE(code * PCM_MAX)
zero = one * -1
if bit == 1:
pcm = one
else:
pcm = zero
frames = pcm.tostring()
wav.writeframes(frames)
else:
bits = []
while True:
frames = wav.readframes(chip.size)
if len(frames) == 0:
break
pcm = numpy.fromstring(frames, dtype=PCM_DTYPE)
data = numpy.float32(pcm)
data = data / (PCM_MAX + 1.0)
one = chip.code()
xc = modxcor(data, one)
i = numpy.argmax(xc ** 2)
if xc[i] > 0:
bit = 1
else:
bit = 0
bits.append(bit)
if len(bits) == 8:
byte = tobyte(bits)
if sys.stdout.isatty():
byte &= 127
sys.stdout.write(chr(byte))
bits = []
wav.close()