Home | History | Annotate | Download | only in scripts
      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