thinksaber/thinksaber.py

198 lines
6.4 KiB
Python

#!/usr/bin/env python
# -*- python -*-
#
# Thinksaber - Turn your Lenovo Thinkpad into a Jedi weapon!
# Copyright (C) 2008 Elf M. Sternberg (elf.sternberg@gmail.com)
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U
__program__ = "thinksaber.py"
__author__ = "Elf M. Sternberg"
__version__ = "0.3"
import os
import re
import sys
import math
import getopt
import pygame
import random
import string
# global constants
FREQ = 44100
BITSIZE = -16
CHANNELS = 2
BUFFER = 1024
FRAMERATE = 30
def stddev(ar):
sumto = sum(ar)
sumsq = sum([i*i for i in ar])
return (math.sqrt((len(ar) * sumsq) - (sumto * sumto)) /
(len(ar)*(len(ar) - 1)))
class Thinksaber:
def __init__(self, opts = {}):
self.options = {'swing': 2.0,
'strike': 4.5,
'hit': 6.0,
'path': '.'}
self.options.update(opts)
self.foundsound = [i for i in os.listdir(self.options['path'])
if i[-4:] in ['.wav', '.mp3']]
def play(self):
try:
pygame.init()
pygame.joystick.init()
pygame.mixer.init(FREQ, BITSIZE, CHANNELS, BUFFER)
except pygame.error, exc:
raise RuntimeError, "Could not initialize sound system: %s" % exc
def gs(m):
r = [pygame.mixer.Sound(os.path.normpath(
os.path.join(self.options['path'], i)))
for i in self.foundsound
if re.match(m + r'\d+\.\w{3}$', i)]
if len(r) < 1:
raise RuntimeError, "Did not find files for %s sounds." % m
return r
sounds = dict([(i, gs(i)) for i in
['start', 'on', 'off', 'idle',
'swing', 'strike', 'hit']])
def find_joy():
for i in xrange(0, pygame.joystick.get_count()):
joy = pygame.joystick.Joystick(i)
if joy.get_name().find('HDAPS joystick') != -1:
return joy
if joy.get_name().find('applesmc') != -1:
return joy
raise RuntimeError, "Did not find HDAPS joystick!"
hdaps = find_joy()
hdaps.init()
queue = {'x': [hdaps.get_axis(0) for i in xrange(0, 8)],
'y': [hdaps.get_axis(1) for i in xrange(0, 8)]}
prev = 0
up = True
def psound(i):
sounds[i][random.randint(0, len(sounds[i]) - 1)].play()
try:
clock = pygame.time.Clock()
sounds['on'][0].play()
while pygame.mixer.get_busy():
clock.tick(FRAMERATE)
idle_channel = pygame.mixer.Channel(0)
idle_channel.set_endevent(pygame.constants.USEREVENT)
idle_channel.play(sounds['idle'][0])
while 1:
event = pygame.event.wait()
if event.type == idle_channel.get_endevent():
idle_channel.play(sounds['idle'][0])
if event.type == pygame.JOYAXISMOTION:
[queue[i].pop(0) for i in queue.keys()]
queue['x'].append(hdaps.get_axis(0) * 100)
queue['y'].append(hdaps.get_axis(1) * 100)
val = max(stddev(queue['x']), stddev(queue['y']))
if (up):
if (val > prev):
prev = val
continue
if (val > self.options['hit']):
psound('hit')
elif (val > self.options['strike']):
psound('strike')
elif (val > self.options['swing']):
psound('swing')
up = False
continue
if (val > prev):
prev = val
up = True
continue
prev = val
except KeyboardInterrupt:
idle_channel.stop()
sounds['off'][0].play()
while pygame.mixer.get_busy():
clock.tick(FRAMERATE)
return 0
def usage(showall = True):
o = ('-s, --swing=NUMBER Threshold at which a "swing" sound occurs.',
'-t, --strike=NUMBER Threshold at which a "strike" sound occurs.',
'-h, --hit=NUMBER Threshold at which a "hit" sound occurs.',
'-u, --usage This help.',
'-v, --version Version information',
'',
'Thresholds are floating point numbers. The highter the number, ',
'the harder you have to swing the laptop to get a sound effect. ',
'Meaningful values are somewhere between 1.0 and 9.0',
'')
print 'Thinksaber version %s' % __version__
if showall:
print string.join(o, '\n')
if __name__ == '__main__':
tsopts = {}
opts, args = getopt.getopt(sys.argv[1:], "p:s:t:h:uv",
["path=", "swing=", "strike=", "hit=", "usage", "version"])
for o, a in opts:
if o in ('-p', '--path'):
if not os.path.isdir(a):
raise RuntimeError, '%s is not a directory' % a
tsopts['path'] = a
if o in ('-s', '--swing', '-t', '--strike', '-h', '--hit'):
tsopts[{'s': 'swing',
't': 'strike',
'h': 'hit'}.get(o.replace('-', ''),
o.replace('-', ''))] = float(a)
if o in ('-u', '--usage'):
usage()
sys.exit(0)
if o in ('-u', '--usage'):
usage(False)
sys.exit(0)
thinksaber = Thinksaber(tsopts)
thinksaber.play()