#!/usr/bin/python3
import array
import math
import wave

# Configuration Constants
SAMPLE_RATE = 10000  # Hz
DOT_TIME = 0.1       # Duration of a dot in seconds
MORSE_TEXT = "  -.. -- ---.. .- -. .  "
TONE_FREQ = 1000     # Audio frequency in Hz
FILENAME = "morse_text.wav"

def make_morse_wav(text, filename, sample_rate, dot_time, frequency):
    two_pi = 2.0 * math.pi
    dot_samples = int(dot_time * sample_rate)
    
    # Pre-calculate audio samples for 1 unit of sound and 1 unit of silence
    sound_unit = []
    silence_unit = [0] * dot_samples
    
    for i in range(dot_samples):
        # Generate a continuous sine wave
        t = i / sample_rate
        sample = math.sin(two_pi * frequency * t) * 32000
        sound_unit.append(int(sample))

    final_signal = []
    
    # Clean up input text: replace multiple spaces with single ones and strip edges
    cleaned_text = " ".join(text.split())

    for i, char in enumerate(cleaned_text):
        if char == ".":
            final_signal.extend(sound_unit)          # 1 unit of sound
            final_signal.extend(silence_unit)        # 1 unit of intra-character gap
        elif char == "-":
            final_signal.extend(sound_unit * 3)      # 3 units of sound
            final_signal.extend(silence_unit)        # 1 unit of intra-character gap
        elif char == " ":
            # Standard word gap is 7 units total. 
            # The previous character already added 1 unit of silence, so we add 6 more.
            final_signal.extend(silence_unit * 6)

    # Efficiently convert the list of signed 16-bit integers ('h') directly to bytes
    binary_data = array.array('h', final_signal).tobytes()
    
    # Write to WAV file
    write_wav(filename, sample_rate, binary_data)
    print(file_name_msg := f"Successfully saved Morse audio to {filename}")

def write_wav(filename, sample_rate, binary_data):
    with wave.open(filename, 'wb') as wav_file:
        # Parameters: (nchannels=1, sampwidth=2 bytes (16-bit), framerate, nframes, comptype, compname)
        wav_file.setparams((1, 2, sample_rate, len(binary_data) // 2, 'NONE', 'not compressed'))
        wav_file.writeframes(binary_data)

def main():
    make_morse_wav(MORSE_TEXT, FILENAME, SAMPLE_RATE, DOT_TIME, TONE_FREQ)

if __name__ == "__main__":
    main()
