|
import gradio as gr |
|
import numpy as np |
|
import tempfile |
|
from scipy.io import wavfile |
|
import speech_recognition as sr |
|
import soundfile as sf |
|
|
|
|
|
MORSE_CODE_DICT = { |
|
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', |
|
'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', |
|
'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.', |
|
'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', |
|
'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--', |
|
'4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..', |
|
'9': '----.', '0': '-----', ' ': '/' |
|
} |
|
MORSE_TO_CHAR = {v: k for k, v in MORSE_CODE_DICT.items()} |
|
|
|
|
|
DIT_DURATION = 0.1 |
|
DAH_DURATION = 3 * DIT_DURATION |
|
SPACE_DURATION = 7 * DIT_DURATION |
|
CHAR_SPACE = DIT_DURATION |
|
SAMPLE_RATE = 44100 |
|
|
|
|
|
def decode_morse_from_audio(audio_data, is_file=False): |
|
if audio_data is None: |
|
return "", "" |
|
if is_file: |
|
sample_rate, data = wavfile.read(audio_data) |
|
else: |
|
sample_rate, data = audio_data |
|
if len(data.shape) > 1: |
|
data = data.mean(axis=1) |
|
data = data / np.max(np.abs(data)) |
|
|
|
threshold = 0.1 |
|
signal = data > threshold |
|
morse_code, decoded_text = "", "" |
|
i = 0 |
|
|
|
while i < len(signal) - int(SAMPLE_RATE * DIT_DURATION): |
|
if signal[i]: |
|
start = i |
|
while i < len(signal) and signal[i]: |
|
i += 1 |
|
duration = (i - start) / sample_rate |
|
morse_code += "-" if duration >= DAH_DURATION else "." |
|
else: |
|
start = i |
|
while i < len(signal) and not signal[i]: |
|
i += 1 |
|
pause = (i - start) / sample_rate |
|
if pause >= SPACE_DURATION and morse_code: |
|
decoded_text += " " |
|
morse_code = "" |
|
elif pause >= DIT_DURATION and morse_code: |
|
decoded_text += MORSE_TO_CHAR.get(morse_code, "?") |
|
morse_code = "" |
|
i += 1 |
|
|
|
if morse_code: |
|
decoded_text += MORSE_TO_CHAR.get(morse_code, "?") |
|
return morse_code, decoded_text.strip() |
|
|
|
|
|
def decode_morse_from_text(morse_text): |
|
if not morse_text: |
|
return "" |
|
words = morse_text.split("/") |
|
decoded_text = "" |
|
for word in words: |
|
chars = word.strip().split() |
|
for char in chars: |
|
decoded_text += MORSE_TO_CHAR.get(char, "?") |
|
decoded_text += " " |
|
return decoded_text.strip() |
|
|
|
|
|
def text_to_morse(text): |
|
text = text.upper() |
|
return " ".join(MORSE_CODE_DICT.get(char, "?") for char in text if char in MORSE_CODE_DICT) |
|
|
|
|
|
def generate_morse_audio(morse): |
|
audio = [] |
|
frequency = 750 |
|
|
|
for symbol in morse.split(): |
|
if symbol == "/": |
|
audio.extend([0] * int(SAMPLE_RATE * SPACE_DURATION)) |
|
else: |
|
for char in symbol: |
|
duration = DAH_DURATION if char == "-" else DIT_DURATION |
|
t = np.linspace(0, duration, int(SAMPLE_RATE * duration), False) |
|
tone = 0.5 * np.sin(2 * np.pi * frequency * t) |
|
audio.extend(tone) |
|
audio.extend([0] * int(SAMPLE_RATE * DIT_DURATION)) |
|
audio.extend([0] * int(SAMPLE_RATE * CHAR_SPACE)) |
|
|
|
audio = np.array(audio, dtype=np.float32) |
|
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file: |
|
sf.write(temp_file.name, audio, SAMPLE_RATE, format="wav") |
|
return temp_file.name |
|
|
|
|
|
def speech_to_text(audio_path): |
|
recognizer = sr.Recognizer() |
|
with sr.AudioFile(audio_path) as source: |
|
audio_data = recognizer.record(source) |
|
try: |
|
return recognizer.recognize_google(audio_data) |
|
except: |
|
return "Speech recognition failed" |
|
|
|
|
|
def generate_alphabet_html(text): |
|
html = "<div style='font-family: monospace; font-size: 16px;'>" |
|
for char in MORSE_CODE_DICT.keys(): |
|
color = "red" if char in text.upper() else "black" |
|
html += f"<span style='color: {color}; margin: 5px;'>{char}: {MORSE_CODE_DICT[char]}</span>" |
|
if char in "AEIMQUZ": |
|
html += "<br>" |
|
html += "</div>" |
|
return html |
|
|
|
|
|
def encode_text_to_morse(text): |
|
morse = text_to_morse(text) |
|
audio = generate_morse_audio(morse) |
|
return morse, text, generate_alphabet_html(text), audio |
|
|
|
def encode_speech_to_morse(audio_path): |
|
text = speech_to_text(audio_path) |
|
morse = text_to_morse(text) |
|
audio = generate_morse_audio(morse) |
|
return morse, text, generate_alphabet_html(text), audio |
|
|
|
|
|
def decode_morse_text(morse_text): |
|
text = decode_morse_from_text(morse_text) |
|
audio = generate_morse_audio(morse_text) |
|
return morse_text, text, generate_alphabet_html(text), audio |
|
|
|
def decode_morse_speech(audio_path): |
|
transcribed = speech_to_text(audio_path).replace("dit", ".").replace("dah", "-").replace("slash", "/") |
|
text = decode_morse_from_text(transcribed) |
|
audio = generate_morse_audio(transcribed) |
|
return transcribed, text, generate_alphabet_html(text), audio |
|
|
|
def decode_morse_audio(audio_path): |
|
morse, text = decode_morse_from_audio(audio_path, is_file=True) |
|
return morse, text, generate_alphabet_html(text), None |
|
|
|
def decode_live_morse(audio_data): |
|
morse, text = decode_morse_from_audio(audio_data, is_file=False) |
|
return morse, text, generate_alphabet_html(text), None |
|
|
|
|
|
with gr.Blocks(title="Morse Code Converter") as demo: |
|
gr.Markdown("# Morse Code Converter") |
|
gr.Markdown("Encode to Morse or decode Morse from text, speech, or audio!") |
|
|
|
with gr.Tab("Encode Text to Morse"): |
|
text_input = gr.Textbox(label="Enter Text", placeholder="e.g., HELLO") |
|
text_btn = gr.Button("Convert to Morse") |
|
text_morse_out = gr.Textbox(label="Morse Code", interactive=False) |
|
text_text_out = gr.Textbox(label="Original Text", interactive=False) |
|
text_alphabet = gr.HTML(label="Alphabet (Highlighted)") |
|
text_audio = gr.Audio(label="Morse Audio", interactive=False) |
|
text_btn.click(fn=encode_text_to_morse, inputs=[text_input], outputs=[text_morse_out, text_text_out, text_alphabet, text_audio]) |
|
|
|
with gr.Tab("Encode Speech to Morse"): |
|
speech_input = gr.Audio(type="filepath", label="Record Speech (e.g., say 'HELLO')") |
|
speech_btn = gr.Button("Convert to Morse") |
|
speech_morse_out = gr.Textbox(label="Morse Code", interactive=False) |
|
speech_text_out = gr.Textbox(label="Transcribed Text", interactive=False) |
|
speech_alphabet = gr.HTML(label="Alphabet (Highlighted)") |
|
speech_audio = gr.Audio(label="Morse Audio", interactive=False) |
|
speech_btn.click(fn=encode_speech_to_morse, inputs=[speech_input], outputs=[speech_morse_out, speech_text_out, speech_alphabet, speech_audio]) |
|
|
|
with gr.Tab("Decode Morse Text"): |
|
morse_text_input = gr.Textbox(label="Enter Morse Text", placeholder="e.g., .... . .-.. .-.. ---") |
|
morse_text_btn = gr.Button("Decode Morse") |
|
morse_text_morse_out = gr.Textbox(label="Morse Code", interactive=False) |
|
morse_text_text_out = gr.Textbox(label="Decoded Text", interactive=False) |
|
morse_text_alphabet = gr.HTML(label="Alphabet (Highlighted)") |
|
morse_text_audio = gr.Audio(label="Morse Audio", interactive=False) |
|
morse_text_btn.click(fn=decode_morse_text, inputs=[morse_text_input], outputs=[morse_text_morse_out, morse_text_text_out, morse_text_alphabet, morse_text_audio]) |
|
|
|
with gr.Tab("Decode Morse Speech"): |
|
morse_speech_input = gr.Audio(type="filepath", label="Record Morse Speech (e.g., say 'dit dit dit dit dit')") |
|
morse_speech_btn = gr.Button("Decode Morse") |
|
morse_speech_morse_out = gr.Textbox(label="Transcribed Morse", interactive=False) |
|
morse_speech_text_out = gr.Textbox(label="Decoded Text", interactive=False) |
|
morse_speech_alphabet = gr.HTML(label="Alphabet (Highlighted)") |
|
morse_speech_audio = gr.Audio(label="Morse Audio", interactive=False) |
|
morse_speech_btn.click(fn=decode_morse_speech, inputs=[morse_speech_input], outputs=[morse_speech_morse_out, morse_speech_text_out, morse_speech_alphabet, morse_speech_audio]) |
|
|
|
with gr.Tab("Decode Morse Audio"): |
|
morse_audio_input = gr.Audio(type="filepath", label="Upload Morse Audio (WAV of beeps)") |
|
morse_audio_btn = gr.Button("Decode Morse") |
|
morse_audio_morse_out = gr.Textbox(label="Detected Morse", interactive=False) |
|
morse_audio_text_out = gr.Textbox(label="Decoded Text", interactive=False) |
|
morse_audio_alphabet = gr.HTML(label="Alphabet (Highlighted)") |
|
morse_audio_btn.click(fn=decode_morse_audio, inputs=[morse_audio_input], outputs=[morse_audio_morse_out, morse_audio_text_out, morse_audio_alphabet]) |
|
|
|
with gr.Tab("Decode Live Morse"): |
|
live_audio_input = gr.Audio(type="numpy", label="Live Morse Input (Use Microphone)", streaming=True) |
|
live_morse_out = gr.Textbox(label="Detected Morse", interactive=False) |
|
live_text_out = gr.Textbox(label="Decoded Text", interactive=False) |
|
live_alphabet = gr.HTML(label="Alphabet (Highlighted)") |
|
live_audio_input.stream(fn=decode_live_morse, inputs=[live_audio_input], outputs=[live_morse_out, live_text_out, live_alphabet]) |
|
|
|
demo.launch() |