issacneedsbread's picture
Update app.py
21a72bc verified
import numpy as np
import wave
from scipy.signal import find_peaks
from scipy.fft import fft, fftfreq
import gradio as gr
import tempfile
from PIL import Image
import io
def log_message(message):
print(message)
def smooth_signal(signal, window_len=11):
"""Apply a smoothing filter to the signal to reduce noise."""
if window_len < 3:
return signal
s = np.r_[signal[window_len-1:0:-1], signal, signal[-2:-window_len-1:-1]]
window = np.hanning(window_len)
smoothed = np.convolve(window/window.sum(), s, mode='valid')
return smoothed
def detect_beeps(audio_data, framerate, freq_zero, freq_one, window_size=2048, step_size=512):
log_message("Starting beep detection with sliding window.")
binary_data = bytearray()
num_windows = len(audio_data) // step_size
previous_bit = None
for i in range(0, len(audio_data) - window_size, step_size):
# Get the window of data
window = audio_data[i:i + window_size]
# Perform FFT to detect the dominant frequency in the window
yf = fft(window)
xf = fftfreq(window_size, 1 / framerate)
magnitude = np.abs(yf[:window_size // 2])
dominant_freq = xf[np.argmax(magnitude)]
# Classify based on the dominant frequency
if np.isclose(dominant_freq, freq_zero, atol=10):
current_bit = 0
elif np.isclose(dominant_freq, freq_one, atol=10):
current_bit = 1
else:
continue # Skip if it doesn't match expected frequencies
# Only record the bit if it differs from the previous bit (avoids repetition)
if current_bit != previous_bit:
binary_data.append(current_bit)
log_message(f"Detected bit: {current_bit} (Frequency: {dominant_freq} Hz)")
previous_bit = current_bit
log_message("Finished beep detection.")
return binary_data
def audio_to_binary(audio_file, freq_zero, freq_one):
log_message("Starting audio_to_binary function.")
# Read the audio file
with wave.open(audio_file.name, 'rb') as wav_file:
framerate = wav_file.getframerate()
n_frames = wav_file.getnframes()
audio_data = wav_file.readframes(n_frames)
audio_data = np.frombuffer(audio_data, dtype=np.int16).astype(np.float32)
audio_data = audio_data / np.max(np.abs(audio_data)) # Normalize to [-1, 1]
# Detect beeps and reconstruct binary data
binary_data = detect_beeps(audio_data, framerate, freq_zero, freq_one)
if not binary_data:
return None, "No binary data detected."
# Convert binary list to bytes
bit_accumulator = 0
bit_count = 0
final_binary_data = bytearray()
for bit in binary_data:
bit_accumulator = (bit_accumulator << 1) | bit
bit_count += 1
if bit_count == 8:
final_binary_data.append(bit_accumulator)
bit_count = 0
bit_accumulator = 0
if bit_count > 0:
final_binary_data.append(bit_accumulator << (8 - bit_count))
log_message(f"Extracted binary data: {final_binary_data[:20]}... (truncated for log)")
return final_binary_data
def binary_to_file(binary_data, file_format):
log_message("Starting binary_to_file function.")
temp_file_path = None
if file_format == 'PNG':
try:
image = Image.open(io.BytesIO(binary_data))
with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_file:
image.save(temp_file, format='PNG')
temp_file_path = temp_file.name
log_message("Successfully reconstructed PNG file.")
except Exception as e:
log_message(f"Failed to reconstruct PNG file: {e}")
elif file_format == 'TXT':
try:
text_data = binary_data.decode('utf-8', errors='replace')
with tempfile.NamedTemporaryFile(delete=False, suffix='.txt') as temp_file:
temp_file.write(text_data.encode('utf-8'))
temp_file_path = temp_file.name
log_message("Successfully reconstructed TXT file.")
except Exception as e:
log_message(f"Failed to reconstruct TXT file: {e}")
else:
log_message("Unsupported file format.")
return temp_file_path
def process_audio(file, freq_zero, freq_one, file_format):
log_message("Starting process_audio function.")
binary_data = audio_to_binary(file, freq_zero, freq_one)
if not binary_data:
log_message("No binary data was extracted from the audio.")
return None, "No data was extracted from the audio file."
original_file_path = binary_to_file(binary_data, file_format)
if original_file_path is None:
return None, "Error in reconstructing the file."
log_message("Processing complete.")
return original_file_path, "File successfully reconstructed."
gr.Interface(
fn=process_audio,
inputs=[
gr.File(label="Upload Binary WAV File"),
gr.Number(label="Frequency for 0 (Hz)", value=1000),
gr.Number(label="Frequency for 1 (Hz)", value=2000),
gr.Dropdown(choices=['PNG', 'TXT'], label="File Format")
],
outputs=[gr.File(label="Download Original File"), gr.Text(label="Status")],
title="Binary WAV to Original File Decoder",
description="Detect beeps with different frequencies in a binary WAV file to reconstruct the original file."
).launch()