Morse Code and Dictionaries in Python (with Sound)

Mose Code is an old method of transmitting text messages. Morse Code dated back to around mid 1800s. The basics of morse code is timing and pulse. Each combination corresponds to an Latin alphbet character or number. Morse Code can also be transmitted visually using a light source by alternating the light on and off. If you are in need of more information about Morse Code I suggest Wikipedia Morse Code entry a a good starting place.

So why implement morse code? Well, because we can. Programming Morse Code is very easy and a great challenge for beginners. I also found very little resource that implemented Morse Code with sound. There is a lot of code around the web to print out Morse Code in python, but I could not find one that outputs sound. As an added benefit you get exposed to something you might need in the future. Morse code is still in use and may save your life. (I know, this is a little extreme). We represent Morse Code on the screen by a dots and dashes. Dots are one unit length, while dashes are three. Here is an example of SOS, the international distress signal:

wpid-SOS_morse_code-2013-01-8-08-28.png

Although there is an international agreement about SOS signal, some of symbols in Morse Code have no standard. For the scope of this article let us limit our discussion to the International Morse Code, which is limited to alphabet and the numbers 0 to 9. As you will see, the program can be modified to represent more symbols to your wishes. Here is the guideline to Morse Code as we will use it:

wpid-450px-International_Morse_Code.svg-2013-01-8-08-28.png
Let us deal with the latter part first, the letters and digits. We will get to the top part in a little bit. Different languages have different data types at you disposal. Python has a tool that fits this problem like a glove, dictionaries. You can read up on python’s dictionaries documentation or download python2.6 documentation. The idea behind dictionaries is that we can map keys to values. Lists in python are numeric indexed from 0 up (lists are also reversed indexed). Dictionaries store data by assigning a key and a particular value. So for example we can initiate an empty dictionary and store the value ‘.-‘ for the key ‘A’. Then we can retrieve the value for key ‘A’ via indexing.

wpid-dictionariesinpythonexample1-2013-01-8-08-28.png

We can also initiate a dictionary with values:

wpid-dictionariesinpythonexample2-2013-01-8-08-28.png

Note that since there was no value for key ‘C’ we got an error. If we want our program to run correctly, we will need to address this issue, but not at the moment. So using a dictionary for our alphabet and numbers and using python’s string properties we can write a fairly simple program that will output text Morse Code. Lets look at the basic implementation of Morse Code:


CODE = {'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': '----.' 
        }


def main():
	
	msg = raw_input('MESSAGE: ')
	
	for char in msg:
		print CODE[char.upper()],
		
if __name__ == "__main__":
	main()


python morse code example

You will notice that we use a string method named upper() to force the input to match our keys. There is a big difference between ‘A’ and ‘a’ in computer programs, they two different keys. So now that we have a basic python morse code script, let us try to improve on it. In our first program we really cannot transfer more than one word. All the words will be concatenated together. According to our code from above we need to modify our script to the following rules:

  1. The length of a dot is one unit
  2. A dash is three units
  3. the space between parts of the same letter is one unit
  4. the space between letters is three units
  5. the space between words is seven units

Until we move on to sound, the first 4 rules are implicitly implemented. What we really need is a space between the words. To do this we will add 7 space for every 1 space in the input, like so:


CODE = {'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': '----.' 
        }


def main():
	
	msg = raw_input('MESSAGE: ')
	
	for char in msg:
		if char == ' ':
			print ' '*7,
		else:
			print CODE[char.upper()],
		
if __name__ == "__main__":
	main()


wpid-pythonmorsecode4-2013-01-8-08-28.png

You can also modify the program to print a newline after each word and more spaces between letters. This will look like this: (full morse code code)

for char in msg:
	if char == ' ':
		print 
	else:
		print CODE[char.upper()] + '  ',

wpid-pythonmorsecode5-2013-01-8-08-28.png

Before we move on to sound, there is one more thing I would like to address, errors. Since we do not have all possible input, our program might raise and error. Foe example, if we tried to convert and email address to Morse Code we will have an error since ‘@‘ and ‘.’ are not keys in the dictionary. Here is what will happen if we tried to convert ’cpt@thelivingpearl.com’ to Morse Code:

wpid-pythonmorsecode6-2013-01-8-08-28.png

That is not good. You can see that the program started to translate, but got stuck along the way. There are several way to handle this, including non at all. A simple way to solve this issue is by scanning the output and checking its values against the dictionary keys. We can do this by using a keys() function of our CODE dictionary. If we find values that we cannot translate to Morse Code, we will notify the user and terminate the program.


import sys

CODE = {'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': '----.' 
        }

def verify(string):
	keys = CODE.keys()
	for char in string:
		if char.upper() not in keys and char != ' ':
			sys.exit('Error the charcter ' + char + ' cannot be translated to Morse Code')

