Browse Source

Initial commit.

feature/balanceutils
Fr3deric 7 years ago committed by Frederic
commit
19eceac3f9
  1. 2
      .gitignore
  2. 152
      blayer-webif/blayerwebif.js
  3. 53
      blayer-webif/index.html
  4. 2
      blayer-webif/jquery-1.8.2.min.js
  5. 2
      blayer-webif/jquery.js
  6. 87
      blayer-webif/style.css
  7. 17
      blayer.cfg
  8. 428
      blayer.py
  9. 379
      blayer.py.old
  10. 68
      blmplay.py
  11. 167
      blphub.py
  12. 4
      blphub.sh
  13. 88
      blpserver.py
  14. 174
      blup/BLP.py
  15. 3
      blup/__init__.py
  16. 344
      blup/animation.py
  17. 97
      blup/font.py
  18. 152
      blup/frame.py
  19. 444
      blup/output.py
  20. 24
      colormarq.py
  21. 44
      colortest.py
  22. 34
      colorwischer.py
  23. 104
      eq.py
  24. 2
      fire,py
  25. 63
      fire.py
  26. 84
      http2telnet.py
  27. 43
      loadbbm.tmp
  28. 23
      lugsaar
  29. 13
      matrix.py
  30. 183
      miniplayer.py
  31. 873
      mrmcd13.bml
  32. 147
      playlist.txt
  33. 143
      playlist2.txt
  34. 456
      pong.py
  35. 178
      r0ketpong.py
  36. 4
      randomPlayer.py
  37. 28
      robot.bml
  38. 39
      smileys.bml
  39. 50
      smileys2.bml
  40. 135
      staticSinePlasma.py
  41. 152
      staticSinePlasma_neopixel.py
  42. 1
      test.txt
  43. 311
      ttrs.py
  44. 49
      writebml.py

2
.gitignore vendored

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
blm/

152
blayer-webif/blayerwebif.js

@ -0,0 +1,152 @@ @@ -0,0 +1,152 @@
SERVER_URL="http://volta:8080/do_request";
UPLOAD_URL="http://volta:8080/do_upload";
function refreshStatus() {
$.ajax({
url: SERVER_URL,
dataType: "json",
type: "POST",
data: JSON.stringify({"cmd": "getcurrentfilename"}),
success: function(data) {
$.blayerwebif.newFilename = data.currentfilename;
if($.blayerwebif.oldFilename == $.blayerwebif.newFilename)
return;
$.blayerwebif.oldFilename = $.blayerwebif.newFilename;
$("#tagtable").empty();
$("#tagtable").append("<tr><td>filename</td><td>"+$.blayerwebif.newFilename+"</td></tr");
$.ajax({
url: SERVER_URL,
dataType: "json",
type: "POST",
data: JSON.stringify({"cmd": "getcurrentfileinfo"}),
success: function(data) {
$.each(data.currentfileinfo, function(key, value) {
$("#tagtable").append("<tr><td>"+key+"</td><td>"+value+"</td></tr");
});
}
});
}
});
};
function refreshFilenames() {
$.ajax({
url: SERVER_URL,
dataType: "json",
type: "POST",
data: JSON.stringify({"cmd": "getallfilenames"}),
success: function(data) {
$("#filenames").empty();
$.each(data.allfilenames, function(key, value) {
//alert("<li><a href=\"#\" onClick=\"playNext(\\\""+value+"\\\")\">"+value+"</a></li>");
$("#filenames").append("<li><a href=\"#\" class=\"playNextLink\">"+value+"</a></li>");
});
$("#animationcount").text(data.allfilenames.length);
$(".playNextLink").click(function() {
linkNode = this;
$.ajax({
url: SERVER_URL,
dataType: "json",
type: "POST",
data: JSON.stringify({"cmd": "playnext", "filename": $(this).text()}),
success: function(data) {
if(data.playnext == "ok")
item = $("<span class=\"notificationtext\">queued...</span>");
else
item = $("<span class=\"notificationtext\">queue full :(</span>");
$(linkNode).after(item);
$(item).delay(1000).fadeOut("slow");
}
});
});
},
});
}
function refreshStatusPeriodic() {
refreshStatus();
setTimeout(refreshStatusPeriodic, 1000);
}
$(document).ready(function() {
$.blayerwebif = {};
$.blayerwebif.oldFilename = "";
setTimeout(refreshStatusPeriodic, 1000);
refreshFilenames();
refreshStatus();
$("#uploadbutton").click(function() {
$.ajax({
url: UPLOAD_URL,
type: "POST",
beforeSend: function() {
$("#uploadform").after("<span class=\"notificationtext\" id=\"uploadingnotification\">uploading...</span>");
},
success: function() {
$("#uploadingnotification").text("done! :)").delay(1000).fadeOut("slow");
refreshFilenames();
},
error: function() {
$("#uploadingnotification").text("failed! :(").delay(1000).fadeOut("slow");
},
contentType: false,
cache: false,
processData: false,
data: new FormData($("#uploadform")[0])
});
});
$("#next").click(function() {
$.ajax({
url: SERVER_URL,
dataType: "json",
type: "POST",
data: JSON.stringify({"cmd": "next"}),
success: function() {
refreshStatus();
}
});
});
$("#pause").click(function() {
button = this;
$.ajax({
url: SERVER_URL,
dataType: "json",
type: "POST",
data: JSON.stringify({"cmd": "togglepaused"}),
success: function(data) {
refreshStatus();
if(data.paused)
$(button).text("play");
else
$(button).text("pause");
}
});
});
$("#filtertext").keyup(function() {
keyword = $("#filtertext").val().toLowerCase();
$("#filenames li").each(function(key, value) {
if($(value).children("a").text().toLowerCase().indexOf(keyword) >= 0)
$(value).show();
else
$(value).hide();
});
});
});

53
blayer-webif/index.html

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
<html>
<head>
<title>blayer web interface</title>
<script src="jquery.js" type="text/javascript"></script>
<script src="blayerwebif.js" type="text/javascript"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="containerleft">
<div class="box">
<p class="boxhead">control</p>
<p class="controlbuttons">
<a href="#" id="next">next</a>
<a href="#" id="pause">play / pause</a>
</p>
</div>
<div class="box">
<p class="boxhead">upload</p>
<form action="#" method="post" id="uploadform">
<input type="file" name="file" />
<input type="button" value="upload" id="uploadbutton" />
</form>
</div>
<div class="box">
<p class="boxhead">current animation</p>
<!--<p><span class="label">Filename:</span><span id="filename"></span></p>-->
<table id="tagtable">
</table>
</div>
</div>
<div id="containerleft">
<div class="box">
<p class="boxhead">animation database</p>
<p><span id="animationcount">###</span> animations in total</p>
<p>filter: <input type="text" id="filtertext" /></p>
<ul id="filenames">
</ul>
</div>
</div>
</body></html>

2
blayer-webif/jquery-1.8.2.min.js vendored

File diff suppressed because one or more lines are too long

2
blayer-webif/jquery.js vendored

File diff suppressed because one or more lines are too long

87
blayer-webif/style.css

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
body {
background-color: #2f2f2f;
font-family: "lucida grande",tahoma, verdana, sans-serif;
font-size: 0.8em;
color: #cccccc;
}
h1 {
font-size: 1.5em;
}
#containerleft {
width: 46%;
margin-left: auto;
padding: 20px;
float: left;
}
#containerright {
width: 46%;
padding: 20px;
float: left;
}
div.box {
border-radius: 10px;
border-color: #000000;
border-width: 1px;
border-style: solid;
/*width: 50%;*/
background-color: #3d3d3d;
margin: auto;
margin-bottom: 30px;
padding: 10px;
box-shadow: 3px 3px 3px 3px #272727;
}
p.boxhead {
color: #006483;
font-weight: bold;
margin-top: 0px;
}
#tagtable td:first-child {
font-style: italic;
padding-right: 30px;
}
#tagtable td {
font-size: 0.8em;
}
#filenames a, #filenames a:visited {
text-decoration: none;
color: #cccccc;
}
.notificationtext {
padding-left: 20px;
color: #ffffff;
font-size: 0.7em;
}
.controlbuttons {
padding: 10px;
}
.controlbuttons a, .controlbutton a:visited {
padding: 5px;
border: 1px solid #cccccc;
border-radius: 4px;
color: #cccccc;
text-decoration: none;
}
.controlbuttons a:hover {
background: #006483;
}
.label {
font-style: italic;
}
.clear {
clear:both;
width: 0px;
height: 0px;
}

17
blayer.cfg

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
[control]
bind_host = 0.0.0.0
bind_port = 4243
[player]
animation_dir = /var/tmp/blup2/
playlist = /var/tmp/blup2/playlist.txt
shuffle = true
autorefresh = true
looptime = 3
maxplaynext = 3
[output]
output = blp:localhost:4242
#output = blp:bastel0:4242
#output = 'shell'

428
blayer.py

@ -0,0 +1,428 @@ @@ -0,0 +1,428 @@
#!/usr/bin/python
import threading
import random
import os.path
import os
import time
import socket
import asyncore
import asynchat
import cmd
import ConfigParser
import sys
import json
import blup.animation as Animation
import blup.output as BlupOutput
import blup.frame as Frame
CONFIG_DEFAULTS = {
'output': 'shell',
'playlist': '',
'animation_dir': '.',
'enabled': False,
'shuffle': False,
'autorefresh': False
}
def find(f, list):
for x in list:
if f(x):
return x
class AnimationInfo():
def __init__(self, filename):
self.__filename = filename
self.__tags = None
self.__valid = None
@property
def filesize(self):
try:
statinfo = os.stat(self.__filename)
return statinfo.st_size
except OSError:
return -1
@property
def mtime(self):
try:
statinfo = os.stat(self.__filename)
return statinfo.st_mtime
except OSError:
return -1
@property
def tags(self):
return self.__tags
@property
def valid(self):
if self.__valid == None:
try:
self.check()
except Animation.AnimationFileError:
pass
return self.__valid
@property
def filename(self):
return self.__filename
def check(self):
self.__valid = False
self.__tags = None
anim = Animation.load(self.__filename)
self.__valid = True
self.__tags = anim.tags
class AnimationDatabase():
def __init__(self, animDir):
self.__animDir = animDir
self.__animInfos = []
self.__lock = threading.Lock()
def update(self):
with self.__lock:
oldAnimInfos = self.__animInfos
animInfos = []
for (dirpath, dirnames, filenames) in os.walk(self.__animDir):
files = map(lambda f: os.path.join(dirpath, f), filenames)
files = map(lambda f: os.path.relpath(os.path.join(dirpath, f), self.__animDir), filenames)
animInfos.extend(map(lambda f: AnimationInfo(f), files))
#animInfos = filter(lambda a: a.valid, animInfos)
newAnimInfos = []
for animInfo in animInfos:
oldAnimInfo = find(lambda a: a.filename == animInfo.filename, oldAnimInfos)
if oldAnimInfo is not None and oldAnimInfo.mtime == animInfo.mtime:
newAnimInfos.append(oldAnimInfo)
else:
if animInfo.valid:
newAnimInfos.append(animInfo)
self.__animInfos = newAnimInfos
def findAnimation(self, filename):
with self.__lock:
animInfo = find(lambda a: a.filename == filename, self.__animInfos)
if animInfo is not None:
return animInfo
else:
raise Exception('animation not found!')
def containsAnimation(self, filename):
with self.__lock:
animInfo = find(lambda a: a.filename == filename, self.__animInfos)
return (animInfo is not None)
def getAllFilenames(self):
with self.__lock:
return map(lambda a: a.filename, self.__animInfos)
#class Playlist(list):
# def __init__(self, animationDatabase, filename=None):
# self.__animDb = animationDatabase
# self.__filename = filename
# if filename == None:
# self.append(self.__animDb.getAllFilenames())
# else:
# f = open(filename, 'r')
# lines = f.read().split('\n')
# f.close()
#
# for line in lines:
# if self.__animDb.containsAnimation(line):
# self.append(line)
#
# def refresh(self):
# #f = open(filename, 'r')
# #lines = f.read().split('\n')
# #f.close()
# pass
#
# #for line in lines:
# # if self.__animDb.containsAnimation(line):
# # self.append(line)
class PlayerThread(threading.Thread):
def __init__(self, database, output):
threading.Thread.__init__(self)
self.__playlist = []
self.database = database
self.__playNext = []
self.maxPlayNext = 3
self.__output = output
self.shuffle = False
self.autoRefresh = True
self.loopTime = 10
self.gap = 800
self.__running = False
self.__player = Animation.AnimationPlayer()
self.__currentIndex = 0
self.__currentFile = ''
self.__paused = False
@property
def currentFile(self):
if not self.__paused:
return self.__currentFile
else:
return ""
@property
def currentFileInfo(self):
if not self.__paused:
return self.database.findAnimation(self.__currentFile)
else:
# TODO: mhh...
return None
@property
def paused(self):
return self.__paused
def playNext(self, next):
if len(self.__playNext) < self.maxPlayNext:
self.__playNext.append(next)
else:
raise Exception
def next(self):
self.__player.stop()
def togglePaused(self):
self.__paused = not self.__paused
if self.__paused:
self.__player.stop()
def refreshPlaylist(self):
self.database.update()
self.__playlist = self.database.getAllFilenames()
def loadPlaylistFile(self):
raise Exception('not yet implemented :(')
def terminate(self):
self.__player.stop()
self.__running = False
def run(self):
self.__running = True
while self.__running:
anim = None
if self.autoRefresh: # and self.__currentIndex == len(self.__playlist) - 1:
self.refreshPlaylist()
if len(self.__playNext) == 0:
if len(self.__playlist) == 0:
print 'busywait!!'
continue
if self.shuffle:
self.__currentFile = self.__playlist[random.randint(0, len(self.__playlist) - 1)]
else:
if self.__currentIndex >= len(self.__playlist):
self.__currentIndex = 0
self.__currentFile = self.__playlist[self.__currentIndex]
self.__currentIndex += 1
else:
self.__currentFile = self.__playNext.pop(0)
anim = Animation.load(self.__currentFile)
count = 1
if anim.tags.has_key('loop') and anim.tags['loop'].lower() in ['yes', 'true']:
if anim.duration < self.loopTime * 1000:
count = (self.loopTime * 1000) / anim.duration
print 'playing:', anim
print 'tags:', anim.tags
self.__player.play(anim, self.__output, count=count)
print 'elapsed: ', self.__player.elapsed
if self.__paused:
# TODO: use correct frame size
self.__output.sendFrame(Frame.Frame(18,8))
while self.__paused:
time.sleep(1)
print 'busywait!!'
if self.gap > 0 and self.__running:
# TODO: use correct frame size
self.__output.sendFrame(Frame.Frame(18,8))
time.sleep(self.gap / 1000.0)
class PlayerControlClientHandler(asynchat.async_chat):
def __init__(self, sock, player):
asynchat.async_chat.__init__(self, sock=sock)
self.set_terminator('\n')
self.__buffer = ''
self.__player = player
def collect_incoming_data(self, data):
self.__buffer += data
def sendPacket(self, data):
self.send(json.dumps(data) + '\n')
def found_terminator(self):
try:
data = json.loads(self.__buffer)
except ValueError:
self.sendPacket({'error': 'invalid json'})
return
finally:
self.__buffer = ''
try:
cmd = data['cmd']
except (TypeError, KeyError):
self.sendPacket({'error': 'no command given'})
return
if cmd == 'refresh':
self.__player.refreshPlaylist()
self.sendPacket({'refresh': 'ok'})
elif cmd == 'next':
self.__player.next()
self.sendPacket({'next': 'ok'})
elif cmd == 'togglepaused':
self.__player.togglePaused()
self.sendPacket({'togglepaused': 'ok', 'paused': self.__player.paused})
elif cmd == 'getpaused':
self.sendPacket({'paused': self.__player.paused})
elif cmd == 'playnext':
if data.has_key('filename') and type(data['filename']) in [str, unicode]:
try:
self.__player.playNext(data['filename'])
except Exception:
self.sendPacket({'error':'too many animations queued'})
else:
self.sendPacket({'playnext':'ok'})
else:
self.sendPacket({'error': 'no or invalid animation file'})
elif cmd == 'getallfilenames':
self.sendPacket({'allfilenames': self.__player.database.getAllFilenames()})
elif cmd == 'getcurrentfileinfo':
if not self.__player.paused:
info = self.__player.currentFileInfo.tags
else:
info = {}
self.sendPacket({'currentfileinfo': info})
elif cmd == 'getcurrentfilename':
self.sendPacket({'currentfilename': self.__player.currentFile})
else:
self.sendPacket({'error': 'unknown command'})
class PlayerControlServer(asyncore.dispatcher):
def __init__(self, host, port, player):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
self.__player = player
def handle_accept(self):
pair = self.accept()
if pair is not None:
sock, addr = pair
print 'control connetcion from', addr
PlayerControlClientHandler(sock, self.__player)
#
# main
#
cfg = ConfigParser.SafeConfigParser(CONFIG_DEFAULTS)
cfg.read('/var/tmp/blup2/blayer.cfg')
try:
out = BlupOutput.getOutput(cfg.get('output', 'output'))
except ConfigParser.NoSectionError:
sys.err.write('config error: missing \'output\' section')
except ConfigParser.NoOptionError:
sys.err.write('config error: missing \'output\' option in \'output\' section')
try:
animation_dir = cfg.get('player', 'animation_dir')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
animation_dir = '.'
db = AnimationDatabase(animation_dir)
print 'updating database...'
db.update()
print 'done with updating database...'
print 'updating database (again)...'
db.update()
print 'done with updating database...'
#print db.getAllFilenames()
#try:
# playlist = Playlist(db, cfg.get('player', 'playlist'))
# print 'file-playluist:', playlist
#except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
# playlist = Playlist(db)
# print 'db-playluist:', playlist
blayer = PlayerThread(db, out)
blayer.refreshPlaylist()
#sys.exit(0)
try:
blayer.loopTime = cfg.getint('player', 'looptime')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
pass
try:
blayer.shuffle = cfg.getboolean('player', 'shuffle')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
pass
try:
blayer.autoRefresh = cfg.getboolean('player', 'autorefresh')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
pass
try:
blayer.maxPlayNext = cfg.getint('player', 'maxplaynext')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
pass
blayer.start()
try:
cser = PlayerControlServer(cfg.get('control', 'bind_host'), cfg.getint('control', 'bind_port'), blayer)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
cser = None
try:
if cser is not None:
asyncore.loop()
else:
blayer.join()
except KeyboardInterrupt:
print 'nawk!!'
blayer.terminate()

379
blayer.py.old

