Compare commits

..

23 commits

Author SHA1 Message Date
Thomas Kolb 66f3e6fe06 particles.lua: fixed some comments 2020-06-23 21:32:43 +02:00
Thomas Kolb d7c5070bb9 sk6812: send END_OF_UPDATE in the last packet 2020-06-23 21:30:11 +02:00
Thomas Kolb f0afdcfa01 particles.lua: apply exponent before distributing energy 2020-06-23 21:29:20 +02:00
Thomas Kolb f172a2d1f2 New script particles.lua 2020-06-18 19:54:30 +00:00
Thomas Kolb 5ac566b1f5 New script: particles 2020-06-14 16:12:02 +00:00
Thomas Kolb 7ad270ca08 sparkler: minor tuning 2020-06-14 14:41:50 +00:00
Thomas Kolb 436b816d1e Added new scripts for 8x16 LED cylinder 2020-06-05 20:45:00 +02:00
Thomas Kolb e587ac073a Some new 2D animation scripts; Changed config to 60 FPS 2020-05-16 21:51:35 +02:00
Thomas Kolb 4041923cc7 Update Lua API to support 2D LED arrays
It’s a whole new dimension!
2020-05-15 23:17:26 +02:00
Thomas Kolb 54609eae89 flame.lua: removed flickering bottom row 2019-12-17 22:10:25 +01:00
Thomas Kolb 3741a9dd12 Port flame.lua to "Musiclight Mini" 2019-12-17 22:09:53 +01:00
Thomas Kolb b3c1e3c895 Fixed build on openSUSE 2019-08-22 15:30:51 +02:00
Thomas Kolb d4e7d558bd New protocol for multiple strips 2018-08-14 21:52:33 +02:00
Thomas Kolb 0ae3492b82 Triple LED Stripe test 2018-06-30 01:42:34 +02:00
Thomas Kolb 0a76acd85b Ported musiclight to RGBW LEDs
Not all scripts are ported yet...
2018-06-24 22:23:39 +02:00
Thomas Kolb 57b2fa6cbc Lots of changes, too long ago to remember 2018-06-19 20:13:22 +00:00
Thomas Kolb 6a11b7a16c Fixed license notice 2013-02-02 21:54:53 +01:00
Thomas Kolb 3fda457f09 New version of pulsetunnel script
This is the pulsetunnel.lua script with a common maximum value derived
from the three color channels. Channels can be weighted using constants
in the lua script.

The new script generates more saturated colors in most musical
situations.
2012-11-26 17:52:06 +01:00
Thomas Kolb 4e1bd47217 Export some #defines to lua scripts 2012-11-26 17:51:30 +01:00
Thomas Kolb 1ed1717c62 Merge branch 'lua'
This combines LUA scripting support with the highly optimized FFT
algorithm.

Conflicts:
	Makefile
	main.c
2012-11-22 19:53:49 +01:00
Thomas Kolb c09ff65f79 Start counting from 0 in LUT generator 2012-11-21 22:07:23 +01:00
Thomas Kolb f6173965f5 FFT now uses a lookup-table for sin and cos values
On x86, this makes the program approx. 5 times faster.
2012-09-03 18:50:11 +02:00
Thomas Kolb 9f196ba5e2 Make the value type configurable
Currently, value_type is typedef'd as double.
2012-09-03 17:16:14 +02:00
39 changed files with 2676 additions and 327 deletions

View file

@ -1,13 +1,13 @@
LUA_CFLAGS=$(shell pkg-config --cflags lua)
LUA_LIBS=$(shell pkg-config --libs lua)
LUA_CFLAGS=$(shell pkg-config --cflags lua5.3)
LUA_LIBS=$(shell pkg-config --libs lua5.3)
CC=gcc
CFLAGS+=-O2 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -D_XOPEN_SOURCE $(LUA_CFLAGS)
LIBS=-lm -lpthread -lrt $(LUA_LIBS)
TARGET=musiclight2
SOURCE=main.c fft.c utils.c ws2801.c lua_utils.c lua_wrappers.c
DEPS=config.h fft.h utils.h ws2801.h lua_utils.h lua_wrappers.h
SOURCE=main.c fft.c utils.c sk6812.c lua_utils.c lua_wrappers.c lut.c
DEPS=config.h fft.h utils.h sk6812.h lua_utils.h lua_wrappers.h lut.h
OBJ=$(patsubst %.c, %.o, $(SOURCE))

View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#ifndef CONFIG_H
@ -15,11 +16,11 @@
// configuration variables for musiclight2
// networking
#define HOST "192.168.23.222"
#define HOST "192.168.42.1"
#define PORT 2703
// FFT transformation parameters
#define FFT_EXPONENT 10
#define FFT_EXPONENT 8 // ATTENTION: when you change this, run gen_lut.py with this value as argument
#define BLOCK_LEN (1 << FFT_EXPONENT) // 2^FFT_EXPONENT
#define SAMPLE_RATE 44100
#define DATALEN (BLOCK_LEN / 2)
@ -27,8 +28,11 @@
// Number of parts in the sample buffer
#define BUFFER_PARTS 2
// update rate for the led strip (in seconds)
#define LED_INTERVAL 0.03
// Update rate for the led strip (in seconds)
// Must be a little faster than the hardware update rate to ensure theres
// always a packet in the queue
//#define LED_INTERVAL 0.01
#define LED_INTERVAL (1.0/61.0)
// frequency ranges for the base colors
#define RED_MIN_FREQ 0
@ -44,4 +48,6 @@
typedef int16_t sample;
typedef int64_t sample_sum;
typedef double value_type;
#endif // CONFIG_H

View file

@ -1,7 +1,8 @@
WS2801_HOST = "192.168.23.222"
WS2801_HOST = "192.168.42.1"
WS2801_PORT = 2703
NUM_MODULES = 20
CENTER_MODULE = 10
NUM_MODULES = 16
NUM_STRIPS = 8
CENTER_MODULE = 8
GAMMA = 2.0

