Compare commits

..

No commits in common. "sk6812_bytewerk_test" and "lua" have entirely different histories.

29 changed files with 276 additions and 1407 deletions

View file

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

View file

@ -1,11 +1,10 @@
/*
* 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
* 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 CONFIG_H
@ -16,20 +15,20 @@
// configuration variables for musiclight2
// networking
#define HOST "musiclight0.wiese.icmp.camp"
#define HOST "192.168.23.222"
#define PORT 2703
// FFT transformation parameters
#define FFT_EXPONENT 8 // ATTENTION: when you change this, run gen_lut.py with this value as argument
#define FFT_EXPONENT 10
#define BLOCK_LEN (1 << FFT_EXPONENT) // 2^FFT_EXPONENT
#define SAMPLE_RATE 48000
#define SAMPLE_RATE 44100
#define DATALEN (BLOCK_LEN / 2)
// Number of parts in the sample buffer
#define BUFFER_PARTS 2
// update rate for the led strip (in seconds)
#define LED_INTERVAL 0.01
#define LED_INTERVAL 0.03
// frequency ranges for the base colors
#define RED_MIN_FREQ 0
@ -45,6 +44,4 @@
typedef int16_t sample;
typedef int64_t sample_sum;
typedef double value_type;
#endif // CONFIG_H

View file

@ -1,7 +1,7 @@
WS2801_HOST = "10.42.6.183"
WS2801_HOST = "192.168.23.222"
WS2801_PORT = 2703
NUM_MODULES = 60
CENTER_MODULE = 30
NUM_MODULES = 20
CENTER_MODULE = 10
GAMMA = 2.0

41
fft.c
View file

@ -1,11 +1,10 @@
/*
* 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
* 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 <stdio.h>
@ -15,10 +14,9 @@
#include "config.h"
#include "lut.h"
#include "fft.h"
value_type hanning_buffer[BLOCK_LEN];
double hanning_buffer[BLOCK_LEN];
int lookup_table[BLOCK_LEN];
@ -42,7 +40,7 @@ void init_fft(void) {
void complex_to_absolute(value_type *re, value_type *im, value_type *result) {
void complex_to_absolute(double *re, double *im, double *result) {
int i;
for(i = 0; i < DATALEN; i++)
@ -62,15 +60,16 @@ void apply_hanning(sample *dftinput) {
void fft_transform(sample *samples, value_type *resultRe, value_type *resultIm) {
void fft_transform(sample *samples, double *resultRe, double *resultIm) {
int i;
int layer, part, element;
int num_parts, num_elements;
int left, right;
value_type x_left_re, x_left_im, x_right_re, x_right_im;
value_type sinval, cosval;
double x_left_re, x_left_im, x_right_re, x_right_im;
double param;
double 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).
@ -106,10 +105,12 @@ void fft_transform(sample *samples, value_type *resultRe, value_type *resultIm)
x_right_re = resultRe[right];
x_right_im = resultIm[right];
// 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);
// 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);
// combine the values according to a butterfly diagram
resultRe[left] = x_right_re + x_left_re * cosval - x_left_im * sinval;
@ -121,9 +122,9 @@ void fft_transform(sample *samples, value_type *resultRe, value_type *resultIm)
}
}
uint32_t find_loudest_frequency(value_type *absFFT) {
uint32_t find_loudest_frequency(double *absFFT) {
int maxPos = 0;
value_type maxVal = 0;
double maxVal = 0;
int i;
for(i = 0; i < BLOCK_LEN; i++) {
@ -133,15 +134,15 @@ uint32_t find_loudest_frequency(value_type *absFFT) {
}
}
return (value_type)maxPos * SAMPLE_RATE / BLOCK_LEN;
return (double)maxPos * SAMPLE_RATE / BLOCK_LEN;
}
value_type get_energy_in_band(value_type *fft, uint32_t minFreq, uint32_t maxFreq) {
double get_energy_in_band(double *fft, uint32_t minFreq, uint32_t maxFreq) {
int firstBlock = minFreq * BLOCK_LEN / SAMPLE_RATE;
int lastBlock = maxFreq * BLOCK_LEN / SAMPLE_RATE;
int i;
value_type energy = 0;
double energy = 0;
for(i = firstBlock; i < lastBlock; i++) {
energy += fft[i];
}

17
fft.h
View file

@ -1,11 +1,10 @@
/*
* 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
* 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 FFT_H
@ -14,10 +13,10 @@
#include "config.h"
void init_fft(void);
void complex_to_absolute(value_type *re, value_type *im, value_type *result);
void complex_to_absolute(double *re, double *im, double *result);
void apply_hanning(sample *dftinput);
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);
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);
#endif // FFT_H

206
flame.lua
View file

@ -1,206 +0,0 @@
COOLDOWN_FACTOR = 0.9998
OVERDRIVE = 1.70
EXPONENT = 1.5
W_EXPONENT = 2.2
M = 2.3 -- mass
D = 1 -- spring strength
DAMPING = {} -- filled in init()
num_modules = 60
center_module = 60
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
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], W_EXPONENT))
end
-- return the 3 color arrays
return red, green, blue, white
end
function init(nmod, cmod)
num_modules = nmod
center_module = nmod --cmod
num_masses = nmod --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.10 * math.pow(math.abs((i - excitement_pos) / num_masses), 2)
end
-- don't use fading
return 0
end

View file

@ -1,174 +0,0 @@
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

View file

@ -1,68 +0,0 @@
#!/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,16 +1,15 @@
/*
* 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
* 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 <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "lua_utils.h"
@ -64,7 +63,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 (%lu) is out of C array range (%lu)!\n", k, len);
fprintf(stderr, "Warning: Lua index (%u) is out of C array range (%u)!\n", k, len);
} else {
numbers[k-1] = v;
}

View file

@ -1,11 +1,10 @@
/*
* 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
* 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 LUA_UTILS_H

View file

@ -1,18 +1,17 @@
/*
* 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
* 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 <semaphore.h>
#include <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "fft.h"

View file

@ -1,11 +1,10 @@
/*
* 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
* 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 LUA_WRAPPERS_H

47
lut.c
View file

@ -1,47 +0,0 @@
// 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
View file

@ -1,19 +0,0 @@
/*
* 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

103
main.c
View file

@ -1,11 +1,10 @@
/*
* 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
* 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 <pthread.h>
@ -17,46 +16,40 @@
#include <stdint.h>
#include <malloc.h>
#include <lua5.3/lua.h>
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "lua_utils.h"
#include "lua_wrappers.h"
#include "fft.h"
#include "utils.h"
#include "sk6812.h"
#include "ws2801.h"
#include "config.h"
// Frames per second
#define FPS ((value_type)BUFFER_PARTS * SAMPLE_RATE / BLOCK_LEN)
#define FPS ((double)BUFFER_PARTS * SAMPLE_RATE / BLOCK_LEN)
// Number of new samples put into the buffer each frame
#define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS)
#define NUM_SK6812 4
value_type fft[BLOCK_LEN];
value_type rms;
value_type redEnergy, greenEnergy, blueEnergy;
value_type lastUpdateTime = 0;
double fft[BLOCK_LEN];
sample signal[BLOCK_LEN];
double rms;
double lastUpdateTime = 0;
sem_t fftSemaphore;
struct sk6812_ctx sk6812;
int running = 1;
void* fft_thread(void *param) {
sample buffer[BLOCK_LEN];
sample block[BLOCK_LEN];
value_type fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
value_type tmpFFT[BLOCK_LEN];
value_type tmpRMS;
double fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
double tmpFFT[BLOCK_LEN];
double tmpRMS;
double nextFrame = get_hires_time() + 0.05;
double curTime;
@ -78,20 +71,16 @@ void* fft_thread(void *param) {
memcpy(block, buffer, BLOCK_LEN * sizeof(sample));
apply_hanning(block);
fft_transform(block, fftOutReal, fftOutImag);
complex_to_absolute(fftOutReal, fftOutImag, tmpFFT);
tmpRMS = 0;
for(i = 0; i < BLOCK_LEN; i++) {
tmpRMS += buffer[i]*buffer[i];
}
tmpRMS = sqrt(tmpRMS/BLOCK_LEN);
if(tmpRMS == 0) {
continue;
}
apply_hanning(block);
fft_transform(block, fftOutReal, fftOutImag);
complex_to_absolute(fftOutReal, fftOutImag, tmpFFT);
// --- SAFE SECTION ---
sem_wait(&fftSemaphore);
@ -121,13 +110,13 @@ void* fft_thread(void *param) {
}
nextFrame += 1.000/FPS;
//sleep_until(nextFrame);
sleep_until(nextFrame);
}
return NULL;
}
value_type gamma_correct(value_type d, value_type gamma) {
double gamma_correct(double d, double gamma) {
return pow(d, gamma);
}
@ -138,12 +127,10 @@ int main(int argc, char **argv) {
pthread_t fftThread;
int active = 1;
//int frame = 0;
double *red;
double *green;
double *blue;
double *white;
int useFading, fadeStep;
@ -153,7 +140,7 @@ int main(int argc, char **argv) {
}
// initialize lua
lua_State *L = luaL_newstate();
lua_State *L = lua_open();
// load the lua libraries
luaL_openlibs(L);
@ -187,21 +174,10 @@ 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));
blue = malloc(num_modules * sizeof(double));
white = malloc(num_modules * sizeof(double));
// load and initialize the script
if(luaL_loadfile(L, argv[1])) {
@ -224,13 +200,13 @@ int main(int argc, char **argv) {
fadeStep = lua_tointeger(L, -1);
useFading = fadeStep > 0;
if(useFading) {
sk6812_set_fadestep(&sk6812, fadeStep);
ws2801_set_fadestep(fadeStep);
printf("Fading enabled with fadestep %i.\n", fadeStep);
}
// initialize the WS2801 library
printf("Connecting to %s:%i\n", host, port);
sk6812_init(&sk6812, host, port);
ws2801_init(host, port);
// create semaphores
sem_init(&fftSemaphore, 0, 1);
@ -242,48 +218,40 @@ int main(int argc, char **argv) {
if(active) {
// call the periodic() function from LUA
lua_getglobal(L, "periodic");
if(lua_pcall(L, 0, 4, 0)) { // no arguments, 4 return values
if(lua_pcall(L, 0, 3, 0)) { // no arguments, 3 return values
lua_showerror(L, "lua_pcall(periodic) failed.");
}
// read the return values (reverse order, as lua uses a stack)
lua_readdoublearray(L, white, num_modules);
lua_readdoublearray(L, blue, num_modules);
lua_readdoublearray(L, green, num_modules);
lua_readdoublearray(L, red, num_modules);
for(int s = 0; s < NUM_SK6812; s++) {
if(useFading) {
for(i = 0; i < num_modules; i++) {
sk6812_fade_color(&sk6812, s, i,
ws2801_fade_color(i,
255 * gamma_correct(red[i], gamma),
255 * gamma_correct(green[i], gamma),
255 * gamma_correct(blue[i], gamma),
255 * gamma_correct(white[i], gamma));
255 * gamma_correct(blue[i], gamma));
}
ws2801_commit();
} else {
for(i = 0; i < num_modules; i++) {
sk6812_set_color(&sk6812, s, i,
ws2801_set_color(i,
255 * gamma_correct(red[i], gamma),
255 * gamma_correct(green[i], gamma),
255 * gamma_correct(blue[i], gamma),
255 * gamma_correct(white[i], gamma));
255 * gamma_correct(blue[i], gamma));
}
ws2801_commit();
}
}
sk6812_commit(&sk6812);
if(lastUpdateTime < nextFrame - 1) {
printf("Idle for 1 second -> stopping updates.\n");
for(i = 0; i < num_modules; i++) {
for(int s = 0; s < NUM_SK6812; s++) {
sk6812_fade_color(&sk6812, s, i, 0, 0, 0, 20);
ws2801_fade_color(i, 20, 20, 20);
}
}
sk6812_commit(&sk6812);
ws2801_commit();
active = 0;
}
@ -296,15 +264,12 @@ int main(int argc, char **argv) {
sleep_until(nextFrame);
}
for(int i = 0; i < NUM_SK6812; i++) {
sk6812_shutdown(&sk6812);
}
ws2801_shutdown();
// free arrays
free(red);
free(green);
free(blue);
free(white);
pthread_join(fftThread, NULL);

View file

@ -1,203 +0,0 @@
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

View file

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

View file

@ -1,100 +0,0 @@
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 = 160
center_module = 80
num_modules = 20
center_module = 10
-- maximum energy values for each band
maxRedEnergy = 1

View file

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

View file

@ -1,143 +0,0 @@
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

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

View file

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

115
sk6812.c
View file

@ -1,115 +0,0 @@
/*
* 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
// 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 = htons(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 = htons(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 = htons(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) {
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);
}

View file

@ -1,36 +0,0 @@
/*
* 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;
uint16_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

View file

@ -1,11 +1,10 @@
/*
* 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
* 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 <errno.h>

View file

@ -1,11 +1,10 @@
/*
* 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
* 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 UTILS_H

112
ws2801.c Normal file
View file

@ -0,0 +1,112 @@
/*
* 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 Normal file
View file

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