1 #! /usr/bin/env python
2 
3 # DAH should be three DOTs.
4 # Space between DOTs and DAHs should be one DOT.
5 # Space between two letters should be one DAH.
6 # Space between two words should be DOT DAH DAH.
7 
8 import sys, math, audiodev
9 
10 DOT = 30
11 DAH = 3 * DOT
12 OCTAVE = 2                              # 1 == 441 Hz, 2 == 882 Hz, ...
13 
14 morsetab = {
15         'A': '.-',              'a': '.-',
16         'B': '-...',            'b': '-...',
17         'C': '-.-.',            'c': '-.-.',
18         'D': '-..',             'd': '-..',
19         'E': '.',               'e': '.',
20         'F': '..-.',            'f': '..-.',
21         'G': '--.',             'g': '--.',
22         'H': '....',            'h': '....',
23         'I': '..',              'i': '..',
24         'J': '.---',            'j': '.---',
25         'K': '-.-',             'k': '-.-',
26         'L': '.-..',            'l': '.-..',
27         'M': '--',              'm': '--',
28         'N': '-.',              'n': '-.',
29         'O': '---',             'o': '---',
30         'P': '.--.',            'p': '.--.',
31         'Q': '--.-',            'q': '--.-',
32         'R': '.-.',             'r': '.-.',
33         'S': '...',             's': '...',
34         'T': '-',               't': '-',
35         'U': '..-',             'u': '..-',
36         'V': '...-',            'v': '...-',
37         'W': '.--',             'w': '.--',
38         'X': '-..-',            'x': '-..-',
39         'Y': '-.--',            'y': '-.--',
40         'Z': '--..',            'z': '--..',
41         '0': '-----',           ',': '--..--',
42         '1': '.----',           '.': '.-.-.-',
43         '2': '..---',           '?': '..--..',
44         '3': '...--',           ';': '-.-.-.',
45         '4': '....-',           ':': '---...',
46         '5': '.....',           "'": '.----.',
47         '6': '-....',           '-': '-....-',
48         '7': '--...',           '/': '-..-.',
49         '8': '---..',           '(': '-.--.-',
50         '9': '----.',           ')': '-.--.-',
51         ' ': ' ',               '_': '..--.-',
52 }
53 
54 nowave = '\0' * 200
55 
56 # If we play at 44.1 kHz (which we do), then if we produce one sine
57 # wave in 100 samples, we get a tone of 441 Hz.  If we produce two
58 # sine waves in these 100 samples, we get a tone of 882 Hz.  882 Hz
59 # appears to be a nice one for playing morse code.
60 def mkwave(octave):
61     sinewave = ''
62     for i in range(100):
63         val = int(math.sin(math.pi * i * octave / 50.0) * 30000)
64         sinewave += chr((val >> 8) & 255) + chr(val & 255)
65     return sinewave
66 
67 defaultwave = mkwave(OCTAVE)
68 
69 def main():
70     import getopt
71     try:
72         opts, args = getopt.getopt(sys.argv[1:], 'o:p:')
73     except getopt.error:
74         sys.stderr.write('Usage ' + sys.argv[0] +
75                          ' [ -o outfile ] [ -p octave ] [ words ] ...\n')
76         sys.exit(1)
77     dev = None
78     wave = defaultwave
79     for o, a in opts:
80         if o == '-o':
81             import aifc
82             dev = aifc.open(a, 'w')
83             dev.setframerate(44100)
84             dev.setsampwidth(2)
85             dev.setnchannels(1)
86         if o == '-p':
87             wave = mkwave(int(a))
88     if not dev:
89         import audiodev
90         dev = audiodev.AudioDev()
91         dev.setoutrate(44100)
92         dev.setsampwidth(2)
93         dev.setnchannels(1)
94         dev.close = dev.stop
95         dev.writeframesraw = dev.writeframes
96     if args:
97         source = [' '.join(args)]
98     else:
99         source = iter(sys.stdin.readline, '')
100     for line in source:
101         mline = morse(line)
102         play(mline, dev, wave)
103         if hasattr(dev, 'wait'):
104             dev.wait()
105     dev.close()
106 
107 # Convert a string to morse code with \001 between the characters in
108 # the string.
109 def morse(line):
110     res = ''
111     for c in line:
112         try:
113             res += morsetab[c] + '\001'
114         except KeyError:
115             pass
116     return res
117 
118 # Play a line of morse code.
119 def play(line, dev, wave):
120     for c in line:
121         if c == '.':
122             sine(dev, DOT, wave)
123         elif c == '-':
124             sine(dev, DAH, wave)
125         else:                   # space
126             pause(dev, DAH + DOT)
127         pause(dev, DOT)
128 
129 def sine(dev, length, wave):
130     for i in range(length):
131         dev.writeframesraw(wave)
132 
133 def pause(dev, length):
134     for i in range(length):
135         dev.writeframesraw(nowave)
136 
137 if __name__ == '__main__':
138     main()
139