1import sys, math 2 3DOT = 30 4DAH = 80 5OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ... 6SAMPWIDTH = 2 7FRAMERATE = 44100 8BASEFREQ = 441 9QSIZE = 20000 10 11morsetab = { 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. 66def 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 76mkwave(OCTAVE) 77 78class 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 110def 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. 153def 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. 163def 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 173def sine(dev, length): 174 dev.writeframesraw(sinewave*length) 175 176def pause(dev, length): 177 dev.writeframesraw(nowave*length) 178 179if __name__ == '__main__' or sys.argv[0] == __name__: 180 main() 181