# 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