Compare commits

...

8 commits
lua ... master

Author SHA1 Message Date
Thomas Kolb 57b2fa6cbc Lots of changes, too long ago to remember 2018-06-19 20:13:22 +00:00
Thomas Kolb 6a11b7a16c Fixed license notice 2013-02-02 21:54:53 +01:00
Thomas Kolb 3fda457f09 New version of pulsetunnel script
This is the pulsetunnel.lua script with a common maximum value derived
from the three color channels. Channels can be weighted using constants
in the lua script.

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

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

View file

@ -6,8 +6,8 @@ CFLAGS+=-O2 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -
LIBS=-lm -lpthread -lrt $(LUA_LIBS)
TARGET=musiclight2
SOURCE=main.c fft.c utils.c ws2801.c lua_utils.c lua_wrappers.c
DEPS=config.h fft.h utils.h ws2801.h lua_utils.h lua_wrappers.h
SOURCE=main.c fft.c utils.c ws2801.c lua_utils.c lua_wrappers.c lut.c
DEPS=config.h fft.h utils.h ws2801.h lua_utils.h lua_wrappers.h lut.h
OBJ=$(patsubst %.c, %.o, $(SOURCE))

View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#ifndef CONFIG_H
@ -19,7 +20,7 @@
#define PORT 2703
// FFT transformation parameters
#define FFT_EXPONENT 10
#define FFT_EXPONENT 8 // ATTENTION: when you change this, run gen_lut.py with this value as argument
#define BLOCK_LEN (1 << FFT_EXPONENT) // 2^FFT_EXPONENT
#define SAMPLE_RATE 44100
#define DATALEN (BLOCK_LEN / 2)
@ -28,7 +29,7 @@
#define BUFFER_PARTS 2
// update rate for the led strip (in seconds)
#define LED_INTERVAL 0.03
#define LED_INTERVAL 0.01
// frequency ranges for the base colors
#define RED_MIN_FREQ 0
@ -44,4 +45,6 @@
typedef int16_t sample;
typedef int64_t sample_sum;
typedef double value_type;
#endif // CONFIG_H

View file

@ -1,7 +1,7 @@
WS2801_HOST = "192.168.23.222"
WS2801_HOST = "192.168.2.136"
WS2801_PORT = 2703
NUM_MODULES = 20
CENTER_MODULE = 10
NUM_MODULES = 128
CENTER_MODULE = 64
GAMMA = 2.0

41
fft.c
View file

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

17
fft.h
View file

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

174
flame.lua Normal file
View file

@ -0,0 +1,174 @@
COOLDOWN_FACTOR = 0.9995
OVERDRIVE = 1.70
EXPONENT = 1.5
M = 1.7 -- mass
D = 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 / 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
-- 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
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

174
flame_diffspeed.lua Normal file
View file

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

68
gen_lut.py Executable file
View file

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

View file

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

View file

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

View file

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

View file

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

47
lut.c Normal file
View file

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

19
lut.h Normal file
View file

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