@ -0,0 +1,379 @@ @@ -0,0 +1,379 @@
#!/usr/bin/python
import threading
import random
import os.path
import os
import time
import socket
import asyncore
import asynchat
import cmd
import ConfigParser
import sys
import blup.animation as Animation
import blup.output as BlupOutput
import blup.frame as Frame
CONFIG_DEFAULTS = {
'output': 'shell',
'playlist': '',
'animation_dir': '.',
'enabled': False,
'shuffle': False,
'autorefresh': False
}
def find(f, list):
for x in list:
if f(x):
return x
class AnimationInfo():
def __init__(self, filename):
self.__filename = filename
self.__tags = None
self.__valid = None
@property
def filesize(self):
try:
statinfo = os.stat(self.__filename)
return statinfo.st_size
except OSError:
return -1
@property
def mtime(self):
try:
statinfo = os.stat(self.__filename)
return statinfo.st_mtime
except OSError:
return -1
@property
def tags(self):
return self.__tags
@property
def valid(self):
if self.__valid == None:
try:
self.check()
except Animation.AnimationFileError:
pass
return self.__valid
@property
def filename(self):
return self.__filename
def check(self):
self.__valid = False
self.__tags = None
anim = Animation.load(self.__filename)
self.__valid = True
self.__tags = anim.tags
class AnimationDatabase():
def __init__(self, animDir):
self.__animDir = animDir
self.__animInfos = []
self.__lock = threading.Lock()
def update(self):
with self.__lock:
oldAnimInfos = self.__animInfos
animInfos = []
for (dirpath, dirnames, filenames) in os.walk(self.__animDir):
files = map(lambda f: os.path.join(dirpath, f), filenames)
files = map(lambda f: os.path.relpath(os.path.join(dirpath, f), self.__animDir), filenames)
animInfos.extend(map(lambda f: AnimationInfo(f), files))
#animInfos = filter(lambda a: a.valid, animInfos)
newAnimInfos = []
for animInfo in animInfos:
oldAnimInfo = find(lambda a: a.filename == animInfo.filename, oldAnimInfos)
if oldAnimInfo is not None and oldAnimInfo.mtime == animInfo.mtime:
newAnimInfos.append(oldAnimInfo)
else:
if animInfo.valid:
newAnimInfos.append(animInfo)
self.__animInfos = newAnimInfos
def findAnimation(self, filename):
with self.__lock:
animInfo = find(lambda a: a.filename == filename, self.__animInfos)
if animInfo is not None:
return animInfo
else:
raise Exception('animation not found!')
def containsAnimation(self, filename):
with self.__lock:
animInfo = find(lambda a: a.filename == filename, self.__animInfos)
return (animInfo is not None)
def getAllFilenames(self):
with self.__lock:
return map(lambda a: a.filename, self.__animInfos)
#class Playlist(list):
# def __init__(self, animationDatabase, filename=None):
# self.__animDb = animationDatabase
# self.__filename = filename
# if filename == None:
# self.append(self.__animDb.getAllFilenames())
# else:
# f = open(filename, 'r')
# lines = f.read().split('\n')
# f.close()
#
# for line in lines:
# if self.__animDb.containsAnimation(line):
# self.append(line)
#
# def refresh(self):
# #f = open(filename, 'r')
# #lines = f.read().split('\n')
# #f.close()
# pass
#
# #for line in lines:
# # if self.__animDb.containsAnimation(line):
# # self.append(line)
class PlayerThread(threading.Thread):
def __init__(self, database, playlist, output):
threading.Thread.__init__(self)
self.__playlist = playlist
self.__database = database
self.__playNext = []
self.maxPlayNext = 3
self.__output = output
self.shuffle = False
self.autoRefresh = True
self.loopTime = 10
self.gap = 800
self.__running = False
self.__player = Animation.AnimationPlayer()
self.__currentIndex = 0
self.__currentFile = ''
@property
def currentFile(self):
return self.__currentFile
def playNext(self, next):
if len(self.__playNext) < self.__maxPlayNext:
self.__playNext.append(next)
else:
raise Exception
def refreshPlaylist(self):
self.__database.update()
self.__playlist = self.__database.getAllFilenames()
def loadPlaylistFile(self):
raise Exception('not yet implemented :(')
def terminate(self):
self.__player.stop()
self.__running = False
def run(self):
self.__running = True
while self.__running:
anim = None
if self.autoRefresh: # and self.__currentIndex == len(self.__playlist) - 1:
self.refreshPlaylist()
if len(self.__playNext) == 0:
if len(self.__playlist) == 0:
print 'busywait!!'
continue
if self.shuffle:
self.__currentFile = self.__playlist[random.randint(0, len(self.__playlist) - 1)]
else:
if self.__currentIndex >= len(self.__playlist):
self.__currentIndex = 0
self.__currentFile = self.__playlist[self.__currentIndex]
self.__currentIndex += 1
else:
self.__currentFile = self.__playNext.pop(0)
anim = Animation.load(self.__currentFile)
count = 1
if anim.tags.has_key('loop') and anim.tags['loop'].lower() in ['yes', 'true']:
if anim.duration < self.loopTime * 1000:
count = (self.loopTime * 1000) / anim.duration
print 'playing:', anim
print 'tags:', anim.tags
self.__player.play(anim, self.__output, count=count)
if self.gap > 0 and self.__running:
self.__output.sendFrame(Frame.Frame(18,8))
time.sleep(self.gap / 1000.0)
class PlayerControlClientHandler(asynchat.async_chat):
def __init__(self, sock, player):
asynchat.async_chat.__init__(self, sock=sock)
self.set_terminator('\n')
self.__buffer = ''
self.__player = player
def collect_incoming_data(self, data):
self.__buffer += data
def found_terminator(self):
args = self.__buffer.split(' ')
args = filter(lambda a: len(a) > 0, args)
if len(args) == 0:
return
self.__buffer = ''
cmd = args.pop(0)
if cmd == 'refresh':
self.__playlist.refresh()
self.send('ok\n')
elif cmd == 'status':
self.send('playing %s\n' % (self.__player.getCurrentFile()))
elif cmd == 'getplaylist':
plist = '\n'.join(self.__playlist.getPlaylist())
self.send(plist + '\n')
elif cmd == 'playnext' and len(args) == 1:
try:
self.__player.playNext(args[0])
self.send('ok\n')
except Exception:
self.send('error\n')
elif cmd == 'loadplaylist' and len(args) == 1:
try:
if args[0] == '.':
self.__playlist.loadDir()
else:
self.__playlist.loadFile(args[0])
self.send('ok\n')
except:
self.send('error\n')
elif cmd == 'quit':
self.send('bye\n')
self.close()
else:
self.send('unknown command\n')
class PlayerControlServer(asyncore.dispatcher):
def __init__(self, host, port, player, playlist):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
self.__player = player
self.__playlist = playlist
def handle_accept(self):
pair = self.accept()
if pair is not None:
sock, addr = pair
print 'control connetcion from', addr
PlayerControlClientHandler(sock, self.__player, self.__playlist)
#
# main
#
cfg = ConfigParser.SafeConfigParser(CONFIG_DEFAULTS)
cfg.read('/var/tmp/blup2/blayer.cfg')
try:
out = BlupOutput.getOutput(cfg.get('output', 'output'))
except ConfigParser.NoSectionError:
sys.err.write('config error: missing \'output\' section')
except ConfigParser.NoOptionError:
sys.err.write('config error: missing \'output\' option in \'output\' section')
try:
animation_dir = cfg.get('player', 'animation_dir')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
animation_dir = '.'
db = AnimationDatabase(animation_dir)
print 'updating database...'
db.update()
print 'done with updating database...'
print 'updating database (again)...'
db.update()
print 'done with updating database...'
#print db.getAllFilenames()
try:
playlist = Playlist(db, cfg.get('player', 'playlist'))
print 'file-playluist:', playlist
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
playlist = Playlist(db)
print 'db-playluist:', playlist
blayer = PlayerThread(db, playlist, out)
#sys.exit(0)
try:
blayer.setLoopTime(cfg.getint('player', 'looptime'))
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
pass
try:
blayer.setShuffle(cfg.getboolean('player', 'shuffle'))
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
pass
try:
blayer.setAutoRefresh(cfg.getboolean('player', 'autorefresh'))
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
pass
try:
blayer.setMaxPlayNext(cfg.getint('player', 'maxplaynext'))
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
pass
blayer.start()
try:
cser = PlayerControlServer(cfg.get('control', 'bind_host'), cfg.getint('control', 'bind_port'), blayer, playlist)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
cser = None
try:
if cser is not None:
asyncore.loop()
else:
blayer.join()
except KeyboardInterrupt:
print 'nawk!!'
blayer.terminate()

68
blmplay.py

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
#!/usr/bin/python
import sys
import getopt
import blup.animation
import blup.output
def printUsage(errMsg=None):
if errMsg is not None:
print 'error: %s\n' % (errMsg)
print 'usage: %s [OPTIONS] FILENAME' % (sys.argv[0])
print 'supported options:'
print ' -o OUTPUT where to output the frames (default: shell)'
print ' --output OUTPUT\n'
print ' -h print this text'
print ' --help'
def main():
try:
(opts, args) = getopt.gnu_getopt(sys.argv, 'ho:', ['help', 'output='])
opts = dict(opts)
except getopt.GetoptError as e:
printUsage(e.msg)
sys.exit(1)
if opts.has_key('--help'):
printUsage()
sys.exit(0)
if opts.has_key('-o'):
output = opts['-o']
elif opts.has_key('--output'):
output = opts['--output']
else:
output = 'shell'
try:
out = blup.output.getOutput(output)
except blup.output.IllegalOutputSpecificationError:
print 'illegal output specification'
print 'available outputs:'
print blup.output.getOutputDescriptions()
sys.exit(1)
except Exception as e:
print 'could not initialize output: %s' % (str(e))
sys.exit(1)
if len(args) != 2:
printUsage()
sys.exit(1)
try:
anim = blup.animation.load(args[1])
except blup.animation.AnimationFileError:
print 'could not load animation'
sys.exit(1)
player = blup.animation.AnimationPlayer()
try:
while True:
player.play(anim, out)
except KeyboardInterrupt:
sys.exit(0)
if __name__ == "__main__":
main()

167
blphub.py

