|
import gradio as gr |
|
import numpy as np |
|
import io |
|
import tempfile |
|
import os |
|
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() |
|
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) |
|
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 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, live_audio=None, upload_audio=None, morse_text=None, morse_speech=None, morse_audio=None): |
|
morse_output, text_output, audio_output = "", "", None |
|
|
|
|
|
if text: |
|
morse_output = text_to_morse(text) |
|
text_output = text |
|
audio_output = generate_morse_audio(morse_output) |
|
|
|
elif speech: |
|
transcribed = speech_to_text(speech) |
|
morse_output = text_to_morse(transcribed) |
|
text_output = transcribed |
|
audio_output = generate_morse_audio(morse_output) |
|
|
|
elif live_audio: |
|
|
|
morse_output, text_output = decode_morse_from_audio(live_audio, is_file=False) |
|
|
|
elif upload_audio: |
|
|
|
morse_output, text_output = decode_morse_from_audio(upload_audio, is_file=True) |
|
|
|
|
|
elif morse_text: |
|
morse_output = morse_text |
|
text_output = decode_morse_from_text(morse_text) |
|
audio_output = generate_morse_audio(morse_text) |
|
|
|
elif morse_speech: |
|
transcribed = speech_to_text(morse_speech).replace("dit", ".").replace("dah", "-").replace("slash", "/") |
|
morse_output = transcribed |
|
text_output = decode_morse_from_text(transcribed) |
|
audio_output = generate_morse_audio(transcribed) |
|
|
|
elif morse_audio: |
|
morse_output, text_output = decode_morse_from_audio(morse_audio, is_file=True) |
|
|
|
alphabet_html = generate_alphabet_html(text_output) |
|
return morse_output, text_output, alphabet_html, audio_output |
|
|
|
|
|
with gr.Blocks(title="Morse Code Converter") as demo: |
|
gr.Markdown("# Morse Code Converter") |
|
gr.Markdown("Encode text/speech to Morse, or decode Morse text/speech/audio to text!") |
|
|
|
|
|
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") |
|
with gr.Row(): |
|
with gr.Column(): |
|
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=process_input, 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") |
|
with gr.Row(): |
|
with gr.Column(): |
|
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=process_input, 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") |
|
with gr.Row(): |
|
with gr.Column(): |
|
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=process_input, 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") |
|
with gr.Row(): |
|
with gr.Column(): |
|
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=process_input, 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") |
|
with gr.Row(): |
|
with gr.Column(): |
|
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=process_input, inputs=[morse_audio_input], outputs=[morse_audio_morse_out, morse_audio_text_out, morse_audio_alphabet, gr.Audio(visible=False)]) |
|
|
|
with gr.Tab("Decode Live Morse Audio"): |
|
live_audio_input = gr.Audio(type="numpy", label="Live Morse Input (Use Microphone)", streaming=True) |
|
with gr.Row(): |
|
with gr.Column(): |
|
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=process_input, inputs=[live_audio_input], outputs=[live_morse_out, live_text_out, live_alphabet, gr.Audio(visible=False)]) |
|
|
|
demo.launch() |
|
|
|
''' |
|
import gradio as gr |
|
import numpy as np |
|
import io |
|
import tempfile |
|
import os |
|
from scipy.io import wavfile |
|
import speech_recognition as sr |
|
import soundfile as sf |
|
|
|
# Morse code dictionary (ITU standard) |
|
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()} |
|
|
|
# Morse code timing (in seconds) |
|
DIT_DURATION = 0.1 # 100ms for dit |
|
DAH_DURATION = 3 * DIT_DURATION # 300ms for dah |
|
SPACE_DURATION = 7 * DIT_DURATION # 700ms for word space |
|
CHAR_SPACE = DIT_DURATION # Space between characters |
|
SAMPLE_RATE = 44100 # Standard audio sample rate |
|
|
|
# Decode Morse from audio (live or uploaded) |
|
def decode_morse_from_audio(audio_data, is_file=False): |
|
if audio_data is None: |
|
return "", "" |
|
|
|
if is_file: |
|
# For uploaded files, audio_data is a file path |
|
sample_rate, data = wavfile.read(audio_data) |
|
else: |
|
# For live streaming, audio_data is (sample_rate, data) |
|
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() |
|
|
|
# Convert text to Morse code |
|
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 |
|
|
|
# Generate Morse code audio and save to temporary file |
|
def generate_morse_audio(morse): |
|
audio = [] |
|
frequency = 750 # Hz for Morse tone |
|
|
|
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)) # Space between dits/dahs |
|
audio.extend([0] * int(SAMPLE_RATE * CHAR_SPACE)) # Space between characters |
|
|
|
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") |
|
temp_file_path = temp_file.name |
|
return temp_file_path |
|
|
|
# Speech to text |
|
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 sr.UnknownValueError: |
|
return "Could not understand audio" |
|
except sr.RequestError: |
|
return "Speech recognition service unavailable" |
|
|
|
# Highlight alphabet in UI |
|
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 |
|
|
|
# Combined processing function |
|
def process_input(text=None, speech=None, live_audio=None, upload_audio=None): |
|
morse, decoded_text, audio_output = "", "", None |
|
|
|
if text: # Text input |
|
morse = text_to_morse(text) |
|
decoded_text = text |
|
audio_output = generate_morse_audio(morse) |
|
|
|
elif speech: # Speech input |
|
text = speech_to_text(speech) |
|
morse = text_to_morse(text) |
|
decoded_text = text |
|
audio_output = generate_morse_audio(morse) |
|
|
|
elif live_audio: # Live audio input |
|
morse, decoded_text = decode_morse_from_audio(live_audio, is_file=False) |
|
|
|
elif upload_audio: # Uploaded audio file |
|
morse, decoded_text = decode_morse_from_audio(upload_audio, is_file=True) |
|
|
|
alphabet_html = generate_alphabet_html(decoded_text) |
|
return morse, decoded_text, alphabet_html, audio_output |
|
|
|
# Gradio UI with Blocks |
|
with gr.Blocks(title="Morse Code Decoder & Generator") as demo: |
|
gr.Markdown("# Morse Code Decoder & Generator") |
|
gr.Markdown("Decode live or uploaded Morse audio, or generate Morse from text/speech!") |
|
|
|
with gr.Tab("Decode Live Audio"): |
|
audio_input = gr.Audio(type="numpy", label="Live Audio Input (Use Microphone)", streaming=True) |
|
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(type="filepath", label="Speak Your Text (Record Audio)") |
|
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] |
|
) |
|
|
|
with gr.Tab("Decode from Audio Upload"): |
|
upload_input = gr.Audio(type="filepath", label="Upload Morse Audio File (WAV)") |
|
upload_btn = gr.Button("Decode Morse") |
|
with gr.Row(): |
|
with gr.Column(): |
|
morse_upload_output = gr.Textbox(label="Detected Morse Code", interactive=False) |
|
text_upload_output = gr.Textbox(label="Decoded Text", interactive=False) |
|
upload_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)") |
|
|
|
upload_btn.click( |
|
fn=process_input, |
|
inputs=[upload_input], |
|
outputs=[morse_upload_output, text_upload_output, upload_alphabet_display, gr.Audio(visible=False)] |
|
) |
|
|
|
# Launch the app |
|
demo.launch() |
|
''' |
|
''' |
|
import gradio as gr |
|
import numpy as np |
|
import io |
|
import tempfile |
|
import os |
|
from scipy.io import wavfile |
|
import speech_recognition as sr |
|
import soundfile as sf |
|
|
|
# Morse code dictionary (ITU standard) |
|
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()} |
|
|
|
# Morse code timing (in seconds) |
|
DIT_DURATION = 0.1 # 100ms for dit |
|
DAH_DURATION = 3 * DIT_DURATION # 300ms for dah |
|
SPACE_DURATION = 7 * DIT_DURATION # 700ms for word space |
|
CHAR_SPACE = DIT_DURATION # Space between characters |
|
SAMPLE_RATE = 44100 # Standard audio sample rate |
|
|
|
# Decode Morse from audio |
|
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() |
|
|
|
# Convert text to Morse code |
|
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 |
|
|
|
# Generate Morse code audio and save to temporary file |
|
def generate_morse_audio(morse): |
|
audio = [] |
|
frequency = 750 # Hz for Morse tone |
|
|
|
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)) # Space between dits/dahs |
|
audio.extend([0] * int(SAMPLE_RATE * CHAR_SPACE)) # Space between characters |
|
|
|
audio = np.array(audio, dtype=np.float32) |
|
# Save to a temporary file |
|
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file: |
|
sf.write(temp_file.name, audio, SAMPLE_RATE, format="wav") |
|
temp_file_path = temp_file.name |
|
return temp_file_path |
|
|
|
# Speech to text |
|
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 sr.UnknownValueError: |
|
return "Could not understand audio" |
|
except sr.RequestError: |
|
return "Speech recognition service unavailable" |
|
|
|
# Highlight alphabet in UI |
|
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 |
|
|
|
# Combined processing function with cleanup |
|
def process_input(text=None, speech=None, audio=None): |
|
morse, decoded_text, audio_output = "", "", None |
|
|
|
if text: # Text input |
|
morse = text_to_morse(text) |
|
decoded_text = text |
|
audio_output = generate_morse_audio(morse) |
|
|
|
elif speech: # Speech input |
|
text = speech_to_text(speech) |
|
morse = text_to_morse(text) |
|
decoded_text = text |
|
audio_output = generate_morse_audio(morse) |
|
|
|
elif audio: # Live audio input |
|
morse, decoded_text = decode_morse_from_audio(audio) |
|
|
|
alphabet_html = generate_alphabet_html(decoded_text) |
|
return morse, decoded_text, alphabet_html, audio_output |
|
|
|
# Gradio UI with Blocks |
|
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(type="numpy", label="Live Audio Input (Use Microphone)", streaming=True) |
|
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(type="filepath", label="Speak Your Text (Record Audio)") |
|
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] |
|
) |
|
|
|
# Launch the app |
|
demo.launch() |
|
''' |
|
|
|
''' |
|
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 dictionary (ITU standard) |
|
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()} |
|
|
|
# Morse code timing (in seconds) |
|
DIT_DURATION = 0.1 # 100ms for dit |
|
DAH_DURATION = 3 * DIT_DURATION # 300ms for dah |
|
SPACE_DURATION = 7 * DIT_DURATION # 700ms for word space |
|
CHAR_SPACE = DIT_DURATION # Space between characters |
|
SAMPLE_RATE = 44100 # Standard audio sample rate |
|
|
|
# Decode Morse from audio |
|
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() |
|
|
|
# Convert text to Morse code |
|
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 |
|
|
|
# Generate Morse code audio |
|
def generate_morse_audio(morse): |
|
audio = [] |
|
frequency = 750 # Hz for Morse tone |
|
|
|
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)) # Space between dits/dahs |
|
audio.extend([0] * int(SAMPLE_RATE * CHAR_SPACE)) # Space between characters |
|
|
|
audio = np.array(audio, dtype=np.float32) |
|
buffer = io.BytesIO() |
|
sf.write(buffer, audio, SAMPLE_RATE, format="wav") |
|
buffer.seek(0) |
|
return buffer |
|
|
|
# Speech to text |
|
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 sr.UnknownValueError: |
|
return "Could not understand audio" |
|
except sr.RequestError: |
|
return "Speech recognition service unavailable" |
|
|
|
# Highlight alphabet in UI |
|
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 |
|
|
|
# Combined processing function |
|
def process_input(text=None, speech=None, audio=None): |
|
morse, decoded_text, audio_output = "", "", None |
|
|
|
if text: # Text input |
|
morse = text_to_morse(text) |
|
decoded_text = text |
|
audio_output = generate_morse_audio(morse) |
|
|
|
elif speech: # Speech input |
|
text = speech_to_text(speech) |
|
morse = text_to_morse(text) |
|
decoded_text = text |
|
audio_output = generate_morse_audio(morse) |
|
|
|
elif audio: # Live audio input |
|
morse, decoded_text = decode_morse_from_audio(audio) |
|
|
|
alphabet_html = generate_alphabet_html(decoded_text) |
|
return morse, decoded_text, alphabet_html, audio_output |
|
|
|
# Gradio UI with Blocks |
|
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(type="numpy", label="Live Audio Input (Use Microphone)", streaming=True) |
|
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(type="filepath", label="Speak Your Text (Record Audio)") |
|
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] |
|
) |
|
|
|
# Launch the app |
|
demo.launch() |
|
''' |
|
|
|
''' |
|
import gradio as gr |
|
import numpy as np |
|
import time |
|
from scipy.io import wavfile |
|
import io |
|
|
|
# Morse code dictionary (ITU standard) |
|
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': '-----', ' ': ' ' |
|
} |
|
|
|
# Reverse dictionary for decoding |
|
MORSE_TO_CHAR = {v: k for k, v in MORSE_CODE_DICT.items()} |
|
|
|
# Function to process audio and detect Morse code (simplified) |
|
def decode_morse_from_audio(audio_data): |
|
if audio_data is None: |
|
return "", "" |
|
|
|
# Audio comes as (sample_rate, data) from Gradio |
|
sample_rate, data = audio_data |
|
if len(data.shape) > 1: # Convert stereo to mono if needed |
|
data = data.mean(axis=1) |
|
|
|
# Normalize audio data |
|
data = data / np.max(np.abs(data)) |
|
|
|
# Threshold for detecting signal (tweak as needed) |
|
threshold = 0.1 |
|
signal = data > threshold |
|
|
|
# Timing parameters (in samples, adjust based on sample_rate) |
|
dit_length = int(sample_rate * 0.1) # 100ms for a dit |
|
dah_length = dit_length * 3 # 300ms for a dah |
|
space_length = dit_length * 7 # 700ms for word space |
|
|
|
morse_code = "" |
|
decoded_text = "" |
|
i = 0 |
|
|
|
while i < len(signal) - dit_length: |
|
if signal[i]: |
|
# Measure signal duration |
|
start = i |
|
while i < len(signal) and signal[i]: |
|
i += 1 |
|
duration = i - start |
|
|
|
# Classify as dit or dah |
|
if duration >= dah_length: |
|
morse_code += "-" |
|
elif duration >= dit_length: |
|
morse_code += "." |
|
|
|
# Check for spaces (pauses) |
|
else: |
|
start = i |
|
while i < len(signal) and not signal[i]: |
|
i += 1 |
|
pause = i - start |
|
|
|
if pause >= space_length: |
|
if morse_code: |
|
decoded_text += MORSE_TO_CHAR.get(morse_code, "?") |
|
decoded_text += " " |
|
morse_code = "" |
|
elif pause >= dit_length and morse_code: |
|
decoded_text += MORSE_TO_CHAR.get(morse_code, "?") |
|
morse_code = "" |
|
|
|
i += 1 |
|
|
|
# Handle any remaining code |
|
if morse_code: |
|
decoded_text += MORSE_TO_CHAR.get(morse_code, "?") |
|
|
|
return morse_code, decoded_text.strip() |
|
|
|
# Function to generate highlighted alphabet UI |
|
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 |
|
|
|
# Gradio streaming function |
|
def stream_morse_decoder(audio): |
|
morse, text = decode_morse_from_audio(audio) |
|
alphabet_html = generate_alphabet_html(text) |
|
return morse, text, alphabet_html |
|
|
|
# Gradio UI with Blocks |
|
with gr.Blocks(title="Morse Code Decoder") as demo: |
|
gr.Markdown("# Morse Code Decoder") |
|
gr.Markdown("Speak or play Morse code into your microphone to decode it live!") |
|
|
|
with gr.Row(): |
|
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) |
|
with gr.Column(): |
|
alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)") |
|
|
|
# Event listener for streaming audio |
|
audio_input.stream( |
|
fn=stream_morse_decoder, |
|
inputs=[audio_input], |
|
outputs=[morse_output, text_output, alphabet_display], |
|
_js="() => { return [navigator.mediaDevices.getUserMedia({ audio: true })];" |
|
) |
|
|
|
# Launch the app |
|
demo.launch() |
|
''' |