Sunday, November 10, 2024
STEM

Text to Morse: codes and sound generation (Python)

In this blog, I’ll discuss how to create a fully functional program that takes user inputs as letters, numbers, and symbols and turns them into International Morse codes, and also play the actual sound of the codes as transmitted at 550Hz (20WMP speed).

This program is written in Python and while I’m not a Morse code expert in any shape or form, I wanted to create an application to generate such…for fun and experiment. I’m happy to report that I was able to create the application in a few hours from scratch (sans the Python part, which also is something I play with occasionally but not every day).

To learn more about International Morse Codes (dots and dashes, and sound for supported characters), you can visit this very nice site. This is where I learned the basics of Morse code representations and the symbols’ audio.

The application will use these Python features: dictionary, list <-> string conversion, checking for numeric, alphabetic, and other character, CPU delay, playing sound and other programming controls.

The program supports alphabets a-z (or, A-Z. NOTE: There’s no difference for cases for morsecodes, comma, period, plus sign, minus sign, question mark, and spaces), numbers (0-9). Everything else that’s not internationally supported in Morse code is ignored.

Application Design

To make matching each character and its representation very efficient, I use dictionary object that uses the key-value pair arragement. So, for all numbers and their respective morse codes, I have a dictionary object declared as:

numbersdic={1:’.—-‘,2:’..—‘,3:’…–‘, 4:’….-‘, 5:’…..’, 6:’-….’, 7: ‘–…’, 8: ‘—..’, 9:’—-.’, 0:’—–‘}

Similarly, I have 2 more dictionary objects: symbolsdic, and alphadic containing symbols (comma, period, exclamation, plus, minus, equal, forward slash, question mark) and all letters of the english alphabet.

Since, morse code is made of dots and dashes only, I also created 1 more dictionary to easily refer to the sound files (I’m using WAV format) by names such as ‘DOT’ and ‘DASH’. Any morse code can be played back using just these two sound types…they’re just in different orders and repetitions depending on the code. An example of that dictionary is:

sounddic={‘DOT’:'[path]\\morse_DOT.wav’, ‘DASH’:'[path]\\morse_DASH.wav’}

I also need an object to store user inputs, and another to store the morse codes for the inputs. For those, List objects will be suitable.

After processing the inputs, we need to translate them and show the code for each character on screen, and if user chooses to, play the audio for the codes.

The Pseudo-Code

  • Get user input
  • For every character, translate it to its morse code, and a) show the code on screen and b) store in memory for audio later.
  • For each input which can be of any length (e.g. “H”, or “Hello world…”), type (e.g. “Hi ship 123! Are you there?”) with a mix of numbers, letters, symbols, we need to separate each generated code with a space. However, if there are words in the input (that is, separated by a space as is “Hello world”), we need to generate extra spaces between code for “Hello” and “world”.
  • If the user wants to hear the audio of the morse code of the input, take each code stored in memory, and turn the array into a continuous stream of characters (a string), and play dot sound whenever a dot appears in code, and play dash sound whenever a dash appears in code, and cause a deliberate delay (pause) for word breakers, so the listener/interpreter can decipher the code correctly.

Code Snippets And Explanation

The user inputs are captured using the classic input().

However, it returns a string. I want the string to be converted into a list by each character. So, if the input is “a1b2”, I want a data structure where it’s stored as “a”, “1”, “b”, “2”…since each of them has their own Morse code that I need to translate to separately. (Additionally, if there were spaces, I need to account for that too)

So, it’s accomplished by using list(). Here’s the snippet:

ui = input(“Enter a letter, word, sentence, or numbers (? , . ! = / space are translated also): “)
uilist = list(ui)

Now we can use “in”[list] in a for loop without explicitly querying the length. Code:
for c in uilist:
if (c.isalpha()):
i=c.upper()
morsecode=alphadic[i]
print(morsecode, end=’ ‘)
morsecodelist.append(morsecode) # each char will be in its own element position in list/array

So, as I traverse the list, I turn them into same case as in my dictionary alphadic. Then using the key, I get its value, the morse code. Additionally, I’m loading up the morsecodelist[] array with the code (I’ll use that later to play the audio for the code).

Similarly, I use if (c.isnumeric()) logic and get the code from numbersdic object using its key as below:
i=int(c)
morsecode=numbersdic[i]
print(morsecode, end=’ ‘)
morsecodelist.append(morsecode)

Continuing with the same logic, I check for symbols and get their values from my symbolsdic object.

Again, any invalid chars in input are simply not translated (ignored) and the program continues without them, processing the next valid one.

After the entire input is processed including spaces, the entire code is now stored in morsecodelist object as individual codes. What I’d like to do next is to flatten that list object into a stream of a single string, because I want to process each character (dot, dash, and space) individually for sound and pause.

To do that, first I use the .join() method as below:

delimiter=’ ‘
morsecode_str = delimiter.join(morsecodelist)

Notice the delimiter is a single space char because each code needs to be 1-space separated, while words will be separated by 2 spaces.

Now we can traverse morsecode_str if user wants to hear sound. If user decides to skip the sound (that is, satisfied with just the text code representation already on screen), they can enter ‘N’ or any other character that is not ‘y’ or ‘Y’.

hear= input(“\nDo you want to hear this code? (Y/N) “)
if (hear !=’y’ and hear !=’Y’):
exit()

If the user chose to hear sound, I traverse each char of the final string and play sound for each dot/dash in a loop and also show on screen (again, just to validate). The snippet below accomplishes that:
for c in morsecode_str:
if (c==’.’):
winsound.PlaySound(sounddic[‘DOT’], winsound.SND_FILENAME)
print(‘.’, end=”)
and

if (c==’-‘):
winsound.PlaySound(sounddic[‘DASH’], winsound.SND_FILENAME)
print(‘-‘, end=”)

and if there’s a word-break (i.e. a space), then do this:

if (c==’ ‘):
print(c, end=”)
time.sleep(0.25) # in seconds

NOTE: In order to use PlaySound(), I had to import import winsound  and for time.sleep(), I had to import time libraries.

And that’s the gist of it! Now, let’s see the actual session’s video.

To verify for yourself, you can compare what’s shown in the video with the reference page. Hope you enjoyed this! Want more details and full source code? Read below…


This post is not meant to be a step-by-step, detailed tutorial, instead to serve key concepts, and approaches to problem-solving. Basic->Intermediate technical/coding knowledge is assumed.
If you like more info or source file to learn/use, or need more basic assistance, you may contact me at tanman1129 at hotmail dot com. To support this voluntary effort, you can donate via Paypal from the button in my Home page, or become a Patron via my Patreon site. A supporter/patron gets direct answers on any of my blogs including code/data/source files whenever possible upon request.

 
 
 
 
 

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top
+