@ -0,0 +1,167 @@ @@ -0,0 +1,167 @@
#!/usr/bin/env python3
import threading
import socket
import time
import getopt
import sys
import blup.BLP
import blup.output
class BLPStreamReceiverThread(threading.Thread):
def __init__(self, addr, port, hub, protocol=blup.BLP.PROTO_BLP):
threading.Thread.__init__(self)
self.__addr = addr
self.__port = port
self.__hub = hub
self.__protocol = protocol
self.__running = False
def run(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((self.__addr, self.__port))
sock.settimeout(1)
self.__running = True
while self.__running:
try:
data, addr = sock.recvfrom(2048)
except socket.timeout:
continue
try:
frame = blup.BLP.blp2frame(data, protocol=self.__protocol)
except ValueError:
print('got an invalid frame from', addr)
else:
self.__hub.sendFrame(frame, self)
def terminate(self):
self.__running = False
class BLPHub():
def __init__(self, output):
self.__output = output
self.__streams = {}
self.__lock = threading.Lock()
self.__lastFrameTimeout = -1
self.__lastFramePriority = -1
def sendFrame(self, frame, stream):
with self.__lock:
if stream not in self.__streams.keys():
return False
priority = self.__streams[stream]['priority']
currentTime = int(time.time() * 1000)
accept = False
if priority >= self.__lastFramePriority:
accept = True
else:
if currentTime > self.__lastFrameTimeout:
accept = True
if accept:
self.__lastFramePriority = priority
self.__lastFrameTimeout = (
currentTime + self.__streams[stream]['timeout']
)
self.__output.sendFrame(frame)
return True
return False
def addStream(self, stream, priority, timeout):
if stream not in self.__streams.keys():
self.__streams[stream] = {'priority': priority, 'timeout': timeout}
def printUsage(errMsg=None):
if errMsg is not None:
print('error: %s\n' % (errMsg))
print('usage: %s [OPTIONS] INPUTSTREAM ...' % (sys.argv[0]))
print('where INPUTSTREAM is given as HOST:PORT:PRIORITY:TIMEOUT')
print('supported options:')
print(' -o OUTPUT where to put the received frames')
print(' --eblp use EBLP instead of BLP')
print(' --e3blp use E3BLP instead of BLP')
print(' -h print this text')
print(' --help')
def main():
(opts, args) = getopt.gnu_getopt(sys.argv, 'hs:o:',
['help', 'eblp', 'e3blp'])
opts = dict(opts)
if '--help' in opts or '-h' in opts:
printUsage()
sys.exit(0)
if '-o' in opts:
output = opts['-o']
else:
output = 'shell'
if '--eblp' in opts:
protocol = blup.BLP.PROTO_EBLP
elif '--e3blp' in opts:
protocol = blup.BLP.PROTO_E3BLP
else:
protocol = blup.BLP.PROTO_BLP
if '--eblp' in opts and '--e3blp' in opts:
printUsage('please only specify one of --eblp or --e3blp')
sys.exit(1)
streams = []
for arg in args[1:]:
try:
(host, port, priority, timeout) = arg.split(':')
port = int(port)
priority = int(priority)
timeout = int(timeout)
if port <= 0 or timeout < 0:
raise ValueError
except ValueError as e:
printUsage('illegal stream specification')
sys.exit(1)
streams.append((host, port, priority, timeout))
if len(streams) == 0:
printUsage('please specify at least one stream')
sys.exit(1)
try:
out = blup.output.getOutput(output)
except ValueError:
printUsage('could not initialize output')
sys.exit(1)
hub = BLPHub(out)
streamThreads = []
firstThread = None
for (host, port, priority, timeout) in streams:
stream = BLPStreamReceiverThread(host, port, hub, protocol)
hub.addStream(stream, priority, timeout)
if firstThread is None:
firstThread = stream
else:
streamThreads.append(stream)
stream.start()
try:
firstThread.run()
except KeyboardInterrupt:
if len(streamThreads) > 0:
print('waiting for listeners to terminate...')
for stream in streamThreads:
stream.terminate()
for stream in streamThreads:
stream.join()
if __name__ == '__main__':
main()

4
blphub.sh

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
#!/bin/bash
python blphub.py -o blp:bastel0:4242 localhost:4242:1:1000 localhost:42421:2:3500

88
blpserver.py

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
import socket
import getopt
import sys
from blup.BLP import BLPServer
import blup.BLP
import blup.output
def printUsage(errMsg=None):
if errMsg is not None:
print 'error: %s\n' % (errMsg)
print 'usage: %s [OPTIONS]' % (sys.argv[0])
print 'supported options:'
print ' -a ADDR address to listen for packets (default: 127.0.0.1)'
print ' --address ADDR\n'
print ' -p PORT port to listen for packets (default: 4242)'
print ' --port PORT\n'
print ' -o OUTPUT where to put the recieved frames (default: shell)'
print ' --output OUTPUT\n'
print ' --eblp use EBLP instead of BLP\n'
print ' --e3blp use E3BLP instead of BLP\n'
print ' -h print this text'
print ' --help'
def main():
try:
(opts, args) = getopt.gnu_getopt(sys.argv, 'ha:p:o:', ['help', 'address=', 'port=', 'output=', 'eblp', 'e3blp'])
opts = dict(opts)
except getopt.GetoptError as e:
printUsage(e.msg)
sys.exit(1)
if opts.has_key('--help'):
printUsage()
sys.exit(0)
if opts.has_key('-a'):
addr = opts['-a']
elif opts.has_key('--address'):
addr = opts['--address']
else:
addr = '127.0.0.1'
if opts.has_key('-p'):
port = opts['-p']
elif opts.has_key('--port'):
port = opts['--port']
else:
port = 4242
if opts.has_key('-o'):
output = opts['-o']
elif opts.has_key('--output'):
output = opts['--output']
else:
output = 'shell'
if opts.has_key('--eblp'):
protocol = blup.BLP.PROTO_EBLP
elif opts.has_key('--e3blp'):
protocol = blup.BLP.PROTO_E3BLP
else:
protocol = blup.BLP.PROTO_BLP
if opts.has_key('--eblp') and opts.has_key('--e3blp'):
printUsage('please only specify one of --eblp or --e3blp')
sys.exit(1)
try:
port = int(port)
except ValueError:
printUsage('invalid port specified')
sys.exit(1)
out = blup.output.getOutput(output)
srv = BLPServer(output=out, addr=addr, port=port, protocol=protocol)
try:
srv.serve()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()

174
blup/BLP.py

@ -0,0 +1,174 @@ @@ -0,0 +1,174 @@
"""
This is a BLP and EBLP implementation as described here:
https://wiki.blinkenarea.org/index.php/BlinkenlightsProtocolEnglish
"""
import threading
import socket
import struct
from .frame import Frame
from .frame import FrameDimension
BLP_MAGIC = b'\xde\xad\xbe\xef'
EBLP_MAGIC = b'\xfe\xed\xbe\xef'
E3BLP_MAGIC = b'\xca\xfe\xbe\xef'
PROTO_BLP = 0
PROTO_EBLP = 1
PROTO_E3BLP = 2
PROTOCOLS = [PROTO_BLP, PROTO_EBLP, PROTO_E3BLP]
def frame2blp(frame, protocol=PROTO_BLP, depth=16):
if protocol not in PROTOCOLS:
raise ValueError('Unknown protocol: %d' % (protocol))
if frame.depth != 2 and protocol == PROTO_BLP:
raise ValueError('BLP does not support greyscale.')
if frame.channels != 3 and protocol == PROTO_E3BLP:
raise ValueError('E3BLP does only support 3-channel frames.')
(w, h) = frame.size
# magic value
if protocol == PROTO_BLP:
packet = BLP_MAGIC
elif protocol == PROTO_EBLP:
packet = EBLP_MAGIC
elif protocol == PROTO_E3BLP:
packet = E3BLP_MAGIC
# frame number, not yet implemented
packet += b'\x00\x00\x00\x00'
# frame dimension
packet += struct.pack('>HH', w, h)
for y in range(h):
for x in range(w):
if protocol == PROTO_BLP:
if frame.getPixel(x, y) == 1:
packet += b'\x01'
else:
packet += b'\x00'
elif protocol == PROTO_EBLP:
packet += struct.pack('B', frame.getPixel(x, y))
elif protocol == PROTO_E3BLP:
(r,g,b) = frame.getPixel(x, y)
packet += struct.pack('BBB', r, g, b)
return packet
def blp2frame(packet, protocol=PROTO_BLP, depth=None):
if protocol not in PROTOCOLS:
raise ValueError('Unknown protocol: %d' % (protocol))
if len(packet) < 13:
raise ValueError('packet is too short')
if ( (packet[0:4] != BLP_MAGIC and protocol == PROTO_BLP) or
(packet[0:4] != EBLP_MAGIC and protocol == PROTO_EBLP) or
(packet[0:4] != E3BLP_MAGIC and protocol == PROTO_E3BLP) ):
raise ValueError('MAGIC does not match')
w = (packet[8]<<8) + packet[9]
h = (packet[10]<<8) + packet[11]
if ( (protocol == PROTO_E3BLP and len(packet) != (w*h*3 + 12)) or
(protocol in [PROTO_BLP, PROTO_EBLP] and len(packet) != (w*h + 12)) ):
print(len(packet))
raise ValueError('packet size does not match')
if protocol == PROTO_BLP:
frm = Frame(FrameDimension(w, h, 2, 1))
elif protocol == PROTO_EBLP:
if depth is None:
depth = 16
frm = Frame(FrameDimension(w, h, depth, 1))
elif protocol == PROTO_E3BLP:
if depth is None:
depth = 8
frm = Frame(FrameDimension(w, h, depth, 3))
pixels = []
for y in range(h):
row = []
for x in range(w):
if protocol == PROTO_BLP:
if packet[12 + y*w + x] == '\x01':
#frm.setPixel(x, y, 1)
row.append(1)
else:
#frm.setPixel(x, y, 0)
row.append(0)
elif protocol == PROTO_EBLP:
row.append(packet[12 + y*w + x])
elif protocol == PROTO_E3BLP:
pos = 12 + (y*w + x) * 3
r = packet[pos]
g = packet[pos + 1]
b = packet[pos + 2]
row.append((r,g,b))
pixels.append(row)
frm.pixels = pixels
return frm
class BLPServer:
def __init__(self, addr='127.0.0.1', port=4242, output=None,
protocol=PROTO_BLP):
if protocol not in PROTOCOLS:
raise ValueError('Unknown protocol: %d' % (protocol))
self.__addr = addr
self.__port = port
self.__output = output
self.__sock = None
self.__protocol = protocol
if not output:
raise ValueError('serving without output isn\'t supported, yet')
def bind(self):
self.__sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.__sock.bind((self.__addr, self.__port))
def handle(self):
if self.__sock is None:
return
data, addr = self.__sock.recvfrom(1024)
try:
frame = blp2frame(data, protocol=self.__protocol)
except ValueError as e:
print('got an invalid frame from', addr)
print(e)
return
else:
self.__output.sendFrame(frame)
def serve(self):
self.bind()
while True:
self.handle()
class BLPServerThread(threading.Thread, BLPServer):
def __init__(self, addr, port, output, protocol=PROTO_BLP):
if protocol not in PROTOCOLS:
raise ValueError('Unknown protocol: %d' % (protocol))
threading.Thread.__init__(self)
BLPServer.__init__(self, addr, port, output, protocol)
self.__running = False
def run(self):
self.bind()
self.__running = True
while self.__running: self.handle()
def serve(self):
self.start()
def terminate(self):
self.__running = False

3
blup/__init__.py

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
# foo bar

344
blup/animation.py

@ -0,0 +1,344 @@ @@ -0,0 +1,344 @@
"""
This module is part of the 'blup' package and defines an animation class along
with the necessary functions to read animations from files.
"""
import re
import time
import xml.etree.ElementTree as ET
from frame import Frame
from frame import FrameDimension
class AnimationFileError(Exception):
def __init__(self, value):
self.__value = value
def __str__(self):
return repr(self.__value)
class AnimationFrame(Frame):
""" This class constitutes a single frame of an animation. """
def __init__(self, dimension, delay=100):
""" Initialize the frame with given dimension and delay. """
Frame.__init__(self, dimension)
self.delay = int(delay)
class AnimationIterator(object):
"""
This iterator can be used to loop over the animation's frames using
python's 'for' statement.
"""
def __init__(self, animation):
""" Initialize the iterator. """
self.__animation = animation
self.__pos = 0
def next(self):
""" Return the next frame (if available). """
if self.__pos >= len(self.__animation):
raise StopIteration
else:
self.__pos += 1
return self.__animation[self.__pos - 1]
class Animation(object):
""" This class constitutes an animation. """
def __init__(self, dimension):
""" Initialize the animation (without frames). """
self.__dimension = dimension
self.__frames = []
self.tags = {}
@property
def dimension(self):
return self.__dimension
@property
def width(self):
return self.__dimension.width
@property
def height(self):
return self.__dimension.height
@property
def depth(self):
return self.__dimension.depth
@property
def channels(self):
return self.__dimension.channels
@property
def duration(self):
""" Compute the duration of the animation. """
return sum(map(lambda f: f.delay, self.__frames))
def addFrame(self, frame):
""" Append a frame to the animation. """
if not isinstance(frame, Frame):
raise ValueError('frame is no \'Frame\' instance')
if self.dimension != frame.dimension:
raise ValueError(('frame dimension %s does not match animation ' +
'dimension %s' )
% (str(self.dimension), str(frame.dimension)))
self.__frames.append(frame)
def __iter__(self):
""" Return an iterator to loop over the animation's frames. """
return AnimationIterator(self)
def __len__(self):
""" Return the number of frames. """
return len(self.__frames)
def __getitem__(self, i):
""" Retrieve a certain frame from the animation. """
if i < 0 or i >= len(self):
raise IndexError('frame index out of bounds')
return self.__frames[i]
def __delitem__(self, i):
""" Delete a certain frame from the animation. """
if i < 0 or i >= len(self):
raise IndexError('frame index out of bounds')
del self.__frames[i]
class AnimationPlayer(object):
"""
This class can be used to play an Animation using an output class that
implements the 'sendFrame()' function.
"""
def __init__(self):
""" Initialize the player. """
self.__playing = False
self.__elapsed = 0
@property
def elapsed(self):
return self.__elapsed
def play(self, animation, output, count=1):
""" Play the animation 'count' times on 'output'. """
self.__playing = True
self.__elapsed = 0
for i in range(count):
for frame in animation:
output.sendFrame(frame)
delay = frame.delay / 1000.0
time.sleep(delay)
self.__elapsed += delay
if not self.__playing:
break
if not self.__playing:
break
def stop(self):
""" Stop the player, if playing. """
self.__playing = False
def loadBlm(filename):
""" Parse a blm file and return an Animation object. """
f = open(filename, 'r')
w = h = 0
tags = {}
header = True
framedelay = 100
frame = []
animframes = []
for line in f:
if header:
m = re.match('^\s*#\s+BlinkenLights Movie (\d+)x(\d+)', line)
if m:
w = int(m.group(1))
h = int(m.group(2))
continue
m = re.match('^\s*#\s+(.+)\s+=\s+(.+)\s+$', line)
if m:
key = m.group(1)
val = m.group(2)
tags[key] = val
continue
m = re.match('^@(\d+)\s+$', line)
if m:
if header:
header = False
framedelay = int(m.group(1))
if len(frame) > 0:
if h == 0:
h = len(frame)
else:
if len(frame) != h:
raise AnimationFileError(
'frame height does not match specified or ' +
'previous height')
frm = AnimationFrame(FrameDimension(w, h, 2, 1),
delay=framedelay)
frm.pixels = frame
print frame.pixels
animframes.append(frm)
frame = []
continue
if not header:
if line.strip() == '' or line.strip().startswith('#'):
continue
if re.match('^(0|1)+$', line):
line = line.strip()
if w == 0:
w = len(line)
else:
if len(line) != w:
raise AnimationFileError(
'frame width does not match specified or ' +
'previous width')
row = map(lambda c: int(c), list(line))
frame.append(row)
if h != 0 and len(frame) == h:
frm = AnimationFrame(FrameDimension(w, h, 2, 1),
delay=framedelay)
frm.pixels = frame
animframes.append(frm)
frame = []
continue
f.close()
if len(frame) > 0:
frm = AnimationFrame(FrameDimension(w, h, 2, 1), delay=framedelay)
frm.pixels = frame
animframes.append(frm)
if len(animframes) == 0:
raise AnimationFileError('no frames found in this file')
a = Animation(FrameDimension(w, h, 2, 1))
a.tags = tags
for f in animframes:
a.addFrame(f)
return a
def loadBml(filename):
""" Parse a bml file and return an Animation object. """
try:
tree = ET.parse(filename)
except ET.ParseError:
raise AnimationFileError('invalid xml')
root = tree.getroot()
if root.tag != 'blm':
raise AnimationFileError('the root tag needs to be a \'blm\' tag')
try:
width = int(root.attrib['width'])
height = int(root.attrib['height'])
bits = int(root.attrib['bits'])
channels = int(root.attrib['channels'])
dim = FrameDimension(width, height, 2**bits, channels)
except KeyError as e:
raise AnimationFileError('the root tag does not contain a ' +
'\'%s\' attribute.' % (e[0]))
if channels not in [1, 3]:
raise AnimationFileError('unsupported channel count')
tags = {}
frames = []
for child in root:
if child.tag == 'header':
for headerchild in child:
tags[headerchild.tag] = headerchild.text
# TODO (maybe) raise an exception in case no 'title' is given
elif child.tag == 'frame':
delay = int(child.attrib['duration'])
currentframe = AnimationFrame(dim, delay)
rows = []
for row in child:
charsPerPixel = channels
if bits > 4:
charsPerPixel *= 2
rowPixels = []
for i in xrange(0, width * charsPerPixel, charsPerPixel):
if channels == 1:
pixel = row.text[i:(i + charsPerPixel)]
rowPixels.append(int(pixel, 16))
elif channels == 3:
charsPerColor = charsPerPixel / 3
r = row.text[i:(i + charsPerColor)]
g = row.text[(i + charsPerColor):(i + 2*charsPerColor)]
b = row.text[(i + 2*charsPerColor):(i + charsPerPixel)]
rowPixels.append((int(r, 16), int(g, 16), int(b, 16)))
rows.append(rowPixels)
currentframe.pixels = rows
frames.append(currentframe)
a = Animation(dim)
a.tags = tags
for f in frames:
a.addFrame(f)
return a
def load(filename):
"""
(Try to) parse the given file using all available parser functions and
return the Animation afterwards.
"""
loaders = [ loadBlm, loadBml ]
anim = None
for loader in loaders:
try:
anim = loader(filename)
except AnimationFileError as e:
pass
if anim:
break
if not anim:
raise AnimationFileError('file could not be read')
return anim

97
blup/font.py

@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
"""
This module is part of the 'blup' package and defines a font class as well as
some methods to load fonts from files and draw text on frames.
"""
import re
class FontFileError(Exception):
def __init__(self, value):
self.__value = value
def __str__(self):
return repr(self.__value)
class Font(object):
def __init__(self):
self.__chars = {}
self.__spacing = 1
self.__height = -1
@property
def spacing(self):
return self.__spacing
@spacing.setter
def spacing(self, value):
if type(self.value) == int and self.value > 0:
self.__spacing = value
else:
raise ValueError('illegal spacing given')
@property
def height(self):
if self.__height == -1:
raise ValueError('this font does not contain any characters')
else:
return self.__height
def __setitem__(self, item, value):
height = len(value)
if self.__height == -1:
self.__height = height
elif height != self.__height:
raise ValueError('character height does not match font height')
if len(set(map(len, value))) != 1:
raise ValueError('character lines differ in width')
allowedValues = set([0,1])
for line in value:
if set(line) != allowedValues:
raise ValueError('character contains invalid pixel value')
self.__chars[item] = value
def __getitem__(self, item):
return self.__chars[item]
charPixels = None
def load(filename):
f = open(filename, 'r')
data = f.read()
f = Font()
for line in f:
m = re.match('^\s*§(\d+)\s*$', line)
if m:
f.spacing = int(m.group(1))
continue
m = re.match('^\s*@(\d+)\|(\d+)\s*$', line):
if m:
charCode = int(m.group(1))
charWidth = int(m.group(2))
charPixels = []
continue
m = re.match('^\s*([01]+)\s*$', line):
if m and charPixels != None:
charRow = m.group(1)
if len(charRow) < charWidth:
raise FontFileError('char row does not contain enough pixels')
row = []
for i in xrange(charWidth):
row.append(int(charRow[i]))
charPixels.append(row)
continue

152
blup/frame.py

@ -0,0 +1,152 @@ @@ -0,0 +1,152 @@
"""
This module is part of the 'blup' package and contains the definition of a
basic Frame class.
"""
class FrameDimension(object):
""" This class serves as container for the dimensions of a frame. """
def __init__(self, width=18, height=8, depth=2, channels=1):
self.width = width
self.height = height
self.depth = depth
self.channels = channels
def size(self):
return (self.width, self.height)
def depth(self):
return self.depth
def channels(self):
return self.channels
def __eq__(self, other):
if ( self.width == other.width and self.height == other.height and
self.depth == other.depth and self.channels == other.channels ):
return True
else:
return False
def __ne__(self, other):
return not self.__eq__(other)
def __str__(self):
return "(%d, %d, %d, %d)" % (self.width, self.height, self.depth,
self.channels)
class Frame(object):
""" This class describes a single frame. """
def __init__(self, dimension):
"""
Initialize the frame with the given dimensions. The 'depth' parameter
describes, how many different values a single pixel can have.
"""
self.__dimension = dimension
width = dimension.width
height = dimension.height
if dimension.channels == 1:
self.__pixels = [ [ 0 ] * width for i in range(height) ]
else:
self.__pixels = [ [ tuple([0]*dimension.channels) ] * width for i in range(height) ]
@property
def dimension(self):
return self.__dimension
@property
def size(self):
return (self.__dimension.width, self.__dimension.height)
@property
def depth(self):
return self.__dimension.depth
@property
def channels(self):
return self.__dimension.channels
@property
def pixels(self):
return self.__pixels
@pixels.setter
def pixels(self, pixels):
if len(pixels) != self.__dimension.height:
raise ValueError('not enough rows given')
widths = set(map(lambda r: len(r), pixels))
if len(widths) != 1:
raise ValueError('rows are not of the same length')
if widths.pop() != self.__dimension.width:
raise ValueError('rows are too short')
# TODO check depth
# TODO check number of channels
self.__pixels = pixels
def transform(self, depth):
""" Transform the frame to a frame with a different depth. """
oldmaxval = self.__dimension.depth - 1
newmaxval = depth - 1
factor = (newmaxval*1.0) / (oldmaxval*1.0)
newdim = FrameDimension(self.__dimension.width,
self.__dimension.height,
depth,
self.__dimension.channels)
newframe = Frame(newdim)
transformfkt = lambda p: int(round(p * factor))
for y in range(self.__dimension.height):
if self.__dimension.channels == 1:
newframe.__pixels[y] = map(transformfkt, self.__pixels[y])
else:
for x in range(self.__dimension.width):
newframe.__pixels[y][x] = tuple(map(transformfkt, p))
return newframe
def getPixel(self, x, y):
""" Return the pixel value at (x, y). """
return self.__pixels[y][x]
def setPixel(self, x, y, value):
""" Set the pixel value at (x, y). """
if self.__dimension.channels == 1:
if value < 0 or value >= self.__dimension.depth:
raise ValueError('pixel value not in depth range')
else:
if len(value) != self.__dimension.channels:
raise ValueError('channel count does not match')
for v in value:
if v < 0 or v >= self.__dimension.depth:
raise ValueError('pixel value not in depth range')
self.__pixels[y][x] = value
def getPixelsAsBytes(self):
""" Return the frame as a byte string. """
if self.__dimension.channels != 1:
raise Exception('cannot convert a multi-channel frame')
bytes = ''
for y in range(self.__dimension.width):
for x in range(self.__dimension.height):
bytes += chr(self.__pixels[x][y])
return bytes
def invert(self):
""" Ivert the frame. """
for y in range(self.__dimension.height):
for x in range(self.__dimension.width):
if self.__dimension.channels == 1:
self.__pixels[x][y] = ((self.__dimension.depth - 1) -
self.__pixels[x][y])
else:
self.__pixels[y][x] = tuple(map(
lambda x: ((self.depth - 1) - x),
self.__pixels[y][x]))

444
blup/output.py

@ -0,0 +1,444 @@ @@ -0,0 +1,444 @@
"""
This module is part of the 'blup' package and provides several output modules
to send frames as well as a mechanism to create them from a string
specification.
"""
import re
import serial
import socket
from blup import BLP
#
# ---- exceptions ----
#
class IllegalOutputSpecificationError(Exception):
"""
Will be thrown when a string is given to getOutput (see below) that is not
matched by any output modules regex.
"""
def __str__(self):
return __class__.__name__
#
# ---- generic output class to be subclassed ----
#
class Output(object):
def sendFrame(self, frame):
raise Exception('not implemented - just a dummy class')
#
# ---- MCUFOutput (MicroController Unit Frame) ----
#
class MCUFOutput(Output):
"""
This output module allows to send frames to blinkendevices over a serial
line using the MCUF protocol.
"""
moduleRegexDesc = 'mcuf:DEVICE:BAUDRATE[:DEPTH]'
moduleRegex = '^mcuf:([^:]+):(\d+)(:(\d+))?$'
def __init__(self, port, baudrate, depth=0):
"""
Initialize the module with given port and baudrate. If depth is
specified, every frame will be transformed, if it not already has the
correct depth.
"""
self.__port = port
self.__baudrate = baudrate
self.__ser = serial.Serial(port=port, baudrate=baudrate)
self.__depth = depth
@classmethod
def fromRegexMatch(cls, regexMatch):
""" Create an instance from a RegexMatch (matched with moduleRegex) """
port = regexMatch.group(1)
baudrate = int(regexMatch.group(2))
if regexMatch.group(4):
depth = int(regexMatch.group(4))
else:
depth = 0
return cls(port, baudrate, depth)
def sendFrame(self, frame):
""" Pass a frame to the module. """
(w, h) = frame.size
if self.__depth != 0:
if frame.depth != self.__depth:
frame = frame.transform(self.__depth)
maxval = frame.depth - 1
framedata = ''
for y in range(h):
for x in range(w):
framedata += chr(frame.getPixel(x, y))
packet = '\x23\x54\x26\x66'
packet += '%s%s%s%s' % (chr(h>>8), chr(h & 0xff),
chr(w>>8), chr(w & 0xff))
packet += '\x00\x01\x00%s' % (chr(maxval))
packet += framedata
self.__ser.write(packet)
return True
#
# ---- SerialBlupOutput ----
#
class SerialBlupOutput(Output):
"""
This output module allows sending frames to 18x8 blinkendevices with
depth 2 over a serial line, by sending every column as a byte.
"""
moduleRegexDesc = 'serialblup:DEVICE:BAUDRATE'
moduleRegex = '^serialblup:([^:]+):(\d+)$'
def __init__(self, port, baudrate):
""" Initialize the output module with the given port. """
self.__port = port
self.__baudrate = baudrate
self.__ser = serial.Serial(port=port, baudrate=baudrate)
self.__stx2 = 'a'
self.__etx2 = 'b'
self.__stx8 = 'q'
self.__etx8 = 'b'
self.__stxRGB = chr(0xca)
self.__etxRGB = chr(0xfe)
@classmethod
def fromRegexMatch(cls, regexMatch):
""" Create an instance from a RegexMatch (matched with moduleRegex) """
port = regexMatch.group(1)
baudrate = int(regexMatch.group(2))
return cls(port, baudrate)
def sendFrame(self, frame):
""" Pass a frame to the module. """
if frame.depth not in [2, 16] and frame.channels == 1:
raise ValueError('%s only supports frames of depth 2 or 16' %
(self.__class__.__name__))
if frame.channels not in [1, 3]:
raise ValueError('%s only supports frames with 1 or 3 channels' %
(self.__class__.__name__))
if frame.size != (18, 8):
raise ValueError('%s currently only supports 18x8 frames' %
(self.__class__.__name__))
if frame.channels == 1 and frame.depth == 2:
bytes = [ 0 ] * 18
for x in range(18):
for y in range(8):
if frame.getPixel(x, y) == 1:
bytes[x] += 2**(7 - y)
packet = self.__stx2 + ''.join(map(lambda b: chr(b), bytes)) + self.__etx2
elif frame.channels == 1 and frame.depth == 16:
bytes = [ 0 ] * (18*4)
for x in range(18):
for y in range(8):
pixelval = frame.getPixel(x, y)
pixelnum = y*18 + x
bytes[pixelnum/2] += (pixelval << ((pixelnum % 2) * 4))
packet = self.__stx8 + ''.join(map(lambda b: chr(b), bytes)) + self.__etx8
elif frame.channels == 3:
bytes = [ 0 ] * (18*8*3)
for y in range(8):
for x in range(18):
(r,g,b) = frame.getPixel(x, y)
pixelnum = y*18 + x
bytes[3*pixelnum] = r
bytes[3*pixelnum + 1] = g
bytes[3*pixelnum + 2] = b
packet = self.__stxRGB + ''.join(map(lambda b: chr(b), bytes)) + self.__etxRGB
self.__ser.write(packet)
return True
#
# ---- ShellOuput ----
#
class ShellOutput(Output):
""" This output module prints frames with depth 2 on the terminal. """
moduleRegexDesc = 'shell[:ON_CHAR:OFF_CHAR]'
moduleRegex = '^shell(:(.):(.))?$'
def __init__(self, onChar='#', offChar=' '):
""" Initialize the output. """
self.__onChar = onChar
self.__offChar = offChar
self.__initialized = False
@classmethod
def fromRegexMatch(cls, regexMatch):
""" Create an instance from a RegexMatch (matched with moduleRegex) """
if regexMatch.group(2) is not None:
return cls(regexMatch.group(2), regexMatch.group(3))
else:
return cls()
def sendFrame(self, frame):
""" Pass a frame to the module. """
if frame.depth != 2:
raise ValueError('%s only supports frames of depth 2' %
(self.__class__.__name__))
(width, height) = frame.size
if not self.__initialized:
self.__initialized = True
print('\n' * height)
print('\x1b[%dA' % (height + 2))
for y in range(height):
line = ''
for x in range(width):
if frame.getPixel(x, y) == 1:
line += self.__onChar
else:
line += self.__offChar
print(line)
print('')
return True
#
# ---- ColorfulShellOuput ----
#
class ColorfulShellOutput(Output):
""" This output module prints frames on the terminal, using colors. """
moduleRegexDesc = 'colorfulshell'
moduleRegex = '^colorfulshell?$'
def __init__(self):
""" Initialize the output. """
self.__initialized = False
@classmethod
def fromRegexMatch(cls, regexMatch):
""" Create an instance from a RegexMatch (matched with moduleRegex) """
return cls()
def sendFrame(self, frame):
""" Pass a frame to the module. """
if frame.channels not in [1, 3]:
raise ValueError('%s only supports frames with 1 or 3 channels' %
(self.__class__.__name__))
(width, height) = frame.size
if not self.__initialized:
self.__initialized = True
print('\n' * height)
print('\x1b[%dA' % (height + 2))
for y in range(height):
line = ''
for x in range(width):
if frame.channels == 3:
(r,g,b) = frame.getPixel(x, y)
if frame.depth != 5:
factor = 5 / ((frame.depth - 1) * 1.0)
r = round(r*factor)
g = round(g*factor)
b = round(b*factor)
colorval = 36*r + 6*g + b + 16
line += '\033[48;05;%dm ' % (colorval)
elif frame.channels == 1:
colorval = frame.getPixel(x, y)
if frame.depth != 24:
factor = (23 / ((frame.depth - 1) * 1.0))
colorval = 232 + colorval * factor
line += '\033[48;05;%dm ' % (colorval)
print(line)
print('')
return True
#
# ---- BLPOutput ----
#
class BLPOutput(Output):
"""
This output module sends frames over the network using the UDP-based BLP
protocol.
"""
moduleRegexDesc = 'blp[:HOST:PORT]'
moduleRegex = '^(blp|eblp|e3blp)(:(.+):(\d+))?$'
def __init__(self, host='127.0.0.1', port=4242, protocol=BLP.PROTO_BLP):
""" Initialize the output. Frames are sent to host:port. """
self.__host = host
self.__port = port
self.__sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.__protocol = protocol
@classmethod
def fromRegexMatch(cls, regexMatch):
""" Create an instance from a RegexMatch (matched with moduleRegex) """
if regexMatch.group(1) == 'blp':
protocol = BLP.PROTO_BLP
elif regexMatch.group(1) == 'eblp':
protocol = BLP.PROTO_EBLP
elif regexMatch.group(1) == 'e3blp':
protocol = BLP.PROTO_E3BLP
if regexMatch.group(3) and regexMatch.group(4):
host = regexMatch.group(3)
port = int(regexMatch.group(4))
return cls(host, port, protocol)
else:
return cls(protocol=protocol)
def sendFrame(self, frame):
""" Pass a frame to the module. """
packet = BLP.frame2blp(frame, protocol=self.__protocol)
self.__sock.sendto(packet, (self.__host, self.__port))
return True
#
# ---- BlinkenbuntHDOutput ----
#
class BlinkenbuntHDOutput(Output):
moduleRegexDesc = 'bbunthd'
moduleRegex = '^bbunthd$'
def __init__(self):
import neopixel
self.w = 22
self.h = 16
LED_COUNT = self.w * self.h
LED_PIN = 13
LED_FREQ_HZ = 800000
LED_DMA = 5
LED_BRIGHTNESS = 50
LED_INVERT = False
LED_PWM = 1
self.strip = neopixel.Adafruit_NeoPixel(
LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT,
LED_BRIGHTNESS, LED_PWM
)
self.strip.begin()
self._color_cls = neopixel.Color
@classmethod
def fromRegexMatch(cls, regexMatch):
return cls()
def sendFrame(self, frame):
for y in range(self.h):
for x in range(self.w):
if x%2 == 0:
lednum = x*self.h + y
else:
lednum = x*self.h - y + 15
pix = frame.getPixel(x, y)
print(pix)
self.strip.setPixelColor(lednum, self._color_cls(*pix))
self.strip.show()
#
# ---- PygameOutput ----
#
class PygameOutput(Output):
moduleRegexDesc = 'pygame'
moduleRegex = '^pygame$'
def __init__(self, width=22, height=16, scalex=8, scaley=8):
self.width = width
self.height = height
self.scalex = scalex
self.scaley = scaley
import pygame
self.__pygame = pygame
self.screen = pygame.display.set_mode((width*scalex, height*scaley))
pygame.display.update()
@classmethod
def fromRegexMatch(cls, regexMatch):
return cls()
def sendFrame(self, frame):
pygame = self.__pygame
for y in range(self.height):
for x in range(self.width):
rect = (x*self.scalex, y*self.scaley, self.scalex, self.scaley)
pygame.draw.rect(self.screen, frame.getPixel(x, y), rect, 0)
pygame.display.update()
#import time
#time.sleep(0.1)
#
# ---- output creator ;) ----
#
__outputModules = {
SerialBlupOutput.moduleRegex: SerialBlupOutput,
MCUFOutput.moduleRegex: MCUFOutput,
ShellOutput.moduleRegex: ShellOutput,
ColorfulShellOutput.moduleRegex: ColorfulShellOutput,
BLPOutput.moduleRegex: BLPOutput,
BlinkenbuntHDOutput.moduleRegex: BlinkenbuntHDOutput,
PygameOutput.moduleRegex: PygameOutput,
}
def getOutput(outputSpec):
"""
Return an output module instance described by the given specification.
"""
for regex in __outputModules.keys():
m = re.match(regex, outputSpec)
if m:
return __outputModules[regex].fromRegexMatch(regexMatch=m)
raise IllegalOutputSpecificationError()
def getOutputDescriptions():
"""
Return a string containing the moduleRegexDesc of every available output
module.
"""
s = ""
for outputModule in __outputModules.values():
s += " %s\n" % (outputModule.moduleRegexDesc)
return s

24
colormarq.py

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
#!/usr/bin/python
import sys
import blup.animation
import writebml
anim = blup.animation.load(sys.argv[1])
plasmaanim = blup.animation.load('/tmp/plasma.bml')
newanim = blup.animation.Animation(anim.dimension)
plasmaFrame = 0
for f in anim:
newframe = blup.animation.AnimationFrame(f.dimension, f.delay)
for x in range(anim.dimension.width):
for y in range(anim.dimension.height):
p = f.getPixel(x,y)
if max(p) > 14:
newframe.setPixel(x,y, plasmaanim[plasmaFrame].getPixel(x,y))
newanim.addFrame(newframe)
plasmaFrame += 1
writebml.writeBml(newanim, '/tmp/colormarq.bml')

44
colortest.py

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
#!/usr/bin/python
import colorsys
import time
import blup.output
import blup.frame
dim = blup.frame.FrameDimension(18,8,16,3)
frame = blup.frame.Frame(dim)
HEIGHT = 8
WIDTH = 18
#h = 0.0
#for y in range(HEIGHT):
# h += 1.0 / (HEIGHT * 1.0)
# v = 0
# s = 0.7
# for x in range(WIDTH):
# v += 1.0 / (WIDTH * 1.0)
# print s
# color = colorsys.hsv_to_rgb(h, s, v)
# color = tuple(map(lambda c: int(round(c * 15)), color))
# print color
# frame.setPixel(x, y, color)
for y in range(HEIGHT):
for x in range(WIDTH):
h = (x * 1.0) / (WIDTH - 1.0)
s = 1.0 - (y * 1.0) / (HEIGHT - 0.0)
v = 1.0 - (y * 1.0) / (HEIGHT - 0.0)
color = colorsys.hsv_to_rgb(h, s, v)
color = tuple(map(lambda c: int(round(c * 15)), color))
frame.setPixel(x, y, color)
out = blup.output.getOutput('e3blp')
while True:
out.sendFrame(frame)
time.sleep(0.4)

34
colorwischer.py

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
#!/usr/bin/python
import sys
import blup.animation
import blup.frame
import writebml
import random
dim = blup.frame.FrameDimension(18, 8, 16, 3)
newanim = blup.animation.Animation(dim)
num = 10
horiz = True
delay = 100
for i in range(num):
newcolor = (random.randint(0, 15), random.randint(0, 15), random.randint(0, 15))
horiz = not horiz
newframe = blup.animation.AnimationFrame(dim, delay)
if horiz:
for x in range(dim.size()[0]):
for y in range(dim.size()[1]):
newframe.setPixel(x, y, newcolor)
newanim.addFrame(newframe)
else:
for y in range(dim.size()[1]):
for x in range(dim.size()[0]):
newframe.setPixel(x, y, newcolor)
newanim.addFrame(newframe)
writebml.writeBml(newanim, '/tmp/colorwischer.bml')

104
eq.py

@ -0,0 +1,104 @@ @@ -0,0 +1,104 @@
# Major library imports
import atexit
import pyaudio
from numpy import zeros, short, fromstring, array
from numpy.fft import fft
import colorsys
import time
import blup.frame
import blup.output
#NUM_SAMPLES = 512
NUM_SAMPLES = 36
#NUM_SAMPLES = 18
#NUM_SAMPLES = 16
#SAMPLING_RATE = 11025
#SAMPLING_RATE = 11024 / 2
SAMPLING_RATE = 1100
_stream = None
def read_fft():
global _stream
pa = None
def cleanup_audio():
if _stream:
_stream.stop_stream()
_stream.close()
pa.terminate()
if _stream is None:
pa = pyaudio.PyAudio()
_stream = pa.open(format=pyaudio.paInt16, channels=1,
rate=SAMPLING_RATE,
input=True, frames_per_buffer=NUM_SAMPLES)
atexit.register(cleanup_audio)
audio_data = fromstring(_stream.read(NUM_SAMPLES), dtype=short)
normalized_data = audio_data / 32768.0
return fft(normalized_data)[1:1+NUM_SAMPLES/2]
def flatten_fft(scale = 1.0):
"""
Produces a nicer graph, I'm not sure if this is correct
"""
for i, v in enumerate(read_fft()):
yield scale * (i * v) / NUM_SAMPLES
def makeColor(x):
hue = (7-x) / 7.0 / 3.0 -0.1
if hue < 0:
hue += 1
rgb = map(lambda x: int(round(x*7)), colorsys.hsv_to_rgb(hue, 1, 1))
return rgb
def makeSpectrumFrame(spectrum):
f = blup.frame.Frame(blup.frame.FrameDimension(18,8,8,3))
for x, y in enumerate(spectrum):
if y > 7:
y = 7
y = int(y)
for i in range(y):
#val = (7,7,7)
val = makeColor(i)
f.setPixel(x, 7-i, val)
return f
def draw():
'''Draw 3 different colour graphs'''
global NUM_SAMPLES
audio = array(list(flatten_fft(scale = 80)))
freqs = len(audio)
bass, mid, treble = triple(audio)
colours = (0.5, 1.0, 0.5), (1, 1, 0), (1, 0.2, 0.5)
fill(0, 0, 1)
rect(0, 0, WIDTH, 400)
translate(50, 200)
for spectrum, col in zip((bass, mid, treble), colours):
fill(col)
for i, s in enumerate(spectrum):
rect(i, 0, 1, -abs(s))
else:
translate(i, 0)
audio = array(list(flatten_fft(scale = 80)))
out = blup.output.getOutput('colorfulshell')
while True:
audio = array(list(flatten_fft(scale=80)))
#audio = map(abs, audio)
#print len(audio)
frame = makeSpectrumFrame([ int((x/18.0)*8) for x in range(18)])
frame = makeSpectrumFrame(audio)
#print map(int,audio)
out.sendFrame(frame)
#time.sleep(0.1)

2
fire,py

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
#!/usr/bin/python

63
fire.py

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
#!/usr/bin/python
import colorsys
import random
import blup.frame
import blup.output
import blup.animation
# thanks to
# http://quiteuseful.co.uk/post/96424751/beautiful-algorithms-1-fire-part-2
dim = blup.frame.FrameDimension(18,8,16,3)
anim = blup.animation.Animation(dim)
def getRandomColor(maxval):
return mmeap(lambda x: int(round(x*maxval)), colorsys.hsv_to_rgb(random.random() % 0.16666666, 1, 1))
def colorAvg(colors):
r = 0
g = 0
b = 0
for c in colors:
r += c[0]
g += c[1]
b += c[2]
avg = (r,g,b)
avg = map(lambda x: int(round(x / (len(colors) * 1.0))), avg)
return avg
for i in range(100):
randRow = [ getRandomColor(dim.depth - 1) for i in range(dim.width) ]
print randRow
f = blup.animation.AnimationFrame(dim, 60)
for y in range(dim.height - 1, -1, -1):
for x in range(dim.width):
colors = []
if x >=1 :
colors.append(f.getPixel(x-1,y))
if x < dim.width - 1:
pass
colors.append(f.getPixel(x+1,y))
if y < dim.height - 1:
colors.append(f.getPixel(x, y+1))
else:
#colors.append(randRow[y])
colors.append(getRandomColor(dim.depth - 1))
#colors = [randRow[x]]
c = colorAvg(colors)
f.setPixel(x, y, c)
anim.addFrame(f)
#out = blup.output.getOutput('e3blp:bbunt:4242')
out = blup.output.getOutput('colorfulshell')
player = blup.animation.AnimationPlayer()
player.play(anim, out)

84
http2telnet.py

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
import socket
import cgi
import json
import time
import os.path
import threading
TELNET_HOST = 'localhost'
TELNET_PORT = 4243
DOCROOT = '/var/tmp/blup2/blayer-webif'
UPLOAD_DIR = '/var/tmp/blup2/blm/incoming'
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((TELNET_HOST, TELNET_PORT))
socklock = threading.Lock()
class HTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
print self.path
#self.wfile.write('<form action="bla" method="post"><input type="text" name="text" /><input type="submit" value="ok" /></form>')
p = os.path.join(DOCROOT, self.path[1:])
print p
if os.path.isfile(p):
f = open(p, 'r')
data = f.read()
f.close()
self.wfile.write(data)
def do_POST(self):
if self.path == '/do_upload':
formdata = cgi.FieldStorage(
fp=self.rfile, headers=self.headers,
environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers['Content-Type']})
fileField = formdata['file']
f = open(os.path.join(UPLOAD_DIR, fileField.filename), 'w')
f.write(fileField.file.read())
f.close()
sock.send(json.dumps({"cmd": "refresh"}) + '\n')
print 'server answer to refresh cmd: ', sock.recv(1024)
self.send_response(200);
self.end_headers();
return
postdata = self.rfile.read(int(self.headers.getheader('content-length')))
#self.wfile.write('test')
if postdata[-1:] != '\n':
postdata += '\n'
print 'postdata:', postdata
with socklock:
sock.send(postdata)
time.sleep(0.1)
resp = sock.recv(1024 * 10)
#sock.shutdown(socket.SHUT_RDWR)
#sock.close()
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header('Content-length', len(resp))
self.end_headers()
print 'resp:', resp
self.wfile.write(resp)
server = HTTPServer(('0.0.0.0',8080), HTTPRequestHandler)
server.serve_forever()

