import wave
import numpy as np
from PIL import Image
import struct

# Define the frequencies for different 3-bit combinations
freq_dict = {
    '000': 800,
    '001': 1000,
    '010': 1200,
    '011': 1400,
    '100': 1600,
    '101': 1800,
    '110': 2000,
    '111': 2200
}

# Define the handshake frequencies
preamble_freqs = [500, 1000, 1500]
start_freq = 2500
end_freq = 3000
postamble_freqs = [2500, 2000, 1500]

# Open the MP3 file
# Note: You'll need to convert the MP3 to a WAV file first. You can use pydub for this:
# AudioSegment.from_mp3("wolftest_sound.mp3").export("wolftest_sound.wav", format="wav")

with wave.open('wolftest_sound.wav', 'rb') as wf:
    # Get audio parameters
    num_channels = wf.getnchannels()
    frame_rate = wf.getframerate()
    sample_width = wf.getsampwidth()
    num_frames = wf.getnframes()

    # Read the audio data
    audio_data = wf.readframes(num_frames)

# Convert audio data to numpy array
audio_data = np.frombuffer(audio_data, dtype=np.int16)

# Function to detect a frequency in a signal
def detect_frequency(signal, freq, sample_rate):
    # Perform a simple frequency detection using FFT
    fft_data = np.fft.fft(signal)
    frequencies = np.fft.fftfreq(len(signal), 1/sample_rate)
    idx = np.argmax(np.abs(fft_data))
    detected_freq = frequencies[idx]
    return abs(detected_freq - freq) < 10  # Allow some tolerance

# Find the start and end of the data transmission
start_index = None
end_index = None

# Detect preamble
for i in range(0, len(audio_data) - 4410, 4410): # Step through in 0.1 second intervals
    if all(detect_frequency(audio_data[i:i+4410], freq, frame_rate) for freq in preamble_freqs):
        start_index = i + 4410 * 3  # Start after the preamble
        break

# Detect start frequency
for i in range(start_index, len(audio_data) - 4410, 4410):
    if detect_frequency(audio_data[i:i+4410], start_freq, frame_rate):
        start_index = i + 4410  # Start after the start frequency
        break

# Detect end frequency
for i in range(start_index, len(audio_data) - 4410, 4410):
    if detect_frequency(audio_data[i:i+4410], end_freq, frame_rate):
        end_index = i
        break

if start_index is None or end_index is None:
    raise ValueError("Could not find start or end of data transmission.")

# Extract the data portion of the audio
data_audio = audio_data[start_index:end_index]

# Split the data audio into chunks
chunk_size = int(frame_rate * 0.005)  # 0.005 seconds per chunk
chunks = [data_audio[i:i+chunk_size] for i in range(0, len(data_audio), chunk_size)]

# Decode the chunks into a binary string
binary_string = ''
for chunk in chunks:
    # Detect the frequency of the chunk
    fft_data = np.fft.fft(chunk)
    frequencies = np.fft.fftfreq(len(chunk), 1/frame_rate)
    idx = np.argmax(np.abs(fft_data))
    detected_freq = frequencies[idx]

    # Find the closest frequency in the dictionary
    closest_freq = min(freq_dict, key=lambda k: abs(freq_dict[k] - detected_freq))
    binary_string += closest_freq

# Remove any padded zeros
binary_string = binary_string.rstrip('0')

# Convert the binary string to bytes
byte_data = bytes(int(binary_string[i:i+8], 2) for i in range(0, len(binary_string), 8))

# Create an image from the bytes
image = Image.frombytes('RGB', (64, 64), byte_data)

# Save the image
image.save('decoded_wolftest.jpg')