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
|
# given the cmdline arg, turns the byte sequencies into a list of frequencies, and vice versa
# 1875 1924 +24, -25, range/2, 1, flipping new info 2 sending or not
import numpy as np
import pyaudio
import struct
from scipy.fftpack import fft
def calculate_send_frequencies(start_freq, freq_range, bytes_per_transmit):
bits_to_send = 8 * bytes_per_transmit + 2 # 8 bits per byte, 2 bits for flags
freq_interval = freq_range / (bits_to_send + 1) # +1 to not include endpoints of range
freq_list = []
for i in range(bits_to_send):
f = int(start_freq + (i + 1) * freq_interval)
freq_list.append(f)
# print(freq_list)
return freq_list
def frequencies_to_bytes(frequencies, expected_freqs):
# get the interval between frequencies, so we can clamp the range around them
freq_interval = expected_freqs[1] - expected_freqs[0]
plus_minus = freq_interval // 2
byte_list = ['0'] * len(expected_freqs)
for freq in frequencies:
for i in range(len(expected_freqs)):
# clamp the range around the frequency to the frequency
if expected_freqs[i] - plus_minus <= freq < expected_freqs[i] + plus_minus:
byte_list[i] = '1'
return byte_list
def play_data(data, start_freq, freq_step, bytes_per_transmit, p):
freq_list = calculate_send_frequencies(start_freq, freq_step, bytes_per_transmit)
for byte in data:
# print(byte)
samples = None
for i, bit in enumerate(byte):
if bit == '1':
# print(freq_list[i])
s = .125 * np.sin(2 * np.pi * np.arange(44100 * 10.0) * freq_list[i] / 44100)
if samples is None:
samples = s
else:
samples = np.add(samples, s)
if samples is not None:
# print(samples)
stream = p.open(format=pyaudio.paFloat32, channels=1, rate=44100, output=True)
stream.write(samples.astype(np.float32).tobytes())
stream.stop_stream()
stream.close()
# listening_stream = p.open(
# format=pyaudio.paInt32,
# channels=1,
# rate=44100,
# input=True,
# output=True,
# frames_per_buffer=2048 * 2,
# )
# if receive_data(listening_stream, start_freq, freq_step, bytes_per_transmit):
# print("Success")
"""
:param data: A string of characters.
:return: A list of binary strings.
"""
def string_to_binary(data):
data_list = []
for char in data:
binary_representation = format(ord(char), 'b').zfill(8)
data_list.append(binary_representation)
return data_list
def receive_string(binary):
binary_string = ''.join(binary)
try:
print(chr(int(binary_string, 2)))
return chr(int(binary_string, 2))
except ValueError:
print("Error: Invalid binary data")
CHUNK = 2048 * 2
RATE = 44100
def read_audio_stream(stream):
data = stream.read(CHUNK)
data_int = struct.unpack(str(CHUNK) + 'i', data)
return data_int
def get_fundamental_frequency(audio_waveform, start_freq, freq_step, bytes_per_transmit):
spectrum = fft(audio_waveform)
# scale and normalize the spectrum, some are imaginary
scaled_spectrum = np.abs(spectrum)
scaled_spectrum = scaled_spectrum / (np.linalg.norm(scaled_spectrum) + 1e-16)
# FIXME: update to self values, given if ur a sender or receiver
starting_freq = 19800
end_freq = 20000
freq_to_index_ratio = CHUNK / RATE
# only accept the scaled spectrum from our starting range to 20000 Hz
starting_range_index = int(starting_freq * freq_to_index_ratio)
ending_range_index = int(end_freq * freq_to_index_ratio)
# print(starting_freq, end_freq, starting_range_index, ending_range_index)
restricted_spectrum = scaled_spectrum[starting_range_index:ending_range_index + 1]
# normalize the restricted spectrum
indices = np.argwhere(restricted_spectrum > .125)
# print(indices)
freqs = [int((indices[i] + starting_range_index) / freq_to_index_ratio) for i in range(len(indices))]
# print(freqs)
p = frequencies_to_bytes(freqs, calculate_send_frequencies(start_freq, freq_step, bytes_per_transmit))
data = p[:8]
# print(data)
data = receive_string(data)
return data
def receive_data(stream, start_freq, freq_step, bytes_per_transmit):
# freq_list = calculate_send_frequencies(start_freq, freq_step, bytes_per_transmit)
data = []
while not data:
waveform = read_audio_stream(stream)
freqs = get_fundamental_frequency(waveform, start_freq, freq_step, bytes_per_transmit)
data.append(freqs)
# if we see the same data twice in a row, we stop receiving
# if data[-1] == data[-2]:
# break
# print(data)
return data[0], True
|