43
loadbbm.tmp

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
def loadBbm(filename):
""" Parse a bbm file and return an Animation object. """
def getint16(vals):
return (cals[2]>>8) + vals[3]
def getint32(vals):
return (vals[0]>>24) + (vals[1]>>16) + (cals[2]>>8) + vals[3]
f = open(filename, 'r')
rawdata = f.read()
f.close()
data = [ ord(x) for x in rawdata ]
if getint32(data[0:4]) != 0x23542666:
raise ValueError('magic does not match')
height = getint16(data[4:6])
width = getint16(data[6:8])
channels = getint16(data[8:10])
maxval = getint16(data[10:12])
framecnt = getint32(data[10:14])
duration = getint32(data[14:18])
frameptr = getint32(data[18:22])
# TODO: parse additional headers
if rawdata[frameptr:(frameptr+4)] != 'frms':
raise ValueError('frame pointer does not point to frame start marker')
framedata = data[frameptr + 4:]
framesize = width*height*channels
frames = []
while True:
pass
raise Exception('uarrgh!!')

23
lugsaar

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
# BlinkenLights Movie 18x8
# loop = yes
@200
000000000000000000
000011100011100000
000111110111110000
000111111111110000
000011111111100000
000000111110000000
000000001000000000
000000000000000000
@800
000011100011100000
000111110111110000
001111111111111000
001111111111111000
000111111111110000
000011111111100000
000000111110000000
000000001000000000

13
matrix.py

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
#!/usr/bin/pyton
import blup.frame
import blup.output
import blup.animation
out = blup.output.getOutput('e3blp')
points = []
for i in

183
miniplayer.py

@ -0,0 +1,183 @@ @@ -0,0 +1,183 @@
#!/usr/bin/python
import threading
import os
import os.path
import random
import time
import sys
import getopt
import blup.output
import blup.animation
import blup.frame
class AnimationLoaderThread(threading.Thread):
"""
This class is used by the player to pre-load an animation while another one
is being played.
"""
def __init__(self, filename):
threading.Thread.__init__(self)
self.__filename = filename
self.__anim = None
self.__error = False
def run(self):
try:
self.__anim = blup.animation.load(self.__filename)
except Exception as e:
print '%s: %s while loading %s' % (self.__class__.__name__,
repr(e),
self.__filename)
self.__error = True
self.__anim = None
def getAnim(self):
self.join()
return self.__anim
class MiniPlayer(object):
"""
Minimal animation player that does nothing but randomly selecting
animations out of a directory and playing them.
"""
def __init__(self, animDir, output):
self.__animDir = animDir
self.__output = output
self.loopTime = 10000
self.gap = 800
self.maxPlayNext = 3
self.__playNext = []
self.__running = False
def terminate(self):
self.__running = False
def playNext(self, filename):
""" Add an animation to the queue. """
if filename.find('/') >= 0:
raise ValueError('filename must not contain slashes')
if ( os.path.isfile(os.path.join(self.__animDir, filename)) and
len(self.__playNext) < self.maxPlayNext ):
self.__playNext.append(filename)
else:
return False
def getNextFilename(self):
"""
Return the next animation filename to be played, either from the queue,
or randomly chosen.
"""
if len(self.__playNext) > 0 and os.path.isfile(self.__playNext[0]):
return self.__playNext.pop(0)
else:
files = os.listdir(self.__animDir)
return random.choice(files)
def run(self):
"""
Runs the player until terminate() gets called (e.g. by another thread).
"""
self.__running = True
currentAnim = None
player = blup.animation.AnimationPlayer()
while self.__running:
# begin to load the next animation
filename = os.path.join(self.__animDir, self.getNextFilename())
loader = AnimationLoaderThread(filename)
loader.start()
# play the animation in case it had been successfully loaded before
if currentAnim is not None:
if currentAnim.duration < self.loopTime:
count = self.loopTime / currentAnim.duration
else:
count = 1
player.play(currentAnim, self.__output, count=count)
# show a blank frame for some thime
if self.gap > 0 and self.__running:
# TODO: use correct frame size
dim = blup.frame.FrameDimension(18,8,8,3)
self.__output.sendFrame(blup.frame.Frame(dim))
time.sleep(self.gap / 1000.0)
# get the next animation from the loader
currentAnim = loader.getAnim()
def printUsage(errMsg=None):
if errMsg is not None:
print 'error: %s\n' % (errMsg)
print 'usage: %s [OPTIONS] PATH' % (sys.argv[0])
print 'where PATH is the directory containing the animations to play'
print 'supported options:'
print ' -o OUTPUT where to output the frames (default: shell)'
print ' --output OUTPUT\n'
print ' -h print this text'
print ' --help'
def main():
try:
(opts, args) = getopt.gnu_getopt(sys.argv, 'ho:', ['help', 'output='])
opts = dict(opts)
except getopt.GetoptError as e:
printUsage(e.msg)
sys.exit(1)
if opts.has_key('--help'):
printUsage()
sys.exit(0)
if opts.has_key('-o'):
output = opts['-o']
elif opts.has_key('--output'):
output = opts['--output']
else:
output = 'shell'
try:
out = blup.output.getOutput(output)
except blup.output.IllegalOutputSpecificationError:
print 'illegal output specification'
print 'available outputs:'
print blup.output.getOutputDescriptions()
sys.exit(1)
except Exception as e:
print 'could not initialize output: %s' % (str(e))
sys.exit(1)
if len(args) != 2:
printUsage()
sys.exit(1)
else:
animDir = args[1]
if not os.path.isdir(animDir):
print '%s is not a directory' % (animDir)
sys.exit(1)
p = MiniPlayer(animDir, out)
try:
p.run()
except KeyboardInterrupt:
sys.exit(0)
if __name__ == '__main__':
main()

873
mrmcd13.bml

