mirror of
https://github.com/brmlab/ledbar.git
synced 2025-06-10 05:44:01 +02:00
Merge branch 'master' of github.com:brmlab/ledbar
This commit is contained in:
commit
eb5bee19b6
7 changed files with 347 additions and 6 deletions
|
@ -349,9 +349,8 @@ int main(int argc, char* argv[])
|
||||||
tcgetattr(fileno(fp), &t);
|
tcgetattr(fileno(fp), &t);
|
||||||
cfsetspeed(&t, B38400);
|
cfsetspeed(&t, B38400);
|
||||||
tcsetattr(fileno(fp), TCSADRAIN, &t);
|
tcsetattr(fileno(fp), TCSADRAIN, &t);
|
||||||
}
|
|
||||||
|
|
||||||
sleep(2);
|
sleep(2);
|
||||||
|
}
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1;
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1;
|
||||||
if (!(screen = SDL_SetVideoMode(RESX, RESY, BPP, SDL_HWSURFACE))) {
|
if (!(screen = SDL_SetVideoMode(RESX, RESY, BPP, SDL_HWSURFACE))) {
|
||||||
|
|
27
host_python/README
Normal file
27
host_python/README
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
INTRODUCTION:
|
||||||
|
|
||||||
|
The scripts in this directory try to work according to the KISS principle. It
|
||||||
|
contains a script which redirects its stdin to serial device
|
||||||
|
(send_to_serial.py), one that simulates the ledbar and sends the data unaltered
|
||||||
|
from its stdin to its stdout, a module that helps programmers to program
|
||||||
|
various graphical effects and some example effect generators using this module.
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES:
|
||||||
|
|
||||||
|
./rainbow.py | ./demo.py >/dev/null
|
||||||
|
- only simulate the rainbow effect, do not send it anywhere
|
||||||
|
|
||||||
|
./rainbow.py | ./send_to_serial.py
|
||||||
|
- only send the data to the serial device, do not show the simulation
|
||||||
|
|
||||||
|
./rainbow.py | ./demo.py | ./send_to_serial.py
|
||||||
|
- combine both options, show a simulation and send the data to the serial
|
||||||
|
device
|
||||||
|
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
|
||||||
|
demo.py requires PyGame, Python wrapper around SDL
|
||||||
|
send_to_serial.py requires PySerial, Python library for work with serial ports
|
||||||
|
equalizer.py requires PyAudio (wrapper around PortAudio) and a microphone
|
76
host_python/demo.py
Executable file
76
host_python/demo.py
Executable file
|
@ -0,0 +1,76 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# vim:et:sw=4:ts=4:sts=4
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import getopt
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
def print_usage():
|
||||||
|
print '''\
|
||||||
|
USAGE:
|
||||||
|
%s [-n number] [-h]
|
||||||
|
OPTIONS:
|
||||||
|
-n number number of controlled boxes
|
||||||
|
-h --help show this help
|
||||||
|
''' % sys.argv[0]
|
||||||
|
|
||||||
|
def read_byte():
|
||||||
|
r = sys.stdin.read(1)
|
||||||
|
if len(r) == 0: raise EOFError
|
||||||
|
return ord(r)
|
||||||
|
|
||||||
|
def write_byte(b):
|
||||||
|
sys.stdout.write(chr(b))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(sys.argv[1:], 'n:h', ['help'])
|
||||||
|
except getopt.GetOptError:
|
||||||
|
print_usage()
|
||||||
|
return 1
|
||||||
|
if len(args):
|
||||||
|
print_usage()
|
||||||
|
return 1
|
||||||
|
number = 10
|
||||||
|
show_help = False
|
||||||
|
for k, v in opts:
|
||||||
|
if k == '-n':
|
||||||
|
if not v.isdigit():
|
||||||
|
print_usage()
|
||||||
|
return 1
|
||||||
|
number = int(v)
|
||||||
|
elif k == '-h' or k == '--help': show_help = True
|
||||||
|
if show_help:
|
||||||
|
print_usage()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
pygame.init()
|
||||||
|
screen_size = [800, 600]
|
||||||
|
screen = pygame.display.set_mode(screen_size)
|
||||||
|
pygame.display.set_caption("ledbar demo viewer")
|
||||||
|
offset = 5
|
||||||
|
pixel_width = (screen_size[0]-offset) / number
|
||||||
|
try:
|
||||||
|
exit = False
|
||||||
|
while not exit:
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
exit = True
|
||||||
|
continue
|
||||||
|
screen.fill([0, 0, 0])
|
||||||
|
for i in xrange(number):
|
||||||
|
r = read_byte()
|
||||||
|
g = read_byte()
|
||||||
|
b = read_byte()
|
||||||
|
pygame.draw.rect(screen, [r, g, b], [pixel_width*i, 0, pixel_width-offset, pixel_width-offset])
|
||||||
|
write_byte(r); write_byte(g); write_byte(b)
|
||||||
|
sys.stdout.flush()
|
||||||
|
pygame.display.flip()
|
||||||
|
except EOFError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
pygame.quit()
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
sys.exit(main())
|
84
host_python/equalizer.py
Executable file
84
host_python/equalizer.py
Executable file
|
@ -0,0 +1,84 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# vim:et:sw=4:ts=4:sts=4
|
||||||
|
|
||||||
|
import pyaudio
|
||||||
|
import struct
|
||||||
|
import math
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import ledbar
|
||||||
|
|
||||||
|
CHUNK_SIZE = 1024
|
||||||
|
FORMAT = pyaudio.paInt16
|
||||||
|
CHANNELS = 1
|
||||||
|
RATE = 44100
|
||||||
|
|
||||||
|
PIXELS = 10
|
||||||
|
|
||||||
|
HISTORY_SIZE = 4
|
||||||
|
SAMPLE_SIZE = CHUNK_SIZE*HISTORY_SIZE
|
||||||
|
MIN_FREQ = 20
|
||||||
|
MAX_FREQ = 12000
|
||||||
|
FREQ_STEP = float(RATE) / (CHUNK_SIZE * HISTORY_SIZE)
|
||||||
|
PIXEL_FREQ_RANGE = math.pow(float(MAX_FREQ) / MIN_FREQ, 1.0/PIXELS)
|
||||||
|
|
||||||
|
p = pyaudio.PyAudio()
|
||||||
|
|
||||||
|
stream = p.open(format = FORMAT,
|
||||||
|
channels = CHANNELS,
|
||||||
|
rate = RATE,
|
||||||
|
input = True,
|
||||||
|
frames_per_buffer = CHUNK_SIZE)
|
||||||
|
|
||||||
|
def get_color(volume):
|
||||||
|
p = 1-15/volume
|
||||||
|
if p <= 0: return (0, 0, 0)
|
||||||
|
p *= p
|
||||||
|
if p <= 0.4: return (0, 0, p*2.5)
|
||||||
|
elif p <= 0.7: return (0, (p-0.4)*3.33, 1.0-(p-0.4)*3.33)
|
||||||
|
elif p <= 0.9: return ((p-0.7)*5.0, 1.0-(p-0.7)*5.0, 0.0)
|
||||||
|
else: return (1.0, (p-0.9)*10.0, (p-0.9)*10.0)
|
||||||
|
|
||||||
|
l = ledbar.Ledbar(PIXELS)
|
||||||
|
history = []
|
||||||
|
window = np.array([0.5*(1-math.cos(2*math.pi*i/(SAMPLE_SIZE-1))) for i in xrange(SAMPLE_SIZE)])
|
||||||
|
work = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
while work:
|
||||||
|
try: data = stream.read(CHUNK_SIZE)
|
||||||
|
except IOError: continue
|
||||||
|
if len(data) == 0: break
|
||||||
|
indata = np.array(struct.unpack('%dh'%CHUNK_SIZE,data))
|
||||||
|
history.append(indata)
|
||||||
|
if len(history) > HISTORY_SIZE: history.pop(0)
|
||||||
|
elif len(history) < HISTORY_SIZE: continue
|
||||||
|
fft = np.fft.rfft(np.concatenate(history)*window)
|
||||||
|
freq_limit = MIN_FREQ
|
||||||
|
freq = 0
|
||||||
|
i = 0
|
||||||
|
while freq < freq_limit:
|
||||||
|
i += 1
|
||||||
|
freq += FREQ_STEP
|
||||||
|
freq_limit *= PIXEL_FREQ_RANGE
|
||||||
|
pixel = 0
|
||||||
|
count = 0
|
||||||
|
volumes = []
|
||||||
|
while pixel < PIXELS:
|
||||||
|
total = 0.0
|
||||||
|
while freq < freq_limit:
|
||||||
|
total += abs(fft[i])**2
|
||||||
|
i += 1; count += 1
|
||||||
|
freq += FREQ_STEP
|
||||||
|
volume = (total/count)**0.5/SAMPLE_SIZE
|
||||||
|
volumes.append(volume)
|
||||||
|
freq_limit *= PIXEL_FREQ_RANGE
|
||||||
|
pixel += 1
|
||||||
|
count = 0
|
||||||
|
for pixel in xrange(PIXELS):
|
||||||
|
c = get_color(volumes[pixel])
|
||||||
|
l.set_pixel(pixel, c[0], c[1], c[2])
|
||||||
|
work = l.update()
|
||||||
|
finally:
|
||||||
|
stream.close()
|
||||||
|
p.terminate()
|
50
host_python/ledbar.py
Normal file
50
host_python/ledbar.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# vim:et:sw=4:ts=4:sts=4
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
class Ledbar:
|
||||||
|
|
||||||
|
def __init__(self, boxes=10, secs_per_frame=0.025):
|
||||||
|
self.boxes = boxes
|
||||||
|
self.secs_per_frame = secs_per_frame
|
||||||
|
self.last_update = time.time()
|
||||||
|
self.pixels = []
|
||||||
|
for i in xrange(boxes):
|
||||||
|
self.pixels.append([0, 0, 0])
|
||||||
|
|
||||||
|
def set_pixel(self, pixel, red, green, blue):
|
||||||
|
self.set_red(pixel, red)
|
||||||
|
self.set_green(pixel, green)
|
||||||
|
self.set_blue(pixel, blue)
|
||||||
|
|
||||||
|
def set_red(self, pixel, red):
|
||||||
|
if red < 0.0 or red > 1.0: raise ValueError('red has to be between 0.0 and 1.0')
|
||||||
|
self.pixels[pixel][0] = int(red*255.99)
|
||||||
|
|
||||||
|
def set_green(self, pixel, green):
|
||||||
|
if green < 0.0 or green > 1.0: raise ValueError('green has to be between 0.0 and 1.0')
|
||||||
|
self.pixels[pixel][1] = int(green*255.99)
|
||||||
|
|
||||||
|
def set_blue(self, pixel, blue):
|
||||||
|
if blue < 0.0 or blue > 1.0: raise ValueError('blue has to be between 0.0 and 1.0')
|
||||||
|
self.pixels[pixel][2] = int(blue*255.99)
|
||||||
|
|
||||||
|
def echo(self, s, no_newline=False):
|
||||||
|
sys.stderr.write(str(s) + ('' if no_newline else '\n'))
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
now = time.time()
|
||||||
|
delta = now - self.last_update
|
||||||
|
if delta < self.secs_per_frame:
|
||||||
|
time.sleep(self.secs_per_frame - delta)
|
||||||
|
try:
|
||||||
|
for p in self.pixels:
|
||||||
|
for c in p:
|
||||||
|
sys.stdout.write(chr(c))
|
||||||
|
sys.stdout.flush()
|
||||||
|
except IOError:
|
||||||
|
return False
|
||||||
|
self.last_update += self.secs_per_frame
|
||||||
|
return True
|
33
host_python/rainbow.py
Executable file
33
host_python/rainbow.py
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# vim:et:sw=4:ts=4:sts=4
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from ledbar import Ledbar
|
||||||
|
|
||||||
|
PIXELS = 10
|
||||||
|
|
||||||
|
def update(t, i):
|
||||||
|
offset = float(i)/PIXELS
|
||||||
|
time = 0.005*t
|
||||||
|
phi = 6*offset+time
|
||||||
|
phase = int(phi%6)
|
||||||
|
part = phi % 1.0
|
||||||
|
inc = part
|
||||||
|
dec = 1-part
|
||||||
|
if phase == 0: return ( 1, inc, 0)
|
||||||
|
elif phase == 1: return (dec, 1, 0)
|
||||||
|
elif phase == 2: return ( 0, 1, inc)
|
||||||
|
elif phase == 3: return ( 0, dec, 1)
|
||||||
|
elif phase == 4: return (inc, 0, 1)
|
||||||
|
elif phase == 5: return ( 1, 0, dec)
|
||||||
|
|
||||||
|
l = Ledbar(PIXELS)
|
||||||
|
t = 0
|
||||||
|
work = True
|
||||||
|
while work:
|
||||||
|
for i in xrange(PIXELS):
|
||||||
|
c = update(t, i)
|
||||||
|
l.set_pixel(i, c[0], c[1], c[2])
|
||||||
|
work = l.update()
|
||||||
|
t += 1
|
72
host_python/send_to_serial.py
Executable file
72
host_python/send_to_serial.py
Executable file
|
@ -0,0 +1,72 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# vim:et:sw=4:ts=4:sts=4
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import serial
|
||||||
|
import getopt
|
||||||
|
|
||||||
|
def print_usage():
|
||||||
|
print '''\
|
||||||
|
USAGE:
|
||||||
|
%s [-h | [-n number] [-b speed] serial]
|
||||||
|
OPTIONS:
|
||||||
|
serial write output to serial device
|
||||||
|
-b speed speed of the serial device
|
||||||
|
-n number number of controlled boxes
|
||||||
|
-h --help show this help
|
||||||
|
''' % sys.argv[0]
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(sys.argv[1:], 's:b:n:h', ['help'])
|
||||||
|
except getopt.GetOptError:
|
||||||
|
print_usage()
|
||||||
|
return 1
|
||||||
|
speed = 38400
|
||||||
|
number = 10
|
||||||
|
show_help = False
|
||||||
|
for k, v in opts:
|
||||||
|
if k == '-n':
|
||||||
|
if not v.isdigit():
|
||||||
|
print_usage()
|
||||||
|
return 1
|
||||||
|
number = int(v)
|
||||||
|
elif k == '-b':
|
||||||
|
if not v.isdigit():
|
||||||
|
print_usage()
|
||||||
|
return 1
|
||||||
|
speed = int(v)
|
||||||
|
elif k == '-h' or k == '--help': show_help = True
|
||||||
|
if show_help:
|
||||||
|
print_usage()
|
||||||
|
return 0
|
||||||
|
if len(args) != 1:
|
||||||
|
print_usage()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
output_stream = serial.Serial(args[0], speed)
|
||||||
|
except serial.serialutil.SerialException:
|
||||||
|
print 'Could not open the serial device'
|
||||||
|
return 1
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
data = ''
|
||||||
|
to_read = number*3
|
||||||
|
while to_read > 0:
|
||||||
|
read = sys.stdin.read(to_read)
|
||||||
|
if len(read) == 0: break
|
||||||
|
to_read -= len(read)
|
||||||
|
data += read
|
||||||
|
if len(read) == 0: break
|
||||||
|
output_stream.write(data)
|
||||||
|
output_stream.flush()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
sys.exit(main())
|
Loading…
Add table
Add a link
Reference in a new issue