74
main.c
View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#include <pthread.h>
@ -30,15 +31,17 @@
#include "config.h"
// Frames per second
#define FPS ((double)BUFFER_PARTS * SAMPLE_RATE / BLOCK_LEN)
#define FPS ((value_type)BUFFER_PARTS * SAMPLE_RATE / BLOCK_LEN)
// Number of new samples put into the buffer each frame
#define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS)
double fft[BLOCK_LEN];
value_type fft[BLOCK_LEN];
value_type rms;
value_type redEnergy, greenEnergy, blueEnergy;
value_type lastUpdateTime = 0;
sample signal[BLOCK_LEN];
double rms;
double lastUpdateTime = 0;
sem_t fftSemaphore;
@ -47,9 +50,9 @@ int running = 1;
void* fft_thread(void *param) {
sample buffer[BLOCK_LEN];
sample block[BLOCK_LEN];
double fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
double tmpFFT[BLOCK_LEN];
double tmpRMS;
value_type fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
value_type tmpFFT[BLOCK_LEN];
value_type tmpRMS;
double nextFrame = get_hires_time() + 0.05;
double curTime;
@ -110,13 +113,13 @@ void* fft_thread(void *param) {
}
nextFrame += 1.000/FPS;
sleep_until(nextFrame);
//sleep_until(nextFrame);
}
return NULL;
}
double gamma_correct(double d, double gamma) {
value_type gamma_correct(value_type d, value_type gamma) {
return pow(d, gamma);
}
@ -127,6 +130,7 @@ int main(int argc, char **argv) {
pthread_t fftThread;
int active = 1;
int frame = 0;
double *red;
double *green;
@ -140,7 +144,7 @@ int main(int argc, char **argv) {
}
// initialize lua
lua_State *L = lua_open();
lua_State *L = luaL_newstate();
// load the lua libraries
luaL_openlibs(L);
@ -174,6 +178,16 @@ int main(int argc, char **argv) {
if(!lua_isnumber(L, -1)) return 2;
int center_module = lua_tointeger(L, -1);
// export some global constants
lua_pushnumber(L, SAMPLE_RATE);
lua_setglobal(L, "SAMPLE_RATE");
lua_pushnumber(L, BLOCK_LEN);
lua_setglobal(L, "BLOCK_LEN");
lua_pushnumber(L, DATALEN);
lua_setglobal(L, "DATALEN");
// allocate arrays
red = malloc(num_modules * sizeof(double));
green = malloc(num_modules * sizeof(double));
@ -227,22 +241,24 @@ int main(int argc, char **argv) {
lua_readdoublearray(L, green, num_modules);
lua_readdoublearray(L, red, num_modules);
if(useFading) {
for(i = 0; i < num_modules; i++) {
ws2801_fade_color(i,
255 * gamma_correct(red[i], gamma),
255 * gamma_correct(green[i], gamma),
255 * gamma_correct(blue[i], gamma));
if((++frame & 1) == 0) {
if(useFading) {
for(i = 0; i < num_modules; i++) {
ws2801_fade_color(i,
255 * gamma_correct(red[i], gamma),
255 * gamma_correct(green[i], gamma),
255 * gamma_correct(blue[i], gamma));
}
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();
}
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();
}
if(lastUpdateTime < nextFrame - 1) {

174
pulsar.lua Normal file
View file

@ -0,0 +1,174 @@
COOLDOWN_FACTOR = 0.9995
OVERDRIVE = 1.50
EXPONENT = 1.5
M = 1.7 -- mass
D = 1 -- spring strength
DAMPING = {} -- filled in init()
num_modules = 128
center_module = 64
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
-- 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 / 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
-- 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
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 = math.floor(cmod/2)
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.5 * math.pow(math.abs((i - excitement_pos) / num_masses), 2)
end
-- don't use fading
return 0
end

View file

@ -1,8 +1,10 @@
COOLDOWN_FACTOR = 0.9998
FADE_FACTOR = 0.985
FADE_FACTOR = 1
OVERDRIVE = 1.30
EXPONENT = 1.8
num_modules = 20
center_module = 10
num_modules = 160
center_module = 80
-- maximum energy values for each band
maxRedEnergy = 1
@ -18,6 +20,14 @@ tmpRed = {}
tmpGreen = {}
tmpBlue = {}
function limit(val)
if val > 1 then
return 1
else
return val
end
end
function periodic()
local redEnergy = get_energy_in_band(0, 400);
local greenEnergy = get_energy_in_band(400, 4000);
@ -48,30 +58,33 @@ function periodic()
-- set the new value for the center module
newRed = redEnergy / maxRedEnergy
if newRed > tmpRed[num_modules] then
tmpRed[1] = newRed
else
tmpRed[1] = tmpRed[num_modules]
end
tmpRed[1] = newRed
--if newRed > tmpRed[num_modules] then
-- tmpRed[1] = newRed
--else
-- tmpRed[1] = tmpRed[num_modules]
--end
newGreen = greenEnergy / maxGreenEnergy
if newGreen > tmpGreen[num_modules] then
tmpGreen[1] = newGreen
else
tmpGreen[1] = tmpGreen[num_modules]
end
tmpGreen[1] = newGreen
--if newGreen > tmpGreen[num_modules] then
-- tmpGreen[1] = newGreen
--else
-- tmpGreen[1] = tmpGreen[num_modules]
--end
newBlue = blueEnergy / maxBlueEnergy
if newBlue > tmpBlue[num_modules] then
tmpBlue[1] = newBlue
else
tmpBlue[1] = tmpBlue[num_modules]
end
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] = tmpRed[i]
green[i] = tmpGreen[i]
blue[i] = tmpBlue[i]
red[i] = limit(OVERDRIVE * math.pow(tmpRed[i], EXPONENT))
green[i] = limit(OVERDRIVE * math.pow(tmpGreen[i], EXPONENT))
blue[i] = limit(OVERDRIVE * math.pow(tmpBlue[i], EXPONENT))
end
-- return the 3 color arrays

100
pulsecircle_ultrafast.lua Normal file
View file

@ -0,0 +1,100 @@
COOLDOWN_FACTOR = 0.9998
FADE_FACTOR = 1
OVERDRIVE = 1.30
EXPONENT = 1.8
SHIFT=2
num_modules = 20
center_module = 10
-- 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-SHIFT,1,-1 do
tmpRed[i+SHIFT] = FADE_FACTOR * tmpRed[i]
tmpGreen[i+SHIFT] = FADE_FACTOR * tmpGreen[i]
tmpBlue[i+SHIFT] = FADE_FACTOR * tmpBlue[i]
end
-- set the new value for the center module
newRed = redEnergy / maxRedEnergy
newGreen = greenEnergy / maxGreenEnergy
newBlue = blueEnergy / maxBlueEnergy
for i = 1,SHIFT do
tmpRed[i] = newRed
tmpGreen[i] = newGreen
tmpBlue[i] = newBlue
end
for i = 1,num_modules do
red[i] = limit(OVERDRIVE * math.pow(tmpRed[i], EXPONENT))
green[i] = limit(OVERDRIVE * math.pow(tmpGreen[i], EXPONENT))
blue[i] = limit(OVERDRIVE * math.pow(tmpBlue[i], EXPONENT))
end
-- return the 3 color arrays
return red, green, blue
end
function init(nmod, cmod)
num_modules = nmod
center_module = cmod
for i = 1,nmod do
red[i] = 0
green[i] = 0
blue[i] = 0
end
for i = 1,nmod do
tmpRed[i] = 0
tmpGreen[i] = 0
tmpBlue[i] = 0
end
-- don't use fading
return 0
end

View file

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

96
pulsetunnel_commonmax.lua Normal file
View file

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

143
pulsetunnel_fast.lua Normal file
View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,10 +1,11 @@
/*
* vim: sw=2 ts=2 expandtab
*
* THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
* do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
* notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a pizza in return.
* - Thomas Kolb
*/
#include <sys/types.h>
@ -23,12 +24,13 @@
#define SET_FADESTEP 3
struct WS2801Packet {
uint8_t metadata;
uint8_t action;
uint8_t module;
uint8_t data[3];
};
int ws2801_socket = -1;
struct WS2801Packet packetQueue[50];
struct WS2801Packet packetQueue[1024];
int queueIndex = 0;
// creates the socket needed for steering the LED strip
@ -69,7 +71,8 @@ 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) {
packetQueue[queueIndex].metadata = (SET_COLOR << 6) | (module & 0x3F);
packetQueue[queueIndex].action = SET_COLOR;
packetQueue[queueIndex].module = module;
packetQueue[queueIndex].data[0] = r;
packetQueue[queueIndex].data[1] = g;
packetQueue[queueIndex].data[2] = b;
@ -77,7 +80,8 @@ 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) {
packetQueue[queueIndex].metadata = (FADE_COLOR << 6) | (module & 0x3F);
packetQueue[queueIndex].action = FADE_COLOR;
packetQueue[queueIndex].module = module;
packetQueue[queueIndex].data[0] = r;
packetQueue[queueIndex].data[1] = g;
packetQueue[queueIndex].data[2] = b;
@ -85,7 +89,8 @@ 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) {
packetQueue[queueIndex].metadata = (ADD_COLOR << 6) | (module & 0x3F);
packetQueue[queueIndex].action = ADD_COLOR;
packetQueue[queueIndex].module = module;
packetQueue[queueIndex].data[0] = r;
packetQueue[queueIndex].data[1] = g;
packetQueue[queueIndex].data[2] = b;
@ -93,7 +98,7 @@ void ws2801_add_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b) {
}
void ws2801_set_fadestep(uint8_t fadestep) {
packetQueue[queueIndex].metadata = (SET_FADESTEP << 6);
packetQueue[queueIndex].action = SET_FADESTEP;
packetQueue[queueIndex].data[0] = fadestep;
queueIndex++;
}

View file

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