"""Translate text strings to Morse code"""
 
FRAMERATE = 22050
SAMPWIDTH = 2
 
BASEFREQ = 441
OCTAVE = 2
 
DOT = 30
DAH = 80
 
morsetab = {
        'a': '.-',
        'b': '-...',
        'c': '-.-.',
        'd': '-..',
        'e': '.',
        'f': '..-.',
        'g': '--.',
        'h': '....',
        'i': '..',
        'j': '.---',
        'k': '-.-',
        'l': '.-..',
        'm': '--',
        'n': '-.',
        'o': '---',
        'p': '.--.',
        'q': '--.-',
        'r': '.-.',
        's': '...',
        't': '-',
        'u': '..-',
        'v': '...-',
        'w': '.--',
        'x': '-..-',
        'y': '-.--',
        'z': '--..',
        '0': '-----',
        '1': '.----',
        '2': '..---',
        '3': '...--',
        '4': '....-',
        '5': '.....',
        '6': '-....',
        '7': '--...',
        '8': '---..',
        '9': '----.',
        ',': '--..--',
        '.': '.-.-.-',
        '?': '..--..',
        ';': '-.-.-.',
        ':': '---...',
        "'": '.----.',
        '-': '-....-',
        '/': '-..-.',
        '(': '-.--.-',
        ')': '-.--.-', # XXX same as code for '(' ???
        '_': '..--.-',
        ' ': ' '
}
 
def morsecode(s):
    from string import lower
    m = ''
    for c in s:
        c = lower(c)
        if morsetab.has_key(c):
            c = morsetab[c] + ' '
        else:
            c = '? '
        m = m + c
    return m
 
 
class BaseMorse:
    "base class for morse transmissions"
 
    def __init__(self):
        "constructor"
        self.dots = DOT
        self.dahs = DAH
 
    def noise(self, duration):
        "beep for given duration"
        pass
 
    def pause(self, duration):
        "pause for given duration"
        pass
 
    def dot(self):
        "short beep"
        self.noise(self.dots)
 
    def dah(self):
        "long beep"
        self.noise(self.dahs)
 
    def pdot(self):
        "pause as long as a dot"
        self.pause(self.dots)
 
    def pdah(self):
        "pause as long as a dah"
        self.pause(self.dahs)
 
    def sendmorse(self, s):
        for c in s:
            if c == '.': self.dot()
            elif c == '-': self.dah()
            else: self.pdah()
            self.pdot()
 
    def sendascii(self, s):
        self.sendmorse(morsecode(s))
 
    def send(self, s):
        self.sendascii(s)
 
 
import Audio_mac
class MyAudio(Audio_mac.Play_Audio_mac):
    def _callback(self, *args):
        if hasattr(self, 'usercallback'): self.usercallback()
        apply(Audio_mac.Play_Audio_mac._callback, (self,) + args)
 
 
class MacMorse(BaseMorse):
    "Mac specific class to play Morse code"
 
    def __init__(self):
        BaseMorse.__init__(self)
        self.dev = MyAudio()
        self.dev.setoutrate(FRAMERATE)
        self.dev.setsampwidth(SAMPWIDTH)
        self.dev.setnchannels(1)
        self.dev.usercallback = self.usercallback
        sinewave = ''
        n = int(FRAMERATE / BASEFREQ)
        octave = OCTAVE
        from math import sin, pi
        for i in range(n):
            val = int(sin(2 * pi * i * octave / n) * 0x7fff)
            sample = chr((val >> 8) & 255) + chr(val & 255)
            sinewave = sinewave + sample[:SAMPWIDTH]
        self.sinewave = sinewave
        self.silence = '\0' * (n*SAMPWIDTH)
        self.morsequeue = ''
 
    def __del__(self):
        self.close()
 
    def close(self):
        self.dev = None
 
    def pause(self, duration):
        self.dev.writeframes(self.silence * duration)
 
    def noise(self, duration):
        self.dev.writeframes(self.sinewave * duration)
 
    def sendmorse(self, s):
        self.morsequeue = self.morsequeue + s
        self.dev.usercallback()
        self.dev.usercallback()
        self.dev.usercallback()
 
    def usercallback(self):
        if self.morsequeue:
            c, self.morsequeue = self.morsequeue[0], self.morsequeue[1:]
            if c == '.': self.dot()
            elif c == '-': self.dah()
            else: self.pdah()
            self.pdot()
 
 
def test():
    m = MacMorse()
    while 1:
        try:
            line = raw_input('Morse line: ')
        except (EOFError, KeyboardInterrupt):
            break
        m.send(line)
        while m.morsequeue: pass
 
test()