Awell00 commited on
Commit
713f3f3
·
1 Parent(s): 4de6c0d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -245
app.py CHANGED
@@ -3,6 +3,7 @@ from scipy.io.wavfile import write
3
  from scipy.signal import find_peaks
4
  from scipy.fft import fft
5
  from tqdm import tqdm
 
6
  import matplotlib.pyplot as plt
7
  from scipy.io.wavfile import read
8
  from scipy import signal
@@ -13,9 +14,6 @@ from scipy.signal import butter, lfilter
13
 
14
  # ---------------Parameters--------------- #
15
 
16
- input_file = 'input_text.wav'
17
- output_file = 'output_filtered_sender.wav'
18
-
19
  low_frequency = 18000
20
  high_frequency = 19000
21
  bit_duration = 0.007
@@ -23,286 +21,137 @@ sample_rate = 44100
23
  amplitude_scaling_factor = 10.0
24
 
25
 
26
- # -----------------Filter----------------- #
27
-
28
- def butter_bandpass(sr, order=5):
29
- """
30
- This function designs a Butterworth bandpass filter.
31
-
32
- Parameters:
33
- sr (int): The sample rate of the audio.
34
- order (int): The order of the filter.
35
-
36
- Returns:
37
- tuple: The filter coefficients `b` and `a`.
38
- """
39
- # Calculate the Nyquist frequency
40
- nyquist = 0.5 * sr
41
 
42
- # Normalize the cutoff frequencies
43
- low = low_frequency / nyquist
44
- high = high_frequency / nyquist
 
 
 
 
 
45
 
46
- # Design the Butterworth bandpass filter
47
- coefficient = butter(order, [low, high], btype='band')
48
 
49
- # Extract the filter coefficients
50
- b = coefficient[0]
51
- a = coefficient[1]
52
 
 
 
 
 
 
 
 
53
  return b, a
54
 
55
 
56
- def butter_bandpass_filter(data, sr, order=5):
57
- """
58
- This function applies the Butterworth bandpass filter to a given data.
59
-
60
- Parameters:
61
- data (array): The audio data to be filtered.
62
- sr (int): The sample rate of the audio.
63
- order (int): The order of the filter.
64
-
65
- Returns:
66
- array: The filtered audio data.
67
- """
68
- # Get the filter coefficients
69
- b, a = butter_bandpass(sr, order=order)
70
-
71
- # Apply the filter to the data
72
  y = lfilter(b, a, data)
73
-
74
  return y
75
 
76
 
77
- def filtered():
78
- """
79
- This function reads an audio file, applies the bandpass filter to the audio data,
80
- and then writes the filtered data to an output file.
 
81
 
82
- Returns:
83
- str: A success message if the audio is filtered correctly, otherwise an error message.
84
- """
85
- try:
86
- # Read the audio data from the input file
87
- sr, data = read(input_file)
88
 
89
- # Apply the bandpass filter to the audio data
90
- filtered_data = butter_bandpass_filter(data, sr)
 
91
 
92
- # Write the filtered data to the output file
93
- write(output_file, sr, np.int16(filtered_data))
94
 
95
- return "Filtered Audio Generated"
96
- except Exception as e:
97
- # If an error occurs, return an error message
98
- return f"Error: {str(e)}"
99
 
 
 
 
 
 
 
100
 
101
- # -----------------Record----------------- #
 
 
102
 
103
- def record(audio):
104
- try:
105
- sr, data = audio
106
- wavio.write("recorded.wav", data, sr)
107
- filtered()
108
- return f"Audio receive correctly"
109
- except Exception as e:
110
- return f"Error: {e}"
111
 
112
 
113
- # -----------------Frame----------------- #
114
-
115
- def calculate_snr(data, start, end, target_frequency):
116
- """
117
- This function calculates the Signal-to-Noise Ratio (SNR) for a given frequency within a segment of data.
118
-
119
- Parameters:
120
- data (array): The audio data.
121
- start (int): The start index of the segment.
122
- end (int): The end index of the segment.
123
- target_frequency (float): The frequency for which the SNR is to be calculated.
124
-
125
- Returns:
126
- float: The calculated SNR.
127
- """
128
- try:
129
- # Extract the segment from the data
130
- segment = data[start:end]
131
 
