Improved some error messages for command line processing.
[python/dscho.git] / Mac / Demo / sound / morse.py
blobbf5fa5fe9f70761f0eadc281ae9993aa1e3eb4fc
1 import sys, math, audiodev
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
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 ' ': ' '
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)
76 mkwave(OCTAVE)
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
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()
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
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)
173 def sine(dev, length):
174 dev.writeframesraw(sinewave*length)
176 def pause(dev, length):
177 dev.writeframesraw(nowave*length)
179 if __name__ == '__main__' or sys.argv[0] == __name__:
180 main()