|
1 import sys, math |
|
2 |
|
3 DOT = 30 |
|
4 DAH = 80 |
|
5 OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ... |
|
6 SAMPWIDTH = 2 |
|
7 FRAMERATE = 44100 |
|
8 BASEFREQ = 441 |
|
9 QSIZE = 20000 |
|
10 |
|
11 morsetab = { |
|
12 'A': '.-', 'a': '.-', |
|
13 'B': '-...', 'b': '-...', |
|
14 'C': '-.-.', 'c': '-.-.', |
|
15 'D': '-..', 'd': '-..', |
|
16 'E': '.', 'e': '.', |
|
17 'F': '..-.', 'f': '..-.', |
|
18 'G': '--.', 'g': '--.', |
|
19 'H': '....', 'h': '....', |
|
20 'I': '..', 'i': '..', |
|
21 'J': '.---', 'j': '.---', |
|
22 'K': '-.-', 'k': '-.-', |
|
23 'L': '.-..', 'l': '.-..', |
|
24 'M': '--', 'm': '--', |
|
25 'N': '-.', 'n': '-.', |
|
26 'O': '---', 'o': '---', |
|
27 'P': '.--.', 'p': '.--.', |
|
28 'Q': '--.-', 'q': '--.-', |
|
29 'R': '.-.', 'r': '.-.', |
|
30 'S': '...', 's': '...', |
|
31 'T': '-', 't': '-', |
|
32 'U': '..-', 'u': '..-', |
|
33 'V': '...-', 'v': '...-', |
|
34 'W': '.--', 'w': '.--', |
|
35 'X': '-..-', 'x': '-..-', |
|
36 'Y': '-.--', 'y': '-.--', |
|
37 'Z': '--..', 'z': '--..', |
|
38 '0': '-----', |
|
39 '1': '.----', |
|
40 '2': '..---', |
|
41 '3': '...--', |
|
42 '4': '....-', |
|
43 '5': '.....', |
|
44 '6': '-....', |
|
45 '7': '--...', |
|
46 '8': '---..', |
|
47 '9': '----.', |
|
48 ',': '--..--', |
|
49 '.': '.-.-.-', |
|
50 '?': '..--..', |
|
51 ';': '-.-.-.', |
|
52 ':': '---...', |
|
53 "'": '.----.', |
|
54 '-': '-....-', |
|
55 '/': '-..-.', |
|
56 '(': '-.--.-', |
|
57 ')': '-.--.-', |
|
58 '_': '..--.-', |
|
59 ' ': ' ' |
|
60 } |
|
61 |
|
62 # If we play at 44.1 kHz (which we do), then if we produce one sine |
|
63 # wave in 100 samples, we get a tone of 441 Hz. If we produce two |
|
64 # sine waves in these 100 samples, we get a tone of 882 Hz. 882 Hz |
|
65 # appears to be a nice one for playing morse code. |
|
66 def mkwave(octave): |
|
67 global sinewave, nowave |
|
68 sinewave = '' |
|
69 n = int(FRAMERATE / BASEFREQ) |
|
70 for i in range(n): |
|
71 val = int(math.sin(2 * math.pi * i * octave / n) * 0x7fff) |
|
72 sample = chr((val >> 8) & 255) + chr(val & 255) |
|
73 sinewave = sinewave + sample[:SAMPWIDTH] |
|
74 nowave = '\0' * (n*SAMPWIDTH) |
|
75 |
|
76 mkwave(OCTAVE) |
|
77 |
|
78 class BufferedAudioDev: |
|
79 def __init__(self, *args): |
|
80 import audiodev |
|
81 self._base = apply(audiodev.AudioDev, args) |
|
82 self._buffer = [] |
|
83 self._filled = 0 |
|
84 self._addmethods(self._base, self._base.__class__) |
|
85 def _addmethods(self, inst, cls): |
|
86 for name in cls.__dict__.keys(): |
|
87 if not hasattr(self, name): |
|
88 try: |
|
89 setattr(self, name, getattr(inst, name)) |
|
90 except: |
|
91 pass |
|
92 for basecls in cls.__bases__: |
|
93 self._addmethods(self, inst, basecls) |
|
94 def writeframesraw(self, frames): |
|
95 self._buffer.append(frames) |
|
96 self._filled = self._filled + len(frames) |
|
97 if self._filled >= QSIZE: |
|
98 self.flush() |
|
99 def wait(self): |
|
100 self.flush() |
|
101 self._base.wait() |
|
102 def flush(self): |
|
103 print 'flush: %d blocks, %d bytes' % (len(self._buffer), self._filled) |
|
104 if self._buffer: |
|
105 import string |
|
106 self._base.writeframes(string.joinfields(self._buffer, '')) |
|
107 self._buffer = [] |
|
108 self._filled = 0 |
|
109 |
|
110 def main(args = sys.argv[1:]): |
|
111 import getopt, string |
|
112 try: |
|
113 opts, args = getopt.getopt(args, 'o:p:') |
|
114 except getopt.error: |
|
115 sys.stderr.write('Usage ' + sys.argv[0] + |
|
116 ' [ -o outfile ] [ args ] ...\n') |
|
117 sys.exit(1) |
|
118 dev = None |
|
119 for o, a in opts: |
|
120 if o == '-o': |
|
121 import aifc |
|
122 dev = aifc.open(a, 'w') |
|
123 dev.setframerate(FRAMERATE) |
|
124 dev.setsampwidth(SAMPWIDTH) |
|
125 dev.setnchannels(1) |
|
126 if o == '-p': |
|
127 mkwave(string.atoi(a)) |
|
128 if not dev: |
|
129 dev = BufferedAudioDev() |
|
130 dev.setoutrate(FRAMERATE) |
|
131 dev.setsampwidth(SAMPWIDTH) |
|
132 dev.setnchannels(1) |
|
133 dev.close = dev.stop |
|
134 if args: |
|
135 line = string.join(args) |
|
136 else: |
|
137 line = sys.stdin.readline() |
|
138 while line: |
|
139 print line |
|
140 mline = morse(line) |
|
141 print mline |
|
142 play(mline, dev) |
|
143 if hasattr(dev, 'wait'): |
|
144 dev.wait() |
|
145 if not args: |
|
146 line = sys.stdin.readline() |
|
147 else: |
|
148 line = '' |
|
149 dev.close() |
|
150 |
|
151 # Convert a string to morse code with \001 between the characters in |
|
152 # the string. |
|
153 def morse(line): |
|
154 res = '' |
|
155 for c in line: |
|
156 try: |
|
157 res = res + morsetab[c] + '\001' |
|
158 except KeyError: |
|
159 pass |
|
160 return res |
|
161 |
|
162 # Play a line of morse code. |
|
163 def play(line, dev): |
|
164 for c in line: |
|
165 if c == '.': |
|
166 sine(dev, DOT) |
|
167 elif c == '-': |
|
168 sine(dev, DAH) |
|
169 else: |
|
170 pause(dev, DAH) |
|
171 pause(dev, DOT) |
|
172 |
|
173 def sine(dev, length): |
|
174 dev.writeframesraw(sinewave*length) |
|
175 |
|
176 def pause(dev, length): |
|
177 dev.writeframesraw(nowave*length) |
|
178 |
|
179 if __name__ == '__main__' or sys.argv[0] == __name__: |
|
180 main() |