132
- # Perform a Fast Fourier Transform on the segment
133
- spectrum = np.fft.fft(segment)
134
 
135
- # Generate the frequencies corresponding to the FFT coefficients
136
- frequencies = np.fft.fftfreq(len(spectrum), 1 / sample_rate)
137
 
138
- # Find the index of the target frequency
139
- target_index = np.abs(frequencies - target_frequency).argmin()
140
 
141
- # Calculate the amplitude of the target frequency
142
- amplitude = np.abs(spectrum[target_index])
143
 
144
- # Define a noise segment
145
- noise_segment = data[100:1000 + len(segment)]
 
 
 
 
146
 
147
- # Perform a Fast Fourier Transform on the noise segment
148
- noise_spectrum = np.fft.fft(noise_segment)
149
 
150
- # Calculate the amplitude of the noise at the target frequency
151
- noise_amplitude = np.abs(noise_spectrum[target_index])
152
 
153
- # Calculate the SNR
154
- snr = 10 * np.log10(amplitude / noise_amplitude)
155
 
156
- return snr
157
- except Exception as e:
158
- # If an error occurs, return an error message
159
- return f"Error: {e}"
160
 
 
161
 
162
- def frame_analyse(filename):
163
- """
164
- This function analyses an audio file and returns the start and end times of the signal of interest.
165
 
166
- Parameters:
167
- filename (str): The path to the audio file.
168
 
169
- Returns:
170
- tuple: The start and end times of the signal of interest.
171
- """
172
- try:
173
- # Read the audio file
174
- sr, y = read(filename)
175
-
176
- # Define the start and end indices of the first and second parts of the audio data
177
- first_part_start = 0
178
- first_part_end = len(y) // 2
179
- second_part_start = len(y) // 2
180
- second_part_end = len(y)
181
-
182
- # Define the segment length and overlap size for the spectrogram
183
- segment_length = 256
184
- overlap_size = 128
185
-
186
- # Calculate the spectrogram of the audio data
187
- f, t, sxx = signal.spectrogram(y, sr, nperseg=segment_length, noverlap=overlap_size)
188
-
189
- # Plot the spectrogram
190
- plt.figure()
191
- plt.pcolormesh(t, f, sxx, shading="gouraud")
192
- plt.xlabel("Time [s]")
193
- plt.ylabel("Frequency [Hz]")
194
- plt.title("Spectrogram of the signal")
195
- plt.show()
196
-
197
- # Define the target frequency
198
- f0 = 18000
199
-
200
- # Find the index of the target frequency
201
- f_idx = np.argmin(np.abs(f - f0))
202
-
203
- # Calculate the SNR thresholds for the start and end of the signal
204
- thresholds_start = calculate_snr(y, first_part_start, first_part_end, low_frequency)
205
- thresholds_end = calculate_snr(y, second_part_start, second_part_end, high_frequency)
206
-
207
- # Find the start and end indices of the signal of interest
208
- t_idx_start = np.argmax(sxx[f_idx] > thresholds_start)
209
- t_idx_end = t_idx_start
210
- while t_idx_end < len(t) and np.max(sxx[f_idx, t_idx_end:]) > thresholds_end:
211
- t_idx_end += 1
212
-
213
- # Convert the start and end indices to times
214
- t_start = t[t_idx_start]
215
- t_end = t[t_idx_end]
216
-
217
- return t_start, t_end
218
- except Exception as e:
219
- # If an error occurs, return an error message
220
- return f"Error: {e}"
221
 
222
 
223
  # -----------------Receiver----------------- #
224
 
225
  def dominant_frequency(signal_value):
226
- """
227
- This function calculates the dominant frequency in a given signal.
228
-
229
- Parameters:
230
- signal_value (array): The signal data.
231
-
232
- Returns:
233
- float: The dominant frequency.
234
- """
235
- # Perform a Fast Fourier Transform on the signal
236
  yf = fft(signal_value)
