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 8import sys, math, audiodev 9 10DOT = 30 11DAH = 3 * DOT 12OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ... 13 14morsetab = { 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 54nowave = '\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. 60def 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 67defaultwave = mkwave(OCTAVE) 68 69def 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. 109def 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. 119def 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 129def sine(dev, length, wave): 130 for i in range(length): 131 dev.writeframesraw(wave) 132 133def pause(dev, length): 134 for i in range(length): 135 dev.writeframesraw(nowave) 136 137if __name__ == '__main__': 138 main() 139