@ -0,0 +1,873 @@ @@ -0,0 +1,873 @@
<?xml version="1.0" encoding="UTF-8"?>
<blm width="18" height="8" bits="4" channels="3">
<frame duration="100">
<row>000000000000000000000000000000000000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000f00f00</row>
<row>000000000000000000000000000000000000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000000000000000f00000000</row>
<row>000000000000000000000000000000000000000000000f00f00000</row>
<row>000000000000000000000000000000000000000000000f00000f00</row>
<row>000000000000000000000000000000000000000000000f00000000</row>
<row>000000000000000000000000000000000000000000000f00000000</row>
<row>000000000000000000000000000000000000000000000f00000000</row>
<row>000000000000000000000000000000000000000000000f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000000000000f00000000000</row>
<row>000000000000000000000000000000000000000000f00f00000000</row>
<row>000000000000000000000000000000000000000000f00000f00000</row>
<row>000000000000000000000000000000000000000000f00000000f00</row>
<row>000000000000000000000000000000000000000000f00000000000</row>
<row>000000000000000000000000000000000000000000f00000000000</row>
<row>000000000000000000000000000000000000000000f00000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000000000f00000000000000</row>
<row>000000000000000000000000000000000000000f00f00000000000</row>
<row>000000000000000000000000000000000000000f00000f00000f00</row>
<row>000000000000000000000000000000000000000f00000000f00000</row>
<row>000000000000000000000000000000000000000f00000000000000</row>
<row>000000000000000000000000000000000000000f00000000000000</row>
<row>000000000000000000000000000000000000000f00000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000000f00000000000000000</row>
<row>000000000000000000000000000000000000f00f00000000000f00</row>
<row>000000000000000000000000000000000000f00000f00000f00000</row>
<row>000000000000000000000000000000000000f00000000f00000000</row>
<row>000000000000000000000000000000000000f00000000000000000</row>
<row>000000000000000000000000000000000000f00000000000000000</row>
<row>000000000000000000000000000000000000f00000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000f00000000000000000f00</row>
<row>000000000000000000000000000000000f00f00000000000f00f00</row>
<row>000000000000000000000000000000000f00000f00000f00000f00</row>
<row>000000000000000000000000000000000f00000000f00000000f00</row>
<row>000000000000000000000000000000000f00000000000000000f00</row>
<row>000000000000000000000000000000000f00000000000000000f00</row>
<row>000000000000000000000000000000000f00000000000000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000f00000000000000000f00000</row>
<row>000000000000000000000000000000f00f00000000000f00f00000</row>
<row>000000000000000000000000000000f00000f00000f00000f00000</row>
<row>000000000000000000000000000000f00000000f00000000f00000</row>
<row>000000000000000000000000000000f00000000000000000f00000</row>
<row>000000000000000000000000000000f00000000000000000f00000</row>
<row>000000000000000000000000000000f00000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000f00000000000000000f00000f00</row>
<row>000000000000000000000000000f00f00000000000f00f00000f00</row>
<row>000000000000000000000000000f00000f00000f00000f00000f00</row>
<row>000000000000000000000000000f00000000f00000000f00000f00</row>
<row>000000000000000000000000000f00000000000000000f00000f00</row>
<row>000000000000000000000000000f00000000000000000f00000f00</row>
<row>000000000000000000000000000f00000000000000000f00000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000f00000000000000000f00000f00f00</row>
<row>000000000000000000000000f00f00000000000f00f00000f00000</row>
<row>000000000000000000000000f00000f00000f00000f00000f00000</row>
<row>000000000000000000000000f00000000f00000000f00000f00f00</row>
<row>000000000000000000000000f00000000000000000f00000f00000</row>
<row>000000000000000000000000f00000000000000000f00000f00000</row>
<row>000000000000000000000000f00000000000000000f00000f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000f00000000000000000f00000f00f00f00</row>
<row>000000000000000000000f00f00000000000f00f00000f00000000</row>
<row>000000000000000000000f00000f00000f00000f00000f00000000</row>
<row>000000000000000000000f00000000f00000000f00000f00f00f00</row>
<row>000000000000000000000f00000000000000000f00000f00000000</row>
<row>000000000000000000000f00000000000000000f00000f00000000</row>
<row>000000000000000000000f00000000000000000f00000f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000f00000000000000000f00000f00f00f00f00</row>
<row>000000000000000000f00f00000000000f00f00000f00000000000</row>
<row>000000000000000000f00000f00000f00000f00000f00000000000</row>
<row>000000000000000000f00000000f00000000f00000f00f00f00f00</row>
<row>000000000000000000f00000000000000000f00000f00000000f00</row>
<row>000000000000000000f00000000000000000f00000f00000000000</row>
<row>000000000000000000f00000000000000000f00000f00000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000f00000000000000000f00000f00f00f00f00f00</row>
<row>000000000000000f00f00000000000f00f00000f00000000000000</row>
<row>000000000000000f00000f00000f00000f00000f00000000000000</row>
<row>000000000000000f00000000f00000000f00000f00f00f00f00f00</row>
<row>000000000000000f00000000000000000f00000f00000000f00000</row>
<row>000000000000000f00000000000000000f00000f00000000000f00</row>
<row>000000000000000f00000000000000000f00000f00000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000f00000000000000000f00000f00f00f00f00f00f00</row>
<row>000000000000f00f00000000000f00f00000f00000000000000000</row>
<row>000000000000f00000f00000f00000f00000f00000000000000000</row>
<row>000000000000f00000000f00000000f00000f00f00f00f00f00f00</row>
<row>000000000000f00000000000000000f00000f00000000f00000000</row>
<row>000000000000f00000000000000000f00000f00000000000f00000</row>
<row>000000000000f00000000000000000f00000f00000000000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000f00000000000000000f00000f00f00f00f00f00f00000</row>
<row>000000000f00f00000000000f00f00000f00000000000000000f00</row>
<row>000000000f00000f00000f00000f00000f00000000000000000f00</row>
<row>000000000f00000000f00000000f00000f00f00f00f00f00f00000</row>
<row>000000000f00000000000000000f00000f00000000f00000000000</row>
<row>000000000f00000000000000000f00000f00000000000f00000000</row>
<row>000000000f00000000000000000f00000f00000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00000000000000000f00000f00f00f00f00f00f00000000</row>
<row>000000f00f00000000000f00f00000f00000000000000000f00000</row>
<row>000000f00000f00000f00000f00000f00000000000000000f00000</row>
<row>000000f00000000f00000000f00000f00f00f00f00f00f00000000</row>
<row>000000f00000000000000000f00000f00000000f00000000000000</row>
<row>000000f00000000000000000f00000f00000000000f00000000000</row>
<row>000000f00000000000000000f00000f00000000000000f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00000000000000000f00000f00f00f00f00f00f00000000f00</row>
<row>000f00f00000000000f00f00000f00000000000000000f00000f00</row>
<row>000f00000f00000f00000f00000f00000000000000000f00000f00</row>
<row>000f00000000f00000000f00000f00f00f00f00f00f00000000f00</row>
<row>000f00000000000000000f00000f00000000f00000000000000f00</row>
<row>000f00000000000000000f00000f00000000000f00000000000f00</row>
<row>000f00000000000000000f00000f00000000000000f00000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000000000000f00000f00f00f00f00f00f00000000f00000</row>
<row>f00f00000000000f00f00000f00000000000000000f00000f00f00</row>
<row>f00000f00000f00000f00000f00000000000000000f00000f00000</row>
<row>f00000000f00000000f00000f00f00f00f00f00f00000000f00000</row>
<row>f00000000000000000f00000f00000000f00000000000000f00000</row>
<row>f00000000000000000f00000f00000000000f00000000000f00000</row>
<row>f00000000000000000f00000f00000000000000f00000000f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000f00000f00f00f00f00f00f00000000f00000000</row>
<row>f00000000000f00f00000f00000000000000000f00000f00f00000</row>
<row>000f00000f00000f00000f00000000000000000f00000f00000f00</row>
<row>000000f00000000f00000f00f00f00f00f00f00000000f00000000</row>
<row>000000000000000f00000f00000000f00000000000000f00000000</row>
<row>000000000000000f00000f00000000000f00000000000f00000000</row>
<row>000000000000000f00000f00000000000000f00000000f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000f00000f00f00f00f00f00f00000000f00000000000</row>
<row>000000000f00f00000f00000000000000000f00000f00f00000000</row>
<row>f00000f00000f00000f00000000000000000f00000f00000f00000</row>
<row>000f00000000f00000f00f00f00f00f00f00000000f00000000f00</row>
<row>000000000000f00000f00000000f00000000000000f00000000000</row>
<row>000000000000f00000f00000000000f00000000000f00000000000</row>
<row>000000000000f00000f00000000000000f00000000f00000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000f00000f00f00f00f00f00f00000000f00000000000000</row>
<row>000000f00f00000f00000000000000000f00000f00f00000000000</row>
<row>000f00000f00000f00000000000000000f00000f00000f00000f00</row>
<row>f00000000f00000f00f00f00f00f00f00000000f00000000f00000</row>
<row>000000000f00000f00000000f00000000000000f00000000000000</row>
<row>000000000f00000f00000000000f00000000000f00000000000000</row>
<row>000000000f00000f00000000000000f00000000f00000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00000f00f00f00f00f00f00000000f00000000000000000</row>
<row>000f00f00000f00000000000000000f00000f00f00000000000f00</row>
<row>f00000f00000f00000000000000000f00000f00000f00000f00000</row>
<row>000000f00000f00f00f00f00f00f00000000f00000000f00000000</row>
<row>000000f00000f00000000f00000000000000f00000000000000000</row>
<row>000000f00000f00000000000f00000000000f00000000000000000</row>
<row>000000f00000f00000000000000f00000000f00000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00000f00f00f00f00f00f00000000f00000000000000000f00</row>
<row>f00f00000f00000000000000000f00000f00f00000000000f00f00</row>
<row>000f00000f00000000000000000f00000f00000f00000f00000f00</row>
<row>000f00000f00f00f00f00f00f00000000f00000000f00000000f00</row>
<row>000f00000f00000000f00000000000000f00000000000000000f00</row>
<row>000f00000f00000000000f00000000000f00000000000000000f00</row>
<row>000f00000f00000000000000f00000000f00000000000000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000f00f00f00f00f00f00000000f00000000000000000f00000</row>
<row>f00000f00000000000000000f00000f00f00000000000f00f00000</row>
<row>f00000f00000000000000000f00000f00000f00000f00000f00000</row>
<row>f00000f00f00f00f00f00f00000000f00000000f00000000f00000</row>
<row>f00000f00000000f00000000000000f00000000000000000f00000</row>
<row>f00000f00000000000f00000000000f00000000000000000f00000</row>
<row>f00000f00000000000000f00000000f00000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00f00f00f00f00f00000000f00000000000000000f00000000</row>
<row>000f00000000000000000f00000f00f00000000000f00f00000f00</row>
<row>000f00000000000000000f00000f00000f00000f00000f00000f00</row>
<row>000f00f00f00f00f00f00000000f00000000f00000000f00000f00</row>
<row>000f00000000f00000000000000f00000000000000000f00000f00</row>
<row>000f00000000000f00000000000f00000000000000000f00000f00</row>
<row>000f00000000000000f00000000f00000000000000000f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00f00f00000000f00000000000000000f00000000f00</row>
<row>f00000000000000000f00000f00f00000000000f00f00000f00000</row>
<row>f00000000000000000f00000f00000f00000f00000f00000f00000</row>
<row>f00f00f00f00f00f00000000f00000000f00000000f00000f00000</row>
<row>f00000000f00000000000000f00000000000000000f00000f00000</row>
<row>f00000000000f00000000000f00000000000000000f00000f00000</row>
<row>f00000000000000f00000000f00000000000000000f00000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00f00000000f00000000000000000f00000000f00f00</row>
<row>000000000000000f00000f00f00000000000f00f00000f00000000</row>
<row>000000000000000f00000f00000f00000f00000f00000f00000000</row>
<row>f00f00f00f00f00000000f00000000f00000000f00000f00000000</row>
<row>000000f00000000000000f00000000000000000f00000f00000000</row>
<row>000000000f00000000000f00000000000000000f00000f00000000</row>
<row>000000000000f00000000f00000000000000000f00000000f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00000000f00000000000000000f00000000f00f00f00</row>
<row>000000000000f00000f00f00000000000f00f00000f00000000000</row>
<row>000000000000f00000f00000f00000f00000f00000f00000000000</row>
<row>f00f00f00f00000000f00000000f00000000f00000f00000000000</row>
<row>000f00000000000000f00000000000000000f00000f00000000000</row>
<row>000000f00000000000f00000000000000000f00000f00000000000</row>
<row>000000000f00000000f00000000000000000f00000000f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00000000f00000000000000000f00000000f00f00f00f00</row>
<row>000000000f00000f00f00000000000f00f00000f00000000000000</row>
<row>000000000f00000f00000f00000f00000f00000f00000000000000</row>
<row>f00f00f00000000f00000000f00000000f00000f00000000000000</row>
<row>f00000000000000f00000000000000000f00000f00000000000000</row>
<row>000f00000000000f00000000000000000f00000f00000000000000</row>
<row>000000f00000000f00000000000000000f00000000f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00000000f00000000000000000f00000000f00f00f00f00f00</row>
<row>000000f00000f00f00000000000f00f00000f00000000000000000</row>
<row>000000f00000f00000f00000f00000f00000f00000000000000000</row>
<row>f00f00000000f00000000f00000000f00000f00000000000000000</row>
<row>000000000000f00000000000000000f00000f00000000000000000</row>
<row>f00000000000f00000000000000000f00000f00000000000000000</row>
<row>000f00000000f00000000000000000f00000000f00f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000f00000000000000000f00000000f00f00f00f00f00f00</row>
<row>000f00000f00f00000000000f00f00000f00000000000000000000</row>
<row>000f00000f00000f00000f00000f00000f00000000000000000000</row>
<row>f00000000f00000000f00000000f00000f00000000000000000000</row>
<row>000000000f00000000000000000f00000f00000000000000000000</row>
<row>000000000f00000000000000000f00000f00000000000000000000</row>
<row>f00000000f00000000000000000f00000000f00f00f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00000000000000000f00000000f00f00f00f00f00f00000</row>
<row>f00000f00f00000000000f00f00000f00000000000000000000000</row>
<row>f00000f00000f00000f00000f00000f00000000000000000000000</row>
<row>000000f00000000f00000000f00000f00000000000000000000000</row>
<row>000000f00000000000000000f00000f00000000000000000000000</row>
<row>000000f00000000000000000f00000f00000000000000000000000</row>
<row>000000f00000000000000000f00000000f00f00f00f00f00f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00000000000000000f00000000f00f00f00f00f00f00000f00</row>
<row>000f00f00000000000f00f00000f00000000000000000000000f00</row>
<row>000f00000f00000f00000f00000f00000000000000000000000f00</row>
<row>000f00000000f00000000f00000f00000000000000000000000f00</row>
<row>000f00000000000000000f00000f00000000000000000000000f00</row>
<row>000f00000000000000000f00000f00000000000000000000000f00</row>
<row>000f00000000000000000f00000000f00f00f00f00f00f00000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000000000000f00000000f00f00f00f00f00f00000f00f00</row>
<row>f00f00000000000f00f00000f00000000000000000000000f00000</row>
<row>f00000f00000f00000f00000f00000000000000000000000f00000</row>
<row>f00000000f00000000f00000f00000000000000000000000f00000</row>
<row>f00000000000000000f00000f00000000000000000000000f00000</row>
<row>f00000000000000000f00000f00000000000000000000000f00000</row>
<row>f00000000000000000f00000000f00f00f00f00f00f00000f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000f00000000f00f00f00f00f00f00000f00f00f00</row>
<row>f00000000000f00f00000f00000000000000000000000f00000000</row>
<row>000f00000f00000f00000f00000000000000000000000f00000000</row>
<row>000000f00000000f00000f00000000000000000000000f00000000</row>
<row>000000000000000f00000f00000000000000000000000f00000000</row>
<row>000000000000000f00000f00000000000000000000000f00000000</row>
<row>000000000000000f00000000f00f00f00f00f00f00000f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000f00000000f00f00f00f00f00f00000f00f00f00f00</row>
<row>000000000f00f00000f00000000000000000000000f00000000000</row>
<row>f00000f00000f00000f00000000000000000000000f00000000000</row>
<row>000f00000000f00000f00000000000000000000000f00000000000</row>
<row>000000000000f00000f00000000000000000000000f00000000000</row>
<row>000000000000f00000f00000000000000000000000f00000000000</row>
<row>000000000000f00000000f00f00f00f00f00f00000f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000f00000000f00f00f00f00f00f00000f00f00f00f00f00</row>
<row>000000f00f00000f00000000000000000000000f00000000000000</row>
<row>000f00000f00000f00000000000000000000000f00000000000000</row>
<row>f00000000f00000f00000000000000000000000f00000000000000</row>
<row>000000000f00000f00000000000000000000000f00000000000000</row>
<row>000000000f00000f00000000000000000000000f00000000000000</row>
<row>000000000f00000000f00f00f00f00f00f00000f00f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00000000f00f00f00f00f00f00000f00f00f00f00f00000</row>
<row>000f00f00000f00000000000000000000000f00000000000000f00</row>
<row>f00000f00000f00000000000000000000000f00000000000000000</row>
<row>000000f00000f00000000000000000000000f00000000000000000</row>
<row>000000f00000f00000000000000000000000f00000000000000000</row>
<row>000000f00000f00000000000000000000000f00000000000000f00</row>
<row>000000f00000000f00f00f00f00f00f00000f00f00f00f00f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00000000f00f00f00f00f00f00000f00f00f00f00f00000000</row>
<row>f00f00000f00000000000000000000000f00000000000000f00000</row>
<row>000f00000f00000000000000000000000f00000000000000000f00</row>
<row>000f00000f00000000000000000000000f00000000000000000f00</row>
<row>000f00000f00000000000000000000000f00000000000000000f00</row>
<row>000f00000f00000000000000000000000f00000000000000f00000</row>
<row>000f00000000f00f00f00f00f00f00000f00f00f00f00f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000f00f00f00f00f00f00000f00f00f00f00f00000000000</row>
<row>f00000f00000000000000000000000f00000000000000f00000000</row>
<row>f00000f00000000000000000000000f00000000000000000f00000</row>
<row>f00000f00000000000000000000000f00000000000000000f00000</row>
<row>f00000f00000000000000000000000f00000000000000000f00000</row>
<row>f00000f00000000000000000000000f00000000000000f00000000</row>
<row>f00000000f00f00f00f00f00f00000f00f00f00f00f00000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00f00f00f00f00f00000f00f00f00f00f00000000000000</row>
<row>000f00000000000000000000000f00000000000000f00000000f00</row>
<row>000f00000000000000000000000f00000000000000000f00000000</row>
<row>000f00000000000000000000000f00000000000000000f00000000</row>
<row>000f00000000000000000000000f00000000000000000f00000000</row>
<row>000f00000000000000000000000f00000000000000f00000000f00</row>
<row>000000f00f00f00f00f00f00000f00f00f00f00f00000000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00f00f00f00f00f00000f00f00f00f00f00000000000000f00</row>
<row>f00000000000000000000000f00000000000000f00000000f00000</row>
<row>f00000000000000000000000f00000000000000000f00000000000</row>
<row>f00000000000000000000000f00000000000000000f00000000000</row>
<row>f00000000000000000000000f00000000000000000f00000000f00</row>
<row>f00000000000000000000000f00000000000000f00000000f00000</row>
<row>000f00f00f00f00f00f00000f00f00f00f00f00000000000f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00f00f00000f00f00f00f00f00000000000000f00f00</row>
<row>000000000000000000000f00000000000000f00000000f00000000</row>
<row>000000000000000000000f00000000000000000f00000000000000</row>
<row>000000000000000000000f00000000000000000f00000000000f00</row>
<row>000000000000000000000f00000000000000000f00000000f00000</row>
<row>000000000000000000000f00000000000000f00000000f00000000</row>
<row>f00f00f00f00f00f00000f00f00f00f00f00000000000f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00f00000f00f00f00f00f00000000000000f00f00f00</row>
<row>000000000000000000f00000000000000f00000000f00000000000</row>
<row>000000000000000000f00000000000000000f00000000000000000</row>
<row>000000000000000000f00000000000000000f00000000000f00f00</row>
<row>000000000000000000f00000000000000000f00000000f00000000</row>
<row>000000000000000000f00000000000000f00000000f00000000000</row>
<row>f00f00f00f00f00000f00f00f00f00f00000000000f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00000f00f00f00f00f00000000000000f00f00f00f00</row>
<row>000000000000000f00000000000000f00000000f00000000000000</row>
<row>000000000000000f00000000000000000f00000000000000000000</row>
<row>000000000000000f00000000000000000f00000000000f00f00f00</row>
<row>000000000000000f00000000000000000f00000000f00000000000</row>
<row>000000000000000f00000000000000f00000000f00000000000000</row>
<row>f00f00f00f00000f00f00f00f00f00000000000f00f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00000f00f00f00f00f00000000000000f00f00f00f00f00</row>
<row>000000000000f00000000000000f00000000f00000000000000000</row>
<row>000000000000f00000000000000000f00000000000000000000000</row>
<row>000000000000f00000000000000000f00000000000f00f00f00f00</row>
<row>000000000000f00000000000000000f00000000f00000000000000</row>
<row>000000000000f00000000000000f00000000f00000000000000000</row>
<row>f00f00f00000f00f00f00f00f00000000000f00f00f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00000f00f00f00f00f00000000000000f00f00f00f00f00000</row>
<row>000000000f00000000000000f00000000f00000000000000000f00</row>
<row>000000000f00000000000000000f00000000000000000000000f00</row>
<row>000000000f00000000000000000f00000000000f00f00f00f00000</row>
<row>000000000f00000000000000000f00000000f00000000000000000</row>
<row>000000000f00000000000000f00000000f00000000000000000000</row>
<row>f00f00000f00f00f00f00f00000000000f00f00f00f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000f00f00f00f00f00000000000000f00f00f00f00f00000000</row>
<row>000000f00000000000000f00000000f00000000000000000f00000</row>
<row>000000f00000000000000000f00000000000000000000000f00000</row>
<row>000000f00000000000000000f00000000000f00f00f00f00000000</row>
<row>000000f00000000000000000f00000000f00000000000000000000</row>
<row>000000f00000000000000f00000000f00000000000000000000000</row>
<row>f00000f00f00f00f00f00000000000f00f00f00f00f00f00f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00f00f00f00f00000000000000f00f00f00f00f00000000000</row>
<row>000f00000000000000f00000000f00000000000000000f00000f00</row>
<row>000f00000000000000000f00000000000000000000000f00000f00</row>
<row>000f00000000000000000f00000000000f00f00f00f00000000f00</row>
<row>000f00000000000000000f00000000f00000000000000000000f00</row>
<row>000f00000000000000f00000000f00000000000000000000000f00</row>
<row>000f00f00f00f00f00000000000f00f00f00f00f00f00f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00f00000000000000f00f00f00f00f00000000000f00</row>
<row>f00000000000000f00000000f00000000000000000f00000f00000</row>
<row>f00000000000000000f00000000000000000000000f00000f00000</row>
<row>f00000000000000000f00000000000f00f00f00f00000000f00000</row>
<row>f00000000000000000f00000000f00000000000000000000f00000</row>
<row>f00000000000000f00000000f00000000000000000000000f00000</row>
<row>f00f00f00f00f00000000000f00f00f00f00f00f00f00000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00000000000000f00f00f00f00f00000000000f00f00</row>
<row>000000000000f00000000f00000000000000000f00000f00000000</row>
<row>000000000000000f00000000000000000000000f00000f00000000</row>
<row>000000000000000f00000000000f00f00f00f00000000f00000000</row>
<row>000000000000000f00000000f00000000000000000000f00000000</row>
<row>000000000000f00000000f00000000000000000000000f00000000</row>
<row>f00f00f00f00000000000f00f00f00f00f00f00f00000000f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00000000000000f00f00f00f00f00000000000f00f00f00</row>
<row>000000000f00000000f00000000000000000f00000f00000000000</row>
<row>000000000000f00000000000000000000000f00000f00000000000</row>
<row>000000000000f00000000000f00f00f00f00000000f00000000000</row>
<row>000000000000f00000000f00000000000000000000f00000000000</row>
<row>000000000f00000000f00000000000000000000000f00000000000</row>
<row>f00f00f00000000000f00f00f00f00f00f00f00000000f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00000000000000f00f00f00f00f00000000000f00f00f00f00</row>
<row>000000f00000000f00000000000000000f00000f00000000000000</row>
<row>000000000f00000000000000000000000f00000f00000000000000</row>
<row>000000000f00000000000f00f00f00f00000000f00000000000000</row>
<row>000000000f00000000f00000000000000000000f00000000000000</row>
<row>000000f00000000f00000000000000000000000f00000000000000</row>
<row>f00f00000000000f00f00f00f00f00f00f00000000f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000000000f00f00f00f00f00000000000f00f00f00f00f00</row>
<row>000f00000000f00000000000000000f00000f00000000000000000</row>
<row>000000f00000000000000000000000f00000f00000000000000000</row>
<row>000000f00000000000f00f00f00f00000000f00000000000000000</row>
<row>000000f00000000f00000000000000000000f00000000000000000</row>
<row>000f00000000f00000000000000000000000f00000000000000000</row>
<row>f00000000000f00f00f00f00f00f00f00000000f00f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000f00f00f00f00f00000000000f00f00f00f00f00000</row>
<row>f00000000f00000000000000000f00000f00000000000000000f00</row>
<row>000f00000000000000000000000f00000f00000000000000000f00</row>
<row>000f00000000000f00f00f00f00000000f00000000000000000f00</row>
<row>000f00000000f00000000000000000000f00000000000000000f00</row>
<row>f00000000f00000000000000000000000f00000000000000000f00</row>
<row>000000000f00f00f00f00f00f00f00000000f00f00f00f00f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000f00f00f00f00f00000000000f00f00f00f00f00000000</row>
<row>000000f00000000000000000f00000f00000000000000000f00000</row>
<row>f00000000000000000000000f00000f00000000000000000f00000</row>
<row>f00000000000f00f00f00f00000000f00000000000000000f00000</row>
<row>f00000000f00000000000000000000f00000000000000000f00000</row>
<row>000000f00000000000000000000000f00000000000000000f00000</row>
<row>000000f00f00f00f00f00f00f00000000f00f00f00f00f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00f00f00f00f00000000000f00f00f00f00f00000000000</row>
<row>000f00000000000000000f00000f00000000000000000f00000000</row>
<row>000000000000000000000f00000f00000000000000000f00000f00</row>
<row>000000000f00f00f00f00000000f00000000000000000f00000000</row>
<row>000000f00000000000000000000f00000000000000000f00000000</row>
<row>000f00000000000000000000000f00000000000000000f00000000</row>
<row>000f00f00f00f00f00f00f00000000f00f00f00f00f00000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00f00f00f00f00000000000f00f00f00f00f00000000000000</row>
<row>f00000000000000000f00000f00000000000000000f00000000f00</row>
<row>000000000000000000f00000f00000000000000000f00000f00000</row>
<row>000000f00f00f00f00000000f00000000000000000f00000000000</row>
<row>000f00000000000000000000f00000000000000000f00000000000</row>
<row>f00000000000000000000000f00000000000000000f00000000000</row>
<row>f00f00f00f00f00f00f00000000f00f00f00f00f00000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00f00000000000f00f00f00f00f00000000000000f00</row>
<row>000000000000000f00000f00000000000000000f00000000f00000</row>
<row>000000000000000f00000f00000000000000000f00000f00000000</row>
<row>000f00f00f00f00000000f00000000000000000f00000000000000</row>
<row>f00000000000000000000f00000000000000000f00000000000000</row>
<row>000000000000000000000f00000000000000000f00000000000000</row>
<row>f00f00f00f00f00f00000000f00f00f00f00f00000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00000000000f00f00f00f00f00000000000000f00f00</row>
<row>000000000000f00000f00000000000000000f00000000f00000f00</row>
<row>000000000000f00000f00000000000000000f00000f00000000f00</row>
<row>f00f00f00f00000000f00000000000000000f00000000000000f00</row>
<row>000000000000000000f00000000000000000f00000000000000f00</row>
<row>000000000000000000f00000000000000000f00000000000000f00</row>
<row>f00f00f00f00f00000000f00f00f00f00f00000000000000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00000000000f00f00f00f00f00000000000000f00f00000</row>
<row>000000000f00000f00000000000000000f00000000f00000f00000</row>
<row>000000000f00000f00000000000000000f00000f00000000f00000</row>
<row>f00f00f00000000f00000000000000000f00000000000000f00000</row>
<row>000000000000000f00000000000000000f00000000000000f00000</row>
<row>000000000000000f00000000000000000f00000000000000f00000</row>
<row>f00f00f00f00000000f00f00f00f00f00000000000000000f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00000000000f00f00f00f00f00000000000000f00f00000000</row>
<row>000000f00000f00000000000000000f00000000f00000f00000f00</row>
<row>000000f00000f00000000000000000f00000f00000000f00000000</row>
<row>f00f00000000f00000000000000000f00000000000000f00000000</row>
<row>000000000000f00000000000000000f00000000000000f00000000</row>
<row>000000000000f00000000000000000f00000000000000f00000f00</row>
<row>f00f00f00000000f00f00f00f00f00000000000000000f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000000f00f00f00f00f00000000000000f00f00000000f00</row>
<row>000f00000f00000000000000000f00000000f00000f00000f00000</row>
<row>000f00000f00000000000000000f00000f00000000f00000000000</row>
<row>f00000000f00000000000000000f00000000000000f00000000000</row>
<row>000000000f00000000000000000f00000000000000f00000000000</row>
<row>000000000f00000000000000000f00000000000000f00000f00000</row>
<row>f00f00000000f00f00f00f00f00000000000000000f00000000f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000f00f00f00f00f00000000000000f00f00000000f00f00</row>
<row>f00000f00000000000000000f00000000f00000f00000f00000000</row>
<row>f00000f00000000000000000f00000f00000000f00000000000000</row>
<row>000000f00000000000000000f00000000000000f00000000000f00</row>
<row>000000f00000000000000000f00000000000000f00000000000000</row>
<row>000000f00000000000000000f00000000000000f00000f00000000</row>
<row>f00000000f00f00f00f00f00000000000000000f00000000f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00f00f00f00f00000000000000f00f00000000f00f00f00</row>
<row>000f00000000000000000f00000000f00000f00000f00000000000</row>
<row>000f00000000000000000f00000f00000000f00000000000000000</row>
<row>000f00000000000000000f00000000000000f00000000000f00f00</row>
<row>000f00000000000000000f00000000000000f00000000000000000</row>
<row>000f00000000000000000f00000000000000f00000f00000000000</row>
<row>000000f00f00f00f00f00000000000000000f00000000f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00f00f00f00f00000000000000f00f00000000f00f00f00f00</row>
<row>f00000000000000000f00000000f00000f00000f00000000000000</row>
<row>f00000000000000000f00000f00000000f00000000000000000000</row>
<row>f00000000000000000f00000000000000f00000000000f00f00f00</row>
<row>f00000000000000000f00000000000000f00000000000000000000</row>
<row>f00000000000000000f00000000000000f00000f00000000000000</row>
<row>000f00f00f00f00f00000000000000000f00000000f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00f00000000000000f00f00000000f00f00f00f00f00</row>
<row>000000000000000f00000000f00000f00000f00000000000000000</row>
<row>000000000000000f00000f00000000f00000000000000000000000</row>
<row>000000000000000f00000000000000f00000000000f00f00f00f00</row>
<row>000000000000000f00000000000000f00000000000000000000000</row>
<row>000000000000000f00000000000000f00000f00000000000000000</row>
<row>f00f00f00f00f00000000000000000f00000000f00f00f00f00f00</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00000000000000f00f00000000f00f00f00f00f00000</row>
<row>000000000000f00000000f00000f00000f00000000000000000f00</row>
<row>000000000000f00000f00000000f00000000000000000000000f00</row>
<row>000000000000f00000000000000f00000000000f00f00f00f00000</row>
<row>000000000000f00000000000000f00000000000000000000000f00</row>
<row>000000000000f00000000000000f00000f00000000000000000f00</row>
<row>f00f00f00f00000000000000000f00000000f00f00f00f00f00000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00000000000000f00f00000000f00f00f00f00f00000000</row>
<row>000000000f00000000f00000f00000f00000000000000000f00000</row>
<row>000000000f00000f00000000f00000000000000000000000f00000</row>
<row>000000000f00000000000000f00000000000f00f00f00f00000000</row>
<row>000000000f00000000000000f00000000000000000000000f00000</row>
<row>000000000f00000000000000f00000f00000000000000000f00000</row>
<row>f00f00f00000000000000000f00000000f00f00f00f00f00000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00000000000000f00f00000000f00f00f00f00f00000000000</row>
<row>000000f00000000f00000f00000f00000000000000000f00000000</row>
<row>000000f00000f00000000f00000000000000000000000f00000000</row>
<row>000000f00000000000000f00000000000f00f00f00f00000000000</row>
<row>000000f00000000000000f00000000000000000000000f00000000</row>
<row>000000f00000000000000f00000f00000000000000000f00000000</row>
<row>f00f00000000000000000f00000000f00f00f00f00f00000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000000000f00f00000000f00f00f00f00f00000000000000</row>
<row>000f00000000f00000f00000f00000000000000000f00000000000</row>
<row>000f00000f00000000f00000000000000000000000f00000000000</row>
<row>000f00000000000000f00000000000f00f00f00f00000000000000</row>
<row>000f00000000000000f00000000000000000000000f00000000000</row>
<row>000f00000000000000f00000f00000000000000000f00000000000</row>
<row>f00000000000000000f00000000f00f00f00f00f00000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000f00f00000000f00f00f00f00f00000000000000000</row>
<row>f00000000f00000f00000f00000000000000000f00000000000000</row>
<row>f00000f00000000f00000000000000000000000f00000000000000</row>
<row>f00000000000000f00000000000f00f00f00f00000000000000000</row>
<row>f00000000000000f00000000000000000000000f00000000000000</row>
<row>f00000000000000f00000f00000000000000000f00000000000000</row>
<row>000000000000000f00000000f00f00f00f00f00000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000f00f00000000f00f00f00f00f00000000000000000000</row>
<row>000000f00000f00000f00000000000000000f00000000000000000</row>
<row>000f00000000f00000000000000000000000f00000000000000000</row>
<row>000000000000f00000000000f00f00f00f00000000000000000000</row>
<row>000000000000f00000000000000000000000f00000000000000000</row>
<row>000000000000f00000f00000000000000000f00000000000000000</row>
<row>000000000000f00000000f00f00f00f00f00000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00f00000000f00f00f00f00f00000000000000000000000</row>
<row>000f00000f00000f00000000000000000f00000000000000000000</row>
<row>f00000000f00000000000000000000000f00000000000000000000</row>
<row>000000000f00000000000f00f00f00f00000000000000000000000</row>
<row>000000000f00000000000000000000000f00000000000000000000</row>
<row>000000000f00000f00000000000000000f00000000000000000000</row>
<row>000000000f00000000f00f00f00f00f00000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00f00000000f00f00f00f00f00000000000000000000000000</row>
<row>f00000f00000f00000000000000000f00000000000000000000000</row>
<row>000000f00000000000000000000000f00000000000000000000000</row>
<row>000000f00000000000f00f00f00f00000000000000000000000000</row>
<row>000000f00000000000000000000000f00000000000000000000000</row>
<row>000000f00000f00000000000000000f00000000000000000000000</row>
<row>000000f00000000f00f00f00f00f00000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00000000f00f00f00f00f00000000000000000000000000000</row>
<row>000f00000f00000000000000000f00000000000000000000000000</row>
<row>000f00000000000000000000000f00000000000000000000000000</row>
<row>000f00000000000f00f00f00f00000000000000000000000000000</row>
<row>000f00000000000000000000000f00000000000000000000000000</row>
<row>000f00000f00000000000000000f00000000000000000000000000</row>
<row>000f00000000f00f00f00f00f00000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000f00f00f00f00f00000000000000000000000000000000</row>
<row>f00000f00000000000000000f00000000000000000000000000000</row>
<row>f00000000000000000000000f00000000000000000000000000000</row>
<row>f00000000000f00f00f00f00000000000000000000000000000000</row>
<row>f00000000000000000000000f00000000000000000000000000000</row>
<row>f00000f00000000000000000f00000000000000000000000000000</row>
<row>f00000000f00f00f00f00f00000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000f00f00f00f00f00000000000000000000000000000000000</row>
<row>000f00000000000000000f00000000000000000000000000000000</row>
<row>000000000000000000000f00000000000000000000000000000000</row>
<row>000000000f00f00f00f00000000000000000000000000000000000</row>
<row>000000000000000000000f00000000000000000000000000000000</row>
<row>000f00000000000000000f00000000000000000000000000000000</row>
<row>000000f00f00f00f00f00000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000f00f00f00f00f00000000000000000000000000000000000000</row>
<row>f00000000000000000f00000000000000000000000000000000000</row>
<row>000000000000000000f00000000000000000000000000000000000</row>
<row>000000f00f00f00f00000000000000000000000000000000000000</row>
<row>000000000000000000f00000000000000000000000000000000000</row>
<row>f00000000000000000f00000000000000000000000000000000000</row>
<row>000f00f00f00f00f00000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00f00000000000000000000000000000000000000000</row>
<row>000000000000000f00000000000000000000000000000000000000</row>
<row>000000000000000f00000000000000000000000000000000000000</row>
<row>000f00f00f00f00000000000000000000000000000000000000000</row>
<row>000000000000000f00000000000000000000000000000000000000</row>
<row>000000000000000f00000000000000000000000000000000000000</row>
<row>f00f00f00f00f00000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00f00000000000000000000000000000000000000000000</row>
<row>000000000000f00000000000000000000000000000000000000000</row>
<row>000000000000f00000000000000000000000000000000000000000</row>
<row>f00f00f00f00000000000000000000000000000000000000000000</row>
<row>000000000000f00000000000000000000000000000000000000000</row>
<row>000000000000f00000000000000000000000000000000000000000</row>
<row>f00f00f00f00000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00f00000000000000000000000000000000000000000000000</row>
<row>000000000f00000000000000000000000000000000000000000000</row>
<row>000000000f00000000000000000000000000000000000000000000</row>
<row>f00f00f00000000000000000000000000000000000000000000000</row>
<row>000000000f00000000000000000000000000000000000000000000</row>
<row>000000000f00000000000000000000000000000000000000000000</row>
<row>f00f00f00000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00f00000000000000000000000000000000000000000000000000</row>
<row>000000f00000000000000000000000000000000000000000000000</row>
<row>000000f00000000000000000000000000000000000000000000000</row>
<row>f00f00000000000000000000000000000000000000000000000000</row>
<row>000000f00000000000000000000000000000000000000000000000</row>
<row>000000f00000000000000000000000000000000000000000000000</row>
<row>f00f00000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>f00000000000000000000000000000000000000000000000000000</row>
<row>000f00000000000000000000000000000000000000000000000000</row>
<row>000f00000000000000000000000000000000000000000000000000</row>
<row>f00000000000000000000000000000000000000000000000000000</row>
<row>000f00000000000000000000000000000000000000000000000000</row>
<row>000f00000000000000000000000000000000000000000000000000</row>
<row>f00000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>f00000000000000000000000000000000000000000000000000000</row>
<row>f00000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>f00000000000000000000000000000000000000000000000000000</row>
<row>f00000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="100">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
</blm>

