Text to Melodie

Code 

# Morse Code Mapping

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': '--..',

    '0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-', 

    '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.',

    '.': '.-.-.-', ',': '--..--', '?': '..--..', "'": '.----.', '!': '-.-.--',

    '/': '-..-.', '(': '-.--.', ')': '-.--.-', '&': '.-...', ':': '---...', 

    ';': '-.-.-.', '=': '-...-', '+': '.-.-.', '-': '-....-', 

    '_': '..--.-', '"': '.-..-.', '@': '.--.-.', ' ': '/'

}


# Note mapping including enharmonic equivalents

NOTE_MAP = {

    'C': 0, 'C#': 1, 'Db': 1, 'D': 2, 'D#': 3, 'Eb': 3, 'E': 4, 'F': 5, 

    'F#': 6, 'Gb': 6, 'G': 7, 'G#': 8, 'Ab': 8, 'A': 9, 'A#': 10, 'Bb': 10, 

    'B': 11

}


# Function to encode text to Morse code

def text_to_morse(text):

    """Convert text to Morse code."""

    morse_code = []

    for char in text:

        code = MORSE_CODE_DICT.get(char.upper(), None)

        if code:

            morse_code.append(code)

        else:

            print(f"Skipping unsupported character: {char}")

    return morse_code


# Function to calculate the pitch based on the key and intervals

def morse_to_pitch(morse_code, key, dot_interval, dash_interval):

    """Convert Morse code to musical pitches based on the key."""

    pitch_list = []

    current_pitch = NOTE_MAP.get(key.upper(), 0)  # Starting note in semitones

    octave = 4  # Start in the 4th octave


    for code in morse_code:

        symbol_pitches = []

        for symbol in code:

            if symbol == '.':

                current_pitch += dot_interval

                if current_pitch >= 12:  # Move up one octave if needed

                    current_pitch -= 12

                    octave += 1

                elif current_pitch < 0:  # Move down one octave if negative

                    current_pitch += 12

                    octave -= 1

                symbol_pitches.append((current_pitch, octave))

            elif symbol == '-':

                current_pitch += dash_interval

                if current_pitch >= 12:

                    current_pitch -= 12

                    octave += 1

                elif current_pitch < 0:

                    current_pitch += 12

                    octave -= 1

                symbol_pitches.append((current_pitch, octave))

            elif symbol == '/':  # For space in Morse code

                symbol_pitches.append('rest')  # Add a rest for space

        pitch_list.append(symbol_pitches)


    return pitch_list


# Function to format and display pitches per letter

def display_pitches_with_labels(text, morse_code_list, pitch_list, key):

    """Displays the formatted output for Morse code and pitch list with labels."""

    print(f"\nMorse Code: {' '.join(morse_code_list)}")

    print(f"Key: {key}4")  # Display the entered key with octave 4


    # Group output by words and rest in Morse code

    for i, char in enumerate(text):

        if char == ' ':

            print("    : rest")

        else:

            morse_letter = morse_code_list[i]

            pitches = pitch_list[i]

            

            # Convert pitch list to note names with octave info

            note_names = []

            for pitch in pitches:

                if isinstance(pitch, tuple):

                    note_names.append(f"{list(NOTE_MAP.keys())[pitch[0]]}{pitch[1]}")

                else:

                    note_names.append(pitch)

            

            print(f"   {char.upper()}: {' '.join(note_names)}")


# Main program

def main():

    user_input = input("Enter text to encode to Morse code: ").strip()

    morse_code_list = text_to_morse(user_input)


    key = input("Enter the Key (C, D, D#, Eb, A, etc.): ").strip()


    # Get intervals for dot and dash and whether to go up or down

    dot_interval = int(input("Enter the interval (in semitones) for dots: ").strip())

    dot_direction = input("Should the dot interval go up or down? (up/down): ").strip().lower()

    if dot_direction == "down":

        dot_interval = -dot_interval

    

    dash_interval = int(input("Enter the interval (in semitones) for dashes: ").strip())

    dash_direction = input("Should the dash interval go up or down? (up/down): ").strip().lower()

    if dash_direction == "down":

        dash_interval = -dash_interval

    

    # Convert Morse code to pitches

    pitch_list = morse_to_pitch(morse_code_list, key, dot_interval, dash_interval)


    # Display formatted output with labels

    display_pitches_with_labels(user_input, morse_code_list, pitch_list, key)


if __name__ == "__main__":

    main()