41
fft.c
View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#include <stdio.h>
@ -14,9 +15,10 @@
#include "config.h"
#include "lut.h"
#include "fft.h"
double hanning_buffer[BLOCK_LEN];
value_type hanning_buffer[BLOCK_LEN];
int lookup_table[BLOCK_LEN];
@ -40,7 +42,7 @@ void init_fft(void) {
void complex_to_absolute(double *re, double *im, double *result) {
void complex_to_absolute(value_type *re, value_type *im, value_type *result) {
int i;
for(i = 0; i < DATALEN; i++)
@ -60,16 +62,15 @@ void apply_hanning(sample *dftinput) {
void fft_transform(sample *samples, double *resultRe, double *resultIm) {
void fft_transform(sample *samples, value_type *resultRe, value_type *resultIm) {
int i;
int layer, part, element;
int num_parts, num_elements;
int left, right;
double x_left_re, x_left_im, x_right_re, x_right_im;
double param;
double sinval, cosval;
value_type x_left_re, x_left_im, x_right_re, x_right_im;
value_type sinval, cosval;
// re-arrange the input array according to the lookup table
// and store it into the real output array (as the input is obviously real).
@ -105,12 +106,10 @@ void fft_transform(sample *samples, double *resultRe, double *resultIm) {
x_right_re = resultRe[right];
x_right_im = resultIm[right];
// precalculate the parameter for sin and cos
param = -M_PI * element / (1 << layer);
// precalculate sinus and cosinus values for param
sinval = sin(param);
cosval = cos(param);
// use lookup table to get sinus and cosinus values for param
//param = -M_PI * element / (1 << layer);
sinval = lookup_sin(layer, element);
cosval = lookup_cos(layer, element);
// combine the values according to a butterfly diagram
resultRe[left] = x_right_re + x_left_re * cosval - x_left_im * sinval;
@ -122,9 +121,9 @@ void fft_transform(sample *samples, double *resultRe, double *resultIm) {
}
}
uint32_t find_loudest_frequency(double *absFFT) {
uint32_t find_loudest_frequency(value_type *absFFT) {
int maxPos = 0;
double maxVal = 0;
value_type maxVal = 0;
int i;
for(i = 0; i < BLOCK_LEN; i++) {
@ -134,15 +133,15 @@ uint32_t find_loudest_frequency(double *absFFT) {
}
}
return (double)maxPos * SAMPLE_RATE / BLOCK_LEN;
return (value_type)maxPos * SAMPLE_RATE / BLOCK_LEN;
}
double get_energy_in_band(double *fft, uint32_t minFreq, uint32_t maxFreq) {
value_type get_energy_in_band(value_type *fft, uint32_t minFreq, uint32_t maxFreq) {
int firstBlock = minFreq * BLOCK_LEN / SAMPLE_RATE;
int lastBlock = maxFreq * BLOCK_LEN / SAMPLE_RATE;
int i;
double energy = 0;
value_type energy = 0;
for(i = firstBlock; i < lastBlock; i++) {
energy += fft[i];
}

17
fft.h
View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#ifndef FFT_H
@ -13,10 +14,10 @@
#include "config.h"
void init_fft(void);
void complex_to_absolute(double *re, double *im, double *result);
void complex_to_absolute(value_type *re, value_type *im, value_type *result);
void apply_hanning(sample *dftinput);
void fft_transform(sample *samples, double *resultRe, double *resultIm);
uint32_t find_loudest_frequency(double *absFFT);
double get_energy_in_band(double *fft, uint32_t minFreq, uint32_t maxFreq);
void fft_transform(sample *samples, value_type *resultRe, value_type *resultIm);
uint32_t find_loudest_frequency(value_type *absFFT);
value_type get_energy_in_band(value_type *fft, uint32_t minFreq, uint32_t maxFreq);
#endif // FFT_H

144
fire.lua Normal file
View file

@ -0,0 +1,144 @@
COOLDOWN_FACTOR = 0.9998
MAX_ENERGY_PROPAGATION = 0.4
RM_ENERGY=0.0100
EXPONENT=1.5
W_EXPONENT=2.2
OVERDRIVE=1.5
num_modules = 1
num_strips = 1
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
-- array storing the flames energy for each pixel
fireRedEnergy = {}
fireGreenEnergy = {}
fireBlueEnergy = {}
fireWhiteEnergy = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function updateFire(newEnergy, energyArray)
avgEnergyPerStrip = newEnergy
for s = 1,num_strips do
-- Add new energy in the bottom row
i = idx(s, 1)
energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip
-- remove energy at the top
i = idx(s, num_modules)
energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION)
-- move energy upwards
for m_out = num_modules,2,-1 do
i_out = idx(s, m_out)
i_in = idx(s, m_out - 1)
energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION
energyArray[i_in] = energyArray[i_in] - energyMoved
energyArray[i_out] = energyArray[i_out] + energyMoved
end
-- globally remove energy
for m = 1,num_modules do
i = idx(s, m)
if energyArray[i] > RM_ENERGY then
energyArray[i] = energyArray[i] - RM_ENERGY
else
energyArray[i] = 0
end
end
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
updateFire((redEnergy / maxRedEnergy)^EXPONENT, fireRedEnergy)
updateFire((greenEnergy / maxGreenEnergy)^EXPONENT, fireGreenEnergy)
updateFire((blueEnergy / maxBlueEnergy)^EXPONENT, fireBlueEnergy)
updateFire((whiteEnergy / maxWhiteEnergy)^W_EXPONENT, fireWhiteEnergy)
-- make colors more exciting + remove the first (flickering) mass
for m = 1,num_modules do
for s = 1,num_strips do
i = idx(s, m)
rval = limit(OVERDRIVE * fireRedEnergy[i])--^EXPONENT)
gval = limit(OVERDRIVE * fireGreenEnergy[i])--^EXPONENT)
bval = limit(OVERDRIVE * fireBlueEnergy[i])--^EXPONENT)
wval = limit(OVERDRIVE * fireWhiteEnergy[i])--^W_EXPONENT)
red[i] = rval
green[i] = gval
blue[i] = bval
white[i] = wval
end
end
-- return the 4 color arrays
return red, green, blue, white
end
function init(nstrip, nmod, cmod)
num_strips = nstrip
num_modules = nmod
for i = 1,(nmod*nstrip) do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
fireRedEnergy[i] = 0
fireGreenEnergy[i] = 0
fireBlueEnergy[i] = 0
fireWhiteEnergy[i] = 0
end
-- don't use fading
return 0
end

159
fire_dual.lua Normal file
View file

@ -0,0 +1,159 @@
COOLDOWN_FACTOR = 0.9998
MAX_ENERGY_PROPAGATION = 0.3
RM_ENERGY=0.0200
EXPONENT=1.5
W_EXPONENT=2.2
OVERDRIVE=1.5
num_modules = 1
num_strips = 1
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
-- array storing the flames energy for each pixel
fireRedEnergy = {}
fireGreenEnergy = {}
fireBlueEnergy = {}
fireWhiteEnergy = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function updateFire(newEnergy, energyArray)
avgEnergyPerStrip = newEnergy
for s = 1,num_strips do
-- Add new energy in the center rows
i = idx(s, num_modules/2)
energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip
i = idx(s, num_modules/2+1)
energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip
-- remove energy at the top and the bottom
i = idx(s, num_modules)
energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION)
i = idx(s, 1)
energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION)
-- move energy upwards
for m_out = num_modules,num_modules/2+2,-1 do
i_out = idx(s, m_out)
i_in = idx(s, m_out - 1)
energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION
energyArray[i_in] = energyArray[i_in] - energyMoved
energyArray[i_out] = energyArray[i_out] + energyMoved
end
-- move energy downwards
for m_out = 1,num_modules/2-1,1 do
i_out = idx(s, m_out)
i_in = idx(s, m_out + 1)
energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION
energyArray[i_in] = energyArray[i_in] - energyMoved
energyArray[i_out] = energyArray[i_out] + energyMoved
end
-- globally remove energy
for m = 1,num_modules do
i = idx(s, m)
if energyArray[i] > RM_ENERGY then
energyArray[i] = energyArray[i] - RM_ENERGY
else
energyArray[i] = 0
end
end
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
updateFire((redEnergy / maxRedEnergy)^EXPONENT, fireRedEnergy)
updateFire((greenEnergy / maxGreenEnergy)^EXPONENT, fireGreenEnergy)
updateFire((blueEnergy / maxBlueEnergy)^EXPONENT, fireBlueEnergy)
updateFire((whiteEnergy / maxWhiteEnergy)^W_EXPONENT, fireWhiteEnergy)
-- make colors more exciting + remove the first (flickering) mass
for m = 1,num_modules do
for s = 1,num_strips do
i = idx(s, m)
rval = limit(OVERDRIVE * (fireRedEnergy[i]))
gval = limit(OVERDRIVE * (fireGreenEnergy[i]))
bval = limit(OVERDRIVE * (fireBlueEnergy[i]))
wval = limit(OVERDRIVE * (fireWhiteEnergy[i]))
red[i] = rval
green[i] = gval
blue[i] = bval
white[i] = wval
end
end
-- return the 4 color arrays
return red, green, blue, white
end
function init(nstrip, nmod, cmod)
num_strips = nstrip
num_modules = nmod
for i = 1,(nmod*nstrip) do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
fireRedEnergy[i] = 0
fireGreenEnergy[i] = 0
fireBlueEnergy[i] = 0
fireWhiteEnergy[i] = 0
end
-- don't use fading
return 0
end

216
flame.lua Normal file
View file

@ -0,0 +1,216 @@
COOLDOWN_FACTOR = 0.9998
OVERDRIVE = 1.70
EXPONENT = 1.5
W_EXPONENT = 2.2
M = 10.0 -- mass
D = 1 -- spring strength
DAMPING = {} -- filled in init()
num_modules = 16
center_module = 16
num_masses = math.floor(num_modules/2)
excitement_pos = 1
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
-- spring-mass-grid values
pos_r = {}
pos_g = {}
pos_b = {}
pos_w = {}
vel_r = {}
vel_g = {}
vel_b = {}
vel_w = {}
acc_r = {}
acc_g = {}
acc_b = {}
acc_w = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
r_tmp = {}
g_tmp = {}
b_tmp = {}
w_tmp = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
local centerIndex = 2 * center_module + 1;
--print(maxRedEnergy .. "\t" .. maxGreenEnergy .. "\t" .. maxBlueEnergy .. "\t" .. maxWhiteEnergy)
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
-- update the spring-mass string
-- the outside masses are special, as they are auto-returned to 0 position
-- { spring-mass pendulum } { friction }
--acc_r[1] = (-pos_r[1] + (pos_r[2] - pos_r[1])) * D / M
--acc_g[1] = (-pos_g[1] + (pos_g[2] - pos_g[1])) * D / M
--acc_b[1] = (-pos_b[1] + (pos_b[2] - pos_b[1])) * D / M
--acc_w[1] = (-pos_w[1] + (pos_w[2] - pos_w[1])) * D / M
acc_r[num_masses] = (-pos_r[num_masses] + (pos_r[num_masses-1] - pos_r[num_masses])) * D / M
acc_g[num_masses] = (-pos_g[num_masses] + (pos_g[num_masses-1] - pos_g[num_masses])) * D / M
acc_b[num_masses] = (-pos_b[num_masses] + (pos_b[num_masses-1] - pos_b[num_masses])) * D / M
acc_w[num_masses] = (-pos_w[num_masses] + (pos_w[num_masses-1] - pos_w[num_masses])) * D / M
-- inside masses are only influenced by their neighbors
for i = 2,num_masses-1 do
acc_r[i] = (pos_r[i-1] + pos_r[i+1] - 2 * pos_r[i]) * D / M
acc_g[i] = (pos_g[i-1] + pos_g[i+1] - 2 * pos_g[i]) * D / M
acc_b[i] = (pos_b[i-1] + pos_b[i+1] - 2 * pos_b[i]) * D / M
acc_w[i] = (pos_w[i-1] + pos_w[i+1] - 2 * pos_w[i]) * D / M
end
-- update velocity and position
for i = 1,num_masses do
vel_r[i] = DAMPING[i] * (vel_r[i] + acc_r[i])
vel_g[i] = DAMPING[i] * (vel_g[i] + acc_g[i])
vel_b[i] = DAMPING[i] * (vel_b[i] + acc_b[i])
vel_w[i] = DAMPING[i] * (vel_w[i] + acc_w[i])
pos_r[i] = pos_r[i] + vel_r[i]
pos_g[i] = pos_g[i] + vel_g[i]
pos_b[i] = pos_b[i] + vel_b[i]
pos_w[i] = pos_w[i] + vel_w[i]
end
-- set the new position for the center module
newRed = redEnergy / maxRedEnergy
pos_r[excitement_pos] = newRed
vel_r[excitement_pos] = 0
acc_r[excitement_pos] = 0
newGreen = greenEnergy / maxGreenEnergy
pos_g[excitement_pos] = newGreen
vel_g[excitement_pos] = 0
acc_g[excitement_pos] = 0
newBlue = blueEnergy / maxBlueEnergy
pos_b[excitement_pos] = newBlue
vel_b[excitement_pos] = 0
acc_b[excitement_pos] = 0
newWhite = whiteEnergy / maxWhiteEnergy
pos_w[excitement_pos] = newWhite
vel_w[excitement_pos] = 0
acc_w[excitement_pos] = 0
-- map to LED modules
for i = 1,num_masses do
r_tmp[i] = pos_r[i]
g_tmp[i] = pos_g[i]
b_tmp[i] = pos_b[i]
w_tmp[i] = pos_w[i]
--r_tmp[num_modules-i+1] = pos_r[i]
--g_tmp[num_modules-i+1] = pos_g[i]
--b_tmp[num_modules-i+1] = pos_b[i]
--w_tmp[num_modules-i+1] = pos_w[i]
--print(i, pos_r[i])
end
-- make colors more exciting + remove the first (flickering) mass
for m = 1,num_modules do
rval = limit(OVERDRIVE * r_tmp[m+1]^EXPONENT)
gval = limit(OVERDRIVE * g_tmp[m+1]^EXPONENT)
bval = limit(OVERDRIVE * b_tmp[m+1]^EXPONENT)
wval = limit(OVERDRIVE * w_tmp[m+1]^W_EXPONENT)
for s = 1,num_strip do
i = idx(s, m)
red[i] = rval
green[i] = gval
blue[i] = bval
white[i] = wval
end
end
-- return the 4 color arrays
return red, green, blue, white
end
function init(nstrip, nmod, cmod)
num_strip = nstrip
num_modules = nmod
center_module = nmod --cmod
num_masses = nmod+1 --math.floor(nmod/2)
excitement_pos = 1
for i = 1,(nmod*nstrip) do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
end
for i = 1,num_masses do
pos_r[i] = 0
pos_g[i] = 0
pos_b[i] = 0
pos_w[i] = 0
vel_r[i] = 0
vel_g[i] = 0
vel_b[i] = 0
vel_w[i] = 0
acc_r[i] = 0
acc_g[i] = 0
acc_b[i] = 0
acc_w[i] = 0
DAMPING[i] = 1 - 0.15 * math.abs((i - excitement_pos) / num_masses)^2
end
-- don't use fading
return 0
end

68
gen_lut.py Executable file
View file

@ -0,0 +1,68 @@
#!/usr/bin/env python3
import sys
from math import *
preamble = """// This file was auto-generated using gen_lut.py
#include "lut.h"
"""
postamble = """
value_type lookup_sin(int layer, int element) {
return sin_lut[layer][element];
}
value_type lookup_cos(int layer, int element) {
return cos_lut[layer][element];
}
"""
if len(sys.argv) < 2:
print("Argument required: FFT_EXPONENT")
exit(1)
fft_exponent = int(sys.argv[1])
with open("lut.c", "w") as ofile:
ofile.write(preamble)
# generate the sin() lookup table
for layer in range(0, fft_exponent):
num_elements = (1 << layer)
ofile.write("value_type sin_lut%i[%i] = {" % (layer, num_elements))
ofile.write("0")
for element in range(1, num_elements):
ofile.write(", %.10f" % sin(-pi * element / num_elements));
ofile.write("};\n\n")
ofile.write("value_type *sin_lut[%i] = {sin_lut0" % fft_exponent);
for i in range(1, fft_exponent):
ofile.write(", sin_lut" + str(i));
ofile.write("};\n");
# generate the cos() lookup table
for layer in range(0, fft_exponent):
num_elements = (1 << layer)
ofile.write("value_type cos_lut%i[%i] = {" % (layer, num_elements))
ofile.write("1")
for element in range(1, num_elements):
ofile.write(", %.10f" % cos(-pi * element / num_elements));
ofile.write("};\n\n")
ofile.write("value_type *cos_lut[%i] = {cos_lut0" % fft_exponent);
for i in range(1, fft_exponent):
ofile.write(", cos_lut" + str(i));
ofile.write("};\n");
ofile.write(postamble)

View file

@ -1,15 +1,16 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
#include "lua_utils.h"
@ -63,7 +64,7 @@ void lua_readdoublearray(lua_State *L, double *numbers, size_t len) {
k = lua_tointeger(L, -1);
if(k > len || k < 1) {
fprintf(stderr, "Warning: Lua index (%u) is out of C array range (%u)!\n", k, len);
fprintf(stderr, "Warning: Lua index (%lu) is out of C array range (%lu)!\n", k, len);
} else {
numbers[k-1] = v;
}

View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#ifndef LUA_UTILS_H

View file

@ -1,19 +1,21 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#include <semaphore.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
#include "fft.h"
#include "utils.h"
#include "config.h"
@ -65,9 +67,24 @@ static int l_get_rms(lua_State *L) {
return 1; // number of return values
}
// calculate the position in the output arrays from strip and module index
static int l_idx(lua_State *L) {
luaL_checktype(L, 1, LUA_TNUMBER);
int strip = lua_tointeger(L, 1) - 1; // -1 because Lua counts from 1
luaL_checktype(L, 2, LUA_TNUMBER);
int module = lua_tointeger(L, 2) - 1; // -1 because Lua counts from 1
lua_pushnumber(L, idx(strip, module) + 1); // +1 because Lua counts from 1
return 1; // number of return values
}
void lua_register_funcs(lua_State *L) {
lua_register(L, "get_energy_in_band", l_get_energy_in_band);
lua_register(L, "get_fft", l_get_fft);
lua_register(L, "get_signal", l_get_signal);
lua_register(L, "get_rms", l_get_rms);
lua_register(L, "idx", l_idx);
}

View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#ifndef LUA_WRAPPERS_H

47
lut.c Normal file
View file

@ -0,0 +1,47 @@
// This file was auto-generated using gen_lut.py
#include "lut.h"
value_type sin_lut0[1] = {0};
value_type sin_lut1[2] = {0, -1.0000000000};
value_type sin_lut2[4] = {0, -0.7071067812, -1.0000000000, -0.7071067812};
value_type sin_lut3[8] = {0, -0.3826834324, -0.7071067812, -0.9238795325, -1.0000000000, -0.9238795325, -0.7071067812, -0.3826834324};
value_type sin_lut4[16] = {0, -0.1950903220, -0.3826834324, -0.5555702330, -0.7071067812, -0.8314696123, -0.9238795325, -0.9807852804, -1.0000000000, -0.9807852804, -0.9238795325, -0.8314696123, -0.7071067812, -0.5555702330, -0.3826834324, -0.1950903220};
value_type sin_lut5[32] = {0, -0.0980171403, -0.1950903220, -0.2902846773, -0.3826834324, -0.4713967368, -0.5555702330, -0.6343932842, -0.7071067812, -0.7730104534, -0.8314696123, -0.8819212643, -0.9238795325, -0.9569403357, -0.9807852804, -0.9951847267, -1.0000000000, -0.9951847267, -0.9807852804, -0.9569403357, -0.9238795325, -0.8819212643, -0.8314696123, -0.7730104534, -0.7071067812, -0.6343932842, -0.5555702330, -0.4713967368, -0.3826834324, -0.2902846773, -0.1950903220, -0.0980171403};
value_type sin_lut6[64] = {0, -0.0490676743, -0.0980171403, -0.1467304745, -0.1950903220, -0.2429801799, -0.2902846773, -0.3368898534, -0.3826834324, -0.4275550934, -0.4713967368, -0.5141027442, -0.5555702330, -0.5956993045, -0.6343932842, -0.6715589548, -0.7071067812, -0.7409511254, -0.7730104534, -0.8032075315, -0.8314696123, -0.8577286100, -0.8819212643, -0.9039892931, -0.9238795325, -0.9415440652, -0.9569403357, -0.9700312532, -0.9807852804, -0.9891765100, -0.9951847267, -0.9987954562, -1.0000000000, -0.9987954562, -0.9951847267, -0.9891765100, -0.9807852804, -0.9700312532, -0.9569403357, -0.9415440652, -0.9238795325, -0.9039892931, -0.8819212643, -0.8577286100, -0.8314696123, -0.8032075315, -0.7730104534, -0.7409511254, -0.7071067812, -0.6715589548, -0.6343932842, -0.5956993045, -0.5555702330, -0.5141027442, -0.4713967368, -0.4275550934, -0.3826834324, -0.3368898534, -0.2902846773, -0.2429801799, -0.1950903220, -0.1467304745, -0.0980171403, -0.0490676743};
value_type sin_lut7[128] = {0, -0.0245412285, -0.0490676743, -0.0735645636, -0.0980171403, -0.1224106752, -0.1467304745, -0.1709618888, -0.1950903220, -0.2191012402, -0.2429801799, -0.2667127575, -0.2902846773, -0.3136817404, -0.3368898534, -0.3598950365, -0.3826834324, -0.4052413140, -0.4275550934, -0.4496113297, -0.4713967368, -0.4928981922, -0.5141027442, -0.5349976199, -0.5555702330, -0.5758081914, -0.5956993045, -0.6152315906, -0.6343932842, -0.6531728430, -0.6715589548, -0.6895405447, -0.7071067812, -0.7242470830, -0.7409511254, -0.7572088465, -0.7730104534, -0.7883464276, -0.8032075315, -0.8175848132, -0.8314696123, -0.8448535652, -0.8577286100, -0.8700869911, -0.8819212643, -0.8932243012, -0.9039892931, -0.9142097557, -0.9238795325, -0.9329927988, -0.9415440652, -0.9495281806, -0.9569403357, -0.9637760658, -0.9700312532, -0.9757021300, -0.9807852804, -0.9852776424, -0.9891765100, -0.9924795346, -0.9951847267, -0.9972904567, -0.9987954562, -0.9996988187, -1.0000000000, -0.9996988187, -0.9987954562, -0.9972904567, -0.9951847267, -0.9924795346, -0.9891765100, -0.9852776424, -0.9807852804, -0.9757021300, -0.9700312532, -0.9637760658, -0.9569403357, -0.9495281806, -0.9415440652, -0.9329927988, -0.9238795325, -0.9142097557, -0.9039892931, -0.8932243012, -0.8819212643, -0.8700869911, -0.8577286100, -0.8448535652, -0.8314696123, -0.8175848132, -0.8032075315, -0.7883464276, -0.7730104534, -0.7572088465, -0.7409511254, -0.7242470830, -0.7071067812, -0.6895405447, -0.6715589548, -0.6531728430, -0.6343932842, -0.6152315906, -0.5956993045, -0.5758081914, -0.5555702330, -0.5349976199, -0.5141027442, -0.4928981922, -0.4713967368, -0.4496113297, -0.4275550934, -0.4052413140, -0.3826834324, -0.3598950365, -0.3368898534, -0.3136817404, -0.2902846773, -0.2667127575, -0.2429801799, -0.2191012402, -0.1950903220, -0.1709618888, -0.1467304745, -0.1224106752, -0.0980171403, -0.0735645636, -0.0490676743, -0.0245412285};
value_type *sin_lut[8] = {sin_lut0, sin_lut1, sin_lut2, sin_lut3, sin_lut4, sin_lut5, sin_lut6, sin_lut7};
value_type cos_lut0[1] = {1};
value_type cos_lut1[2] = {1, 0.0000000000};
value_type cos_lut2[4] = {1, 0.7071067812, 0.0000000000, -0.7071067812};
value_type cos_lut3[8] = {1, 0.9238795325, 0.7071067812, 0.3826834324, 0.0000000000, -0.3826834324, -0.7071067812, -0.9238795325};
value_type cos_lut4[16] = {1, 0.9807852804, 0.9238795325, 0.8314696123, 0.7071067812, 0.5555702330, 0.3826834324, 0.1950903220, 0.0000000000, -0.1950903220, -0.3826834324, -0.5555702330, -0.7071067812, -0.8314696123, -0.9238795325, -0.9807852804};
value_type cos_lut5[32] = {1, 0.9951847267, 0.9807852804, 0.9569403357, 0.9238795325, 0.8819212643, 0.8314696123, 0.7730104534, 0.7071067812, 0.6343932842, 0.5555702330, 0.4713967368, 0.3826834324, 0.2902846773, 0.1950903220, 0.0980171403, 0.0000000000, -0.0980171403, -0.1950903220, -0.2902846773, -0.3826834324, -0.4713967368, -0.5555702330, -0.6343932842, -0.7071067812, -0.7730104534, -0.8314696123, -0.8819212643, -0.9238795325, -0.9569403357, -0.9807852804, -0.9951847267};
value_type cos_lut6[64] = {1, 0.9987954562, 0.9951847267, 0.9891765100, 0.9807852804, 0.9700312532, 0.9569403357, 0.9415440652, 0.9238795325, 0.9039892931, 0.8819212643, 0.8577286100, 0.8314696123, 0.8032075315, 0.7730104534, 0.7409511254, 0.7071067812, 0.6715589548, 0.6343932842, 0.5956993045, 0.5555702330, 0.5141027442, 0.4713967368, 0.4275550934, 0.3826834324, 0.3368898534, 0.2902846773, 0.2429801799, 0.1950903220, 0.1467304745, 0.0980171403, 0.0490676743, 0.0000000000, -0.0490676743, -0.0980171403, -0.1467304745, -0.1950903220, -0.2429801799, -0.2902846773, -0.3368898534, -0.3826834324, -0.4275550934, -0.4713967368, -0.5141027442, -0.5555702330, -0.5956993045, -0.6343932842, -0.6715589548, -0.7071067812, -0.7409511254, -0.7730104534, -0.8032075315, -0.8314696123, -0.8577286100, -0.8819212643, -0.9039892931, -0.9238795325, -0.9415440652, -0.9569403357, -0.9700312532, -0.9807852804, -0.9891765100, -0.9951847267, -0.9987954562};
value_type cos_lut7[128] = {1, 0.9996988187, 0.9987954562, 0.9972904567, 0.9951847267, 0.9924795346, 0.9891765100, 0.9852776424, 0.9807852804, 0.9757021300, 0.9700312532, 0.9637760658, 0.9569403357, 0.9495281806, 0.9415440652, 0.9329927988, 0.9238795325, 0.9142097557, 0.9039892931, 0.8932243012, 0.8819212643, 0.8700869911, 0.8577286100, 0.8448535652, 0.8314696123, 0.8175848132, 0.8032075315, 0.7883464276, 0.7730104534, 0.7572088465, 0.7409511254, 0.7242470830, 0.7071067812, 0.6895405447, 0.6715589548, 0.6531728430, 0.6343932842, 0.6152315906, 0.5956993045, 0.5758081914, 0.5555702330, 0.5349976199, 0.5141027442, 0.4928981922, 0.4713967368, 0.4496113297, 0.4275550934, 0.4052413140, 0.3826834324, 0.3598950365, 0.3368898534, 0.3136817404, 0.2902846773, 0.2667127575, 0.2429801799, 0.2191012402, 0.1950903220, 0.1709618888, 0.1467304745, 0.1224106752, 0.0980171403, 0.0735645636, 0.0490676743, 0.0245412285, 0.0000000000, -0.0245412285, -0.0490676743, -0.0735645636, -0.0980171403, -0.1224106752, -0.1467304745, -0.1709618888, -0.1950903220, -0.2191012402, -0.2429801799, -0.2667127575, -0.2902846773, -0.3136817404, -0.3368898534, -0.3598950365, -0.3826834324, -0.4052413140, -0.4275550934, -0.4496113297, -0.4713967368, -0.4928981922, -0.5141027442, -0.5349976199, -0.5555702330, -0.5758081914, -0.5956993045, -0.6152315906, -0.6343932842, -0.6531728430, -0.6715589548, -0.6895405447, -0.7071067812, -0.7242470830, -0.7409511254, -0.7572088465, -0.7730104534, -0.7883464276, -0.8032075315, -0.8175848132, -0.8314696123, -0.8448535652, -0.8577286100, -0.8700869911, -0.8819212643, -0.8932243012, -0.9039892931, -0.9142097557, -0.9238795325, -0.9329927988, -0.9415440652, -0.9495281806, -0.9569403357, -0.9637760658, -0.9700312532, -0.9757021300, -0.9807852804, -0.9852776424, -0.9891765100, -0.9924795346, -0.9951847267, -0.9972904567, -0.9987954562, -0.9996988187};
value_type *cos_lut[8] = {cos_lut0, cos_lut1, cos_lut2, cos_lut3, cos_lut4, cos_lut5, cos_lut6, cos_lut7};
value_type lookup_sin(int layer, int element) {
return sin_lut[layer][element];
}
value_type lookup_cos(int layer, int element) {
return cos_lut[layer][element];
}

19
lut.h Normal file
View file

@ -0,0 +1,19 @@
/*
* vim: sw=2 ts=2 expandtab
*
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#ifndef LUT_H
#define LUT_H
#include "config.h"
value_type lookup_sin(int layer, int element);
value_type lookup_cos(int layer, int element);
#endif // LUT_H

132
main.c
View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#include <pthread.h>
@ -16,40 +17,46 @@
#include <stdint.h>
#include <malloc.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
#include "lua_utils.h"
#include "lua_wrappers.h"
#include "fft.h"
#include "utils.h"
#include "ws2801.h"
#include "sk6812.h"
#include "config.h"
// Frames per second
#define FPS ((double)BUFFER_PARTS * SAMPLE_RATE / BLOCK_LEN)
#define FPS ((value_type)BUFFER_PARTS * SAMPLE_RATE / BLOCK_LEN)
// Number of new samples put into the buffer each frame
#define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS)
double fft[BLOCK_LEN];
value_type fft[BLOCK_LEN];
value_type rms;
value_type lastUpdateTime = 0;
sample signal[BLOCK_LEN];
double rms;
double lastUpdateTime = 0;
sem_t fftSemaphore;
struct sk6812_ctx sk6812;
int num_modules;
int num_strips;
int running = 1;
void* fft_thread(void *param) {
sample buffer[BLOCK_LEN];
sample block[BLOCK_LEN];
double fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
double tmpFFT[BLOCK_LEN];
double tmpRMS;
value_type fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
value_type tmpFFT[BLOCK_LEN];
value_type tmpRMS;
double nextFrame = get_hires_time() + 0.05;
double curTime;
@ -71,16 +78,20 @@ void* fft_thread(void *param) {
memcpy(block, buffer, BLOCK_LEN * sizeof(sample));
apply_hanning(block);
fft_transform(block, fftOutReal, fftOutImag);
complex_to_absolute(fftOutReal, fftOutImag, tmpFFT);
tmpRMS = 0;
for(i = 0; i < BLOCK_LEN; i++) {
tmpRMS += buffer[i]*buffer[i];
}
tmpRMS = sqrt(tmpRMS/BLOCK_LEN);
if(tmpRMS == 0) {
continue;
}
apply_hanning(block);
fft_transform(block, fftOutReal, fftOutImag);
complex_to_absolute(fftOutReal, fftOutImag, tmpFFT);
// --- SAFE SECTION ---
sem_wait(&fftSemaphore);
@ -110,13 +121,13 @@ void* fft_thread(void *param) {
}
nextFrame += 1.000/FPS;
sleep_until(nextFrame);
//sleep_until(nextFrame);
}
return NULL;
}
double gamma_correct(double d, double gamma) {
value_type gamma_correct(value_type d, value_type gamma) {
return pow(d, gamma);
}
@ -127,10 +138,12 @@ int main(int argc, char **argv) {
pthread_t fftThread;
int active = 1;
//int frame = 0;
double *red;
double *green;
double *blue;
double *white;
int useFading, fadeStep;
@ -140,7 +153,7 @@ int main(int argc, char **argv) {
}
// initialize lua
lua_State *L = lua_open();
lua_State *L = luaL_newstate();
// load the lua libraries
luaL_openlibs(L);
@ -168,16 +181,31 @@ int main(int argc, char **argv) {
lua_getglobal(L, "NUM_MODULES");
if(!lua_isnumber(L, -1)) return 2;
int num_modules = lua_tointeger(L, -1);
num_modules = lua_tointeger(L, -1);
lua_getglobal(L, "NUM_STRIPS");
if(!lua_isnumber(L, -1)) return 2;
num_strips = lua_tointeger(L, -1);
lua_getglobal(L, "CENTER_MODULE");
if(!lua_isnumber(L, -1)) return 2;
int center_module = lua_tointeger(L, -1);
// export some global constants
lua_pushnumber(L, SAMPLE_RATE);
lua_setglobal(L, "SAMPLE_RATE");
lua_pushnumber(L, BLOCK_LEN);
lua_setglobal(L, "BLOCK_LEN");
lua_pushnumber(L, DATALEN);
lua_setglobal(L, "DATALEN");
// allocate arrays
red = malloc(num_modules * sizeof(double));
green = malloc(num_modules * sizeof(double));
blue = malloc(num_modules * sizeof(double));
red = malloc(num_strips * num_modules * sizeof(double));
green = malloc(num_strips * num_modules * sizeof(double));
blue = malloc(num_strips * num_modules * sizeof(double));
white = malloc(num_strips * num_modules * sizeof(double));
// load and initialize the script
if(luaL_loadfile(L, argv[1])) {
@ -191,22 +219,23 @@ int main(int argc, char **argv) {
// call the init function
lua_getglobal(L, "init");
lua_pushnumber(L, num_strips);
lua_pushnumber(L, num_modules);
lua_pushnumber(L, center_module);
if(lua_pcall(L, 2, 1, 0)) {
if(lua_pcall(L, 3, 1, 0)) {
lua_showerror(L, "lua_pcall(init) failed.");
}
fadeStep = lua_tointeger(L, -1);
useFading = fadeStep > 0;
if(useFading) {
ws2801_set_fadestep(fadeStep);
sk6812_set_fadestep(&sk6812, fadeStep);
printf("Fading enabled with fadestep %i.\n", fadeStep);
}
// initialize the WS2801 library
printf("Connecting to %s:%i\n", host, port);
ws2801_init(host, port);
sk6812_init(&sk6812, host, port);
// create semaphores
sem_init(&fftSemaphore, 0, 1);
@ -218,40 +247,50 @@ int main(int argc, char **argv) {
if(active) {
// call the periodic() function from LUA
lua_getglobal(L, "periodic");
if(lua_pcall(L, 0, 3, 0)) { // no arguments, 3 return values
if(lua_pcall(L, 0, 4, 0)) { // no arguments, 4 return values
lua_showerror(L, "lua_pcall(periodic) failed.");
}
// read the return values (reverse order, as lua uses a stack)
lua_readdoublearray(L, blue, num_modules);
lua_readdoublearray(L, green, num_modules);
lua_readdoublearray(L, red, num_modules);
lua_readdoublearray(L, white, num_strips*num_modules);
lua_readdoublearray(L, blue, num_strips*num_modules);
lua_readdoublearray(L, green, num_strips*num_modules);
lua_readdoublearray(L, red, num_strips*num_modules);
for(int s = 0; s < num_strips; s++) {
if(useFading) {
for(i = 0; i < num_modules; i++) {
ws2801_fade_color(i,
255 * gamma_correct(red[i], gamma),
255 * gamma_correct(green[i], gamma),
255 * gamma_correct(blue[i], gamma));
int lidx = idx(s, i);
sk6812_fade_color(&sk6812, s, i,
255 * gamma_correct(red[lidx], gamma),
255 * gamma_correct(green[lidx], gamma),
255 * gamma_correct(blue[lidx], gamma),
255 * gamma_correct(white[lidx], gamma));
}
ws2801_commit();
} else {
for(i = 0; i < num_modules; i++) {
ws2801_set_color(i,
255 * gamma_correct(red[i], gamma),
255 * gamma_correct(green[i], gamma),
255 * gamma_correct(blue[i], gamma));
int lidx = idx(s, i);
sk6812_set_color(&sk6812, s, i,
255 * gamma_correct(red[lidx], gamma),
255 * gamma_correct(green[lidx], gamma),
255 * gamma_correct(blue[lidx], gamma),
255 * gamma_correct(white[lidx], gamma));
}
ws2801_commit();
}
}
sk6812_commit(&sk6812);
if(lastUpdateTime < nextFrame - 1) {
printf("Idle for 1 second -> stopping updates.\n");
for(i = 0; i < num_modules; i++) {
ws2801_fade_color(i, 20, 20, 20);
for(int s = 0; s < num_strips; s++) {
sk6812_fade_color(&sk6812, s, i, 0, 0, 0, 20);
}
ws2801_commit();
}
sk6812_commit(&sk6812);
active = 0;
}
@ -264,12 +303,13 @@ int main(int argc, char **argv) {
sleep_until(nextFrame);
}
ws2801_shutdown();
sk6812_shutdown(&sk6812);
// free arrays
free(red);
free(green);
free(blue);
free(white);
pthread_join(fftThread, NULL);

2
old_scripts/README.txt Normal file
View file

@ -0,0 +1,2 @@
The scripts in this directory are no longer compatible with the current API and
are preserved just for their algorithms.

206
old_scripts/flame.lua Normal file
View file

@ -0,0 +1,206 @@
COOLDOWN_FACTOR = 0.9998
OVERDRIVE = 1.70
EXPONENT = 1.5
W_EXPONENT = 2.2
M = 10.0 -- mass
D = 1 -- spring strength
DAMPING = {} -- filled in init()
num_modules = 16
center_module = 16
num_masses = math.floor(num_modules/2)
excitement_pos = 1
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
-- spring-mass-grid values
pos_r = {}
pos_g = {}
pos_b = {}
pos_w = {}
vel_r = {}
vel_g = {}
vel_b = {}
vel_w = {}
acc_r = {}
acc_g = {}
acc_b = {}
acc_w = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
r_tmp = {}
g_tmp = {}
b_tmp = {}
w_tmp = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
local centerIndex = 2 * center_module + 1;
--print(maxRedEnergy .. "\t" .. maxGreenEnergy .. "\t" .. maxBlueEnergy .. "\t" .. maxWhiteEnergy)
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
-- update the spring-mass string
-- the outside masses are special, as they are auto-returned to 0 position
-- { spring-mass pendulum } { friction }
--acc_r[1] = (-pos_r[1] + (pos_r[2] - pos_r[1])) * D / M
--acc_g[1] = (-pos_g[1] + (pos_g[2] - pos_g[1])) * D / M
--acc_b[1] = (-pos_b[1] + (pos_b[2] - pos_b[1])) * D / M
--acc_w[1] = (-pos_w[1] + (pos_w[2] - pos_w[1])) * D / M
acc_r[num_masses] = (-pos_r[num_masses] + (pos_r[num_masses-1] - pos_r[num_masses])) * D / M
acc_g[num_masses] = (-pos_g[num_masses] + (pos_g[num_masses-1] - pos_g[num_masses])) * D / M
acc_b[num_masses] = (-pos_b[num_masses] + (pos_b[num_masses-1] - pos_b[num_masses])) * D / M
acc_w[num_masses] = (-pos_w[num_masses] + (pos_w[num_masses-1] - pos_w[num_masses])) * D / M
-- inside masses are only influenced by their neighbors
for i = 2,num_masses-1 do
acc_r[i] = (pos_r[i-1] + pos_r[i+1] - 2 * pos_r[i]) * D / M
acc_g[i] = (pos_g[i-1] + pos_g[i+1] - 2 * pos_g[i]) * D / M
acc_b[i] = (pos_b[i-1] + pos_b[i+1] - 2 * pos_b[i]) * D / M
acc_w[i] = (pos_w[i-1] + pos_w[i+1] - 2 * pos_w[i]) * D / M
end
-- update velocity and position
for i = 1,num_masses do
vel_r[i] = DAMPING[i] * (vel_r[i] + acc_r[i])
vel_g[i] = DAMPING[i] * (vel_g[i] + acc_g[i])
vel_b[i] = DAMPING[i] * (vel_b[i] + acc_b[i])
vel_w[i] = DAMPING[i] * (vel_w[i] + acc_w[i])
pos_r[i] = pos_r[i] + vel_r[i]
pos_g[i] = pos_g[i] + vel_g[i]
pos_b[i] = pos_b[i] + vel_b[i]
pos_w[i] = pos_w[i] + vel_w[i]
end
-- set the new position for the center module
newRed = redEnergy / maxRedEnergy
pos_r[excitement_pos] = newRed
vel_r[excitement_pos] = 0
acc_r[excitement_pos] = 0
newGreen = greenEnergy / maxGreenEnergy
pos_g[excitement_pos] = newGreen
vel_g[excitement_pos] = 0
acc_g[excitement_pos] = 0
newBlue = blueEnergy / maxBlueEnergy
pos_b[excitement_pos] = newBlue
vel_b[excitement_pos] = 0
acc_b[excitement_pos] = 0
newWhite = whiteEnergy / maxWhiteEnergy
pos_w[excitement_pos] = newWhite
vel_w[excitement_pos] = 0
acc_w[excitement_pos] = 0
-- map to LED modules
for i = 1,num_masses do
r_tmp[i] = pos_r[i]
g_tmp[i] = pos_g[i]
b_tmp[i] = pos_b[i]
w_tmp[i] = pos_w[i]
--r_tmp[num_modules-i+1] = pos_r[i]
--g_tmp[num_modules-i+1] = pos_g[i]
--b_tmp[num_modules-i+1] = pos_b[i]
--w_tmp[num_modules-i+1] = pos_w[i]
--print(i, pos_r[i])
end
-- make colors more exciting + remove the first (flickering) mass
for i = 1,num_modules do
red[i] = limit(OVERDRIVE * r_tmp[i+1]^EXPONENT)
green[i] = limit(OVERDRIVE * g_tmp[i+1]^EXPONENT)
blue[i] = limit(OVERDRIVE * b_tmp[i+1]^EXPONENT)
white[i] = limit(OVERDRIVE * w_tmp[i+1]^W_EXPONENT)
end
-- return the 4 color arrays
return red, green, blue, white
end
function init(nmod, cmod)
num_modules = nmod
center_module = nmod --cmod
num_masses = nmod+1 --math.floor(nmod/2)
excitement_pos = 1
for i = 1,nmod do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
end
for i = 1,num_masses do
pos_r[i] = 0
pos_g[i] = 0
pos_b[i] = 0
pos_w[i] = 0
vel_r[i] = 0
vel_g[i] = 0
vel_b[i] = 0
vel_w[i] = 0
acc_r[i] = 0
acc_g[i] = 0
acc_b[i] = 0
acc_w[i] = 0
DAMPING[i] = 1 - 0.15 * math.abs((i - excitement_pos) / num_masses)^2
end
-- don't use fading
return 0
end

View file

@ -0,0 +1,174 @@
COOLDOWN_FACTOR = 0.9995
OVERDRIVE = 1.70
EXPONENT = 1.5
M = {2.3, 1.3, 1.0} -- mass
D = {1, 1, 1} -- spring strength
DAMPING = {} -- filled in init()
num_modules = 128
center_module = 64
num_masses = math.floor(num_modules/2)
excitement_pos = 1
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
-- spring-mass-grid values
pos_r = {}
pos_g = {}
pos_b = {}
vel_r = {}
vel_g = {}
vel_b = {}
acc_r = {}
acc_g = {}
acc_b = {}
-- output color buffers
red = {}
green = {}
blue = {}
r_tmp = {}
g_tmp = {}
b_tmp = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 22000);
local centerIndex = 2 * center_module + 1;
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
-- update the spring-mass string
-- the outside masses are special, as they are auto-returned to 0 position
-- { spring-mass pendulum } { friction }
--acc_r[1] = (-pos_r[1] + (pos_r[2] - pos_r[1])) * D / M
--acc_g[1] = (-pos_g[1] + (pos_g[2] - pos_g[1])) * D / M
--acc_b[1] = (-pos_b[1] + (pos_b[2] - pos_b[1])) * D / M
acc_r[num_masses] = (-pos_r[num_masses] + (pos_r[num_masses-1] - pos_r[num_masses])) * D[1] / M[1]
acc_g[num_masses] = (-pos_g[num_masses] + (pos_g[num_masses-1] - pos_g[num_masses])) * D[2] / M[2]
acc_b[num_masses] = (-pos_b[num_masses] + (pos_b[num_masses-1] - pos_b[num_masses])) * D[3] / M[3]
-- inside masses are only influenced by their neighbors
for i = 2,num_masses-1 do
acc_r[i] = (pos_r[i-1] + pos_r[i+1] - 2 * pos_r[i]) * D[1] / M[1]
acc_g[i] = (pos_g[i-1] + pos_g[i+1] - 2 * pos_g[i]) * D[2] / M[2]
acc_b[i] = (pos_b[i-1] + pos_b[i+1] - 2 * pos_b[i]) * D[3] / M[3]
end
-- update velocity and position
for i = 1,num_masses do
vel_r[i] = DAMPING[i] * (vel_r[i] + acc_r[i])
vel_g[i] = DAMPING[i] * (vel_g[i] + acc_g[i])
vel_b[i] = DAMPING[i] * (vel_b[i] + acc_b[i])
pos_r[i] = pos_r[i] + vel_r[i]
pos_g[i] = pos_g[i] + vel_g[i]
pos_b[i] = pos_b[i] + vel_b[i]
end
-- set the new position for the center module
newRed = redEnergy / maxRedEnergy
pos_r[excitement_pos] = newRed
vel_r[excitement_pos] = 0
acc_r[excitement_pos] = 0
newGreen = greenEnergy / maxGreenEnergy
pos_g[excitement_pos] = newGreen
vel_b[excitement_pos] = 0
acc_b[excitement_pos] = 0
newBlue = blueEnergy / maxBlueEnergy
pos_b[excitement_pos] = newBlue
vel_b[excitement_pos] = 0
acc_b[excitement_pos] = 0
-- map to LED modules
for i = 1,num_masses do
r_tmp[i] = pos_r[i]
g_tmp[i] = pos_g[i]
b_tmp[i] = pos_b[i]
r_tmp[num_modules-i+1] = pos_r[i]
g_tmp[num_modules-i+1] = pos_g[i]
b_tmp[num_modules-i+1] = pos_b[i]
--print(i, pos_r[i])
end
-- make colors more exciting
for i = 1,num_modules do
red[i] = limit(OVERDRIVE * math.pow(r_tmp[i], EXPONENT))
green[i] = limit(OVERDRIVE * math.pow(g_tmp[i], EXPONENT))
blue[i] = limit(OVERDRIVE * math.pow(b_tmp[i], EXPONENT))
end
-- return the 3 color arrays
return red, green, blue
end
function init(nmod, cmod)
num_modules = nmod
center_module = cmod
num_masses = math.floor(nmod/2)
excitement_pos = 1
for i = 1,nmod do
red[i] = 0
green[i] = 0
blue[i] = 0
end
for i = 1,num_masses do
pos_r[i] = 0
pos_g[i] = 0
pos_b[i] = 0
vel_r[i] = 0
vel_g[i] = 0
vel_b[i] = 0
acc_r[i] = 0
acc_g[i] = 0
acc_b[i] = 0
DAMPING[i] = 1 - 0.08 * math.pow(math.abs((i - excitement_pos) / num_masses), 2)
end
-- don't use fading
return 0
end

203
old_scripts/pulsar.lua Normal file
View file

@ -0,0 +1,203 @@
COOLDOWN_FACTOR = 0.9995
OVERDRIVE = 1.50
EXPONENT = 1.5
M = 5.0--1.7 -- mass
D = 1 -- spring strength
DAMPING = {} -- filled in init()
num_modules = 300
center_module = 150
num_masses = math.floor(num_modules/2)
excitement_pos = math.floor(center_module/2)
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
-- spring-mass-grid values
pos_r = {}
pos_g = {}
pos_b = {}
pos_w = {}
vel_r = {}
vel_g = {}
vel_b = {}
vel_w = {}
acc_r = {}
acc_g = {}
acc_b = {}
acc_w = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
r_tmp = {}
g_tmp = {}
b_tmp = {}
w_tmp = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
local centerIndex = 2 * center_module + 1;
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
-- update the spring-mass string
-- the outside masses are special, as they are auto-returned to 0 position
-- { spring-mass pendulum } { friction }
acc_r[1] = (-pos_r[1] + (pos_r[2] - pos_r[1])) * D / M
acc_g[1] = (-pos_g[1] + (pos_g[2] - pos_g[1])) * D / M
acc_b[1] = (-pos_b[1] + (pos_b[2] - pos_b[1])) * D / M
acc_w[1] = (-pos_w[1] + (pos_w[2] - pos_w[1])) * D / M
acc_r[num_masses] = (-pos_r[num_masses] + (pos_r[num_masses-1] - pos_r[num_masses])) * D / M
acc_g[num_masses] = (-pos_g[num_masses] + (pos_g[num_masses-1] - pos_g[num_masses])) * D / M
acc_b[num_masses] = (-pos_b[num_masses] + (pos_b[num_masses-1] - pos_b[num_masses])) * D / M
acc_w[num_masses] = (-pos_w[num_masses] + (pos_w[num_masses-1] - pos_w[num_masses])) * D / M
-- inside masses are only influenced by their neighbors
for i = 2,num_masses-1 do
acc_r[i] = (pos_r[i-1] + pos_r[i+1] - 2 * pos_r[i]) * D / M
acc_g[i] = (pos_g[i-1] + pos_g[i+1] - 2 * pos_g[i]) * D / M
acc_b[i] = (pos_b[i-1] + pos_b[i+1] - 2 * pos_b[i]) * D / M
acc_w[i] = (pos_w[i-1] + pos_w[i+1] - 2 * pos_w[i]) * D / M
end
-- update velocity and position
for i = 1,num_masses do
vel_r[i] = DAMPING[i] * (vel_r[i] + acc_r[i])
vel_g[i] = DAMPING[i] * (vel_g[i] + acc_g[i])
vel_b[i] = DAMPING[i] * (vel_b[i] + acc_b[i])
vel_w[i] = DAMPING[i] * (vel_w[i] + acc_w[i])
pos_r[i] = pos_r[i] + vel_r[i]
pos_g[i] = pos_g[i] + vel_g[i]
pos_b[i] = pos_b[i] + vel_b[i]
pos_w[i] = pos_w[i] + vel_w[i]
end
-- set the new position for the center module
newRed = redEnergy / maxRedEnergy
pos_r[excitement_pos] = newRed
vel_r[excitement_pos] = 0
acc_r[excitement_pos] = 0
newGreen = greenEnergy / maxGreenEnergy
pos_g[excitement_pos] = newGreen
vel_g[excitement_pos] = 0
acc_g[excitement_pos] = 0
newBlue = blueEnergy / maxBlueEnergy
pos_b[excitement_pos] = newBlue
vel_b[excitement_pos] = 0
acc_b[excitement_pos] = 0
newWhite = whiteEnergy / maxWhiteEnergy
pos_w[excitement_pos] = newWhite
vel_w[excitement_pos] = 0
acc_w[excitement_pos] = 0
-- map to LED modules
for i = 1,num_masses do
r_tmp[i] = pos_r[i]
g_tmp[i] = pos_g[i]
b_tmp[i] = pos_b[i]
w_tmp[i] = pos_w[i]
r_tmp[num_modules-i+1] = pos_r[i]
g_tmp[num_modules-i+1] = pos_g[i]
b_tmp[num_modules-i+1] = pos_b[i]
w_tmp[num_modules-i+1] = pos_w[i]
--print(i, pos_r[i])
end
-- make colors more exciting
for i = 1,num_modules do
red[i] = limit(OVERDRIVE * math.pow(r_tmp[i], EXPONENT))
green[i] = limit(OVERDRIVE * math.pow(g_tmp[i], EXPONENT))
blue[i] = limit(OVERDRIVE * math.pow(b_tmp[i], EXPONENT))
white[i] = limit(OVERDRIVE * math.pow(w_tmp[i], EXPONENT))
end
-- return the 3 color arrays
return red, green, blue, white
end
function init(nmod, cmod)
num_modules = nmod
center_module = cmod
num_masses = math.floor(nmod)
excitement_pos = math.floor(cmod)
for i = 1,nmod do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
end
for i = 1,num_masses do
pos_r[i] = 0
pos_g[i] = 0
pos_b[i] = 0
pos_w[i] = 0
vel_r[i] = 0
vel_g[i] = 0
vel_b[i] = 0
vel_w[i] = 0
acc_r[i] = 0
acc_g[i] = 0
acc_b[i] = 0
acc_w[i] = 0
DAMPING[i] = 1 - 0.5 * math.pow(math.abs((i - excitement_pos) / num_masses), 2)
end
-- don't use fading
return 0
end

112
old_scripts/pulsecircle.lua Normal file
View file

@ -0,0 +1,112 @@
COOLDOWN_FACTOR = 0.9998
FADE_FACTOR = 1
OVERDRIVE = 1.30
EXPONENT = 1.8
num_modules = 160
center_module = 80
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
-- output color buffers
red = {}
green = {}
blue = {}
tmpRed = {}
tmpGreen = {}
tmpBlue = {}
function limit(val)
if val > 1 then
return 1
else
return val
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 22000);
local centerIndex = 2 * center_module + 1;
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
-- move the color buffers on by one
for i = num_modules-1,1,-1 do
tmpRed[i+1] = FADE_FACTOR * tmpRed[i]
tmpGreen[i+1] = FADE_FACTOR * tmpGreen[i]
tmpBlue[i+1] = FADE_FACTOR * tmpBlue[i]
end
-- set the new value for the center module
newRed = redEnergy / maxRedEnergy
tmpRed[1] = newRed
--if newRed > tmpRed[num_modules] then
-- tmpRed[1] = newRed
--else
-- tmpRed[1] = tmpRed[num_modules]
--end
newGreen = greenEnergy / maxGreenEnergy
tmpGreen[1] = newGreen
--if newGreen > tmpGreen[num_modules] then
-- tmpGreen[1] = newGreen
--else
-- tmpGreen[1] = tmpGreen[num_modules]
--end
newBlue = blueEnergy / maxBlueEnergy
tmpBlue[1] = newBlue
--if newBlue > tmpBlue[num_modules] then
-- tmpBlue[1] = newBlue
--else
-- tmpBlue[1] = tmpBlue[num_modules]
--end
for i = 1,num_modules do
red[i] = limit(OVERDRIVE * math.pow(tmpRed[i], EXPONENT))
green[i] = limit(OVERDRIVE * math.pow(tmpGreen[i], EXPONENT))
blue[i] = limit(OVERDRIVE * math.pow(tmpBlue[i], EXPONENT))
end
-- return the 3 color arrays
return red, green, blue
end
function init(nmod, cmod)
num_modules = nmod
center_module = cmod
for i = 1,nmod do
red[i] = 0
green[i] = 0
blue[i] = 0
end
for i = 1,nmod do
tmpRed[i] = 0
tmpGreen[i] = 0
tmpBlue[i] = 0
end
-- don't use fading
return 0
end

View file

@ -1,5 +1,9 @@
COOLDOWN_FACTOR = 0.9998
FADE_FACTOR = 0.985
FADE_FACTOR = 1
OVERDRIVE = 1.30
EXPONENT = 1.8
SHIFT=2
num_modules = 20
center_module = 10
@ -18,6 +22,14 @@ tmpRed = {}
tmpGreen = {}
tmpBlue = {}
function limit(val)
if val > 1 then
return 1
else
return val
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
@ -40,38 +52,27 @@ function periodic()
end
-- move the color buffers on by one
for i = num_modules-1,1,-1 do
tmpRed[i+1] = FADE_FACTOR * tmpRed[i]
tmpGreen[i+1] = FADE_FACTOR * tmpGreen[i]
tmpBlue[i+1] = FADE_FACTOR * tmpBlue[i]
for i = num_modules-SHIFT,1,-1 do
tmpRed[i+SHIFT] = FADE_FACTOR * tmpRed[i]
tmpGreen[i+SHIFT] = FADE_FACTOR * tmpGreen[i]
tmpBlue[i+SHIFT] = FADE_FACTOR * tmpBlue[i]
end
-- set the new value for the center module
newRed = redEnergy / maxRedEnergy
if newRed > tmpRed[num_modules] then
tmpRed[1] = newRed
else
tmpRed[1] = tmpRed[num_modules]
end
newGreen = greenEnergy / maxGreenEnergy
if newGreen > tmpGreen[num_modules] then
tmpGreen[1] = newGreen
else
tmpGreen[1] = tmpGreen[num_modules]
end
newBlue = blueEnergy / maxBlueEnergy
if newBlue > tmpBlue[num_modules] then
tmpBlue[1] = newBlue
else
tmpBlue[1] = tmpBlue[num_modules]
for i = 1,SHIFT do
tmpRed[i] = newRed
tmpGreen[i] = newGreen
tmpBlue[i] = newBlue
end
for i = 1,num_modules do
red[i] = tmpRed[i]
green[i] = tmpGreen[i]
blue[i] = tmpBlue[i]
red[i] = limit(OVERDRIVE * math.pow(tmpRed[i], EXPONENT))
green[i] = limit(OVERDRIVE * math.pow(tmpGreen[i], EXPONENT))
blue[i] = limit(OVERDRIVE * math.pow(tmpBlue[i], EXPONENT))
end
-- return the 3 color arrays

View file

@ -1,7 +1,7 @@
COOLDOWN_FACTOR = 0.9998
num_modules = 20
center_module = 10
num_modules = 160
center_module = 80
-- maximum energy values for each band
maxRedEnergy = 1

View file

@ -0,0 +1,96 @@
COOLDOWN_FACTOR = 0.995
BALANCE_RED = 7.0
BALANCE_GREEN = 2.0
BALANCE_BLUE = 1.5
num_modules = 20
center_module = 10
-- maximum energy value
maxEnergy = 1
-- output color buffers
red = {}
green = {}
blue = {}
tmpRed = {}
tmpGreen = {}
tmpBlue = {}
function weighted_avg(array, centerIndex)
return 0.20 * array[centerIndex - 1] +
0.60 * array[centerIndex] +
0.20 * array[centerIndex + 1]
end
function periodic()
local redEnergy = get_energy_in_band(0, 400) * BALANCE_RED
local greenEnergy = get_energy_in_band(400, 5000) * BALANCE_GREEN
local blueEnergy = get_energy_in_band(5000, 22000) * BALANCE_BLUE
local centerIndex = 2 * center_module + 1;
maxEnergy = maxEnergy * COOLDOWN_FACTOR
if redEnergy > maxEnergy then
maxEnergy = redEnergy
end
if greenEnergy > maxEnergy then
maxEnergy = greenEnergy
end
if blueEnergy > maxEnergy then
maxEnergy = blueEnergy
end
-- move the color buffers on by one in each direction
for i = 2,centerIndex,1 do
tmpRed[i-1] = tmpRed[i]
tmpGreen[i-1] = tmpGreen[i]
tmpBlue[i-1] = tmpBlue[i]
end
for i = #tmpRed-1,centerIndex,-1 do
tmpRed[i+1] = tmpRed[i]
tmpGreen[i+1] = tmpGreen[i]
tmpBlue[i+1] = tmpBlue[i]
end
-- set the new value for the center module
tmpRed[centerIndex] = redEnergy / maxEnergy
tmpGreen[centerIndex] = greenEnergy / maxEnergy
tmpBlue[centerIndex] = blueEnergy / maxEnergy
for i = 1,num_modules do
--red[i] = tmpRed[i+centerIndex-num_modules/2]
--green[i] = tmpGreen[i+centerIndex-num_modules/2]
--blue[i] = tmpBlue[i+centerIndex-num_modules/2]
red[i] = weighted_avg(tmpRed, 2*i)
green[i] = weighted_avg(tmpGreen, 2*i)
blue[i] = weighted_avg(tmpBlue, 2*i)
end
-- return the 3 color arrays
return red, green, blue
end
function init(nmod, cmod)
num_modules = nmod
center_module = cmod
for i = 1,nmod do
red[i] = 0
green[i] = 0
blue[i] = 0
end
for i = 1,2*(nmod+1) do
tmpRed[i] = 0
tmpGreen[i] = 0
tmpBlue[i] = 0
end
-- don't use fading
return 0
end

View file

@ -0,0 +1,143 @@
COOLDOWN_FACTOR = 0.9998
FADE_FACTOR = 1
OVERDRIVE = 1.30
EXPONENT = 1.8
INTERP_FACTOR = 2
INTERP_FILTER = {0.5, 1.0, 0.5}
num_modules = 128
center_module = 64
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
-- output color buffers
red = {}
green = {}
blue = {}
tmpRed = {}
tmpGreen = {}
tmpBlue = {}
tmpRed2 = {}
tmpGreen2 = {}
tmpBlue2 = {}
tmpRed3 = {}
tmpGreen3 = {}
tmpBlue3 = {}
function limit(val)
if val > 1 then
return 1
else
return val
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 22000);
local centerIndex = 2 * center_module + 1;
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
-- move the color buffers on by one
for i = center_module/INTERP_FACTOR,1,-1 do
tmpRed[i+1] = FADE_FACTOR * tmpRed[i]
tmpGreen[i+1] = FADE_FACTOR * tmpGreen[i]
tmpBlue[i+1] = FADE_FACTOR * tmpBlue[i]
end
for i = center_module/INTERP_FACTOR+1,num_modules/INTERP_FACTOR,1 do
tmpRed[i-1] = FADE_FACTOR * tmpRed[i]
tmpGreen[i-1] = FADE_FACTOR * tmpGreen[i]
tmpBlue[i-1] = FADE_FACTOR * tmpBlue[i]
end
-- set the new value for the center module
newRed = redEnergy / maxRedEnergy
tmpRed[1] = newRed
tmpRed[num_modules/INTERP_FACTOR] = newRed
newGreen = greenEnergy / maxGreenEnergy
tmpGreen[1] = newGreen
tmpGreen[num_modules/INTERP_FACTOR] = newGreen
newBlue = blueEnergy / maxBlueEnergy
tmpBlue[1] = newBlue
tmpBlue[num_modules/INTERP_FACTOR] = newBlue
for i = INTERP_FACTOR,num_modules,INTERP_FACTOR do
tmpRed2[i] = tmpRed[math.floor(i/INTERP_FACTOR)]
tmpGreen2[i] = tmpGreen[math.floor(i/INTERP_FACTOR)]
tmpBlue2[i] = tmpBlue[math.floor(i/INTERP_FACTOR)]
end
for i = 1,num_modules do
tmpRed3[i] = 0
tmpGreen3[i] = 0
tmpBlue3[i] = 0
for j = 1,#INTERP_FILTER do
idx = math.floor(i+j-#INTERP_FILTER/2)
if idx >= 1 and idx <= num_modules then
tmpRed3[i] = tmpRed3[i] + tmpRed2[idx] * INTERP_FILTER[j]
tmpGreen3[i] = tmpGreen3[i] + tmpGreen2[idx] * INTERP_FILTER[j]
tmpBlue3[i] = tmpBlue3[i] + tmpBlue2[idx] * INTERP_FILTER[j]
end
end
end
for i = 1,num_modules do
red[i] = limit(OVERDRIVE * math.pow(tmpRed3[i], EXPONENT))
green[i] = limit(OVERDRIVE * math.pow(tmpGreen3[i], EXPONENT))
blue[i] = limit(OVERDRIVE * math.pow(tmpBlue3[i], EXPONENT))
end
-- return the 3 color arrays
return red, green, blue
end
function init(nmod, cmod)
num_modules = nmod
center_module = cmod
for i = 1,nmod do
red[i] = 0
green[i] = 0
blue[i] = 0
end
for i = 1,nmod do
tmpRed[i] = 0
tmpGreen[i] = 0
tmpBlue[i] = 0
tmpRed2[i] = 0
tmpGreen2[i] = 0
tmpBlue2[i] = 0
end
-- don't use fading
return 0
end

146
particles.lua Normal file
View file

@ -0,0 +1,146 @@
COOLDOWN_FACTOR = 0.9998
MAX_ENERGY_PROPAGATION = 0.5
EXPONENT=1.8
W_EXPONENT=2.2
OVERDRIVE=1
FADE_FACTOR = 0.96
AVG_LEDS_ACTIVATED = 0.05
WHITE_EXTRA_SCALE = 0.5
num_modules = 1
num_strips = 1
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
-- array storing the energy for each pixel
fireRedEnergy = {}
fireGreenEnergy = {}
fireBlueEnergy = {}
fireWhiteEnergy = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function fade2black(energyArray)
for s = 1,num_strips do
for m = 1,num_modules do
i = idx(s, m)
energyArray[i] = energyArray[i] * FADE_FACTOR
end
end
end
function distributeEnergy(newEnergy, energyArray)
remainingEnergy = AVG_LEDS_ACTIVATED * newEnergy * num_modules * num_strips
while remainingEnergy > 0 do
rndEnergy = math.random() * newEnergy * 5
rndStrip = math.floor(math.random() * num_strips)
rndModule = math.floor(math.random() * num_modules)
if rndEnergy > remainingEnergy then
rndEnergy = remainingEnergy
remainingEnergy = 0
else
remainingEnergy = remainingEnergy - rndEnergy
end
i = idx(rndStrip+1, rndModule+1)
energyArray[i] = energyArray[i] + rndEnergy
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
fade2black(fireRedEnergy)
fade2black(fireGreenEnergy)
fade2black(fireBlueEnergy)
fade2black(fireWhiteEnergy)
distributeEnergy((redEnergy / maxRedEnergy)^EXPONENT, fireRedEnergy)
distributeEnergy((greenEnergy / maxGreenEnergy)^EXPONENT, fireGreenEnergy)
distributeEnergy((blueEnergy / maxBlueEnergy)^EXPONENT, fireBlueEnergy)
distributeEnergy((whiteEnergy / maxWhiteEnergy)^W_EXPONENT, fireWhiteEnergy)
-- Color post-processing
for m = 1,num_modules do
for s = 1,num_strips do
i = idx(s, m)
rval = limit(OVERDRIVE * fireRedEnergy[i])
gval = limit(OVERDRIVE * fireGreenEnergy[i])
bval = limit(OVERDRIVE * fireBlueEnergy[i])
wval = limit(OVERDRIVE * fireWhiteEnergy[i] * WHITE_EXTRA_SCALE)
red[i] = rval
green[i] = gval
blue[i] = bval
white[i] = wval
end
end
-- return the 4 color arrays
return red, green, blue, white
end
function init(nstrip, nmod, cmod)
num_strips = nstrip
num_modules = nmod
for i = 1,(nmod*nstrip) do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
fireRedEnergy[i] = 0
fireGreenEnergy[i] = 0
fireBlueEnergy[i] = 0
fireWhiteEnergy[i] = 0
end
-- don't use fading
return 0
end

134
pixelation.lua Normal file
View file

@ -0,0 +1,134 @@
COOLDOWN_FACTOR = 0.9998
MAX_ENERGY_PROPAGATION = 0.5
EXPONENT=1.0
W_EXPONENT=1.0
OVERDRIVE=1
num_modules = 1
num_strips = 1
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
-- array storing the flames energy for each pixel
fireRedEnergy = {}
fireGreenEnergy = {}
fireBlueEnergy = {}
fireWhiteEnergy = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function updateFire(newEnergy, energyArray)
avgEnergyPerStrip = newEnergy * 2 / num_strips
for s = 1,num_strips do
-- Add new energy in the bottom row
i = idx(s, 1)
energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip
-- remove energy at the top
i = idx(s, num_modules)
energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION)
-- move energy upwards
for m_out = num_modules,2,-1 do
i_out = idx(s, m_out)
i_in = idx(s, m_out - 1)
energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION
energyArray[i_in] = energyArray[i_in] - energyMoved
energyArray[i_out] = energyArray[i_out] + energyMoved
end
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
updateFire(redEnergy / maxRedEnergy, fireRedEnergy)
updateFire(greenEnergy / maxGreenEnergy, fireGreenEnergy)
updateFire(blueEnergy / maxBlueEnergy, fireBlueEnergy)
updateFire(whiteEnergy / maxWhiteEnergy, fireWhiteEnergy)
-- make colors more exciting + remove the first (flickering) mass
-- TODO: update
for m = 1,num_modules do
for s = 1,num_strips do
i = idx(s, m)
rval = limit(OVERDRIVE * fireRedEnergy[i]^EXPONENT)
gval = limit(OVERDRIVE * fireGreenEnergy[i]^EXPONENT)
bval = limit(OVERDRIVE * fireBlueEnergy[i]^EXPONENT)
wval = limit(OVERDRIVE * fireWhiteEnergy[i]^W_EXPONENT)
red[i] = rval
green[i] = gval
blue[i] = bval
white[i] = wval
end
end
-- return the 4 color arrays
return red, green, blue, white
end
function init(nstrip, nmod, cmod)
num_strips = nstrip
num_modules = nmod
for i = 1,(nmod*nstrip) do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
fireRedEnergy[i] = 0
fireGreenEnergy[i] = 0
fireBlueEnergy[i] = 0
fireWhiteEnergy[i] = 0
end
-- don't use fading
return 0
end

View file

@ -1,4 +1,4 @@
#!/bin/sh
#dd if=/tmp/mpd.fifo bs=1024 | ./musiclight2
./musiclight2 $* < /tmp/mpd.fifo
./musiclight2 $* < /tmp/musiclight.fifo

View file

@ -13,7 +13,7 @@ case "$MODE" in
*)
# soundkarte
parec -d "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" --raw --rate=44100 --channels=1 --format=s16 | ./musiclight2 $*
parec --raw --rate=44100 --channels=1 --format=s16 | ./musiclight2 $*
;;
esac

View file

@ -1,3 +1,3 @@
#!/bin/sh
nc -l -p 12345 | ./musiclight2 $*
socat TCP:cubietruck:6601 STDOUT | ./musiclight2 $*

120
sk6812.c Normal file
View file

@ -0,0 +1,120 @@
/*
* vim: sw=2 ts=2 expandtab
*
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "sk6812.h"
#define SET_COLOR 0
#define FADE_COLOR 1
#define ADD_COLOR 2
#define SET_FADESTEP 3
#define END_OF_UPDATE 254
// creates the socket needed for steering the LED strip
int sk6812_init(struct sk6812_ctx *ctx, const char *host, unsigned short port) {
struct addrinfo hints;
struct addrinfo *result;
char portstr[6];
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
sprintf(portstr, "%u", port);
if(getaddrinfo(host, portstr, &hints, &result) != 0) {
perror("getaddrinfo() failed");
return 1;
}
ctx->socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ctx->socket == -1) {
perror("socket() failed");
freeaddrinfo(result);
return 2;
}
if (connect(ctx->socket, result->ai_addr, result->ai_addrlen) == -1) {
perror("connect() failed");
freeaddrinfo(result);
return 3;
}
freeaddrinfo(result);
ctx->queueIndex = 0;
return 0;
}
void sk6812_set_color(struct sk6812_ctx *ctx, uint8_t strip, uint16_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
ctx->packetQueue[ctx->queueIndex].action = SET_COLOR;
ctx->packetQueue[ctx->queueIndex].module = (uint8_t)(module);
ctx->packetQueue[ctx->queueIndex].strip = strip;
ctx->packetQueue[ctx->queueIndex].data[0] = r;
ctx->packetQueue[ctx->queueIndex].data[1] = g;
ctx->packetQueue[ctx->queueIndex].data[2] = b;
ctx->packetQueue[ctx->queueIndex].data[3] = w;
ctx->queueIndex++;
}
void sk6812_fade_color(struct sk6812_ctx *ctx, uint8_t strip, uint16_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
ctx->packetQueue[ctx->queueIndex].action = FADE_COLOR;
ctx->packetQueue[ctx->queueIndex].module = (uint8_t)(module);
ctx->packetQueue[ctx->queueIndex].strip = strip;
ctx->packetQueue[ctx->queueIndex].data[0] = r;
ctx->packetQueue[ctx->queueIndex].data[1] = g;
ctx->packetQueue[ctx->queueIndex].data[2] = b;
ctx->packetQueue[ctx->queueIndex].data[3] = w;
ctx->queueIndex++;
}
void sk6812_add_color(struct sk6812_ctx *ctx, uint8_t strip, uint16_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
ctx->packetQueue[ctx->queueIndex].action = ADD_COLOR;
ctx->packetQueue[ctx->queueIndex].module = (uint8_t)(module);
ctx->packetQueue[ctx->queueIndex].strip = strip;
ctx->packetQueue[ctx->queueIndex].data[0] = r;
ctx->packetQueue[ctx->queueIndex].data[1] = g;
ctx->packetQueue[ctx->queueIndex].data[2] = b;
ctx->packetQueue[ctx->queueIndex].data[3] = w;
ctx->queueIndex++;
}
void sk6812_set_fadestep(struct sk6812_ctx *ctx, uint8_t fadestep) {
ctx->packetQueue[ctx->queueIndex].action = SET_FADESTEP;
ctx->packetQueue[ctx->queueIndex].data[0] = fadestep;
ctx->queueIndex++;
}
int sk6812_commit(struct sk6812_ctx *ctx) {
// send end-of-update packet in the end
ctx->packetQueue[ctx->queueIndex].action = END_OF_UPDATE;
ctx->queueIndex++;
if(send(ctx->socket, ctx->packetQueue, ctx->queueIndex * sizeof(struct SK6812Packet), 0) == -1) {
return 1;
}
ctx->queueIndex = 0;
return 0;
}
void sk6812_shutdown(struct sk6812_ctx *ctx) {
close(ctx->socket);
}

36
sk6812.h Normal file
View file

@ -0,0 +1,36 @@
/*
* vim: sw=2 ts=2 expandtab
*
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#ifndef SK6812_H
#define SK6812_H
struct __attribute__((__packed__)) SK6812Packet {
uint8_t action;
uint8_t strip;
uint8_t module;
uint8_t data[4];
};
struct sk6812_ctx {
int socket;
struct __attribute__((__packed__)) SK6812Packet packetQueue[1024];
int queueIndex;
};
int sk6812_init(struct sk6812_ctx *ctx, const char *host, unsigned short port);
void sk6812_set_color(struct sk6812_ctx *ctx, uint8_t strip, uint16_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void sk6812_fade_color(struct sk6812_ctx *ctx, uint8_t strip, uint16_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void sk6812_add_color(struct sk6812_ctx *ctx, uint8_t strip, uint16_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void sk6812_set_fadestep(struct sk6812_ctx *ctx, uint8_t fadestep);
int sk6812_commit(struct sk6812_ctx *ctx);
void sk6812_shutdown(struct sk6812_ctx *ctx);
#endif // SK6812_H

159
sparkler.lua Normal file
View file

@ -0,0 +1,159 @@
COOLDOWN_FACTOR = 0.9998
MAX_ENERGY_PROPAGATION = 0.3
RM_ENERGY=0.0200
EXPONENT=1.0
W_EXPONENT=2.2
OVERDRIVE=1.5
num_modules = 1
num_strips = 1
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
-- array storing the flames energy for each pixel
fireRedEnergy = {}
fireGreenEnergy = {}
fireBlueEnergy = {}
fireWhiteEnergy = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function updateFire(newEnergy, energyArray)
avgEnergyPerStrip = newEnergy * 0.7
for s = 1,num_strips do
-- Add new energy in the center rows
i = idx(s, num_modules/2)
energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip
i = idx(s, num_modules/2+1)
energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip
-- remove energy at the top and the bottom
i = idx(s, num_modules)
energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION)
i = idx(s, 1)
energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION)
-- move energy upwards
for m_out = num_modules,num_modules/2+2,-1 do
i_out = idx(s, m_out)
i_in = idx(s, m_out - 1)
energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION
energyArray[i_in] = energyArray[i_in] - energyMoved
energyArray[i_out] = energyArray[i_out] + energyMoved
end
-- move energy downwards
for m_out = 1,num_modules/2-1,1 do
i_out = idx(s, m_out)
i_in = idx(s, m_out + 1)
energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION
energyArray[i_in] = energyArray[i_in] - energyMoved
energyArray[i_out] = energyArray[i_out] + energyMoved
end
-- globally remove energy
for m = 1,num_modules do
i = idx(s, m)
if energyArray[i] > RM_ENERGY then
energyArray[i] = energyArray[i] - RM_ENERGY
else
energyArray[i] = 0
end
end
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
updateFire((redEnergy / maxRedEnergy)^EXPONENT, fireRedEnergy)
updateFire((greenEnergy / maxGreenEnergy)^EXPONENT, fireGreenEnergy)
updateFire((blueEnergy / maxBlueEnergy)^EXPONENT, fireBlueEnergy)
updateFire((whiteEnergy / maxWhiteEnergy)^W_EXPONENT, fireWhiteEnergy)
-- make colors more exciting + remove the first (flickering) mass
for m = 1,num_modules do
for s = 1,num_strips do
i = idx(s, m)
rval = limit(OVERDRIVE * (fireRedEnergy[i]))
gval = limit(OVERDRIVE * (fireGreenEnergy[i]))
bval = limit(OVERDRIVE * (fireBlueEnergy[i]))
wval = limit(OVERDRIVE * (fireWhiteEnergy[i]))
red[i] = rval
green[i] = gval
blue[i] = bval
white[i] = wval
end
end
-- return the 4 color arrays
return red, green, blue, white
end
function init(nstrip, nmod, cmod)
num_strips = nstrip
num_modules = nmod
for i = 1,(nmod*nstrip) do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
fireRedEnergy[i] = 0
fireGreenEnergy[i] = 0
fireBlueEnergy[i] = 0
fireWhiteEnergy[i] = 0
end
-- don't use fading
return 0
end

View file

@ -0,0 +1,221 @@
COOLDOWN_FACTOR = 0.9998
MAX_ENERGY_PROPAGATION = 0.3
RM_ENERGY=0.0100
EXPONENT=1.5
W_EXPONENT=2.2
OVERDRIVE=1.5
num_modules = 1
num_strips = 1
max_new_energy_per_strip = 2.00*RM_ENERGY * num_modules
-- warning: these must also be updated in init()
max_target_energy = num_strips * num_modules
-- maximum energy values for each band
maxRedEnergy = 1
maxGreenEnergy = 1
maxBlueEnergy = 1
maxWhiteEnergy = 1
redMomentum = 0
greenMomentum = 0
blueMomentum = 0
whiteMomentum = 0
-- array storing the flames energy for each pixel
fireRedEnergy = {}
fireGreenEnergy = {}
fireBlueEnergy = {}
fireWhiteEnergy = {}
-- output color buffers
red = {}
green = {}
blue = {}
white = {}
function limit(val)
if val > 1 then
return 1
elseif val < 0 then
return 0
else
return val
end
end
function updateFire(targetEnergy, energyArray, momentum)
local totalEnergy = 0
local avgEnergyPerStrip
for s = 1,num_strips do
for m = 1,num_modules do
totalEnergy = totalEnergy + energyArray[idx(s,m)]
end
end
if targetEnergy > totalEnergy then
avgEnergyPerStrip = (targetEnergy - totalEnergy) / num_strips
avgEnergyPerStrip = base_new_energy_per_strip * momentum
if avgEnergyPerStrip > max_new_energy_per_strip then
avgEnergyPerStrip = max_new_energy_per_strip
end
momentum = momentum + 1
else
avgEnergyPerStrip = 0
momentum = momentum - 1
if momentum < 0 then
momentum = 0
end
end
for s = 1,num_strips do
-- Add new energy in the center rows
i = idx(s, num_modules/2)
energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip
i = idx(s, num_modules/2+1)
energyArray[i] = energyArray[i] + math.random() * avgEnergyPerStrip
-- remove energy at the top and the bottom
i = idx(s, num_modules)
energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION)
i = idx(s, 1)
energyArray[i] = energyArray[i] * (1.0 - math.random() * MAX_ENERGY_PROPAGATION)
-- move energy upwards
for m_out = num_modules,num_modules/2+2,-1 do
i_out = idx(s, m_out)
i_in = idx(s, m_out - 1)
energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION
energyArray[i_in] = energyArray[i_in] - energyMoved
energyArray[i_out] = energyArray[i_out] + energyMoved
end
-- move energy downwards
for m_out = 1,num_modules/2-1,1 do
i_out = idx(s, m_out)
i_in = idx(s, m_out + 1)
energyMoved = energyArray[i_in] * math.random() * MAX_ENERGY_PROPAGATION
energyArray[i_in] = energyArray[i_in] - energyMoved
energyArray[i_out] = energyArray[i_out] + energyMoved
end
-- globally remove energy
for m = 1,num_modules do
i = idx(s, m)
if energyArray[i] > RM_ENERGY then
energyArray[i] = energyArray[i] - RM_ENERGY
else
energyArray[i] = 0
end
end
end
return momentum
end
function fractionToEnergy(fract, max)
return math.sqrt(fract) * max
--dB = 20*math.log(fract)/math.log(10)
--result = max * (dB + 40) / 40
--if result > 0 then
-- return result
--else
-- return 0
--end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
local blueEnergy = get_energy_in_band(4000, 12000);
local whiteEnergy = get_energy_in_band(12000, 22000);
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
if redEnergy > maxRedEnergy then
maxRedEnergy = redEnergy
end
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
if greenEnergy > maxGreenEnergy then
maxGreenEnergy = greenEnergy
end
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
if blueEnergy > maxBlueEnergy then
maxBlueEnergy = blueEnergy
end
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
if whiteEnergy > maxWhiteEnergy then
maxWhiteEnergy = whiteEnergy
end
redMomentum = updateFire(fractionToEnergy(redEnergy / maxRedEnergy, max_target_energy), fireRedEnergy, redMomentum)
greenMomentum = updateFire(fractionToEnergy(greenEnergy / maxGreenEnergy, max_target_energy), fireGreenEnergy, greenMomentum)
blueMomentum = updateFire(fractionToEnergy(blueEnergy / maxBlueEnergy, max_target_energy), fireBlueEnergy, blueMomentum)
whiteMomentum = updateFire(fractionToEnergy((whiteEnergy / maxWhiteEnergy)^W_EXPONENT, max_target_energy), fireWhiteEnergy, whiteMomentum)
--updateFire(2 * max_target_energy, fireRedEnergy)
--updateFire(0 * max_target_energy, fireGreenEnergy)
--updateFire(0 * max_target_energy, fireBlueEnergy)
--updateFire(0 * max_target_energy, fireWhiteEnergy)
-- make colors more exciting + remove the first (flickering) mass
for m = 1,num_modules do
for s = 1,num_strips do
i = idx(s, m)
rval = limit(OVERDRIVE * (fireRedEnergy[i]))
gval = limit(OVERDRIVE * (fireGreenEnergy[i]))
bval = limit(OVERDRIVE * (fireBlueEnergy[i]))
wval = limit(OVERDRIVE * (fireWhiteEnergy[i]))
red[i] = rval
green[i] = gval
blue[i] = bval
white[i] = wval
end
end
-- return the 4 color arrays
return red, green, blue, white
end
function init(nstrip, nmod, cmod)
num_strips = nstrip
num_modules = nmod
max_new_energy_per_strip = num_modules * RM_ENERGY * 2
base_new_energy_per_strip = num_modules * RM_ENERGY * 0.1
max_target_energy = 0.2 * num_strips * num_modules
for i = 1,(nmod*nstrip) do
red[i] = 0
green[i] = 0
blue[i] = 0
white[i] = 0
fireRedEnergy[i] = 0
fireGreenEnergy[i] = 0
fireBlueEnergy[i] = 0
fireWhiteEnergy[i] = 0
end
-- don't use fading
return 0
end

15
utils.c
View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#include <errno.h>
@ -14,6 +15,8 @@
#include "utils.h"
extern int num_modules;
double get_hires_time(void) {
struct timespec clk;
clock_gettime(CLOCK_REALTIME, &clk);
@ -40,3 +43,7 @@ void sleep_until(double hires_time) {
} while(ret == EINTR);
}
int idx(int strip, int module)
{
return strip * num_modules + module;
}

10
utils.h
View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#ifndef UTILS_H
@ -13,5 +14,6 @@
double get_hires_time(void);
void fsleep(double d);
void sleep_until(double hires_time);
int idx(int strip, int module);
#endif // UTILS_H

112
ws2801.c
View file

@ -1,112 +0,0 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "ws2801.h"
#define SET_COLOR 0
#define FADE_COLOR 1
#define ADD_COLOR 2
#define SET_FADESTEP 3
struct WS2801Packet {
uint8_t metadata;
uint8_t data[3];
};
int ws2801_socket = -1;
struct WS2801Packet packetQueue[50];
int queueIndex = 0;
// creates the socket needed for steering the LED strip
int ws2801_init(const char *host, unsigned short port) {
struct addrinfo hints;
struct addrinfo *result;
char portstr[6];
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
sprintf(portstr, "%u", port);
if(getaddrinfo(host, portstr, &hints, &result) != 0) {
perror("getaddrinfo() failed");
return 1;
}
ws2801_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ws2801_socket == -1) {
perror("socket() failed");
freeaddrinfo(result);
return 2;
}
if (connect(ws2801_socket, result->ai_addr, result->ai_addrlen) == -1) {
perror("connect() failed");
freeaddrinfo(result);
return 3;
}
freeaddrinfo(result);
return 0;
}
void ws2801_set_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b) {
packetQueue[queueIndex].metadata = (SET_COLOR << 6) | (module & 0x3F);
packetQueue[queueIndex].data[0] = r;
packetQueue[queueIndex].data[1] = g;
packetQueue[queueIndex].data[2] = b;
queueIndex++;
}
void ws2801_fade_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b) {
packetQueue[queueIndex].metadata = (FADE_COLOR << 6) | (module & 0x3F);
packetQueue[queueIndex].data[0] = r;
packetQueue[queueIndex].data[1] = g;
packetQueue[queueIndex].data[2] = b;
queueIndex++;
}
void ws2801_add_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b) {
packetQueue[queueIndex].metadata = (ADD_COLOR << 6) | (module & 0x3F);
packetQueue[queueIndex].data[0] = r;
packetQueue[queueIndex].data[1] = g;
packetQueue[queueIndex].data[2] = b;
queueIndex++;
}
void ws2801_set_fadestep(uint8_t fadestep) {
packetQueue[queueIndex].metadata = (SET_FADESTEP << 6);
packetQueue[queueIndex].data[0] = fadestep;
queueIndex++;
}
int ws2801_commit(void) {
if(send(ws2801_socket, packetQueue, queueIndex * sizeof(struct WS2801Packet), 0) == -1) {
return 1;
}
queueIndex = 0;
return 0;
}
void ws2801_shutdown() {
close(ws2801_socket);
}

View file

@ -1,21 +0,0 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
*/
#ifndef WS2801_H
#define WS2801_H
int ws2801_init(const char *host, unsigned short port);
void ws2801_set_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b);
void ws2801_fade_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b);
void ws2801_add_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b);
void ws2801_set_fadestep(uint8_t fadestep);
int ws2801_commit(void);
void ws2801_shutdown(void);
#endif // WS2801_H