-
Notifications
You must be signed in to change notification settings - Fork 0
/
fsk.py
72 lines (56 loc) · 1.97 KB
/
fsk.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
# coding=utf-8
import math
import itertools
import sys
import audiogen
import threading
import trame
MARK_HZ = 900.0
SPACE_HZ = 1500.0
BAUD_RATE = 600.0
FRAME_RATE = audiogen.sampler.FRAME_RATE
TWO_PI = 2.0 * math.pi
class Fsk(threading.Thread) :
def __init__(self, conf, initial_data = b""):
threading.Thread.__init__(self)
self.to_send = initial_data
self.conf = conf
self.terminate = False
self.finish_terminated = False
def encode(self, data):
for sample in itertools.chain.from_iterable((self.modulatebyte(c) for c in data)):
yield sample
def modulatebyte(self, byte):
#print byte
seconds_per_sample = 1.0 / FRAME_RATE
phase, seconds, bits = 0, 0, 0
clock = (x / BAUD_RATE for x in itertools.count(1))
tones = (SPACE_HZ if i == 0 or not((byte >> (i-1)) & 1) and i <= 8 else MARK_HZ for i in range(10))
for boundary, frequency in itertools.izip(clock, tones):
# frequency of current symbol is determined by how much
# we advance the signal's phase in each audio frame
phase_change_per_sample = TWO_PI / (FRAME_RATE / frequency)
# produce samples for the current symbol
# until we reach the next clock boundary
while seconds < boundary:
yield math.sin(phase)
seconds += seconds_per_sample
phase += phase_change_per_sample
if phase > TWO_PI:
phase -= TWO_PI
bits += 1
# print int(frequency == MARK_HZ)
def feed(self, data):
self.to_send = data
def run(self):
self.terminate = False
while not self.terminate:
try:
audiogen.sampler.write_wav(sys.stdout, self.encode(trame.trame(self.to_send, self.conf)))
except:
pass
self.finish_terminated = True
def stop(self):
self.terminate = True
while not self.finish_terminated: pass
print("Termainated FSK")