147
playlist.txt

@ -0,0 +1,147 @@ @@ -0,0 +1,147 @@
#heart.blm
#countdown.blm
test.blm
klonfish-dancing.blm
blm/invasion.blm
blm/torus.blm
blm/antiwar.blm
blm/billard.blm
blm/x-ball.blm
blm/game.blm
blm/tropfen.blm
blm/moewe_frontal.blm
blm/fireworks_2.blm
blm/thunderstorm.blm
blm/biker.blm
blm/fantasticspace.blm
blm/allyourbase.blm
blm/21st_century_man.blm
blm/dont_try_at_home.blm
blm/spin.blm
blm/heart.blm
blm/encyclops.blm
blm/fant.blm
blm/schnecke.blm
blm/peao.blm
blm/falling_pix.blm
blm/tetris.blm
blm/text.blm
blm/landing_zone.blm
blm/dance_micky_chickee.blm
blm/supermaennchen.blm
blm/allon.blm
blm/kame.blm
blm/kiss.blm
blm/fallingrows.blm
blm/jesus.blm
blm/vlhurg.blm
blm/wasserhahn.blm
blm/gewaber.blm
blm/tla_them.blm
blm/quix_glitter.blm
blm/herz.blm
blm/sanduhr.blm
blm/defect_car.blm
blm/peepshow.blm
blm/countdown.blm
blm/luftballoons.blm
blm/impaexpa.blm
blm/wein_trinken.blm
blm/coffee.blm
blm/camel.blm
blm/matrix.blm
blm/life.blm
blm/snake.blm
blm/windshield.blm
blm/raumschiff_enterprise.blm
blm/pumpkin.blm
blm/yeastman.blm
blm/genomix.blm
blm/bad_luck.blm
blm/om_sweet_om.blm
blm/invaders_andreas.blm
blm/manifesto5.blm
blm/chat_noir.blm
blm/rakete.blm
blm/manifesto3.blm
blm/relativity.blm
blm/fussballer.blm
blm/sinus.blm
blm/love_triangles.blm
blm/ascii_people.blm
blm/hanoi.blm
blm/monster.blm
blm/come_together.blm
blm/matrix_maennchen.blm
blm/silent_night.blm
blm/halt.blm
blm/das_leben_ist_schoen.blm
blm/moving_car.blm
blm/spirals.blm
blm/mandel.blm
blm/alloff.blm
blm/manifesto1.blm
blm/quantorenlyrik.blm
blm/manifesto4.blm
blm/warterad.blm
blm/surprise.blm
blm/oneon.blm
blm/manifesto7.blm
blm/fireworks.blm
blm/labyrinth.blm
blm/brainfuck.blm
blm/die_erde.blm
blm/klo.blm
blm/psychowarrior.blm
blm/timeless.blm
blm/auge.blm
blm/worm.blm
blm/colagoboom.blm
blm/musterbeispiel.blm
blm/fallingpixels.blm
blm/franknstoned.blm
blm/rollo_grow.blm
blm/illuminati.blm
blm/3rd_advent.blm
blm/chaosknoten.blm
blm/be_happy.blm
blm/binary_god.blm
blm/kingzilla.blm
blm/paradox.blm
blm/dj.blm
blm/hut.blm
blm/sortofselftest.blm
blm/blubb.blm
blm/bleeeh.blm
blm/rain.blm
blm/flash.blm
blm/femina_light.blm
blm/gator_rogat.blm
blm/speedit.blm
blm/scooter.blm
blm/pixie_in_the_box.blm
blm/zeichen.blm
blm/humanistic.blm
blm/pacman_saga.blm
blm/die_autobahn.blm
blm/mytest3.blm
blm/yin_yang.blm
blm/klettermensch.blm
blm/baustein.blm
blm/pwm.blm
blm/babelfish.blm
blm/mytest2.blm
blm/winslows.blm
blm/dance.blm
blm/martelo.blm
blm/raindrops.blm
blm/g.blm
blm/clear.blm
blm/sport_haelt_fit.blm
blm/kreise.blm
blm/railroad.blm
blm/3D_cube.blm
blm/balloon.blm
blm/flipp.blm
blm/mytest.blm
blm/tux.blm

143
playlist2.txt

