PageRenderTime 53ms CodeModel.GetById 28ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/Mac/Demo/sound/morse.py

http://unladen-swallow.googlecode.com/
Python | 180 lines | 173 code | 3 blank | 4 comment | 0 complexity | 5ac3016d94cfc93f5f8f4709151de651 MD5 | raw file
  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()