#!/usr/bin/python """ play a rtttl file by sending the tone lengths to the arduino protocol information taken from http://merwin.bespin.org/t4a/specs/nokia_rtttl.txt """ from __future__ import division import re import serial import struct import sys import time BAUDRATE = 9600 PAUSE = .001 _rtttl_re = re.compile('^\s*([0-9]+)?([a-hp]#?)(\.?)([0-9]?)\s*$') freqs = { 'c': 261.626, 'c#': 277.183, 'd': 293.665, 'd#': 311.127, 'e': 329.628, 'f': 349.228, 'f#': 369.994, 'g': 391.995, 'g#': 415.305, 'a': 440.000, 'a#': 466.164, 'b': 493.883, 'h': 493.883, 'p': 0, } def parse_defaults(s): defaults = { 'd': 4, # duration 'o': 6, # octave 'b': 63, # beats per minute } if s == '': return defaults for option in s.split(','): k,v = option.split('=') defaults[k] = v return defaults def parse(s): name, defs, music = s.split(':') defaults = parse_defaults(defs) defaultlength = int(defaults['d']) defaultoctave = int(defaults['o']) timefactor = 60/int(defaults['b']) # for m in _rtttl_re.finditer(music): for tone in music.split(","): m = _rtttl_re.match(tone) if not m: print("Didn't match:", tone) continue l, t, ld, o = m.groups() if l: length = 1/int(l) else: length = 1/defaultlength if ld: length = length * 1.5 length = length*timefactor tone = freqs[t.lower()] if o: octave = o else: octave = defaultoctave tone = tone * 2**(int(octave) - 4) yield (length, tone) def send(sounds, device): ser = serial.Serial(device, BAUDRATE) try: for length, freq in sounds: sys.stderr.write('len: %.3f, ton: %9.3f, send: %d' % (length, freq, freq2t(freq))) ser.write(struct.pack('>H', freq2t(freq))) time.sleep(length) sys.stderr.write('\n') ser.write('\0\0') time.sleep(PAUSE) finally: ser.write('\0\0') ser.close() def freq2t(freq): if freq == 0: return 0 return 2000000/freq if __name__ == '__main__': if len(sys.argv) > 1: if sys.argv[1] == '-d': for length, freq in parse(sys.stdin.read()): print 'len: %.3f, ton: %9.3f' % (length, freq) else: send(parse(sys.stdin.read()), sys.argv[1]) else: print >>sys.stderr, "Usage: %s -d|/dev/ttyUSBx" % sys.argv[0]