@ -0,0 +1,143 @@ @@ -0,0 +1,143 @@
blm/invasion.blm
blm/torus.blm
blm/antiwar.blm
blm/billard.blm
blm/x-ball.blm
blm/game.blm
blm/tropfen.blm
blm/moewe_frontal.blm
blm/fireworks_2.blm
blm/thunderstorm.blm
blm/biker.blm
blm/fantasticspace.blm
blm/allyourbase.blm
blm/21st_century_man.blm
blm/dont_try_at_home.blm
blm/spin.blm
blm/heart.blm
blm/encyclops.blm
blm/fant.blm
blm/schnecke.blm
blm/peao.blm
blm/falling_pix.blm
blm/tetris.blm
blm/text.blm
blm/landing_zone.blm
blm/dance_micky_chickee.blm
blm/supermaennchen.blm
blm/allon.blm
blm/kame.blm
blm/kiss.blm
blm/fallingrows.blm
blm/jesus.blm
blm/vlhurg.blm
blm/wasserhahn.blm
blm/gewaber.blm
blm/tla_them.blm
blm/quix_glitter.blm
blm/herz.blm
blm/sanduhr.blm
blm/defect_car.blm
blm/peepshow.blm
blm/countdown.blm
blm/luftballoons.blm
blm/impaexpa.blm
blm/wein_trinken.blm
blm/coffee.blm
blm/camel.blm
blm/matrix.blm
blm/life.blm
blm/snake.blm
blm/windshield.blm
blm/raumschiff_enterprise.blm
blm/pumpkin.blm
blm/yeastman.blm
blm/genomix.blm
blm/bad_luck.blm
blm/om_sweet_om.blm
blm/invaders_andreas.blm
blm/manifesto5.blm
blm/chat_noir.blm
blm/rakete.blm
blm/manifesto3.blm
blm/relativity.blm
blm/fussballer.blm
blm/sinus.blm
blm/love_triangles.blm
blm/ascii_people.blm
blm/hanoi.blm
blm/monster.blm
blm/come_together.blm
blm/matrix_maennchen.blm
blm/silent_night.blm
blm/halt.blm
blm/das_leben_ist_schoen.blm
blm/moving_car.blm
blm/spirals.blm
blm/mandel.blm
blm/alloff.blm
blm/manifesto1.blm
blm/quantorenlyrik.blm
blm/manifesto4.blm
blm/warterad.blm
blm/surprise.blm
blm/oneon.blm
blm/manifesto7.blm
blm/fireworks.blm
blm/labyrinth.blm
blm/brainfuck.blm
blm/die_erde.blm
blm/klo.blm
blm/psychowarrior.blm
blm/timeless.blm
blm/auge.blm
blm/worm.blm
blm/colagoboom.blm
blm/musterbeispiel.blm
blm/fallingpixels.blm
blm/franknstoned.blm
blm/rollo_grow.blm
blm/illuminati.blm
blm/3rd_advent.blm
blm/chaosknoten.blm
blm/be_happy.blm
blm/binary_god.blm
blm/kingzilla.blm
blm/paradox.blm
blm/dj.blm
blm/hut.blm
blm/sortofselftest.blm
blm/blubb.blm
blm/bleeeh.blm
blm/rain.blm
blm/flash.blm
blm/femina_light.blm
blm/gator_rogat.blm
blm/speedit.blm
blm/scooter.blm
blm/pixie_in_the_box.blm
blm/zeichen.blm
blm/humanistic.blm
blm/pacman_saga.blm
blm/die_autobahn.blm
blm/mytest3.blm
blm/yin_yang.blm
blm/klettermensch.blm
blm/baustein.blm
blm/pwm.blm
blm/babelfish.blm
blm/mytest2.blm
blm/winslows.blm
blm/dance.blm
blm/martelo.blm
blm/raindrops.blm
blm/g.blm
blm/clear.blm
blm/sport_haelt_fit.blm
blm/kreise.blm
blm/railroad.blm
blm/3D_cube.blm
blm/balloon.blm
blm/flipp.blm
blm/mytest.blm
blm/tux.blm

456
pong.py

@ -0,0 +1,456 @@ @@ -0,0 +1,456 @@
#!/usr/bin/python
import time
import random
import sys
import colorsys
import blup.frame
import blup.output
__numbers = {
1: [[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0,]],
2: [[1,1,1,1,1],[0,0,0,0,1],[1,1,1,1,1],[1,0,0,0,0],[1,1,1,1,1,]],
3: [[1,1,1,1,1],[0,0,0,0,1],[0,0,1,1,1],[0,0,0,0,1],[1,1,1,1,1,]],
4: [[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[0,0,0,0,1],[0,0,0,0,1,]],
5: [[1,1,1,1,1],[1,0,0,0,0],[1,1,1,1,1],[0,0,0,0,1],[1,1,1,1,1,]],
6: [[1,1,1,1,1],[1,0,0,0,0],[1,1,1,1,1],[1,0,0,0,1],[1,1,1,1,1,]],
7: [[1,1,1,1,1],[0,0,0,0,1],[0,0,0,0,1],[0,0,0,0,1],[0,0,0,0,1,]],
8: [[1,1,1,1,1],[1,0,0,0,1],[1,1,1,1,1],[1,0,0,0,1],[1,1,1,1,1,]],
9: [[1,1,1,1,1],[1,0,0,0,1],[1,1,1,1,1],[0,0,0,0,1],[1,1,1,1,1,]],
0: [[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1,]],
}
class Paddle(object):
def __init__(self, playground, xpos, ypos, size):
self.__playground = playground
self.__xpos = xpos
self.__size = size
self.__ypos = ypos
self.__nextMove = 0
@property
def nextMove(self):
return self.__nextMove
@nextMove.setter
def nextMove(self, value):
if value in [-1, 0, 1]:
self.__nextMove = value
else:
raise ValueError('invalid move')
@property
def xpos(self):
return self.__xpos
@property
def ypos(self):
return self.__ypos
@property
def size(self):
return self.__size
@property
def nextMove(self):
return self.__nextMove
def containsPoint(self, x, y):
if x == self.__xpos and y in range(self.__ypos, self.__ypos + self.__size):
return True
else:
return False
def nextMoveUp(self):
self.__nextMove = -1
def nextMoveDown(self):
self.__nextMove = 1
def doNextMove(self):
if self.__nextMove is not 0:
if self.__nextMove == -1 and self.__ypos > 0:
self.__ypos -= 1
elif self.__nextMove == 1 and self.__ypos + self.__size < self.__playground.height:
self.__ypos += 1
self.__nextMove = 0
class Wall(object):
HORIZONTAL = 1
VERTICAL = 2
def __init__(self, orientation):
self.orientation = orientation
class Ball(object):
def __init__(self, playground, xpos, ypos, xspeed, yspeed):
self.__playground = playground
self.__xpos = xpos
self.__ypos = ypos
self.__xspeed = xspeed
self.__yspeed = yspeed
self.__hitCallbacks = []
@property
def xpos(self):
return self.__xpos
@property
def ypos(self):
return self.__ypos
@property
def xspeed(self):
return self.__xspeed
@property
def yspeed(self):
return self.__yspeed
@xpos.setter
def xpos(self, value):
self.__xpos = value
@ypos.setter
def ypos(self, value):
self.__ypos = value
@xspeed.setter
def xspeed(self, value):
self.__xspeed = value
@yspeed.setter
def yspeed(self, value):
self.__yspeed = value
def addHitCallback(self, callback):
self.__hitCallbacks.append(callback)
def doHitCallbacks(self, obj):
for callback in self.__hitCallbacks:
callback(obj)
def move(self, ignorePaddles=False):
if self.__xspeed == 0 and self.__yspeed == 0:
return
foundpos = False
while not foundpos:
if self.__xspeed == 0 and self.__yspeed == 0:
break
newx = self.__xpos + self.__xspeed
newy = self.__ypos + self.__yspeed
newobj = self.__playground.getObjectAtPosition(newx, newy)
if isinstance(newobj, Wall):
self.doHitCallbacks(newobj)
# bounce off at horizontal wall
if newobj.orientation == Wall.HORIZONTAL:
self.__yspeed *= -1
else:
#self.__xspeed *= -1
foundpos = True
elif isinstance(newobj, Paddle) and not ignorePaddles:
self.doHitCallbacks(newobj)
self.__xspeed *= -1
# bounce off at the paddle
if self.__yspeed == 0:
if self.__playground.getObjectAtPosition(newobj.xpos, newobj.ypos - 1) is None:
self.__yspeed = -1
elif self.__plauground.getObjectAtPosition(newobj.xpos, newobj.ypos + 1) is None:
self.__yspeed = 1
else:
if newobj.xpos < self.__xpos:
if self.__playground.getObjectAtPosition(self.__xpos - 1, self.__ypos) is None:
self.__yspeed *= -1
if newobj.xpos > self.__xpos:
if self.__playground.getObjectAtPosition(self.__xpos + 1, self.__ypos) is None:
self.__yspeed *= -1
if newobj.nextMove != 0 and random.randint(0, 2) == 0:
self.__yspeed += newobj.nextMove
elif abs(self.__yspeed) != 1:
self.__yspeed = 1 if self.__yspeed > 0 else -1
else:
adjobj = self.__playground.getObjectAtPosition(newx, self.__ypos)
if not ignorePaddles and isinstance(adjobj, Paddle):
self.doHitCallbacks(adjobj)
self.__xspeed *= -1
else:
foundpos = True
self.__xpos = newx
self.__ypos = newy
class Playground(object):
def __init__(self, width, height, paddlesize=3):
self.__width = width
self.__height = height
paddleLeft = Paddle(self, 0, (height - paddlesize)/2, paddlesize)
paddleRight = Paddle(self, width - 1, (height - paddlesize)/2, paddlesize)
self.__paddles = [paddleLeft, paddleRight]
self.__ball = Ball(self, 0, 0, 1, 1)
self.__gameTickCallbacks = []
self.__newRoundCallbacks = []
@property
def width(self):
return self.__width
@property
def height(self):
return self.__height
@property
def leftPaddle(self):
return self.__paddles[0]
@property
def rightPaddle(self):
return self.__paddles[1]
@property
def ball(self):
return self.__ball
def containsPoint(self, x, y):
if x >= 0 and x < self.width and y >= 0 and y < self.height:
return True
else:
return False
def addGameTickCallback(self, callback):
self.__gameTickCallbacks.append(callback)
print 'registered callback',callback
def addNewRoundCallback(self, callback):
self.__newRoundCallbacks.append(callback)
def getObjectAtPosition(self, x, y):
if x >= self.__width or x < 0:
return Wall(Wall.VERTICAL)
elif y >= self.__height or y < 0:
return Wall(Wall.HORIZONTAL)
elif y == self.__ball.ypos and x == self.__ball.xpos:
return self.__ball
else:
for paddle in self.__paddles:
if paddle.containsPoint(x, y):
return paddle
def play(self, serve=None):
leftPaddle = self.__paddles[0]
rightPaddle = self.__paddles[1]
ball = self.__ball
if serve not in self.__paddles:
serve = self.__paddles[random.randint(0, 1)]
ball.ypos = self.__height / 2
ball.xpos = self.__width / 2
if serve == rightPaddle and self.__width % 2 == 1:
ball.xpos += 1
ball.yspeed = 0
if serve == rightPaddle:
ball.xspeed = 1
else:
ball.yspeed = -1
for callback in self.__newRoundCallbacks:
callback()
while True:
time.sleep(0.1)
ball.move()
leftPaddle.doNextMove()
rightPaddle.doNextMove()
if not self.containsPoint(ball.xpos, ball.ypos):
break
for callback in self.__gameTickCallbacks:
print callback
callback()
if ball.xpos >= self.width:
return leftPaddle
elif ball.xpos <= 0:
return rightPaddle
def getRandomColor(maxval):
return map(lambda x: int(round(x*maxval)), colorsys.hsv_to_rgb(random.random(), 1, 1))
#return map(lambda x: int(round(x*maxval)), colorsys.hsv_to_rgb(random.random(), random.random(), random.random()))
class PlaygroundPainter(object):
def __init__(self, out, dimension, playground):
self.__out = out
self.__playground = playground
self.__dimension = dimension
self.__playground.addGameTickCallback(self.update)
self.__playground.ball.addHitCallback(self.ballhit)
if dimension.channels == 1:
self.__ballColor = 1
self.__paddleColor = 1
else:
self.__ballColor = getRandomColor(dimension.depth - 1)
self.__leftPaddleColor = getRandomColor(dimension.depth - 1)
self.__rightPaddleColor = getRandomColor(dimension.depth - 1)
def update(self):
frame = blup.frame.Frame(self.__dimension)
#self.__paddleColor = getRandomColor(self.__dimension.depth - 1)
if self.__dimension.channels == 3:
for x in range(self.__dimension.width):
for y in range(self.__dimension.height):
frame.setPixel(x, y, (0,0,0))
frame.setPixel(self.__playground.ball.xpos, self.__playground.ball.ypos, self.__ballColor)
for i in range(self.__playground.leftPaddle.size):
frame.setPixel(self.__playground.leftPaddle.xpos, self.__playground.leftPaddle.ypos + i, self.__leftPaddleColor)
for i in range(self.__playground.rightPaddle.size):
frame.setPixel(self.__playground.rightPaddle.xpos, self.__playground.rightPaddle.ypos + i, self.__rightPaddleColor)
self.__out.sendFrame(frame)
def ballhit(self, obj):
if self.__dimension.channels == 3:
if isinstance(obj, Paddle):
self.__ballColor = getRandomColor(self.__dimension.depth - 1)
if obj.xpos == 0:
self.__leftPaddleColor = self.__ballColor
else:
self.__rightPaddleColor = self.__ballColor
class PongBot(object):
def __init__(self, playground, ownPaddle, dullness=0):
self.__playground = playground
self.__ownPaddle = ownPaddle
self.__dullness = dullness
self.__playground.addGameTickCallback(self.onGameTick)
self.__playground.addNewRoundCallback(self.onNewRound)
self.__playground.ball.addHitCallback(self.onHit)
self.__hitpoint = None
self.__oldHitpoint = None
self.__dull = False
def updateHitpoint(self):
origball = self.__playground.ball
ball = Ball(self.__playground, origball.xpos, origball.ypos, origball.xspeed, origball.yspeed)
ball.move()
hitpoint = None
while hitpoint is None:
if ball.xpos >= self.__playground.width - 1 or ball.xpos <= 0:
hitpoint = (ball.xpos, ball.ypos)
break
ball.move(ignorePaddles=True)
self.__oldHitpoint = self.__hitpoint
self.__hitpoint = hitpoint
def onHit(self, obj):
print 'hit!', obj
if isinstance(obj, Paddle) and obj is not self.__ownPaddle:
self.updateHitpoint()
if self.__dullness > random.randint(0, 4):
self.__dull = True
else:
self.__dull = False
def onNewRound(self):
self.updateHitpoint()
self.__oldHitpoint = None
self.__dull = False
def onGameTick(self):
#self.updateHitpoint()
print 'hitpoint', self.__hitpoint
(hitx, hity) = self.__hitpoint
if hitx == self.__ownPaddle.xpos:
if abs(self.__playground.ball.xpos - self.__ownPaddle.xpos) < 15:
if not self.__dull:
if not self.__ownPaddle.containsPoint(hitx, hity):
print 'moving!!'
if self.__ownPaddle.ypos < hity:
self.__ownPaddle.nextMoveDown()
else:
self.__ownPaddle.nextMoveUp()
else:
if self.__ownPaddle.containsPoint(hitx, hity):
print 'moving!!'
if hity < self.__ownPaddle.size:
self.__ownPaddle.nextMoveDown()
else:
self.__ownPaddle.nextMoveUp()
elif self.__dull:
r = random.randint(-1, 1)
if r == -1:
self.__ownPaddle.nextMoveUp()
elif r == 1:
self.__ownPaddle.nextMoveDown()
def displayScore(out, dimension, leftScore, rightScore, delay=0):
leftNumber = __numbers[leftScore]
rightNumber = __numbers[rightScore]
frame = blup.frame.Frame(dimension)
if dimension.channels == 1:
dotcolor = 1
numcolor = 1
else:
dotcolor = getRandomColor(dimension.depth - 1)
numcolor = getRandomColor(dimension.depth - 1)
frame.setPixel(8, 1, dotcolor)
frame.setPixel(9, 1, dotcolor)
frame.setPixel(8, 2, dotcolor)
frame.setPixel(9, 2, dotcolor)
frame.setPixel(8, 4, dotcolor)
frame.setPixel(9, 4, dotcolor)
frame.setPixel(8, 5, dotcolor)
frame.setPixel(9, 5, dotcolor)
for x in range(5):
for y in range(5):
if leftNumber[y][x] == 1:
frame.setPixel(x+1, y+1, numcolor)
if rightNumber[y][x] == 1:
frame.setPixel(x+12, y+1, numcolor)
out.sendFrame(frame)
if delay > 0:
time.sleep(delay / 1000.0)
def main():
print 'running a \'Bot vs. Bot\' round...'
#out = blup.output.getOutput('blp:localhost:42421')
#out = blup.output.getOutput('e3blp:bastel0:4242')
out = blup.output.getOutput('e3blp:localhost:4242')
#out = blup.output.getOutput('e3blp:bbunt:42429')
#dim = blup.frame.FrameDimension(18, 8, 8, 3)
dim = blup.frame.FrameDimension(22, 16, 255, 3)
playground = Playground(22, 16, paddlesize=4)
pp = PlaygroundPainter(out, dim, playground)
leftPaddle = playground.leftPaddle
rightPaddle = playground.rightPaddle
ball = playground.ball
leftBot = PongBot(playground, leftPaddle, 1)
rightBot = PongBot(playground, rightPaddle, 1)
print playground.play()
if __name__ == '__main__':
main()

178
r0ketpong.py

@ -0,0 +1,178 @@ @@ -0,0 +1,178 @@
#!/usr/bin/python
import time
import threading
import sys
import blup.frame
import blup.output
sys.path.append('/var/tmp/r0ket/tools/game')
#sys.path.append('/var/tmp/r0ket_misc/game_noprint')
import r0ketrem0te.game
import pong
logo = [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0],
[1,0,1,0,1,0,0,1,0,1,1,0,1,0,1,0,0,1],
[1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0,0,0],
[1,1,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,1],
[1,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1],
[1,0,0,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]
onePlayer = [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,0,0,1,1,1,1,0,0,0,1,1,1,0,0],
[0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0],
[0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0],
[0,0,0,1,0,0,1,1,1,1,0,0,0,0,1,0,0,0],
[0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]
def convertPixels(dimension, pixels):
p = []
maxval = dimension.depth - 1
for i in range(len(pixels)):
row = []
for j in range(len(pixels[i])):
if pixels[i][j] == 1:
row.append((maxval, maxval, maxval))
else:
row.append((0,0,0))
p.append(row)
return p
class R0ketPongPlayer(object):
def __init__(self, playground, ownPaddle, r0ketPlayer):
self.__playground = playground
self.__ownPaddle = ownPaddle
self.__r0ketPlayer = r0ketPlayer
self.__ready = False
@property
def ownPaddle(self):
return self.__ownPaddle
@property
def ready(self):
return self.__ready
def receivedPacket(self, packet):
if self.__r0ketPlayer is not None:
if packet.id == self.__r0ketPlayer.id:
if isinstance(packet, r0ketrem0te.packets.Button):
print 'button=', packet.button
if packet.button == 1:
self.__ownPaddle.nextMoveUp()
print 'up'
if packet.button == 2:
self.__ownPaddle.nextMoveDown()
print 'down'
if packet.button == 16:
self.__ready = True
class R0ketPong(object):
def __init__(self, out, color=False, port='/dev/ttyACM0', gameName='pong'):
self.__playground = None
self.__out = out
self.__rem0te = r0ketrem0te.game.Game(port, gameName, 83, 87, [ord(x) for x in 'REM0T'], 2, False)
self.__rem0te.registerPlayerCallback(self.playerCallback)
self.__color = color
self.__players = []
self.__playersChangedCondition = threading.Condition()
if color:
self.__dimension = blup.frame.FrameDimension(18, 8, 8, 3)
else:
self.__dimension = blup.frame.FrameDimension(18, 8, 2, 1)
def playerCallback(self, action, player):
if self.__playground is None:
return
print '\n\n\n\nplayer added',player,'\n\n\n\n'
if action == 'added' and len(self.__players) < 2:
if len(self.__players) == 0:
playerPaddle = self.__playground.leftPaddle
else:
playerPaddle = self.__playground.rightPaddle
player = R0ketPongPlayer(self.__playground, playerPaddle, player)
self.__rem0te.bridge.registerCallback(player.receivedPacket)
self.__players.append(player)
with self.__playersChangedCondition:
self.__playersChangedCondition.notifyAll()
def runGame(self):
print 'starting a game...'
scoreLeft = 0
scoreRight = 0
self.__playground = pong.Playground(18, 8)
pp = pong.PlaygroundPainter(out, self.__dimension, self.__playground)
while len(self.__players) == 0:
print 'waiting for player...'
with self.__playersChangedCondition:
self.__playersChangedCondition.wait()
frame = blup.frame.Frame(self.__dimension)
global onePlayer
if self.__color:
frame.pixels = convertPixels(self.__dimension, onePlayer)
else:
frame.pixels = onePlayer
self.__out.sendFrame(frame)
while len(self.__players) == 1 and not self.__players[0].ready:
print 'waiting for another player...'
time.sleep(1)
self.__out.sendFrame(frame)
frame = blup.frame.Frame(self.__dimension)
global logo
if self.__color:
frame.pixels = convertPixels(self.__dimension, logo)
else:
frame.pixels = logo
self.__out.sendFrame(frame)
time.sleep(1)
if len(self.__players) == 1:
bot = pong.PongBot(self.__playground, self.__playground.rightPaddle, 2)
self.__players.append(bot)
while max(scoreLeft, scoreRight) < 9:
winner = self.__playground.play()
if winner is self.__players[0].ownPaddle:
scoreLeft += 1
else:
scoreRight += 1
pong.displayScore(self.__out, self.__dimension, scoreLeft, scoreRight, 3000)
for i in range(3):
frame = blup.frame.Frame(self.__dimension)
self.__out.sendFrame(frame)
time.sleep(0.5)
pong.displayScore(self.__out, self.__dimension, scoreLeft, scoreRight, 500)
frame = blup.frame.Frame(self.__dimension)
self.__out.sendFrame(frame)
self.__playground = None
self.__players = []
out = blup.output.getOutput('e3blp:localhost:4242')
p0ng = R0ketPong(out, color=True)
while True:
p0ng.runGame()
sys.exit(0)

4
randomPlayer.py

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
#!/usr/bin/python
import blup

28
robot.bml

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<blm width="18" height="8" bits="4" channels="3">
<header>
<creator>Blimp (version 0.1.5)</creator>
</header>
<frame duration="500">
<row>000000000FF00F0FF0000000000000000000FF00F0FF0000000000</row>
<row>0000000000F00F00F00000000000000000000F00F00F0000000000</row>
<row>000000000000090000000000000000000000000090000000000000</row>
<row>0000000000F00F00F00000900000000000000F00F00F0000090000</row>
<row>0000900900F0FF00F00900900000000900900F0FF00F0090090000</row>
<row>0000900000F00F00F00000000000000900000F00F00F0000000000</row>
<row>0000000000F00F00F00000000000000000000F00F00F0000000000</row>
<row>000000000090000090000000000000000000090000090000000000</row>
</frame>
<frame duration="500">
<row>000000000FF00F0FF0000000000000000000FF00F0FF0000000000</row>
<row>0000000000F00F00F00000000000000000000F00F00F0000000000</row>
<row>000000000000090000000000000000000000000090000000000000</row>
<row>0000900000F00F00F00000000000000900000F00F00F0000000000</row>
<row>0000900900F0FF00F00900900000000900900F0FF00F0090090000</row>
<row>0000000000F00F00F00000900000000000000F00F00F0000090000</row>
<row>0000000000F00F00F00000000000000000000F00F00F0000000000</row>
<row>000000000090000090000000000000000000090000090000000000</row>
</frame>
</blm>

39
smileys.bml

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<blm width="18" height="8" bits="4" channels="3">
<header>
<creator>Blimp (version 0.1.5)</creator>
</header>
<frame duration="500">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>0000FF0000000FF000000FF0000000FF0000000F0F000000F0F000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>0000FF0000000FF000000FF0000000FF0000000F0F000000F0F000</row>
<row>0000000FF0FF000000000000FF0FF0000000000000F0FF0F000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="500">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>0000F00000000F0000000F00000000F0000000000F00000000F000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>0000F00000000F0000000F00000000F0000000000F00000000F000</row>
<row>0000000F00F0000000000000F00F0000000000000000F00F000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="500">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000FFF000000FFF000000FFF000000FFF000000FFF000000FFF000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000FFF000000FFF000000FFF000000FFF000000FFF000000FFF000</row>
<row>000000FFFFFF000000000000FFFFFF000000000000FFFFFF000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
</blm>

50
smileys2.bml

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<blm width="18" height="8" bits="4" channels="3">
<header>
<creator>Blimp (version 0.1.5)</creator>
</header>
<frame duration="500">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000FF0000000FF0000000F0F000000F0F000</row>
<row>0000FF0000000FF000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000FF0000000FF0000000F0F000000F0F000</row>
<row>0000FF0000000FF000000000FF0FF0000000000000F0FF0F000000</row>
<row>0000000FF0FF000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="500">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>0000F00000000F000000000000000000000000000F00000000F000</row>
<row>000000000000000000000F00000000F00000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>0000F00000000F000000000000000000000000000F00000000F000</row>
<row>0000000F00F0000000000F00000000F0000000000000F00F000000</row>
<row>000000000000000000000000F00F00000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="500">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000FFF000000FFF000000FFF000000FFF000000000000000000000</row>
<row>000000000000000000000000000000000000000FFF000000FFF000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000FFF000000FFF000000FFF000000FFF000000000000000000000</row>
<row>000000FFFFFF000000000000FFFFFF000000000FFF000000FFF000</row>
<row>000000000000000000000000000000000000000000FFFFFF000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
<frame duration="500">
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000FF0000000FF0000FF0000000FF0000FF0000000FF0000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000FF0000000FF0000FF0000000FF0000FF0000000FF0000000</row>
<row>000000000FF0FF0000000000FF0FF0000000000FF0FF0000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
<row>000000000000000000000000000000000000000000000000000000</row>
</frame>
</blm>

135
staticSinePlasma.py

@ -0,0 +1,135 @@ @@ -0,0 +1,135 @@
#!/usr/bin/python
# inspired by:
# http://lodev.org/cgtutor/plasma.html
import sys
import time
import math
#import pygame
import colorsys
import blup.frame
import blup.output
class Plasma(object):
def __init__(self, width, height):
self.width = width
self.height = height
self.pixelvalues = [[0] * height for i in xrange(width)]
self.pixelsReady = False
self.offset = 0
self.update()
@property
def minValue(self):
return min(map(min, self.pixelvalues))
@property
def maxValue(self):
return max(map(max, self.pixelvalues))
def applyPalette(self, palette):
min = self.minValue
max = self.maxValue
norm = lambda x: ((x - min) / max)
pixeldata = [ [None] * self.height for i in xrange(self.width) ]
for x in xrange(self.width):
rowvalues = self.pixelvalues[x]
for y in xrange(self.height):
pixeldata[x][y] = palette.getColorValue(norm(rowvalues[y]))
return pixeldata
def update(self):
#if self.pixelsReady:
# return
self.offset += 1
for x in xrange(self.width):
for y in xrange(self.height):
xx = x+self.offset
yy = y+self.offset
p = 128 + 128 * math.sin(xx / 9.0)
p += 128 + 128 * math.sin(yy / 16.0)
p += 128 + 128 * math.sin((yy + xx) / 16.0)
p += 128 + 128 * math.sin(math.sqrt(yy*yy + xx*xx) / 16.0)
p += 128 + 8 * math.sin(math.sqrt(yy* xx) / 16.0)
self.pixelvalues[x][y] = p
self.pixelsReady = True
class Palette(object):
def __init__(self):
self.offset = 0
self.cache = {}
def getColorValue(self, x):
x = round(x, 3)
if self.cache.has_key(x):
return self.cache[x]
c = colorsys.hsv_to_rgb((x + self.offset) % 1, 1, 1)
c = map(lambda x: int(x * 255), c)
self.cache[x] = c
return c
def update(self):
self.cache = {}
self.offset += 0.01
if self.offset > 1:
self.offset -= 1
##############################################
w = 22
h = 16
#w = 80
#h = 18
scalex = 30
scaley = 60
plasma = Plasma(w,h)
palette= Palette()
#screen = pygame.display.set_mode((w*scalex, h*scaley))
#pygame.display.update()
#dim = blup.frame.FrameDimension(w, h, 8, 3)
dim = blup.frame.FrameDimension(w, h, 256, 3)
#out = blup.output.getOutput('serialblup:/dev/ttyUSB0:115200')
#out = blup.output.getOutput('colorfulshell')
#out = blup.output.getOutput('e3blp:bastel0:4242')
out = blup.output.getOutput('e3blp')
while True:
#screen.fill((0,0,0))
#print 'updating palette...'
palette.update()
#print 'updating plasma...'
plasma.update()
#print 'applying palette...'
pixeldata = plasma.applyPalette(palette)
#print 'drawing...'
f = blup.frame.Frame(dim)
for x in xrange(w):
#rowdata = pixeldata[x]
for y in xrange(h):
#pygame.draw.rect(screen, pixeldata[x][y], (x*scalex, y*scaley, scalex, scaley), 0)
#pygame.draw.circle(screen, rowdata[y], (x, y), 1, 1)
i= f.setPixel(x, y, pixeldata[x][y])
#print frame.channels, frame.depth
#print 'done drawing'
out.sendFrame(f)
#pygame.display.update()
#print 'done updating'
#time.sleep(0.05)

152
staticSinePlasma_neopixel.py

@ -0,0 +1,152 @@ @@ -0,0 +1,152 @@
#!/usr/bin/python
# inspired by:
# http://lodev.org/cgtutor/plasma.html
import sys
import time
import math
#import pygame
import colorsys
from neopixel import *
class Plasma(object):
def __init__(self, width, height):
self.width = width
self.height = height
self.pixelvalues = [[0] * height for i in xrange(width)]
self.pixelsReady = False
self.offset = 0
self.update()
@property
def minValue(self):
return min(map(min, self.pixelvalues))
@property
def maxValue(self):
return max(map(max, self.pixelvalues))
def applyPalette(self, palette):
min = self.minValue
max = self.maxValue
norm = lambda x: ((x - min) / max)
pixeldata = [ [None] * self.height for i in xrange(self.width) ]
for x in xrange(self.width):
rowvalues = self.pixelvalues[x]
for y in xrange(self.height):
pixeldata[x][y] = palette.getColorValue(norm(rowvalues[y]))
return pixeldata
def update(self):
#if self.pixelsReady:
# return
self.offset += 1
for x in xrange(self.width):
for y in xrange(self.height):
xx = x+self.offset
yy = y+self.offset
#xx = 10*x+self.offset
#yy = 10*y+self.offset
p = 128 + 128 * math.sin(xx / 9.0)
p += 128 + 128 * math.sin(yy / 16.0)
p += 128 + 128 * math.sin((yy + xx) / 16.0)
p += 128 + 128 * math.sin(math.sqrt(yy*yy + xx*xx) / 16.0)
p += 128 + 8 * math.sin(math.sqrt(yy* xx) / 16.0)
self.pixelvalues[x][y] = p
self.pixelsReady = True
class Palette(object):
def __init__(self):
self.offset = 0
self.cache = {}
def getColorValue(self, x):
x = round(x, 3)
if self.cache.has_key(x):
return self.cache[x]
c = colorsys.hsv_to_rgb((x + self.offset) % 1, 1, 1)
#c = map(lambda x: int(x * 7), c)
depth = 255
c = map(lambda x: int(x * depth), c)
self.cache[x] = c
return c
def update(self):
self.cache = {}
self.offset += 0.01
if self.offset > 1:
self.offset -= 1
##############################################
w = 22
h = 16
#w = 80
#h = 18
scalex = 30
scaley = 60
plasma = Plasma(w,h)
palette= Palette()
#screen = pygame.display.set_mode((w*scalex, h*scaley))
#pygame.display.update()
##dim = blup.frame.FrameDimension(w, h, 8, 3)
#dim = blup.frame.FrameDimension(w, h, 8, 3)
##out = blup.output.getOutput('serialblup:/dev/ttyUSB0:115200')
##out = blup.output.getOutput('colorfulshell')
##out = blup.output.getOutput('e3blp:bastel0:4242')
#out = blup.output.getOutput('e3blp')
# LED strip configuration:
LED_COUNT = 352 # Number of LED pixels.
LED_PIN = 13 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 5 # DMA channel to use for generating signal (try 5)
LED_BRIGHTNESS = 50 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_PWM = 1
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_PWM)
strip.begin()
while True:
#screen.fill((0,0,0))
#print 'updating palette...'
palette.update()
#print 'updating plasma...'
plasma.update()
#print 'applying palette...'
pixeldata = plasma.applyPalette(palette)
#print 'drawing...'
#f = blup.frame.Frame(dim)
for y in xrange(h):
for x in xrange(w):
if x%2 == 0:
lednum = x*h + y
else:
lednum = x*h - y + 15
strip.setPixelColor(lednum, Color(*pixeldata[x][y]))
strip.show()
#print 'done drawing'
#out.sendFrame(f)
#pygame.display.update()
#print 'done updating'
#time.sleep(0.01)

