Compare commits
23 commits
lua
...
musiclight
Author | SHA1 | Date | |
---|---|---|---|
Thomas Kolb | 66f3e6fe06 | ||
Thomas Kolb | d7c5070bb9 | ||
Thomas Kolb | f0afdcfa01 | ||
Thomas Kolb | f172a2d1f2 | ||
Thomas Kolb | 5ac566b1f5 | ||
Thomas Kolb | 7ad270ca08 | ||
Thomas Kolb | 436b816d1e | ||
Thomas Kolb | e587ac073a | ||
Thomas Kolb | 4041923cc7 | ||
Thomas Kolb | 54609eae89 | ||
Thomas Kolb | 3741a9dd12 | ||
Thomas Kolb | b3c1e3c895 | ||
Thomas Kolb | d4e7d558bd | ||
Thomas Kolb | 0ae3492b82 | ||
Thomas Kolb | 0a76acd85b | ||
Thomas Kolb | 57b2fa6cbc | ||
Thomas Kolb | 6a11b7a16c | ||
Thomas Kolb | 3fda457f09 | ||
Thomas Kolb | 4e1bd47217 | ||
Thomas Kolb | 1ed1717c62 | ||
Thomas Kolb | c09ff65f79 | ||
Thomas Kolb | f6173965f5 | ||
Thomas Kolb | 9f196ba5e2 |
8
Makefile
8
Makefile
|
@ -1,13 +1,13 @@
|
||||||
LUA_CFLAGS=$(shell pkg-config --cflags lua)
|
LUA_CFLAGS=$(shell pkg-config --cflags lua5.3)
|
||||||
LUA_LIBS=$(shell pkg-config --libs lua)
|
LUA_LIBS=$(shell pkg-config --libs lua5.3)
|
||||||
|
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS+=-O2 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -D_XOPEN_SOURCE $(LUA_CFLAGS)
|
CFLAGS+=-O2 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -D_XOPEN_SOURCE $(LUA_CFLAGS)
|
||||||
LIBS=-lm -lpthread -lrt $(LUA_LIBS)
|
LIBS=-lm -lpthread -lrt $(LUA_LIBS)
|
||||||
|
|
||||||
TARGET=musiclight2
|
TARGET=musiclight2
|
||||||
SOURCE=main.c fft.c utils.c ws2801.c lua_utils.c lua_wrappers.c
|
SOURCE=main.c fft.c utils.c sk6812.c lua_utils.c lua_wrappers.c lut.c
|
||||||
DEPS=config.h fft.h utils.h ws2801.h lua_utils.h lua_wrappers.h
|
DEPS=config.h fft.h utils.h sk6812.h lua_utils.h lua_wrappers.h lut.h
|
||||||
|
|
||||||
OBJ=$(patsubst %.c, %.o, $(SOURCE))
|
OBJ=$(patsubst %.c, %.o, $(SOURCE))
|
||||||
|
|
||||||
|
|
22
config.h
22
config.h
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
|
@ -15,11 +16,11 @@
|
||||||
// configuration variables for musiclight2
|
// configuration variables for musiclight2
|
||||||
|
|
||||||
// networking
|
// networking
|
||||||
#define HOST "192.168.23.222"
|
#define HOST "192.168.42.1"
|
||||||
#define PORT 2703
|
#define PORT 2703
|
||||||
|
|
||||||
// FFT transformation parameters
|
// 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 BLOCK_LEN (1 << FFT_EXPONENT) // 2^FFT_EXPONENT
|
||||||
#define SAMPLE_RATE 44100
|
#define SAMPLE_RATE 44100
|
||||||
#define DATALEN (BLOCK_LEN / 2)
|
#define DATALEN (BLOCK_LEN / 2)
|
||||||
|
@ -27,8 +28,11 @@
|
||||||
// Number of parts in the sample buffer
|
// Number of parts in the sample buffer
|
||||||
#define BUFFER_PARTS 2
|
#define BUFFER_PARTS 2
|
||||||
|
|
||||||
// update rate for the led strip (in seconds)
|
// Update rate for the led strip (in seconds)
|
||||||
#define LED_INTERVAL 0.03
|
// Must be a little faster than the hardware update rate to ensure there’s
|
||||||
|
// always a packet in the queue
|
||||||
|
//#define LED_INTERVAL 0.01
|
||||||
|
#define LED_INTERVAL (1.0/61.0)
|
||||||
|
|
||||||
// frequency ranges for the base colors
|
// frequency ranges for the base colors
|
||||||
#define RED_MIN_FREQ 0
|
#define RED_MIN_FREQ 0
|
||||||
|
@ -44,4 +48,6 @@
|
||||||
typedef int16_t sample;
|
typedef int16_t sample;
|
||||||
typedef int64_t sample_sum;
|
typedef int64_t sample_sum;
|
||||||
|
|
||||||
|
typedef double value_type;
|
||||||
|
|
||||||
#endif // CONFIG_H
|
#endif // CONFIG_H
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
WS2801_HOST = "192.168.23.222"
|
WS2801_HOST = "192.168.42.1"
|
||||||
WS2801_PORT = 2703
|
WS2801_PORT = 2703
|
||||||
|
|
||||||
NUM_MODULES = 20
|
NUM_MODULES = 16
|
||||||
CENTER_MODULE = 10
|
NUM_STRIPS = 8
|
||||||
|
CENTER_MODULE = 8
|
||||||
|
|
||||||
GAMMA = 2.0
|
GAMMA = 2.0
|
||||||
|
|
41
fft.c
41
fft.c
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -14,9 +15,10 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "lut.h"
|
||||||
#include "fft.h"
|
#include "fft.h"
|
||||||
|
|
||||||
double hanning_buffer[BLOCK_LEN];
|
value_type hanning_buffer[BLOCK_LEN];
|
||||||
int lookup_table[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;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < DATALEN; 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 i;
|
||||||
int layer, part, element;
|
int layer, part, element;
|
||||||
int num_parts, num_elements;
|
int num_parts, num_elements;
|
||||||
|
|
||||||
int left, right;
|
int left, right;
|
||||||
|
|
||||||
double x_left_re, x_left_im, x_right_re, x_right_im;
|
value_type x_left_re, x_left_im, x_right_re, x_right_im;
|
||||||
double param;
|
value_type sinval, cosval;
|
||||||
double sinval, cosval;
|
|
||||||
|
|
||||||
// re-arrange the input array according to the lookup table
|
// re-arrange the input array according to the lookup table
|
||||||
// and store it into the real output array (as the input is obviously real).
|
// 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_re = resultRe[right];
|
||||||
x_right_im = resultIm[right];
|
x_right_im = resultIm[right];
|
||||||
|
|
||||||
// precalculate the parameter for sin and cos
|
// use lookup table to get sinus and cosinus values for param
|
||||||
param = -M_PI * element / (1 << layer);
|
//param = -M_PI * element / (1 << layer);
|
||||||
|
sinval = lookup_sin(layer, element);
|
||||||
// precalculate sinus and cosinus values for param
|
cosval = lookup_cos(layer, element);
|
||||||
sinval = sin(param);
|
|
||||||
cosval = cos(param);
|
|
||||||
|
|
||||||
// combine the values according to a butterfly diagram
|
// combine the values according to a butterfly diagram
|
||||||
resultRe[left] = x_right_re + x_left_re * cosval - x_left_im * sinval;
|
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;
|
int maxPos = 0;
|
||||||
double maxVal = 0;
|
value_type maxVal = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < BLOCK_LEN; 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 firstBlock = minFreq * BLOCK_LEN / SAMPLE_RATE;
|
||||||
int lastBlock = maxFreq * BLOCK_LEN / SAMPLE_RATE;
|
int lastBlock = maxFreq * BLOCK_LEN / SAMPLE_RATE;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
double energy = 0;
|
value_type energy = 0;
|
||||||
for(i = firstBlock; i < lastBlock; i++) {
|
for(i = firstBlock; i < lastBlock; i++) {
|
||||||
energy += fft[i];
|
energy += fft[i];
|
||||||
}
|
}
|
||||||
|
|
17
fft.h
17
fft.h
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FFT_H
|
#ifndef FFT_H
|
||||||
|
@ -13,10 +14,10 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
void init_fft(void);
|
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 apply_hanning(sample *dftinput);
|
||||||
void fft_transform(sample *samples, double *resultRe, double *resultIm);
|
void fft_transform(sample *samples, value_type *resultRe, value_type *resultIm);
|
||||||
uint32_t find_loudest_frequency(double *absFFT);
|
uint32_t find_loudest_frequency(value_type *absFFT);
|
||||||
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);
|
||||||
|
|
||||||
#endif // FFT_H
|
#endif // FFT_H
|
||||||
|
|
144
fire.lua
Normal file
144
fire.lua
Normal 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 flame’s 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
159
fire_dual.lua
Normal 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 flame’s 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
216
flame.lua
Normal 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
68
gen_lut.py
Executable 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)
|
17
lua_utils.c
17
lua_utils.c
|
@ -1,15 +1,16 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lua.h>
|
#include <lua5.3/lua.h>
|
||||||
#include <lualib.h>
|
#include <lua5.3/lualib.h>
|
||||||
#include <lauxlib.h>
|
#include <lua5.3/lauxlib.h>
|
||||||
|
|
||||||
#include "lua_utils.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);
|
k = lua_tointeger(L, -1);
|
||||||
|
|
||||||
if(k > len || k < 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 {
|
} else {
|
||||||
numbers[k-1] = v;
|
numbers[k-1] = v;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LUA_UTILS_H
|
#ifndef LUA_UTILS_H
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
|
|
||||||
#include <lua.h>
|
#include <lua5.3/lua.h>
|
||||||
#include <lualib.h>
|
#include <lua5.3/lualib.h>
|
||||||
#include <lauxlib.h>
|
#include <lua5.3/lauxlib.h>
|
||||||
|
|
||||||
#include "fft.h"
|
#include "fft.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -65,9 +67,24 @@ static int l_get_rms(lua_State *L) {
|
||||||
return 1; // number of return values
|
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) {
|
void lua_register_funcs(lua_State *L) {
|
||||||
lua_register(L, "get_energy_in_band", l_get_energy_in_band);
|
lua_register(L, "get_energy_in_band", l_get_energy_in_band);
|
||||||
lua_register(L, "get_fft", l_get_fft);
|
lua_register(L, "get_fft", l_get_fft);
|
||||||
lua_register(L, "get_signal", l_get_signal);
|
lua_register(L, "get_signal", l_get_signal);
|
||||||
lua_register(L, "get_rms", l_get_rms);
|
lua_register(L, "get_rms", l_get_rms);
|
||||||
|
|
||||||
|
lua_register(L, "idx", l_idx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LUA_WRAPPERS_H
|
#ifndef LUA_WRAPPERS_H
|
||||||
|
|
47
lut.c
Normal file
47
lut.c
Normal 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
19
lut.h
Normal 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
|
220
main.c
220
main.c
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
@ -16,64 +17,66 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
#include <lua.h>
|
#include <lua5.3/lua.h>
|
||||||
#include <lualib.h>
|
#include <lua5.3/lualib.h>
|
||||||
#include <lauxlib.h>
|
#include <lua5.3/lauxlib.h>
|
||||||
|
|
||||||
#include "lua_utils.h"
|
#include "lua_utils.h"
|
||||||
#include "lua_wrappers.h"
|
#include "lua_wrappers.h"
|
||||||
|
|
||||||
#include "fft.h"
|
#include "fft.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "ws2801.h"
|
#include "sk6812.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
// Frames per second
|
// 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
|
// Number of new samples put into the buffer each frame
|
||||||
#define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS)
|
#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];
|
sample signal[BLOCK_LEN];
|
||||||
double rms;
|
|
||||||
double lastUpdateTime = 0;
|
|
||||||
|
|
||||||
sem_t fftSemaphore;
|
sem_t fftSemaphore;
|
||||||
|
|
||||||
|
struct sk6812_ctx sk6812;
|
||||||
|
|
||||||
|
int num_modules;
|
||||||
|
int num_strips;
|
||||||
|
|
||||||
int running = 1;
|
int running = 1;
|
||||||
|
|
||||||
void* fft_thread(void *param) {
|
void* fft_thread(void *param) {
|
||||||
sample buffer[BLOCK_LEN];
|
sample buffer[BLOCK_LEN];
|
||||||
sample block[BLOCK_LEN];
|
sample block[BLOCK_LEN];
|
||||||
double fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
|
value_type fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
|
||||||
double tmpFFT[BLOCK_LEN];
|
value_type tmpFFT[BLOCK_LEN];
|
||||||
double tmpRMS;
|
value_type tmpRMS;
|
||||||
|
|
||||||
double nextFrame = get_hires_time() + 0.05;
|
double nextFrame = get_hires_time() + 0.05;
|
||||||
double curTime;
|
double curTime;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
init_fft();
|
init_fft();
|
||||||
|
|
||||||
while(running) {
|
while(running) {
|
||||||
// shift the buffer left
|
// shift the buffer left
|
||||||
memmove(buffer, buffer + READ_SAMPLES,
|
memmove(buffer, buffer + READ_SAMPLES,
|
||||||
(BLOCK_LEN - READ_SAMPLES) * sizeof(sample));
|
(BLOCK_LEN - READ_SAMPLES) * sizeof(sample));
|
||||||
|
|
||||||
size_t ret = fread(buffer + (BLOCK_LEN - READ_SAMPLES),
|
size_t ret = fread(buffer + (BLOCK_LEN - READ_SAMPLES),
|
||||||
sizeof(sample), READ_SAMPLES, stdin);
|
sizeof(sample), READ_SAMPLES, stdin);
|
||||||
if(ret != READ_SAMPLES) {
|
if(ret != READ_SAMPLES) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(block, buffer, BLOCK_LEN * sizeof(sample));
|
memcpy(block, buffer, BLOCK_LEN * sizeof(sample));
|
||||||
|
|
||||||
apply_hanning(block);
|
|
||||||
fft_transform(block, fftOutReal, fftOutImag);
|
|
||||||
complex_to_absolute(fftOutReal, fftOutImag, tmpFFT);
|
|
||||||
|
|
||||||
tmpRMS = 0;
|
tmpRMS = 0;
|
||||||
for(i = 0; i < BLOCK_LEN; i++) {
|
for(i = 0; i < BLOCK_LEN; i++) {
|
||||||
|
@ -81,6 +84,14 @@ void* fft_thread(void *param) {
|
||||||
}
|
}
|
||||||
tmpRMS = sqrt(tmpRMS/BLOCK_LEN);
|
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 ---
|
// --- SAFE SECTION ---
|
||||||
sem_wait(&fftSemaphore);
|
sem_wait(&fftSemaphore);
|
||||||
|
|
||||||
|
@ -88,49 +99,51 @@ void* fft_thread(void *param) {
|
||||||
memcpy(signal, buffer, sizeof(signal));
|
memcpy(signal, buffer, sizeof(signal));
|
||||||
rms = tmpRMS;
|
rms = tmpRMS;
|
||||||
|
|
||||||
curTime = get_hires_time();
|
curTime = get_hires_time();
|
||||||
lastUpdateTime = curTime;
|
lastUpdateTime = curTime;
|
||||||
|
|
||||||
sem_post(&fftSemaphore);
|
sem_post(&fftSemaphore);
|
||||||
// --- END SAFE SECTION ---
|
// --- END SAFE SECTION ---
|
||||||
|
|
||||||
if(curTime > nextFrame + 0.05) {
|
if(curTime > nextFrame + 0.05) {
|
||||||
printf("Frame too late! Skipping.\n");
|
printf("Frame too late! Skipping.\n");
|
||||||
nextFrame = -1;
|
nextFrame = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(curTime < nextFrame - 0.05) {
|
if(curTime < nextFrame - 0.05) {
|
||||||
printf("Frame too early.\n");
|
printf("Frame too early.\n");
|
||||||
nextFrame = -1;
|
nextFrame = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nextFrame < 0) {
|
if(nextFrame < 0) {
|
||||||
printf("Frame time reset.\n");
|
printf("Frame time reset.\n");
|
||||||
nextFrame = curTime;
|
nextFrame = curTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextFrame += 1.000/FPS;
|
nextFrame += 1.000/FPS;
|
||||||
sleep_until(nextFrame);
|
//sleep_until(nextFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
double gamma_correct(double d, double gamma) {
|
value_type gamma_correct(value_type d, value_type gamma) {
|
||||||
return pow(d, gamma);
|
return pow(d, gamma);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
double nextFrame = get_hires_time() + LED_INTERVAL;
|
double nextFrame = get_hires_time() + LED_INTERVAL;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
pthread_t fftThread;
|
pthread_t fftThread;
|
||||||
|
|
||||||
int active = 1;
|
int active = 1;
|
||||||
|
//int frame = 0;
|
||||||
|
|
||||||
double *red;
|
double *red;
|
||||||
double *green;
|
double *green;
|
||||||
double *blue;
|
double *blue;
|
||||||
|
double *white;
|
||||||
|
|
||||||
int useFading, fadeStep;
|
int useFading, fadeStep;
|
||||||
|
|
||||||
|
@ -140,7 +153,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize lua
|
// initialize lua
|
||||||
lua_State *L = lua_open();
|
lua_State *L = luaL_newstate();
|
||||||
|
|
||||||
// load the lua libraries
|
// load the lua libraries
|
||||||
luaL_openlibs(L);
|
luaL_openlibs(L);
|
||||||
|
@ -168,16 +181,31 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
lua_getglobal(L, "NUM_MODULES");
|
lua_getglobal(L, "NUM_MODULES");
|
||||||
if(!lua_isnumber(L, -1)) return 2;
|
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");
|
lua_getglobal(L, "CENTER_MODULE");
|
||||||
if(!lua_isnumber(L, -1)) return 2;
|
if(!lua_isnumber(L, -1)) return 2;
|
||||||
int center_module = lua_tointeger(L, -1);
|
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
|
// allocate arrays
|
||||||
red = malloc(num_modules * sizeof(double));
|
red = malloc(num_strips * num_modules * sizeof(double));
|
||||||
green = malloc(num_modules * sizeof(double));
|
green = malloc(num_strips * num_modules * sizeof(double));
|
||||||
blue = malloc(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
|
// load and initialize the script
|
||||||
if(luaL_loadfile(L, argv[1])) {
|
if(luaL_loadfile(L, argv[1])) {
|
||||||
|
@ -191,67 +219,78 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
// call the init function
|
// call the init function
|
||||||
lua_getglobal(L, "init");
|
lua_getglobal(L, "init");
|
||||||
|
lua_pushnumber(L, num_strips);
|
||||||
lua_pushnumber(L, num_modules);
|
lua_pushnumber(L, num_modules);
|
||||||
lua_pushnumber(L, center_module);
|
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.");
|
lua_showerror(L, "lua_pcall(init) failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fadeStep = lua_tointeger(L, -1);
|
fadeStep = lua_tointeger(L, -1);
|
||||||
useFading = fadeStep > 0;
|
useFading = fadeStep > 0;
|
||||||
if(useFading) {
|
if(useFading) {
|
||||||
ws2801_set_fadestep(fadeStep);
|
sk6812_set_fadestep(&sk6812, fadeStep);
|
||||||
printf("Fading enabled with fadestep %i.\n", fadeStep);
|
printf("Fading enabled with fadestep %i.\n", fadeStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the WS2801 library
|
// initialize the WS2801 library
|
||||||
printf("Connecting to %s:%i\n", host, port);
|
printf("Connecting to %s:%i\n", host, port);
|
||||||
ws2801_init(host, port);
|
sk6812_init(&sk6812, host, port);
|
||||||
|
|
||||||
// create semaphores
|
// create semaphores
|
||||||
sem_init(&fftSemaphore, 0, 1);
|
sem_init(&fftSemaphore, 0, 1);
|
||||||
|
|
||||||
// run the fft thread
|
// run the fft thread
|
||||||
pthread_create(&fftThread, NULL, fft_thread, NULL);
|
pthread_create(&fftThread, NULL, fft_thread, NULL);
|
||||||
|
|
||||||
while(running) {
|
while(running) {
|
||||||
if(active) {
|
if(active) {
|
||||||
// call the periodic() function from LUA
|
// call the periodic() function from LUA
|
||||||
lua_getglobal(L, "periodic");
|
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.");
|
lua_showerror(L, "lua_pcall(periodic) failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the return values (reverse order, as lua uses a stack)
|
// read the return values (reverse order, as lua uses a stack)
|
||||||
lua_readdoublearray(L, blue, num_modules);
|
lua_readdoublearray(L, white, num_strips*num_modules);
|
||||||
lua_readdoublearray(L, green, num_modules);
|
lua_readdoublearray(L, blue, num_strips*num_modules);
|
||||||
lua_readdoublearray(L, red, num_modules);
|
lua_readdoublearray(L, green, num_strips*num_modules);
|
||||||
|
lua_readdoublearray(L, red, num_strips*num_modules);
|
||||||
|
|
||||||
if(useFading) {
|
for(int s = 0; s < num_strips; s++) {
|
||||||
for(i = 0; i < num_modules; i++) {
|
if(useFading) {
|
||||||
ws2801_fade_color(i,
|
for(i = 0; i < num_modules; i++) {
|
||||||
255 * gamma_correct(red[i], gamma),
|
int lidx = idx(s, i);
|
||||||
255 * gamma_correct(green[i], gamma),
|
sk6812_fade_color(&sk6812, s, i,
|
||||||
255 * gamma_correct(blue[i], gamma));
|
255 * gamma_correct(red[lidx], gamma),
|
||||||
|
255 * gamma_correct(green[lidx], gamma),
|
||||||
|
255 * gamma_correct(blue[lidx], gamma),
|
||||||
|
255 * gamma_correct(white[lidx], gamma));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(i = 0; i < num_modules; i++) {
|
||||||
|
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();
|
|
||||||
} 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));
|
|
||||||
}
|
|
||||||
ws2801_commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sk6812_commit(&sk6812);
|
||||||
|
|
||||||
if(lastUpdateTime < nextFrame - 1) {
|
if(lastUpdateTime < nextFrame - 1) {
|
||||||
printf("Idle for 1 second -> stopping updates.\n");
|
printf("Idle for 1 second -> stopping updates.\n");
|
||||||
|
|
||||||
for(i = 0; i < num_modules; i++) {
|
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;
|
active = 0;
|
||||||
}
|
}
|
||||||
|
@ -262,18 +301,19 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
nextFrame += LED_INTERVAL;
|
nextFrame += LED_INTERVAL;
|
||||||
sleep_until(nextFrame);
|
sleep_until(nextFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
ws2801_shutdown();
|
sk6812_shutdown(&sk6812);
|
||||||
|
|
||||||
// free arrays
|
// free arrays
|
||||||
free(red);
|
free(red);
|
||||||
free(green);
|
free(green);
|
||||||
free(blue);
|
free(blue);
|
||||||
|
free(white);
|
||||||
|
|
||||||
pthread_join(fftThread, NULL);
|
pthread_join(fftThread, NULL);
|
||||||
|
|
||||||
lua_close(L);
|
lua_close(L);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
2
old_scripts/README.txt
Normal file
2
old_scripts/README.txt
Normal 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
206
old_scripts/flame.lua
Normal 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
|
174
old_scripts/flame_diffspeed.lua
Normal file
174
old_scripts/flame_diffspeed.lua
Normal 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
203
old_scripts/pulsar.lua
Normal 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
112
old_scripts/pulsecircle.lua
Normal 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
|
|
@ -1,5 +1,9 @@
|
||||||
COOLDOWN_FACTOR = 0.9998
|
COOLDOWN_FACTOR = 0.9998
|
||||||
FADE_FACTOR = 0.985
|
FADE_FACTOR = 1
|
||||||
|
OVERDRIVE = 1.30
|
||||||
|
EXPONENT = 1.8
|
||||||
|
|
||||||
|
SHIFT=2
|
||||||
|
|
||||||
num_modules = 20
|
num_modules = 20
|
||||||
center_module = 10
|
center_module = 10
|
||||||
|
@ -18,6 +22,14 @@ tmpRed = {}
|
||||||
tmpGreen = {}
|
tmpGreen = {}
|
||||||
tmpBlue = {}
|
tmpBlue = {}
|
||||||
|
|
||||||
|
function limit(val)
|
||||||
|
if val > 1 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function periodic()
|
function periodic()
|
||||||
local redEnergy = get_energy_in_band(0, 400);
|
local redEnergy = get_energy_in_band(0, 400);
|
||||||
local greenEnergy = get_energy_in_band(400, 4000);
|
local greenEnergy = get_energy_in_band(400, 4000);
|
||||||
|
@ -40,38 +52,27 @@ function periodic()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- move the color buffers on by one
|
-- move the color buffers on by one
|
||||||
for i = num_modules-1,1,-1 do
|
for i = num_modules-SHIFT,1,-1 do
|
||||||
tmpRed[i+1] = FADE_FACTOR * tmpRed[i]
|
tmpRed[i+SHIFT] = FADE_FACTOR * tmpRed[i]
|
||||||
tmpGreen[i+1] = FADE_FACTOR * tmpGreen[i]
|
tmpGreen[i+SHIFT] = FADE_FACTOR * tmpGreen[i]
|
||||||
tmpBlue[i+1] = FADE_FACTOR * tmpBlue[i]
|
tmpBlue[i+SHIFT] = FADE_FACTOR * tmpBlue[i]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- set the new value for the center module
|
-- set the new value for the center module
|
||||||
newRed = redEnergy / maxRedEnergy
|
newRed = redEnergy / maxRedEnergy
|
||||||
if newRed > tmpRed[num_modules] then
|
|
||||||
tmpRed[1] = newRed
|
|
||||||
else
|
|
||||||
tmpRed[1] = tmpRed[num_modules]
|
|
||||||
end
|
|
||||||
|
|
||||||
newGreen = greenEnergy / maxGreenEnergy
|
newGreen = greenEnergy / maxGreenEnergy
|
||||||
if newGreen > tmpGreen[num_modules] then
|
|
||||||
tmpGreen[1] = newGreen
|
|
||||||
else
|
|
||||||
tmpGreen[1] = tmpGreen[num_modules]
|
|
||||||
end
|
|
||||||
|
|
||||||
newBlue = blueEnergy / maxBlueEnergy
|
newBlue = blueEnergy / maxBlueEnergy
|
||||||
if newBlue > tmpBlue[num_modules] then
|
|
||||||
tmpBlue[1] = newBlue
|
for i = 1,SHIFT do
|
||||||
else
|
tmpRed[i] = newRed
|
||||||
tmpBlue[1] = tmpBlue[num_modules]
|
tmpGreen[i] = newGreen
|
||||||
|
tmpBlue[i] = newBlue
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 1,num_modules do
|
for i = 1,num_modules do
|
||||||
red[i] = tmpRed[i]
|
red[i] = limit(OVERDRIVE * math.pow(tmpRed[i], EXPONENT))
|
||||||
green[i] = tmpGreen[i]
|
green[i] = limit(OVERDRIVE * math.pow(tmpGreen[i], EXPONENT))
|
||||||
blue[i] = tmpBlue[i]
|
blue[i] = limit(OVERDRIVE * math.pow(tmpBlue[i], EXPONENT))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- return the 3 color arrays
|
-- return the 3 color arrays
|
|
@ -1,7 +1,7 @@
|
||||||
COOLDOWN_FACTOR = 0.9998
|
COOLDOWN_FACTOR = 0.9998
|
||||||
|
|
||||||
num_modules = 20
|
num_modules = 160
|
||||||
center_module = 10
|
center_module = 80
|
||||||
|
|
||||||
-- maximum energy values for each band
|
-- maximum energy values for each band
|
||||||
maxRedEnergy = 1
|
maxRedEnergy = 1
|
96
old_scripts/pulsetunnel_commonmax.lua
Normal file
96
old_scripts/pulsetunnel_commonmax.lua
Normal 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
|
143
old_scripts/pulsetunnel_fast.lua
Normal file
143
old_scripts/pulsetunnel_fast.lua
Normal 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
146
particles.lua
Normal 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
134
pixelation.lua
Normal 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 flame’s 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
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#dd if=/tmp/mpd.fifo bs=1024 | ./musiclight2
|
#dd if=/tmp/mpd.fifo bs=1024 | ./musiclight2
|
||||||
./musiclight2 $* < /tmp/mpd.fifo
|
./musiclight2 $* < /tmp/musiclight.fifo
|
||||||
|
|
|
@ -13,7 +13,7 @@ case "$MODE" in
|
||||||
|
|
||||||
*)
|
*)
|
||||||
# soundkarte
|
# 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
|
esac
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
nc -l -p 12345 | ./musiclight2 $*
|
socat TCP:cubietruck:6601 STDOUT | ./musiclight2 $*
|
||||||
|
|
120
sk6812.c
Normal file
120
sk6812.c
Normal 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
36
sk6812.h
Normal 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
159
sparkler.lua
Normal 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 flame’s 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
|
221
sparkler_energycontrolled.lua
Normal file
221
sparkler_energycontrolled.lua
Normal 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 flame’s 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
15
utils.c
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -14,6 +15,8 @@
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
extern int num_modules;
|
||||||
|
|
||||||
double get_hires_time(void) {
|
double get_hires_time(void) {
|
||||||
struct timespec clk;
|
struct timespec clk;
|
||||||
clock_gettime(CLOCK_REALTIME, &clk);
|
clock_gettime(CLOCK_REALTIME, &clk);
|
||||||
|
@ -40,3 +43,7 @@ void sleep_until(double hires_time) {
|
||||||
} while(ret == EINTR);
|
} while(ret == EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int idx(int strip, int module)
|
||||||
|
{
|
||||||
|
return strip * num_modules + module;
|
||||||
|
}
|
||||||
|
|
10
utils.h
10
utils.h
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* vim: sw=2 ts=2 expandtab
|
* vim: sw=2 ts=2 expandtab
|
||||||
*
|
*
|
||||||
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
* "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
|
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||||
* do whatever you want with this stuff. If we meet some day, and you think
|
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||||
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
|
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||||
|
* - Thomas Kolb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef UTILS_H
|
#ifndef UTILS_H
|
||||||
|
@ -13,5 +14,6 @@
|
||||||
double get_hires_time(void);
|
double get_hires_time(void);
|
||||||
void fsleep(double d);
|
void fsleep(double d);
|
||||||
void sleep_until(double hires_time);
|
void sleep_until(double hires_time);
|
||||||
|
int idx(int strip, int module);
|
||||||
|
|
||||||
#endif // UTILS_H
|
#endif // UTILS_H
|
||||||
|
|
112
ws2801.c
112
ws2801.c
|
@ -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);
|
|
||||||
}
|
|
21
ws2801.h
21
ws2801.h
|
@ -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
|
|
Loading…
Reference in a new issue