/Mac/Demo/sound/morse.py

http://unladen-swallow.googlecode.com/ · Python · 180 lines · 162 code · 11 blank · 7 comment · 28 complexity · 5ac3016d94cfc93f5f8f4709151de651 MD5 · raw file

  1. import sys, math
  2. DOT = 30
  3. DAH = 80
  4. OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ...
  5. SAMPWIDTH = 2
  6. FRAMERATE = 44100
  7. BASEFREQ = 441
  8. QSIZE = 20000
  9. morsetab = {
  10. 'A': '.-', 'a': '.-',
  11. 'B': '-...', 'b': '-...',
  12. 'C': '-.-.', 'c': '-.-.',
  13. 'D': '-..', 'd': '-..',
  14. 'E': '.', 'e': '.',
  15. 'F': '..-.', 'f': '..-.',
  16. 'G': '--.', 'g': '--.',
  17. 'H': '....', 'h': '....',
  18. 'I': '..', 'i': '..',
  19. 'J': '.---', 'j': '.---',
  20. 'K': '-.-', 'k': '-.-',
  21. 'L': '.-..', 'l': '.-..',
  22. 'M': '--', 'm': '--',
  23. 'N': '-.', 'n': '-.',
  24. 'O': '---', 'o': '---',
  25. 'P': '.--.', 'p': '.--.',
  26. 'Q': '--.-', 'q': '--.-',
  27. 'R': '.-.', 'r': '.-.',
  28. 'S': '...', 's': '...',
  29. 'T': '-', 't': '-',
  30. 'U': '..-', 'u': '..-',
  31. 'V': '...-', 'v': '...-',
  32. 'W': '.--', 'w': '.--',
  33. 'X': '-..-', 'x': '-..-',
  34. 'Y': '-.--', 'y': '-.--',
  35. 'Z': '--..', 'z': '--..',
  36. '0': '-----',
  37. '1': '.----',
  38. '2': '..---',
  39. '3': '...--',
  40. '4': '....-',
  41. '5': '.....',
  42. '6': '-....',
  43. '7': '--...',
  44. '8': '---..',
  45. '9': '----.',
  46. ',': '--..--',
  47. '.': '.-.-.-',
  48. '?': '..--..',
  49. ';': '-.-.-.',
  50. ':': '---...',
  51. "'": '.----.',
  52. '-': '-....-',
  53. '/': '-..-.',
  54. '(': '-.--.-',
  55. ')': '-.--.-',
  56. '_': '..--.-',
  57. ' ': ' '
  58. }
  59. # If we play at 44.1 kHz (which we do), then if we produce one sine
  60. # wave in 100 samples, we get a tone of 441 Hz. If we produce two
  61. # sine waves in these 100 samples, we get a tone of 882 Hz. 882 Hz
  62. # appears to be a nice one for playing morse code.
  63. def mkwave(octave):
  64. global sinewave, nowave
  65. sinewave = ''
  66. n = int(FRAMERATE / BASEFREQ)
  67. for i in range(n):
  68. val = int(math.sin(2 * math.pi * i * octave / n) * 0x7fff)
  69. sample = chr((val >> 8) & 255) + chr(val & 255)
  70. sinewave = sinewave + sample[:SAMPWIDTH]
  71. nowave = '\0' * (n*SAMPWIDTH)
  72. mkwave(OCTAVE)
  73. class BufferedAudioDev:
  74. def __init__(self, *args):
  75. import audiodev
  76. self._base = apply(audiodev.AudioDev, args)
  77. self._buffer = []
  78. self._filled = 0
  79. self._addmethods(self._base, self._base.__class__)
  80. def _addmethods(self, inst, cls):
  81. for name in cls.__dict__.keys():
  82. if not hasattr(self, name):
  83. try:
  84. setattr(self, name, getattr(inst, name))
  85. except:
  86. pass
  87. for basecls in cls.__bases__:
  88. self._addmethods(self, inst, basecls)
  89. def writeframesraw(self, frames):
  90. self._buffer.append(frames)
  91. self._filled = self._filled + len(frames)
  92. if self._filled >= QSIZE:
  93. self.flush()
  94. def wait(self):
  95. self.flush()
  96. self._base.wait()
  97. def flush(self):
  98. print 'flush: %d blocks, %d bytes' % (len(self._buffer), self._filled)
  99. if self._buffer:
  100. import string
  101. self._base.writeframes(string.joinfields(self._buffer, ''))
  102. self._buffer = []
  103. self._filled = 0
  104. def main(args = sys.argv[1:]):
  105. import getopt, string
  106. try:
  107. opts, args = getopt.getopt(args, 'o:p:')
  108. except getopt.error:
  109. sys.stderr.write('Usage ' + sys.argv[0] +
  110. ' [ -o outfile ] [ args ] ...\n')
  111. sys.exit(1)
  112. dev = None
  113. for o, a in opts:
  114. if o == '-o':
  115. import aifc
  116. dev = aifc.open(a, 'w')
  117. dev.setframerate(FRAMERATE)
  118. dev.setsampwidth(SAMPWIDTH)
  119. dev.setnchannels(1)
  120. if o == '-p':
  121. mkwave(string.atoi(a))
  122. if not dev:
  123. dev = BufferedAudioDev()
  124. dev.setoutrate(FRAMERATE)
  125. dev.setsampwidth(SAMPWIDTH)
  126. dev.setnchannels(1)
  127. dev.close = dev.stop
  128. if args:
  129. line = string.join(args)
  130. else:
  131. line = sys.stdin.readline()
  132. while line:
  133. print line
  134. mline = morse(line)
  135. print mline
  136. play(mline, dev)
  137. if hasattr(dev, 'wait'):
  138. dev.wait()
  139. if not args:
  140. line = sys.stdin.readline()
  141. else:
  142. line = ''
  143. dev.close()
  144. # Convert a string to morse code with \001 between the characters in
  145. # the string.
  146. def morse(line):
  147. res = ''
  148. for c in line:
  149. try:
  150. res = res + morsetab[c] + '\001'
  151. except KeyError:
  152. pass
  153. return res
  154. # Play a line of morse code.
  155. def play(line, dev):
  156. for c in line:
  157. if c == '.':
  158. sine(dev, DOT)
  159. elif c == '-':
  160. sine(dev, DAH)
  161. else:
  162. pause(dev, DAH)
  163. pause(dev, DOT)
  164. def sine(dev, length):
  165. dev.writeframesraw(sinewave*length)
  166. def pause(dev, length):
  167. dev.writeframesraw(nowave*length)
  168. if __name__ == '__main__' or sys.argv[0] == __name__:
  169. main()