cpython/Mac/Demo/sound/morse.py

181 lines
4.0 KiB
Python

import sys, math, audiodev
DOT = 30
DAH = 80
OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ...
SAMPWIDTH = 2
FRAMERATE = 44100
BASEFREQ = 441
QSIZE = 20000
morsetab = {
'A': '.-', 'a': '.-',
'B': '-...', 'b': '-...',
'C': '-.-.', 'c': '-.-.',
'D': '-..', 'd': '-..',
'E': '.', 'e': '.',
'F': '..-.', 'f': '..-.',
'G': '--.', 'g': '--.',
'H': '....', 'h': '....',
'I': '..', 'i': '..',
'J': '.---', 'j': '.---',
'K': '-.-', 'k': '-.-',
'L': '.-..', 'l': '.-..',
'M': '--', 'm': '--',
'N': '-.', 'n': '-.',
'O': '---', 'o': '---',
'P': '.--.', 'p': '.--.',
'Q': '--.-', 'q': '--.-',
'R': '.-.', 'r': '.-.',
'S': '...', 's': '...',
'T': '-', 't': '-',
'U': '..-', 'u': '..-',
'V': '...-', 'v': '...-',
'W': '.--', 'w': '.--',
'X': '-..-', 'x': '-..-',
'Y': '-.--', 'y': '-.--',
'Z': '--..', 'z': '--..',
'0': '-----',
'1': '.----',
'2': '..---',
'3': '...--',
'4': '....-',
'5': '.....',
'6': '-....',
'7': '--...',
'8': '---..',
'9': '----.',
',': '--..--',
'.': '.-.-.-',
'?': '..--..',
';': '-.-.-.',
':': '---...',
"'": '.----.',
'-': '-....-',
'/': '-..-.',
'(': '-.--.-',
')': '-.--.-',
'_': '..--.-',
' ': ' '
}
# If we play at 44.1 kHz (which we do), then if we produce one sine
# wave in 100 samples, we get a tone of 441 Hz. If we produce two
# sine waves in these 100 samples, we get a tone of 882 Hz. 882 Hz
# appears to be a nice one for playing morse code.
def mkwave(octave):
global sinewave, nowave
sinewave = ''
n = int(FRAMERATE / BASEFREQ)
for i in range(n):
val = int(math.sin(2 * math.pi * i * octave / n) * 0x7fff)
sample = chr((val >> 8) & 255) + chr(val & 255)
sinewave = sinewave + sample[:SAMPWIDTH]
nowave = '\0' * (n*SAMPWIDTH)
mkwave(OCTAVE)
class BufferedAudioDev:
def __init__(self, *args):
import audiodev
self._base = apply(audiodev.AudioDev, args)
self._buffer = []
self._filled = 0
self._addmethods(self._base, self._base.__class__)
def _addmethods(self, inst, cls):
for name in cls.__dict__.keys():
if not hasattr(self, name):
try:
setattr(self, name, getattr(inst, name))
except:
pass
for basecls in cls.__bases__:
self._addmethods(self, inst, basecls)
def writeframesraw(self, frames):
self._buffer.append(frames)
self._filled = self._filled + len(frames)
if self._filled >= QSIZE:
self.flush()
def wait(self):
self.flush()
self._base.wait()
def flush(self):
print 'flush: %d blocks, %d bytes' % (len(self._buffer), self._filled)
if self._buffer:
import string
self._base.writeframes(string.joinfields(self._buffer, ''))
self._buffer = []
self._filled = 0
def main(args = sys.argv[1:]):
import getopt, string
try:
opts, args = getopt.getopt(args, 'o:p:')
except getopt.error:
sys.stderr.write('Usage ' + sys.argv[0] +
' [ -o outfile ] [ args ] ...\n')
sys.exit(1)
dev = None
for o, a in opts:
if o == '-o':
import aifc
dev = aifc.open(a, 'w')
dev.setframerate(FRAMERATE)
dev.setsampwidth(SAMPWIDTH)
dev.setnchannels(1)
if o == '-p':
mkwave(string.atoi(a))
if not dev:
dev = BufferedAudioDev()
dev.setoutrate(FRAMERATE)
dev.setsampwidth(SAMPWIDTH)
dev.setnchannels(1)
dev.close = dev.stop
if args:
line = string.join(args)
else:
line = sys.stdin.readline()
while line:
print line
mline = morse(line)
print mline
play(mline, dev)
if hasattr(dev, 'wait'):
dev.wait()
if not args:
line = sys.stdin.readline()
else:
line = ''
dev.close()
# Convert a string to morse code with \001 between the characters in
# the string.
def morse(line):
res = ''
for c in line:
try:
res = res + morsetab[c] + '\001'
except KeyError:
pass
return res
# Play a line of morse code.
def play(line, dev):
for c in line:
if c == '.':
sine(dev, DOT)
elif c == '-':
sine(dev, DAH)
else:
pause(dev, DAH)
pause(dev, DOT)
def sine(dev, length):
dev.writeframesraw(sinewave*length)
def pause(dev, length):
dev.writeframesraw(nowave*length)
if __name__ == '__main__' or sys.argv[0] == __name__:
main()