def main():
	
	msg = raw_input('MESSAGE: ')
	
	verify(msg)
	
	for char in msg:
		if char == ' ':
			print ' '*7,
		else:
			print CODE[char.upper()],
		
if __name__ == "__main__":
	main()

wpid-pythonmorsecode7-2013-01-8-08-28.png

Now we have a complete morse code program. How about we add some sound to this? To add the sound we will utilize PyGame (download PyGame). We can download sound files for Morse Code from wikimedia commons. I have conviently downloaded all the sound files and made them available to download Mose Code Sounds in zip format. There is an example python script inside the zip file that plays a sound example called play_ogg.py, here is what it looks like:


import pygame
import time
pygame.init()

pygame.mixer.music.load("A_morse_code.ogg")
pygame.mixer.music.play()
time.sleep(1)

This script will output the letter ‘A’ in morse code. Make sure you have your speakers on. Here is how are program will look like with the added sound files.


import sys
import pygame
import time

CODE = {'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': '----.' 
        }
        
ONE_UNIT = 0.5
THREE_UNITS = 3 * ONE_UNIT
SEVEN_UNITS = 7 * ONE_UNIT
PATH = 'morse_sound_files/'

def verify(string):
	keys = CODE.keys()
	for char in string:
		if char.upper() not in keys and char != ' ':
			sys.exit('Error the charcter ' + char + ' cannot be translated to Morse Code')

def main():
	
	msg = raw_input('MESSAGE: ')
	verify(msg)
	
	pygame.init()
	
	for char in msg:
		if char == ' ':
			print ' '*7,
			time.sleep(SEVEN_UNITS)
		else:
			print CODE[char.upper()],
			pygame.mixer.music.load(PATH + char.upper() + '_morse_code.ogg')
			pygame.mixer.music.play()
			time.sleep(THREE_UNITS)
		
if __name__ == "__main__":
	main()


Here is a short video demonstrating ‘SOS’ in Morse Code:

Here is another video transmitting ‘HELLO WORLD’ in Morse Code:

As a last note. We have gone through how to successfully encode and transmit a message into Morse Code. That is only half the problem. To decode a text message in Morse Code, you can reverse the dictionary and have the Morse Code as keys and alphabet as values. This is rather trivial and you can see this as a challenge. To decode the sound waves, this will require more effort. Maybe one day I will have the time to write some code for that. For now, you can write your own code to decode morse code, or you can decode it using the image from the top of this post. Either way, this was fun.

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.
  • Pingback: Play Ogg File in Python « The Black Velvet Room

  • Paddy McCarthy

    Here's one I did earlier for Rosetta Code: http://rosettacode.org/wiki/Morse_code#Python

    In the comments near the end I show how to create an "audible quine". Note too that the code while output the morse for "?" for unknown characters.

    - Paddy.

    • CptDeadBones

      I did come across that code. The problem is that you need winsound to get it to work. In my case you will need PyGame, which is cross platform. Both are good solutions to the problem.

  • chroto

    Great post. I was happy you took it to the logical conclusion and outputted the sounds.

    I would make one suggestion to replace the `if char.upper() not in keys and char != ' ':` with a try, except block. I feel that would be more readable and you would replace a key search with a simple dictionary lookup.

    ```
    try:
    CODE.get(char)
    except KeyError:
    sys.exit('Error the...
    ```
    Of course you would need to add ' ' to CODE dict as well.

    • CptDeadBones

      Thanks. That is a fair comment and a great modification. I will try to include more try-except block in future code. Both versions should be fine, however, try-except block produce more reliable code for a general input. Good catch sir.

  • Pingback: high pop canada goose jacket

  • Pingback: IO Project | Encoder e Decoder de código Morse em Python

  • Paul Brewer

    Note: In your article there is a claim that "@" isn't in the morse table. Traditionally, it wasn't. The ITU added morse code for the "@" email symbol as ditdahdahditdahdit .--.-. which is an A and C run together. This is longer than AT, which also could have been a reasonable substitute for @, ditdah dah From http://en.wikipedia.org/wiki/Morse_code

    • CptDeadBones

      Thanks! I did not know that.

  • Shah Parshwa

    Can any one help me i have 3 Morse Code Message That I can't understand as below

    T U T E A U A E WR IB E I F S L H

    G E A P E RI O I T R D S P A W S A G N H A B I N E O D

    E N A E D N E N E T O R F Y I M R W

  • Matt Gibson

    Rather than do:
    if char == ' ':
    print ' '*7,

    Would it not be easier to do this instead:

    ONE_UNIT = 0.5
    THREE_UNITS = 3 * ONE_UNIT
    SEVEN_UNITS = 7 * ONE_UNIT
    CODE[' ']=7 * ONE_UNIT

  • GK PL

    It says syntax error on line 49:

    if __name__ == "__main__":

    The version without the sound works fine.