1
test.txt

@ -0,0 +1 @@ @@ -0,0 +1 @@
test.blm

311
ttrs.py

@ -0,0 +1,311 @@ @@ -0,0 +1,311 @@
#!/usr/bin/env python3
import time
import enum
import math
import collections
import blup.frame
import blup.output
import random
class InvalidMoveError(Exception):
pass
class Point(collections.namedtuple('Point', ['x', 'y'])):
__slots__ = ()
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def floored(self):
return Point(math.floor(self.x), math.floor(self.y))
Block = collections.namedtuple('Block', ['pos', 'color'])
class Tetrimino():
def __init__(self, shape, playground, pos):
self.shape = shape
self.playground = playground
self.pos = pos
@property
def width(self):
x = list(map(lambda s: s.pos.x, self.shape))
return max(x) - min(x)
@property
def height(self):
y = list(map(lambda s: s.pos.y, self.shape))
return max(y) - min(y)
@property
def blocks(self):
ret = { Block((self.pos + b.pos).floored(), b.color) for b in
self.shape }
return ret
def __calc_points(self, pos=None, shape=None):
if pos is None:
pos = self.pos
if shape is None:
shape = self.shape
return { (pos + b.pos).floored() for b in shape }
@property
def points(self):
return self.__calc_points()
def __check_collision(self, newpoints):
if not self.playground.contains_points(newpoints):
raise InvalidMoveError('out of playground bounds')
print(self.playground.block_points)
print(self.playground.blocks)
print('new', newpoints)
if not self.playground.block_points.isdisjoint(newpoints):
raise InvalidMoveError('new position already occupied')
other_mino_points = self.playground.mino_points - self.points
if not other_mino_points.isdisjoint(newpoints):
raise InvalidMoveError('other Tetrimino at new position')
def rotate(self, ccw=False):
if ccw:
transform = lambda s: Block(Point(s.pos.y, -s.pos.x), s.color)
else:
transform = lambda s: Block(Point(-s.pos.y, s.pos.x), s.color)
newshape = set(map(transform, self.shape))
newpoints = self.__calc_points(shape=newshape)
self.__check_collision(newpoints)
self.shape = newshape
def move(self, m):
newpos = self.pos + m
newpoints = self.__calc_points(pos=newpos)
self.__check_collision(newpoints)
self.pos = newpos
class TetriL(Tetrimino):
def __init__(self, playground, pos):
color = (255,165,0)
points = [(-1, 1), (-1, 0), (0, 0), (1, 0)]
shape = { Block(Point(x, y), color) for (x, y) in points }
Tetrimino.__init__(self, shape, playground, pos)
class TetriJ(Tetrimino):
def __init__(self, playground, pos):
color = (0,0,255)
points = [(-1, 0), (0, 0), (1, 0), (1, 1)]
shape = { Block(Point(x, y), color) for (x, y) in points }
Tetrimino.__init__(self, shape, playground, pos)
class TetriI(Tetrimino):
def __init__(self, playground, pos):
color = (0,255,255)
points = {(1.5, -0.5), (0.5, -0.5), (-0.5, -0.5), (-1.5, -0.5)}
shape = { Block(Point(x, y), color) for (x, y) in points }
Tetrimino.__init__(self, shape, playground, pos)
class TetriO(Tetrimino):
def __init__(self, playground, pos):
color = (255,255,0)
points = {(-0.5, -0.5), (-0.5, 0.5), (0.5, -0.5), (0.5, 0.5)}
shape = { Block(Point(x, y), color) for (x, y) in points }
Tetrimino.__init__(self, shape, playground, pos)
class TetriS(Tetrimino):
def __init__(self, playground, pos):
color = (128,255,0)
points = {(-1, 0), (0, 0), (0, -1), (1, -1)}
shape = { Block(Point(x, y), color) for (x, y) in points }
Tetrimino.__init__(self, shape, playground, pos)
class TetriZ(Tetrimino):
def __init__(self, playground, pos):
color = (255,0,0)
points = {(-1, 0), (0, 0), (0, 1), (1, 1)}
shape = { Block(Point(x, y), color) for (x, y) in points }
Tetrimino.__init__(self, shape, playground, pos)
class TetriT(Tetrimino):
def __init__(self, playground, pos):
color = (128,0,128)
points = {(-1, 0), (0, 0), (1, 0), (0, 1)}
shape = { Block(Point(x, y), color) for (x, y) in points }
Tetrimino.__init__(self, shape, playground, pos)
class Playground():
def __init__(self, width=10, height=22):
self.width = width
self.height = height
self.blocks = set()
self.minos = set()
@property
def block_points(self):
return set([ b.pos for b in self.blocks ])
@property
def mino_points(self):
return set.union(set(), *[ m.points for m in self.minos ])
def contains_points(self, points):
for p in points:
if p.x >= self.width or p.y >= self.height or p.x < 0 or p.y < 0:
return False
return True
def paint(self, frame, xpos, ypos):
for x in range(frame.dimension.width):
for y in range(frame.dimension.height):
frame.setPixel(x, y, (0, 0, 0))
for b in set.union(self.blocks, *[ m.blocks for m in self.minos ]):
frame.setPixel(xpos + int(b.pos.x), ypos + int(b.pos.y), b.color)
class TtrsGame():
def __init__(self, playground):
self.playground = playground
self.running = False
self.next_move = 0
self.rotate = False
self.drop = False
self.tick_callbacks = []
def add_tick_callback(self, cb):
self.tick_callbacks.append(cb)
def run(self):
self.running = True
spawnpos = Point(self.playground.width // 2, 0)
mino = None
TICK_TIME = 0.1
FALL_INTERVAL = 5
MOVE_INTERVAL = 1
ticks = 0
lastfall = 0
lastmove = 0
while self.running:
for cb in self.tick_callbacks:
cb()
#time.sleep(TICK_TIME)
ticks += 1
x = input()
if x == 'a':
self.next_move = -1
elif x == 'd':
self.next_move = 1
elif x == 'w':
self.rotate = True
elif x == 's':
self.drop = True
else:
self.drop = False
self.rotate = False
self.next_move = 0
if mino is None:
newminocls = random.choice(Tetrimino.__subclasses__())
mino = newminocls(self.playground, spawnpos)
self.playground.minos = {mino}
for y in range(self.playground.height):
row = { Point(x, y) for x in range(self.playground.width) }
if row.issubset(self.playground.block_points):
for b in list(self.playground.blocks):
if b.pos.y == y:
self.playground.blocks.remove(b)
elif b.pos.y < y:
self.playground.blocks.remove(b)
newb = Block(b.pos + Point(0, 1), b.color)
self.playground.blocks.add(newb)
if ticks - lastfall >= FALL_INTERVAL or self.drop:
lastfall = ticks
try:
mino.move(Point(0, 1))
except InvalidMoveError:
self.playground.blocks.update(mino.blocks)
mino = None
self.playground.minos = set()
continue
if ticks - lastmove >= MOVE_INTERVAL and self.next_move != 0:
lastmove = ticks
try:
mino.move(Point(self.next_move, 0))
except InvalidMoveError:
pass
self.next_move = 0
if self.rotate:
self.rotate = False
try:
mino.rotate()
except InvalidMoveError:
pass
if __name__ == '__main__':
w = 22
h = 16
dim = blup.frame.FrameDimension(w, h, 256, 3)
frame = blup.frame.Frame(dim)
out = blup.output.getOutput('e3blp')
pg = Playground(10, 16)
pg.paint(frame, 0, 0)
out.sendFrame(frame)
time.sleep(0.5)
def repaint():
pg.paint(frame, 0, 0)
out.sendFrame(frame)
game = TtrsGame(pg)
game.add_tick_callback(repaint)
game.run()
#t = TetriL(pg, Point(2, 2))
#pg.minos.add(t)
#pg.paint(frame, 0, 0)
#out.sendFrame(frame)
#time.sleep(0.5)
#for i in range(10):
# t.rotate(ccw=(i>=5))
# pg.paint(frame, 0, 0)
# out.sendFrame(frame)
# time.sleep(0.1)

49
writebml.py

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
import math
import xml.etree.ElementTree as ET
def writeBml(anim, filename):
root = ET.Element('blm')
root.attrib['width'] = str(anim.dimension.width)
root.attrib['height'] = str(anim.dimension.height)
bits = int(math.ceil(math.log(anim.dimension.depth, 2)))
root.attrib['bits'] = str(bits)
root.attrib['channels'] = str(anim.dimension.channels)
header = ET.Element('header')
for (name, val) in anim.tags:
elem = ET.Element(name)
elem.text = str(val)
header.append(elem)
root.append(header)
for animFrame in anim:
frame = ET.Element('frame')
frame.attrib['duration'] = str(animFrame.delay)
for y in range(anim.dimension.height):
rowData = ''
for x in range(anim.dimension.width):
p = animFrame.getPixel(x,y)
if type(p) == tuple or type(p) == list:
for v in p:
if bits >= 5:
rowData += '%02x' % (v)
else:
rowData += '%x' % (v)
else:
if bits >= 5:
rowData += '%02x' % (p)
else:
rowData += '%x' % (p)
row = ET.Element('row')
row.text = rowData
frame.append(row)
root.append(frame)
f = open(filename, 'w')
ET.ElementTree(root).write(f)
f.close()
Loading…
Cancel
Save