| import gradio as gr |
| import numpy as np |
| import io |
| 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): |
| if audio_data is None: |
| return "", "" |
| 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 text_to_morse(text): |
| text = text.upper() |
| morse = " ".join(MORSE_CODE_DICT.get(char, "?") for char in text if char in MORSE_CODE_DICT) |
| return morse |
|
|
| |
| 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) |
| buffer = io.BytesIO() |
| sf.write(buffer, audio, SAMPLE_RATE, format="wav") |
| buffer.seek(0) |
| return buffer |
|
|
| |
| def speech_to_text(audio): |
| recognizer = sr.Recognizer() |
| with sr.AudioFile(audio) as source: |
| audio_data = recognizer.record(source) |
| try: |
| return recognizer.recognize_google(audio_data) |
| except sr.UnknownValueError: |
| return "Could not understand audio" |
| except sr.RequestError: |
| return "Speech recognition service unavailable" |
|
|
| |
| def generate_alphabet_html(decoded_text): |
| html = "<div style='font-family: monospace; font-size: 16px;'>" |
| for char in MORSE_CODE_DICT.keys(): |
| color = "red" if char in decoded_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 process_input(text=None, speech=None, audio=None): |
| morse, decoded_text, audio_output = "", "", None |
| |
| if text: |
| morse = text_to_morse(text) |
| decoded_text = text |
| audio_output = generate_morse_audio(morse) |
| |
| elif speech: |
| text = speech_to_text(speech) |
| morse = text_to_morse(text) |
| decoded_text = text |
| audio_output = generate_morse_audio(morse) |
| |
| elif audio: |
| morse, decoded_text = decode_morse_from_audio(audio) |
| |
| alphabet_html = generate_alphabet_html(decoded_text) |
| return morse, decoded_text, alphabet_html, audio_output |
|
|
| |
| with gr.Blocks(title="Morse Code Decoder & Generator") as demo: |
| gr.Markdown("# Morse Code Decoder & Generator") |
| gr.Markdown("Decode live Morse audio, or generate Morse from text/speech!") |
| |
| with gr.Tab("Decode Live Audio"): |
| audio_input = gr.Audio(source="microphone", type="numpy", streaming=True, label="Live Audio Input") |
| with gr.Row(): |
| with gr.Column(): |
| morse_output = gr.Textbox(label="Detected Morse Code", interactive=False) |
| text_output = gr.Textbox(label="Decoded Text", interactive=False) |
| alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)") |
| |
| audio_input.stream( |
| fn=process_input, |
| inputs=[audio_input], |
| outputs=[morse_output, text_output, alphabet_display, gr.Audio(visible=False)], |
| ) |
| |
| with gr.Tab("Generate from Text"): |
| text_input = gr.Textbox(label="Enter Text", placeholder="Type here...") |
| generate_btn = gr.Button("Generate Morse") |
| with gr.Row(): |
| with gr.Column(): |
| morse_gen_output = gr.Textbox(label="Morse Code", interactive=False) |
| text_gen_output = gr.Textbox(label="Original Text", interactive=False) |
| gen_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)") |
| audio_playback = gr.Audio(label="Morse Audio Playback", interactive=False) |
| |
| generate_btn.click( |
| fn=process_input, |
| inputs=[text_input], |
| outputs=[morse_gen_output, text_gen_output, gen_alphabet_display, audio_playback] |
| ) |
| |
| with gr.Tab("Generate from Speech"): |
| speech_input = gr.Audio(source="microphone", type="filepath", label="Speak Your Text") |
| speech_btn = gr.Button("Convert Speech to Morse") |
| with gr.Row(): |
| with gr.Column(): |
| morse_speech_output = gr.Textbox(label="Morse Code", interactive=False) |
| text_speech_output = gr.Textbox(label="Transcribed Text", interactive=False) |
| speech_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)") |
| speech_audio_playback = gr.Audio(label="Morse Audio Playback", interactive=False) |
| |
| speech_btn.click( |
| fn=process_input, |
| inputs=[speech_input], |
| outputs=[morse_speech_output, text_speech_output, speech_alphabet_display, speech_audio_playback] |
| ) |
|
|
| |
| demo.launch() |