#! /usr/bin/env python # # pytronome.py - a simple metronome tool # version 1.1 # Homepage: http://code.google.com/p/eljunior-labs/ # Author: Elias Junior # # Copyright 2007, 2008 Elias Junior # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys, os, re, ossaudiodev, wave from optparse import OptionParser # this import is only needed for embedding wave files import base64, cStringIO # global variables: dsp = None frames1 = frames2 = '\0' max_to_read = 0 def abort(errmsg): sys.stderr.write('Error: ' + errmsg + '\n') sys.exit(1) class Dsp: def __init__(self): self.dsp_handle = None; self.depth = 0 self.channels = 0 self.speed = 0 def init(self, sampwidth, channels, samplerate): dsp_format = sampwidth * 8 if dsp_format not in (ossaudiodev.AFMT_U8, ossaudiodev.AFMT_S16_LE): abort("only 8 and 16 bits per sample are supported") if channels not in (1,2): abort("number of channels must be 1 (mono) or 2 (stereo)") if samplerate < 8000 or samplerate > 96000: abort("samplerate must be between 8000 and 96000") # open the audio device dsp_handle = ossaudiodev.open('w') new_dsp_format = dsp_handle.setfmt(dsp_format) if new_dsp_format != dsp_format: abort("your dsp device does not seem to support format specified") dsp_channels = dsp_handle.channels(channels) if dsp_channels != channels: abort("channels: %d dsp_channels %d" % (channels, dsp_channels)) dsp_speed = dsp_handle.speed(samplerate) if dsp_speed != samplerate: abort("different samplerates: will sound funny! ;)") self.dsp_handle = dsp_handle self.depth = dsp_format/8 self.channels = dsp_channels self.speed = dsp_speed def close(self): if self.dsp_handle: self.dsp_handle.close() def write(self, data): if not self.dsp_handle: abort("dsp not properly initialized") count = len(data) written = self.dsp_handle.write(data) if written != len(data): abort("tried to write %d bytes, only %d written" % (written,count)) def le_waves(): global dsp, frames1, frames2, max_to_read # globals # embedded wave files wav_tac=cStringIO.StringIO(base64.decodestring("""UklGRuAaAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YbwaAADC/5D/fP+v/1//wf8s /33/Of+P/33/X/99/13/r/9d/5H/Xf9e/2r/bP+b/zn/fP9q/03/rf9r/5D/nP9K/5D/av+v/y3/ fP+w/13/nf+P/5H/wP99/53/kP+b/57/j//B/87/nf/C/83/rv/O/8P/4P+v/w4Ar/+v/67/r/9q /7D/j//C/2r/j/+w/53/nP+P/67/kf+v/5z/wv+b/6//nf/C/3z/zv+R/83/z//h/83/wv9r/8H/ Of/g/1//nP/P/5v/rv9s/5z/jv+w/2r/ff+v/3z/nf/N/33/wf9q/33/kP+P/4//bP+O/5z/a/+d /6//av+u/5z/kP+u/17/nP+d/5z/r/9+/4//kf/A/37/af9s/3v/nf+P/5D/a/+Q/5z/fv98/33/ XP8s/5H/Sv+v/5D/fv+w/33/r/98/8L/YP+b/5H/m/8CAJr/AgCb/+H/nv+u/5v/kP+Q/5H/r/+P /8L/ff+c/5D/j/9+/33/m/+e/8H/sP+v//P/j//1/5D/wv+v/6//nf+c/8L/4f/g/wAA8//i/5D/ /v9+/83/sP/N/8//rv/h/5D/4P/i/67/z//h/7D/3//P/+H/wP/P/87/sP///2r/z//B/0r/z/9+ /8//fP+w/87/ff+v/53/4P+w/8D/sP+v/17/nP+P/2r/AQCQ/6//j/9+/67/kf9q/17/m/9e/3z/ DQCw//P/8v8fAA0A9P8AAPT////P/+D/AADh/5H/3/+x/2n/j/9M/0z/OP99/0v/af/i/2r/sP85 /33/av9p/2v/j/+c/5H/r//C/8H/zv/B/8L/a/98/33/sP/B/87/4f/D/87/fP+R/5D/a/9L/zf/ OP9e/0r/ff99/+H/nf/h/67/AAAAAAwAMgAyADIAHwD//wwAwf/h/7D/fP9e/0v/S/9r/0z/j/9d /0z/S/8r/3z/Lf99/5z/rv/0/wAAAQAeAM7/HwDP/wwAsP/N/w4Am//0/8H/sP/C/8H/zv8CAAAA CwAzAM////////T/4v/+/33/z/+c/8L/4f89AM7/PgABAA0A4f+c/wwAnf9RAAwAHwA+AOH/IACb /8H/sP+Q/8L/r/+b/53/m/99/9D/fP/C/67/nf+u/33/nf+b/+L/AAALAA0ADgAfAFIAggCDAIMA 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 TP+P/yz/8/5A/l3+6P2E/j/+tv60/vX+a//g/1EA1ADHAG8AAACd/w0AMQD0/zf/1v7m/vT+Lf8Z /xj/wv6j/qP+ov5e/nH+kf4F/yz/9P6R/qH+pP4G/xn/j/99//P/9P+WAB8AMQAMAJH/wf/g/1MA UQA/AGMAZACUAOcASwHTAaIBrwFuAbYA6ADTAPoAtABkAPT/nf9d/yz/Bf9L/1//kf////T/DAA9 ANYAGAENAccAtADVAPkAGAG1AFEANACUAOcAZQAeADn/X/8F/+j+OP/n/hn/hf5w/qP+Gf9L/+L/ //+R/0v/Gf/n/vT+5/70/hj/Xv9L/wf/LP6W/e38q/x4/Kj8IP2G/V3++/35/bb9Df4//rX+kP6P /tb+Bv+c/5H/OP+1/nH+U/6D/jf/Of+c/xr/Sv8H/xr/N/+c//X/CwBwAGUAlQBwAJYATwABAA0A AAALADMADABxAJUAtQAOAbMA+gBLAdQBwQGOAckAbwDHAF4B5gGiARkBDAE/AXAB8gHzAaIB0wF9 AUwBDAELAWQA9f8G/5D+Pf5y/uf+8/4Z//T+K/8b/0v/1P6Q/kD++v3b/fr9tf4I/6//Of8s/5D+ tP6k/tP+1v7B/vP+g/71/sL+kP4Z/tv9d/1S/an9qP1x/nL+cf5d/l/+Df4//ub9hf2E/bb9LP6Q /qL+8/7o/qP+of6R/vT+j//C/z0AMgA/AHAAHwAzAM3/ZABRAKMAlwAZAT0B+gCiAB4A4v8eAMkA oQANAQwB1QDnAGQAPgDP/5v/rv/O/z4AlgDUAA0BwgGiAdMB0wGuARkCJQIkAqMB5gCXAFAA4f/P /5z/m/9L/0v/Of85/xn/ov6j/kD+cf6Q/sH+6f5J/wEAZACXAFAADgDf/zMA4f8fAA0APQDi/zIA zv+w/+D/bP+v/0r/CP/m/hv/K/9q/87/nP9d/yz/1v4Z/j/+Df4a/l3+X/7n/iv/ff99/37/kP98 /6//AAAyAAsAUgAxAFIA8/+b/yz/1v6E/lH+w/6P/mv/rv9lAAwAMQDg/2UAxwCDAJUAPwBkAIIA yAC1AKIAgwALAFEAnf8yAAwAMgBjAK//av85/yv/nP+R/6//wv+t/0AAogD5ALYAYwBvAIQAyADn AAwBCwG1AMgAlwD6ANMA+wAMARkBXAGhAecBoQFfAcYAUgDC/5v/wv8BAP//IQAxAPP/nf/A/5H/ zv/i////z/8AAFEAAQAeAM7/4P/P/zEAcADz/2UAAADz/5YAZQCVAGMAQACv/2v/kP4s/rX9tv36 /XH+1P6w////ZAANAFAAMQBSAKMAggDVABgBXgFcAQ0BgwAzAJz/PgDh/7QAMwCCAOD/nv9q/wj/ GP9f/+D/4v8NAM3/av9r/wb/CP9L/+H/4f/N//T/nf+Q/0v/8/6i/tX+Lf8AAIMAswCWAMcA1AC1 AJcAbwAgAB8Azv/h/5z/4f/O/8L/AABq/2r/nP9M/8H/a/99/+D/kP9jAOH/DAAyAOH/DgAeAOL/ 8/9r/0z/wv7U/uf+S/+w/zIAtQDUAMcA1QCVAIQAgwBwAGQAcAC1AIIA6ABvAOH/j//0/jn/8/44 /zn/Xv/N/wEA4P/g/17/TP9q/2v/jv8hAG8A1AC1AGQAm/+d/2r/fv/C/+H/HQD0/3AAIADO/yz/ 5v63/uf+Gf9e/4//z/8xAIMAPwA9AAIAXv83/wj/wf4a/xn/TP/z/iz/K/+2/lL+LP4//vv9Xf7D /vP+Sv+Q/53/fv9L/zf/Xv8s/yz/Of8r/zn/9P44/2v/Gf8H/8H+Uf4t/nD+pP45/4//4P/C/8L/ X/8G/zf/TP85/xj/Tf9d/8P/jv9s/13/LP+v/83/ZABwAHAAMQAfAOH/sP+u/yEACwCFAFEAMgAx AOP/AAAyAP//IAAeAHIAogBPAAEAw/8Y//T+6P7W/l7/K/9q/17/Gf8I/6L+1P6E/uj+fP9r/w0A zf/0/0z/Xf84/0z/OP83/2r/TP9M/8D+tf63/gX/ff+Q/+H/nP+w/0v/Bv+k/gz+hf6i/gf/nP99 /67/Gf+R/l7+qP0//oX+Kv8u/47/r/85/47/B/8I/+f+j/7m/iz/nf/N/3IA//8NACAADADz/wwA AADB/7D/8/4G/wf/8/4a/yz/Sv8r/7H/m/8+AD8AHwDz/x8AHwC0AKMAtQAgAAAAzv///5z/MgDP /x8AZABxAIMAbwCDAAwB+QCiALYAAAANAH3/OP/W/gb/LP8G/xj/S/8t/5v/kf99/5H/af/D/x8A 8/8fAOL/wf/D/67/sP83/33/9P7V/sH+1v4s/nH+Pv5y/tT+6P5d/5v/sf/N/53/DQAwAB8A9f98 /zj/6f4H/8H+S/9p/5z/w//C/8D/rv/0/wEAMQCDAJYAowD4AJUA+gAfAAEAav/D/8L/zf8hAN// z/+d/5z/S/8s/0v/Lf/A/wEA9P9QAAEAHwBL/7D/nf9d/8//wf9q/xn/1f6j/sH+CP99/wsAZQAx AAIAnP+P/8L/fP/1/x4APwCiAIMAhAC0AGQA8//C//T/bwCWANUAgwBjADEA0P/0/67/rv8OAHAA ggDnANQAlQCDAJ3/ff+1/iz/B/8F//T+B/8G/yz/Gv+c/8L/rf8NAOD/UgAeAJcAgwBQAHIAHgAx ADMADQALAAAAnf+v//T/zv9e/5z/YP8q/9X+wv7o/sL+9P7V/iz/Xf98/8//IAALAA4ADAAeACEA zv+c/4//Xv99/0v/ff/C/63/IQAeADIAQAA9AOH/AADO//X/PgAAAML/4P/i/8H/zv8G/yz/Bv84 /8L/DAAzAIIAcQCiAA4A9P/B//P/9P8eAM7/MwD//8L/av/o/sL+tv62/rT+Xv84/2r/Tf8H/8L+ Bv/n/vX+Bf/o/jn/j//0/wEADAAxAPP/ff99/5H+tv6R/iz+tP5x/gb/1v45/8L+P/5d/l7+t/4q /2r/1v4s/13+hP4a/oP+5/5+/zAAgwAsAQwBLAHIAFAAsP/N/5z/nf/N/+H/4f/C/3z/a/8Z/5D/ r/8xAKEAgwANAWQAUAAMAH7/z//B//P/MQDQ/w0AXf+P/1//nP8eAPX/owCiAD0AUgDh/83/nv+O /1//wv+b/8//a/9p/y3/5v7o/qL+G/8r/wf/GP/V/oP+ov5f/sL+o/44/5D/rv9e/0v/Of+P/5z/ X/98/zn/Xv9+/13/Gv9R/oT+Gv49/oT+cP5x/un+1P4r/xn/j/9f//P+Gf+R/rb+wv6h/i3/9P6d /0v/nP8AAGv/kP/0/uf+8/5f////cgCDAJUA7//s/9T/6P/g/w4AEQBFADIAPgAyANP/6P+7/8H/ 8/8bAFcAfACcAJ0AewCWAIoAgwBvAF4ALAAyAAwABgATAPP/AAD6/zgAVgBZAFAALQArADEARgA2 AF8AIAA2AC0AHwAyACsAGgAZAAUABwD6/9r/vP/P/6//5v/o/wYAHwABABgABgAAAPr/+/8mADEA MgD0/9r/tP9+/3f/Xv9v/5D/pP+v/9T/5////wYA1P/c/8j/7f/s/+L/+v/n////GgA3ACYAMwD5 /+3/r//g/87/4f/7/w0APwA+AF8APwAqADMAWAA4AGQARQBRAEQAWAA4ABMA8//U//T/5v8AADMA UQBdAHcAXQCLAF4AUABGAEoAXgB2AHcAagBFACwAPQATABoA5v/O/+L/BwBJAFgAZABLACoAFAAT AOz/AADt/+H/EQABAF0AGgBEABIA2v/n/+7/AAAfACUAJgAaAAwADADa/+n/zv/6/9//9P8BAOf/ DAAGABMA///n//T/9f/y/0YASgBAADcALAAzABgAAADW/8D/qf/U/+3/BgAHAPP/5/+8/6L/ov9Z /33/ff+J/7X/wf+v/5z/lv+V/5D/j/+8/7z/2v8HAOf/4f+c/6H/i/+h/9X/2/8FABoAHwAxAB8A HgD1/9r/1P/J/+L/zf/P/8H/tP+v/4r/kP+i/9r/9P/u/wAA7f8AAAYAIABWAFIAPgA4ABMA7v/v /9r/2/+6/87/1P/h/+7/9P/m/8H/qf+2/7X/tP+v/7X/r//J/9X/1P///wAA+v/o/83/6P+6//T/ 7v/5/+3/yP/H/6n/tv+h/7D/x/+1/+3/4v8MAAEA4P/i/7T/yP+8/7v/qP+p/4T/dv9e/0v/Xv98 /2v/dv99/3b/pP+V/5z/ov+w/4//1f/O/9P/2//m/8n/u/+i/7X/lv+1/7T/qf+2/4n/tv+C/5b/ ff98/5H/lf+1/+H/1P/H/+L/tf/H/7v/pP/U/8D/7v/u/9T/zv/b/9z/4P/h//P/""")) wav_tic=cStringIO.StringIO(base64.decodestring("""UklGRugXAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YcQXAADn/9X/zv/h/8H/5/+w /87/tf/V/83/w//N/8L/4f/D/9P/wv/B/8j/yv/Z/7b/z//H/7v/4f/I/9T/3P+6/9X/x//h/67/ z//g/8L/2//V/9P/6f/N/9r/1f/c/9v/0//m/+3/2//m/+7/4v/t/+f/8v/h/wYA4v/g/+H/4f/H /+L/1f/n/8f/0//i/9r/2v/V/+D/1f/i/9r/5v/a/+L/2f/o/8//7f/U/+7/7P/0/+z/6P/I/+j/ tP/z/8P/2//s/9z/4P/H/9v/1P/i/8f/zv/g/87/2//u/87/5//J/8z/1P/V/9X/yP/U/9r/x//b /+D/yP/h/9v/1P/h/8P/2f/c/9n/4v/N/9b/0//o/83/yP/J/87/2v/V/9T/yP/T/9v/z//N/87/ wv+v/9X/u//h/9P/zv/i/83/4v/N/+n/wP/c/9P/2v8CANr////b//T/3P/h/9r/1f/U/9T/4f/T /+j/z//a/9b/1P/P/87/2v/Z/+j/4f/h//r/1P/6/9T/5//h/+D/2v/a/+j/9P/y/wEA+f/0/9T/ AQDN/+3/4f/t/+7/4P/0/9T/9P/y/+H/7v/y/+L/9P/u//P/5//u/+z/4P8BAMj/7v/m/7z/7f/O /+3/z//g/+7/zf/i/9v/8//h/+b/4P/i/8L/2//U/8n////W/+D/1P/N/+H/0//I/8P/2v/A/87/ BwDh//r/+v8MAAcA+f8AAPn/AgDr//X////z/9X/9f/h/8j/1P+6/73/tf/P/7z/yP/z/8f/4v+1 /87/yf/I/8j/1P/b/9T/4f/o/+b/7f/o/+b/x//O/8//4f/m/+7/8//o/+3/zf/U/9X/x/+7/7b/ tf/D/7v/zv/P//P/2v/z/+H/AQAAAAYAEgATABMADgD//wYA5//z/+H/z//B/7v/vP/I/7v/1P/D /7v/u/+u/8//r//P/9r/4f/6/wEAAAANAOz/DgDs/wcA4P/v/wYA2v/5/+n/4f/m/+j/7v////// BwATAOz/AAABAPr/9P8AAM3/7f/b/+j/9P8ZAO3/GAABAAYA8//b/wYA2v8gAAUADAAaAPP/DQDb /+b/4v/T/+f/4v/Z/9v/2v/P/+z/zv/o/+D/3P/h/83/2//c//P/AAAFAAYABgANAB4AMwAyADIA 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 ZQEwASEB2QCcAGQAXwC6AFEBrwHaAcEBigHGATkCuQL0AuYCbwLzAVYBtQAUAJX/Of8Z/xn/Pv+E /67/7f8sAHYArgDTAAcB8wAGAacAnQBKAPT/fP8m/y3/wv8FAD8A8/9r/z7/Rv99/3H/lv9p/7D/ zf8mABkA4f9Q/+7++v6D/1cA7QAaAd8AWADV/3b/a/+D/9T/DQAyAGoAcABAALX/Y/8T/yD/Uf/O /1IADAF2ATgBtQCp/x//sP7G/or+hP53/sP+H//h/14AhAB1AFEAUQB8AJYAzgDbANoA7QC2AHYA UQAZAPP/8/+j/6j/cv+C/6r/wf/t/xoAVgCpAM0A7QAUATEBQwFGAUMBcQGiAbQBUgHgAKkAcQCD AOD/tf+J/8P/yP/B/67/nv+h/6n/qv+7/7X/yP/J/5b/av8+/1//Sv9q/zP/4f7o/vn+Xf+X/3H/ H//a/uH+w/7t/g3/E/9E/0D/OP8M/xn/Zf+J/5z/zf+d/6n/p//V/zIAJwAxAB8AJgBdALUA3AAk AVgBdgFkAVwBHwHVAGQAKwAFAPn/MwANAOz/vf+v/6f/nf+C/37/ov/m/73/zf+X/3b/a/98/33/ b/+p/83/5/8HAFcAZAAmAKP/GP8C/wD/gv/D/+H/5v+p/7b/ov/J/83/wf+j/8j/PwDtAI8BggEs AacAdgBGABkA2v/W/9v/0//n/8j/zv/b/7v/sP9D/w7/Bv8T/3L/Yv+L/2T/cP99/3z/tf+K/2// ff9r/4v/lf99/0X/IP8G/wD/Rv+K/67/5v+x/8H/tP/J/7X/wv/z/wYAIADI/8f/4v8eAF0AUQBA AFgAoQDPANkArgBqAD8ABwALABMALABSACoAFAD0/8b/9P/g//X/4P/B/7b/tv+v/6f/bP9X/0v/ eP/H//P/DgDS/7b/lv+v/7z/tv+z/4r/dv93/2T/g/99/2v/Jv8B//P+Bv8M/0b/RP9x/7b/u//J /8z/+/8gAD4AJgAMAO3/+f8ZACwAFADg/8L/lv+p/4T/TP8//w3/Vv+v/xMAEwDh/4P/Pv8z/1f/ kP/m/2UALABLAO3/5//t//r/DAABAO3/BgBFAHcAnACJAFYAPwBrAJAAlACEADcAAQDh/9T/9P/b /yQA+v8ZABIAOADo/wcA7f/Z/+j/8/8HAAAAMQAsAAAA4P/h/wYAEwAHAAAA///u/wAA2v/n/73/ uv/V/6//nP9Y/2P/Of9x/1f/g/+E/5z/x//0/yAAUgBKACwA/v/c/wUAEwD7/7X/jv+W/53/r/+o /6n/if9+/3z/ff9k/2z/df+k/6//nP92/33/ff+j/6n/1P/N//r/+/84AAsAFQAGANX/5//0/x0A HwAaACUAJgA5AFYAfgCvAJsAogCJAEUAVwBSAF0ARQAkAPr/2//D/67/o/+7/8D/1v8AAPr/BgAY AFIAagBjAEsARABTAFwAagBFAB4AEwA5AFYAJgAMALX/wv+k/5X/tf+W/6j/cv9p/3//qP+8//P/ AADU/7z/qP+W/5z/l/+c/6n/wf+9/6P/UP8Z/93+wf6w/sH+7v4T/2X/Pv8//yT/Rv9X/4P/eP92 /4//o//c/9T/tP+D/2r/X/9v/7b/tv/Z/6n/vf+h/6j/t//a//r/BwAqACYAOQArADcAIQD//wcA //8GABQABQAsADkARQBjAEQAXwB7AK8AqQCVAEsALABKAIQAtQCbAGoAZAB2AIoAvAC7AJoArwCR AHwAZABiACcA+v+i/3f/WP9q/5f/nP+o/5z/sP+o/7v/j/93/1n/P/8y/z7/hP+h/+L/tP+x/3b/ gv99/5H/kP+K/5z/cf+c/4r/d/9K/zL/Dv8B/x7/If9q/2r/af9l/2T/Rf9X/zn/E/8T/yf/Uv91 /37/nP+W/37/fP93/53/1f/n/xoAEQAZACsADQAUAO3/JQAgAD4ANwBrAHYAXwA9AA0A8/8NAEsA PwBjAGQAUABXACUAGQDu/9v/4f/u/xkANwBQAGQAqQCcAK4AsAChAMkAzADOAJ0AVwA3AB8A9P/u /9v/2/+6/7z/tv+1/6n/fP9//1b/a/93/4r/lf+8//7/JwA4AB8ABwDy/xQA8/8MAAcAGAD1/xMA 7P/i//L/yf/g/7v/ov+W/6j/r//J/+z/2//B/7D/j/9M/1j/RP9L/2T/Zf+W/67/zv/O/87/0//P /+D/AQASAAUAHwAUACAA+f/c/67/kf9v/1//iv92/8f/4v8lAAcAEgD1/yYASgAyADkAGQAmADEA SwBGAD4AMgAGAB8A2/8TAAcAEgAlAOL/yP+1/63/3P/V/+D/6P/g/xgAPwBeAEUAJQArADIASwBY AGQAYwBGAEoAOQBdAFEAXgBjAGsAggCdALYAmgCDAEwAHgDp/9r/5/8AAP//DQASAPv/2v/o/9T/ 7f/0////7f///yAA//8NAO3/9P/t/xIALAD7/yUA///7/zgAJgA4ACUAGQDh/8j/d/9Q/yf/Jf8/ /2v/j//g/wEAJgAGACAAEgAgAD0AMgBRAGsAgwCDAGQAMQAUANr/GAD1/0QAFAAxAPX/2v/J/6P/ p//C//T/8/8HAO3/yP/I/6L/o/+8//P/8//t//n/2//V/7v/nf97/5D/r/8AADIARQA3AEwAUQBF ADgALAANAAwA7v/z/9r/9P/t/+j////J/8j/2v+8/+b/yP/N//P/1f8nAPL/BwASAPT/BwANAPP/ +f/I/7z/if+Q/5b/u//h/xIARQBSAEoAUQA4ADIAMQAsACUALABEADIAWAArAPP/1f+d/7T/nf+0 /7T/wv/u////9f/y/8P/uv/I/8j/1f8LACwAUQBFACYA2//Z/8n/zv/o//T/DAD5/y0ADADt/6// lf+E/5X/qf/C/9L/7/8TADAAGgAYAAEAwf+2/6L/if+o/6n/u/+c/6//sP+C/1//UP9X/z//Zf+K /5z/uv/U/9v/zv+8/7T/wv+v/67/tv+v/7X/nP+0/8n/qP+j/4r/Xf9Q/2r/ff+3/9T/8//o/+f/ wf+k/7T/vP+z/6r/u//C/+f/0//J/8L/r//g/+3/JgAtACsAFAALAPX/4f/h/wsACAAyAB8AEgAT APL/AQATAP7/DQANACoAPgAgAAEA5/+o/5z/lv+P/8P/r//I/8L/qf+i/37/kP9w/5b/z//H/wYA 7v/6/7r/wv+2/7z/s/+1/8n/uv+7/4n/g/+D/6T/zv/U//X/2f/i/7r/o/99/0X/cP99/6P/2v/N /+H/qv91/2b/Hv9Y/3L/rv+v/9X/4f+1/9P/o/+k/5X/eP+V/6//2//t/ywA//8GAAwACAD5/wYA AADm/+L/nP+h/6L/nv+o/67/vP+v/+H/2v8ZABgADQD6/w0ADABEAD4ARQANAAAA7f8AANv/EwDs /w0AJQArADIALAAyAGQAXQA+AEYA//8GAM7/tP+Q/6T/rv+j/6j/vP+u/9z/1f/N/9T/yf/m/w4A +f8NAPL/5//o/+H/4P+2/87/nP+P/4v/j/9S/2r/V/9s/4//l//C/9n/4f/v/9r/BgAUAAwA+f/O /7T/lv+k/4n/uv/H/9v/6P/m/+f/4f/7////EgAzADgAPwBdADkAXgALAAEAxv/o/+j/7f8MAPT/ 7f/b/9n/vP+w/7r/r//n/wAA+/8gAP//DQC6/+H/2v/C/+7/5v/J/6n/jv9+/4j/pP/O/wUAJgAS AAEA2f/V/+f/zv/7/wsAGQA+ADIAMgBEACYA+//n//n/KgA6AFEAMQAlABQA7f/5/+L/4f8FACwA MwBXAFEAOAAyANn/zv+D/6//o/+j/5z/o/+h/7D/qP/c/+b/4v8GAPL/IQAMADgAMwAgACsADAAT ABMABgAGAAAA2v/j//j/7v/B/9v/wv+v/5H/if+V/4n/nf+Q/67/w//O/+z/DgAGAAYABQANAA0A 7f/a/9X/wP/Q/7r/zv/p/9//DQAMABMAGgAZAPT/AADt//v/GAAAAOf/8//z/+f/7v+h/7D/of+1 /+f/BwATADEALAA/AAUA+v/o//j/+v8MAO7/EwAAAOf/xv+W/4n/g/+F/4P/wf+1/8f/vf+h/4r/ o/+V/53/o/+W/7T/1P/6/wAABwATAPv/zv/N/3f/g/94/1L/g/9q/6H/kP+3/4j/V/9l/2T/gv+w /8j/j/+v/2X/b/9L/3H/lf/O/xMAMQBxAGIAcABLAB4A4f/u/9v/2v/u//T/9P/n/87/xv+p/9X/ 4f8SAD4AMgBlACUAHwAGAND/7f/m//r/EwDu/wUAw//V/8H/2f8NAPr/PQBAABcAIAD0/+z/2//V /8H/6f/a/+3/x//K/67/lv+V/37/qf+u/6T/qP+Q/3D/fv9k/4r/ff+1/9P/4f/D/7r/tv/V/9v/ wf/P/7X/wv/P/8D/qf9d/3H/Tf9X/3D/av9q/5f/j/+u/6r/1f/C/5v/qv93/4T/if99/6//nf/b /7v/2v///8n/0/+d/5b/nP/D////KwAzADcA7v8=""")) try: w1 = wave.open(wav_tac,'r') except: abort("error trying to open tac.wav") try: w2 = wave.open(wav_tic,'r') except: abort("error trying to open tic.wav") dsp = Dsp() # initialize dsp dsp.init(w1.getsampwidth(), w1.getnchannels(), w1.getframerate()) max_to_read = dsp.depth * dsp.channels * dsp.speed / 2 frames1 = w1.readframes(max_to_read) frames2 = w2.readframes(max_to_read) # some checks... # check sampler width and number of channels if w1.getsampwidth() != w2.getsampwidth(): abort("both wave files must have the same sampler width") if w1.getnchannels() != w2.getnchannels(): abort("both wave files must have the same number of channels") # read and checks done, may close waves now w1.close() w2.close() # check length of frames if len(frames1) < 10: abort("w1 too short") if len(frames2) < 10: abort("w2 too short") # This is the most interesting function: # this is where goes the code for the samples manipulation, # and the program playing (as the name already told you ;) def play_program(program): global dsp, frames1, frames2, max_to_read # globals! we know you love them! if len(program) == 0: program = [['4/4', 120, 0]] # safety defaults depth_chan = dsp.depth * dsp.channels prog_count = 0 try: try: while prog_count < len(program): (meter, tempo, count) = program[prog_count] meter = [int(elem) for elem in meter.split('/')] dsp_patt_len = max_to_read * 120 / tempo if dsp_patt_len % depth_chan != 0: # adjust pattern length dsp_patt_len += depth_chan - dsp_patt_len % depth_chan # XXX: Time for some poor ad hoc string manipulation! # The problem here is that the method write() of an # ossaudiodev Audio Device doesn't accept a parameter for # how many bytes it should send, so we have to build # a string in the right size. Ugly, but works, and seems # to be unobstrusive. Let me know if you find a better way. if len(frames1) < dsp_patt_len: frames1 += '\0' * (dsp_patt_len - len(frames1)) # pads... else: frames1 = frames1[0:dsp_patt_len] # or slices if len(frames2) < dsp_patt_len: frames2 += '\0' * (dsp_patt_len - len(frames2)) # pads... else: frames2 = frames2[0:dsp_patt_len] # or slices (again!) infinite = False if count == 0: infinite = True while infinite or count > 0: dsp.write(frames1) # tic for i in range(meter[0]-1): dsp.write(frames2) # tac tac ... count -= 1 prog_count += 1 except: print 'Exiting...' finally: dsp.close() def parse_program_file(filename): program=[] try: try: f = open(filename) i = 0 for line in f: i += 1 # skip comments and blank lines if re.compile(r'^\s*(#.*)?$').match(line): continue # check syntax patt = re.compile(r'^\s*(\d\d?/\d\d?)\s+(\d+)(\s+\d+)?\s*$') m = patt.match(line) if not m: abort('Program file has error in line: %d' % i) count = m.group(3) if not count: count = 0 program.append([m.group(1), int(m.group(2)), int(count)]) except: abort("problem dealing with input file: %s" % filename) finally: f.close() return program def parse_options(): parser = OptionParser(version="%prog 1.1") parser.add_option("-m", "--meter", dest="meter", default="4/4", help="define meter signature default: 4/4") parser.add_option("-t", "--tempo", dest="tempo", default="120", help="beats per minute default: 120") parser.add_option("-n", "--measures", dest="count", default="0", help="play just NUMBER measures then exit", metavar="NUMBER") parser.add_option("-p", "--program-file", dest="prog_file", default=None, help="play only the scripted in FILE", metavar="FILE") (options, args) = parser.parse_args() # do some basic checks... if options.prog_file: if not os.access(options.prog_file, os.F_OK | os.R_OK): abort("not possible to access file %s", options.prog_file) if not re.compile("^[0-9][0-9]?/[0-9][0-9]?$").match(options.meter): abort("meter must be in form NUMBER/NUMBER e.g.: 3/4, 4/4 ...") try: options.tempo = int(options.tempo) if options.tempo < 40 or options.tempo > 240: raise Exception('TempoOutOfRange') except: abort("tempo must be a NUMBER, between 40 and 240") try: options.count = int(options.count) except: abort("NUMBER must be a number (duh!)") return options if __name__ == '__main__': options = parse_options() le_waves() program = [] if options.prog_file: # if given, read a program file program = parse_program_file(options.prog_file) if not program: program = [[options.meter, options.tempo, options.count]] print 'Hit Ctrl+C to stop' play_program(program)