237
-
238
- # Generate the frequencies corresponding to the FFT coefficients
239
  xf = np.linspace(0.0, sample_rate / 2.0, len(signal_value) // 2)
240
-
241
- # Find the peaks in the absolute values of the FFT coefficients
242
  peaks, _ = find_peaks(np.abs(yf[0:len(signal_value) // 2]))
243
-
244
- # Return the frequency corresponding to the peak with the highest amplitude
245
  return xf[peaks[np.argmax(np.abs(yf[0:len(signal_value) // 2][peaks]))]]
246
 
247
 
248
  def binary_to_text(binary):
249
- """
250
- This function converts a binary string to text.
251
-
252
- Parameters:
253
- binary (str): The binary string.
254
-
255
- Returns:
256
- str: The converted text.
257
- """
258
  try:
259
- # Convert each 8-bit binary number to a character and join them together
260
  return ''.join(chr(int(binary[i:i + 8], 2)) for i in range(0, len(binary), 8))
261
  except Exception as e:
262
- # If an error occurs, return an error message
263
- return f"Error: {e}"
264
 
265
 
266
  def decode_rs(binary_string, ecc_bytes):
267
- """
268
- This function decodes a Reed-Solomon encoded binary string.
269
-
270
- Parameters:
271
- binary_string (str): The binary string.
272
- ecc_bytes (int): The number of error correction bytes used in the encoding.
273
-
274
- Returns:
275
- str: The decoded binary string.
276
- """
277
- # Convert the binary string to a bytearray
278
  byte_data = bytearray(int(binary_string[i:i + 8], 2) for i in range(0, len(binary_string), 8))
279
-
280
- # Initialize a Reed-Solomon codec
281
  rs = reedsolo.RSCodec(ecc_bytes)
282
-
283
- # Decode the bytearray
284
  corrected_data_tuple = rs.decode(byte_data)
285
  corrected_data = corrected_data_tuple[0]
286
 
287
- # Remove trailing null bytes
288
  corrected_data = corrected_data.rstrip(b'\x00')
289
 
290
- # Convert the bytearray back to a binary string
291
  corrected_binary_string = ''.join(format(byte, '08b') for byte in corrected_data)
292
 
293
  return corrected_binary_string
294
 
295
 
296
  def manchester_decoding(binary_string):
297
- """
298
- This function decodes a Manchester encoded binary string.
299
-
300
- Parameters:
301
- binary_string (str): The binary string.
302
-
303
- Returns:
304
- str: The decoded binary string.
305
- """
306
  decoded_string = ''
307
  for i in tqdm(range(0, len(binary_string), 2), desc="Decoding"):
308
  if i + 1 < len(binary_string):
@@ -317,27 +166,16 @@ def manchester_decoding(binary_string):
317
 
318
 
319
  def signal_to_binary_between_times(filename):
320
- """
321
- This function converts a signal to a binary string between specified times.
322
-
323
- Parameters:
324
- filename (str): The path to the audio file.
325
-
326
- Returns:
327
- str: The binary string.
328
- """
329
- # Get the start and end times of the signal of interest
330
  start_time, end_time = frame_analyse(filename)
331
 
332
- # Read the audio file
333
  sr, data = read(filename)
334
 
335
- # Calculate the start and end samples of the signal of interest
336
  start_sample = int((start_time - 0.007) * sr)
337
  end_sample = int((end_time - 0.007) * sr)
338
  binary_string = ''
339
 
340
- # Convert each sample to a binary digit
 
341
  for i in tqdm(range(start_sample, end_sample, int(sr * bit_duration))):
342
  signal_value = data[i:i + int(sr * bit_duration)]
343
  frequency = dominant_frequency(signal_value)
@@ -346,10 +184,10 @@ def signal_to_binary_between_times(filename):
346
  else:
347
  binary_string += '1'
348
 
349
- # Find the start and end indices of the binary string
350
  index_start = binary_string.find("1000001")
351
  substrings = ["0111110", "011110"]
352
  index_end = -1
 
353
  for substring in substrings:
354
  index = binary_string.find(substring)
355
  if index != -1:
@@ -359,33 +197,21 @@ def signal_to_binary_between_times(filename):
359
  print("Binary String:", binary_string)
360
  binary_string_decoded = manchester_decoding(binary_string[index_start + 7:index_end])
361
 
362
- # Decode the binary string
363
  decoded_binary_string = decode_rs(binary_string_decoded, 20)
364
 
365
  return decoded_binary_string
366
 
367
 
368
  def receive():
369
- """
370
- This function receives an audio signal, converts it to a binary string, and then converts the binary string to text.
371
-
372
- Returns:
373
- str: The received text.
374
- """
375
  try:
376
- # Convert the audio signal to a binary string
377
  audio_receive = signal_to_binary_between_times('output_filtered_receiver.wav')
378
-
379
- # Convert the binary string to text
380
  return binary_to_text(audio_receive)
381
  except Exception as e:
382
- # If an error occurs, return an error message
383
  return f"Error: {e}"
384
 
385
 
386
  # -----------------Interface----------------- #
387
 
388
- # Start a Gradio Blocks interface
389
  with gr.Blocks() as demo:
390
  input_audio = gr.Audio(sources=["upload"])
391
  output_text = gr.Textbox(label="Record Sound")
 
3
  from scipy.signal import find_peaks
4
  from scipy.fft import fft
5
  from tqdm import tqdm
6
+ import time
7
  import matplotlib.pyplot as plt
8
  from scipy.io.wavfile import read
9
  from scipy import signal
 
14
 
15
  # ---------------Parameters--------------- #
16
 
 
 
 
17
  low_frequency = 18000
18
  high_frequency = 19000
19
  bit_duration = 0.007
 
21
  amplitude_scaling_factor = 10.0
22
 
23
 
24
+ # -----------------Record----------------- #
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ def record(audio):
27
+ try:
28
+ sr, data = audio
29
+ wavio.write("recorded.wav", data, sr)
30
+ main()
31
+ return f"Audio receive correctly"
32
+ except Exception as e:
33
+ return f"Error: {e}"
34
 
 
 
35
 
36
+ # -----------------Filter----------------- #
 
 
37
 
38
+ def butter_bandpass(lowcut, highcut, sr, order=5):
39
+ nyquist = 0.5 * sr
40
+ low = lowcut / nyquist
41
+ high = highcut / nyquist
42
+ coef = butter(order, [low, high], btype='band')
43
+ b = coef[0]
44
+ a = coef[1]
45
  return b, a
46
 
47
 
48
+ def butter_bandpass_filter(data, lowcut, highcut, sr, order=5):
49
+ b, a = butter_bandpass(lowcut, highcut, sr, order=order)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  y = lfilter(b, a, data)
 
51
  return y
52
 
53
 
54
+ def main():
55
+ input_file = 'recorded.wav'
56
+ output_file = 'output_filtered_receiver.wav'
57
+ lowcut = 17500
58
+ highcut = 19500
59
 
60
+ sr, data = read(input_file)
 
 
 
 
 
61
 
62
+ filtered_data = butter_bandpass_filter(data, lowcut, highcut, sr)
63
+ write(output_file, sr, np.int16(filtered_data))
64
+ return "Filtered Audio Generated"
65
 
 
 
66
 
67
+ # -----------------Frame----------------- #
 
 
 
68
 
69
+ def calculate_snr(data, start, end, target_frequency):
70
+ segment = data[start:end]
71
+ spectrum = np.fft.fft(segment)
72
+ frequencies = np.fft.fftfreq(len(spectrum), 1 / sample_rate)
73
+ target_index = np.abs(frequencies - target_frequency).argmin()
74
+ amplitude = np.abs(spectrum[target_index])
75
 
76
+ noise_segment = data[100:1000 + len(segment)]
77
+ noise_spectrum = np.fft.fft(noise_segment)
78
+ noise_amplitude = np.abs(noise_spectrum[target_index])
79
 
80
+ snr = 10 * np.log10(amplitude / noise_amplitude)
81
+ return snr
 
 
 
 
 
 
82
 
83
 
84
+ def frame_analyse(filename):
85
+ sr, y = read(filename)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
+ first_part_start = 0
88
+ first_part_end = len(y) // 2
89
 
90
+ second_part_start = len(y) // 2
91
+ second_part_end = len(y)
92
 
93
+ segment_length = 256
94
+ overlap_size = 128
95
 
96
+ f, t, sxx = signal.spectrogram(y, sr, nperseg=segment_length, noverlap=overlap_size)
 
97
 
98
+ plt.figure()
99
+ plt.pcolormesh(t, f, sxx, shading="gouraud")
100
+ plt.xlabel("Time [s]")
101
+ plt.ylabel("Frequency [Hz]")
102
+ plt.title("Spectrogram of the signal")
103
+ plt.show()
104
 
105
+ f0 = 18000
 
106
 
107
+ f_idx = np.argmin(np.abs(f - f0))
 
108
 
109
+ thresholds_start = calculate_snr(y, first_part_start, first_part_end, low_frequency)
110
+ thresholds_end = calculate_snr(y, second_part_start, second_part_end, high_frequency)
111
 
112
+ t_idx_start = np.argmax(sxx[f_idx] > thresholds_start)
 
 
 
113
 
114
+ t_start = t[t_idx_start]
115
 
116
+ t_idx_end = t_idx_start
117
+ while t_idx_end < len(t) and np.max(sxx[f_idx, t_idx_end:]) > thresholds_end:
118
+ t_idx_end += 1
119
 
120
+ t_end = t[t_idx_end]
 
121
 
122
+ return t_start, t_end
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
 
125
  # -----------------Receiver----------------- #
126
 
127
  def dominant_frequency(signal_value):
 
 
 
 
 
 
 
 
 
 
128
  yf = fft(signal_value)
 
 
129
  xf = np.linspace(0.0, sample_rate / 2.0, len(signal_value) // 2)
 
 
130
  peaks, _ = find_peaks(np.abs(yf[0:len(signal_value) // 2]))
 
 
131
  return xf[peaks[np.argmax(np.abs(yf[0:len(signal_value) // 2][peaks]))]]
132
 
133
 
134
  def binary_to_text(binary):
 
 
 
 
 
 
 
 
 
135
  try:
 
136
  return ''.join(chr(int(binary[i:i + 8], 2)) for i in range(0, len(binary), 8))
137
  except Exception as e:
138
+ return f"Except: {e}"
 
139
 
140
 
141
  def decode_rs(binary_string, ecc_bytes):
 
 
 
 
 
 
 
 
 
 
 
142
  byte_data = bytearray(int(binary_string[i:i + 8], 2) for i in range(0, len(binary_string), 8))
 
 
143
  rs = reedsolo.RSCodec(ecc_bytes)
 
 
144
  corrected_data_tuple = rs.decode(byte_data)
145
  corrected_data = corrected_data_tuple[0]
146
 
 
147
  corrected_data = corrected_data.rstrip(b'\x00')
148
 
 
149
  corrected_binary_string = ''.join(format(byte, '08b') for byte in corrected_data)
150
 
151
  return corrected_binary_string
152
 
153
 
154
  def manchester_decoding(binary_string):
 
 
 
 
 
 
 
 
 
155
  decoded_string = ''
156
  for i in tqdm(range(0, len(binary_string), 2), desc="Decoding"):
157
  if i + 1 < len(binary_string):
 
166
 
167
 
168
  def signal_to_binary_between_times(filename):
 
 
 
 
 
 
 
 
 
 
169
  start_time, end_time = frame_analyse(filename)
170
 
 
171
  sr, data = read(filename)
172
 
 
173
  start_sample = int((start_time - 0.007) * sr)
174
  end_sample = int((end_time - 0.007) * sr)
175
  binary_string = ''
176
 
177
+ start_analyse_time = time.time()
178
+
179
  for i in tqdm(range(start_sample, end_sample, int(sr * bit_duration))):
180
  signal_value = data[i:i + int(sr * bit_duration)]
181
  frequency = dominant_frequency(signal_value)
 
184
  else:
185
  binary_string += '1'
186
 
 
187
  index_start = binary_string.find("1000001")
188
  substrings = ["0111110", "011110"]
189
  index_end = -1
190
+
191
  for substring in substrings:
192
  index = binary_string.find(substring)
193
  if index != -1:
 
197
  print("Binary String:", binary_string)
198
  binary_string_decoded = manchester_decoding(binary_string[index_start + 7:index_end])
199
 
 
200
  decoded_binary_string = decode_rs(binary_string_decoded, 20)
201
 
202
  return decoded_binary_string
203
 
204
 
205
  def receive():
 
 
 
 
 
 
206
  try:
 
207
  audio_receive = signal_to_binary_between_times('output_filtered_receiver.wav')
 
 
208
  return binary_to_text(audio_receive)
209
  except Exception as e:
 
210
  return f"Error: {e}"
211
 
212
 
213
  # -----------------Interface----------------- #
214
 
 
215
  with gr.Blocks() as demo:
216
  input_audio = gr.Audio(sources=["upload"])
217
  output_text = gr.Textbox(label="Record Sound")