Merge branch 'lua'
This combines LUA scripting support with the highly optimized FFT algorithm. Conflicts: Makefile main.c
This commit is contained in:
commit
1ed1717c62
11
Makefile
11
Makefile
|
@ -1,10 +1,13 @@
|
||||||
|
LUA_CFLAGS=$(shell pkg-config --cflags lua)
|
||||||
|
LUA_LIBS=$(shell pkg-config --libs lua)
|
||||||
|
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS+=-O3 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -D_XOPEN_SOURCE
|
CFLAGS+=-O2 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -D_XOPEN_SOURCE $(LUA_CFLAGS)
|
||||||
LIBS=-lm -lpthread -lrt
|
LIBS=-lm -lpthread -lrt $(LUA_LIBS)
|
||||||
|
|
||||||
TARGET=musiclight2
|
TARGET=musiclight2
|
||||||
SOURCE=main.c fft.c utils.c ws2801.c lut.c
|
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 lut.h
|
DEPS=config.h fft.h utils.h ws2801.h lua_utils.h lua_wrappers.h lut.h
|
||||||
|
|
||||||
OBJ=$(patsubst %.c, %.o, $(SOURCE))
|
OBJ=$(patsubst %.c, %.o, $(SOURCE))
|
||||||
|
|
||||||
|
|
7
config.h
7
config.h
|
@ -30,9 +30,6 @@
|
||||||
// update rate for the led strip (in seconds)
|
// update rate for the led strip (in seconds)
|
||||||
#define LED_INTERVAL 0.03
|
#define LED_INTERVAL 0.03
|
||||||
|
|
||||||
// number of modules in LED strip
|
|
||||||
#define NUM_MODULES 20
|
|
||||||
|
|
||||||
// frequency ranges for the base colors
|
// frequency ranges for the base colors
|
||||||
#define RED_MIN_FREQ 0
|
#define RED_MIN_FREQ 0
|
||||||
#define RED_MAX_FREQ 400
|
#define RED_MAX_FREQ 400
|
||||||
|
@ -43,10 +40,6 @@
|
||||||
|
|
||||||
#define COLOR_MAX_REDUCTION_FACTOR 0.9998
|
#define COLOR_MAX_REDUCTION_FACTOR 0.9998
|
||||||
|
|
||||||
#define CENTER_MODULE 10
|
|
||||||
|
|
||||||
#define GAMMA 2.0
|
|
||||||
|
|
||||||
// sample data types
|
// sample data types
|
||||||
typedef int16_t sample;
|
typedef int16_t sample;
|
||||||
typedef int64_t sample_sum;
|
typedef int64_t sample_sum;
|
||||||
|
|
7
config.lua
Normal file
7
config.lua
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
WS2801_HOST = "192.168.23.222"
|
||||||
|
WS2801_PORT = 2703
|
||||||
|
|
||||||
|
NUM_MODULES = 20
|
||||||
|
CENTER_MODULE = 10
|
||||||
|
|
||||||
|
GAMMA = 2.0
|
73
lua_utils.c
Normal file
73
lua_utils.c
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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 <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
#include "lua_utils.h"
|
||||||
|
|
||||||
|
void lua_showerror(lua_State *L, const char *msg) {
|
||||||
|
fprintf(stderr, "\nLUA ERROR:\n %s: %s\n\n",
|
||||||
|
msg, lua_tostring(L, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void lua_pushdoublearray(lua_State *L, double *numbers, size_t len) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
// create an empty table
|
||||||
|
lua_createtable(L, len, 0);
|
||||||
|
|
||||||
|
for(i = 0; i < len; i++) {
|
||||||
|
// push key and value
|
||||||
|
lua_pushnumber(L, i+1); // lua arrays count from 1
|
||||||
|
lua_pushnumber(L, numbers[i]);
|
||||||
|
|
||||||
|
// store the values in the table
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lua_pushsamplearray(lua_State *L, sample *numbers, size_t len) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
// create an empty table
|
||||||
|
lua_createtable(L, len, 0);
|
||||||
|
|
||||||
|
for(i = 0; i < len; i++) {
|
||||||
|
// push key and value
|
||||||
|
lua_pushnumber(L, i+1); // lua arrays count from 1
|
||||||
|
lua_pushnumber(L, numbers[i]);
|
||||||
|
|
||||||
|
// store the values in the table
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lua_readdoublearray(lua_State *L, double *numbers, size_t len) {
|
||||||
|
size_t k;
|
||||||
|
double v;
|
||||||
|
|
||||||
|
// go to the top of the stack
|
||||||
|
lua_pushnil(L);
|
||||||
|
|
||||||
|
while(lua_next(L, -2)) {
|
||||||
|
v = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
numbers[k-1] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
20
lua_utils.h
Normal file
20
lua_utils.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 LUA_UTILS_H
|
||||||
|
#define LUA_UTILS_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
void lua_showerror(lua_State *L, const char *msg);
|
||||||
|
void lua_pushdoublearray(lua_State *L, double *numbers, size_t len);
|
||||||
|
void lua_pushsamplearray(lua_State *L, sample *numbers, size_t len);
|
||||||
|
void lua_readdoublearray(lua_State *L, double *numbers, size_t len);
|
||||||
|
|
||||||
|
#endif // LUA_UTILS_H
|
73
lua_wrappers.c
Normal file
73
lua_wrappers.c
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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 <semaphore.h>
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
#include "fft.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "lua_utils.h"
|
||||||
|
#include "lua_wrappers.h"
|
||||||
|
|
||||||
|
extern sem_t fftSemaphore;
|
||||||
|
extern double fft[BLOCK_LEN];
|
||||||
|
extern sample signal[BLOCK_LEN];
|
||||||
|
extern double rms;
|
||||||
|
|
||||||
|
static int l_get_energy_in_band(lua_State *L) {
|
||||||
|
int lowerFreq, higherFreq;
|
||||||
|
|
||||||
|
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||||
|
lowerFreq = lua_tointeger(L, 1);
|
||||||
|
|
||||||
|
luaL_checktype(L, 2, LUA_TNUMBER);
|
||||||
|
higherFreq = lua_tointeger(L, 2);
|
||||||
|
|
||||||
|
sem_wait(&fftSemaphore);
|
||||||
|
lua_pushnumber(L, get_energy_in_band(fft, lowerFreq, higherFreq));
|
||||||
|
sem_post(&fftSemaphore);
|
||||||
|
|
||||||
|
return 1; // number of arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_get_fft(lua_State *L) {
|
||||||
|
sem_wait(&fftSemaphore);
|
||||||
|
lua_pushdoublearray(L, fft, BLOCK_LEN);
|
||||||
|
sem_post(&fftSemaphore);
|
||||||
|
|
||||||
|
return 1; // number of return values
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_get_signal(lua_State *L) {
|
||||||
|
sem_wait(&fftSemaphore);
|
||||||
|
lua_pushsamplearray(L, signal, BLOCK_LEN);
|
||||||
|
sem_post(&fftSemaphore);
|
||||||
|
|
||||||
|
return 1; // number of return values
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_get_rms(lua_State *L) {
|
||||||
|
sem_wait(&fftSemaphore);
|
||||||
|
lua_pushnumber(L, rms);
|
||||||
|
sem_post(&fftSemaphore);
|
||||||
|
|
||||||
|
return 1; // number of return values
|
||||||
|
}
|
||||||
|
|
||||||
|
void lua_register_funcs(lua_State *L) {
|
||||||
|
lua_register(L, "get_energy_in_band", l_get_energy_in_band);
|
||||||
|
lua_register(L, "get_fft", l_get_fft);
|
||||||
|
lua_register(L, "get_signal", l_get_signal);
|
||||||
|
lua_register(L, "get_rms", l_get_rms);
|
||||||
|
}
|
21
lua_wrappers.h
Normal file
21
lua_wrappers.h
Normal 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 LUA_WRAPPERS_H
|
||||||
|
#define LUA_WRAPPERS_H
|
||||||
|
|
||||||
|
void lua_register_funcs(lua_State *L);
|
||||||
|
|
||||||
|
/*
|
||||||
|
static int l_get_energy_in_band(lua_State *L);
|
||||||
|
static int l_get_fft(lua_State *L);
|
||||||
|
static int l_get_signal(lua_State *L);
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif // LUA_WRAPPERS_H
|
228
main.c
228
main.c
|
@ -14,6 +14,14 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
#include "lua_utils.h"
|
||||||
|
#include "lua_wrappers.h"
|
||||||
|
|
||||||
#include "fft.h"
|
#include "fft.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
@ -27,14 +35,13 @@
|
||||||
// Number of new samples put into the buffer each frame
|
// Number of new samples put into the buffer each frame
|
||||||
#define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS)
|
#define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS)
|
||||||
|
|
||||||
#define COLORBUF_SIZE (2*(NUM_MODULES+1))
|
|
||||||
#define CENTER_POS (2*CENTER_MODULE)
|
|
||||||
|
|
||||||
value_type fft[BLOCK_LEN];
|
value_type fft[BLOCK_LEN];
|
||||||
value_type rms;
|
value_type rms;
|
||||||
value_type redEnergy, greenEnergy, blueEnergy;
|
value_type redEnergy, greenEnergy, blueEnergy;
|
||||||
value_type lastUpdateTime = 0;
|
value_type lastUpdateTime = 0;
|
||||||
|
|
||||||
|
sample signal[BLOCK_LEN];
|
||||||
|
|
||||||
sem_t fftSemaphore;
|
sem_t fftSemaphore;
|
||||||
|
|
||||||
int running = 1;
|
int running = 1;
|
||||||
|
@ -72,7 +79,7 @@ void* fft_thread(void *param) {
|
||||||
|
|
||||||
tmpRMS = 0;
|
tmpRMS = 0;
|
||||||
for(i = 0; i < BLOCK_LEN; i++) {
|
for(i = 0; i < BLOCK_LEN; i++) {
|
||||||
tmpRMS += block[i]*block[i];
|
tmpRMS += buffer[i]*buffer[i];
|
||||||
}
|
}
|
||||||
tmpRMS = sqrt(tmpRMS/BLOCK_LEN);
|
tmpRMS = sqrt(tmpRMS/BLOCK_LEN);
|
||||||
|
|
||||||
|
@ -80,10 +87,8 @@ void* fft_thread(void *param) {
|
||||||
sem_wait(&fftSemaphore);
|
sem_wait(&fftSemaphore);
|
||||||
|
|
||||||
memcpy(fft, tmpFFT, sizeof(fft));
|
memcpy(fft, tmpFFT, sizeof(fft));
|
||||||
|
memcpy(signal, buffer, sizeof(signal));
|
||||||
rms = tmpRMS;
|
rms = tmpRMS;
|
||||||
redEnergy = get_energy_in_band(fft, RED_MIN_FREQ, RED_MAX_FREQ);
|
|
||||||
greenEnergy = get_energy_in_band(fft, GREEN_MIN_FREQ, GREEN_MAX_FREQ);
|
|
||||||
blueEnergy = get_energy_in_band(fft, BLUE_MIN_FREQ, BLUE_MAX_FREQ);
|
|
||||||
|
|
||||||
curTime = get_hires_time();
|
curTime = get_hires_time();
|
||||||
lastUpdateTime = curTime;
|
lastUpdateTime = curTime;
|
||||||
|
@ -113,64 +118,97 @@ void* fft_thread(void *param) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type gamma_correct(value_type d) {
|
value_type gamma_correct(value_type d, value_type gamma) {
|
||||||
return pow(d, GAMMA);
|
return pow(d, gamma);
|
||||||
}
|
|
||||||
|
|
||||||
void text_bar(value_type fill) {
|
|
||||||
int fillCnt = 10 * fill;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < fillCnt; i++) {
|
|
||||||
printf("|");
|
|
||||||
}
|
|
||||||
|
|
||||||
for(; i < 10; i++) {
|
|
||||||
printf("-");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type weighted_avg(uint8_t colorBuf[COLORBUF_SIZE][3], int channel, int centerPos) {
|
|
||||||
return 0.20 * colorBuf[centerPos - 1][channel] +
|
|
||||||
0.60 * colorBuf[centerPos][channel] +
|
|
||||||
0.20 * colorBuf[centerPos + 1][channel];
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_status(value_type curRed, value_type maxRed, value_type curGreen, value_type maxGreen, value_type curBlue, value_type maxBlue) {
|
|
||||||
printf("\r");
|
|
||||||
|
|
||||||
printf("[\033[31m");
|
|
||||||
text_bar(curRed / maxRed);
|
|
||||||
printf("\033[0m] ");
|
|
||||||
printf("\033[1;31m%7.2e\033[0m ", maxRed / (RED_MAX_FREQ - RED_MIN_FREQ));
|
|
||||||
|
|
||||||
printf("[\033[32m");
|
|
||||||
text_bar(curGreen / maxGreen);
|
|
||||||
printf("\033[0m] ");
|
|
||||||
printf("\033[1;32m%7.2e\033[0m ", maxGreen / (GREEN_MAX_FREQ - GREEN_MIN_FREQ));
|
|
||||||
|
|
||||||
printf("[\033[34m");
|
|
||||||
text_bar(curBlue / maxBlue);
|
|
||||||
printf("\033[0m] ");
|
|
||||||
printf("\033[1;34m%7.2e\033[0m ", maxBlue / (BLUE_MAX_FREQ - BLUE_MIN_FREQ));
|
|
||||||
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
double nextFrame = get_hires_time() + LED_INTERVAL;
|
double nextFrame = get_hires_time() + LED_INTERVAL;
|
||||||
|
|
||||||
int i, j;
|
int i;
|
||||||
pthread_t fftThread;
|
pthread_t fftThread;
|
||||||
|
|
||||||
int active = 1;
|
int active = 1;
|
||||||
|
|
||||||
uint8_t colorBuf[COLORBUF_SIZE][3];
|
double *red;
|
||||||
|
double *green;
|
||||||
|
double *blue;
|
||||||
|
|
||||||
value_type curRedEnergy, curGreenEnergy, curBlueEnergy;
|
int useFading, fadeStep;
|
||||||
value_type maxRedEnergy = 1, maxGreenEnergy = 1, maxBlueEnergy = 1;
|
|
||||||
|
|
||||||
memset(colorBuf, 0, sizeof(colorBuf));
|
if(argc < 2) {
|
||||||
|
fprintf(stderr, "LUA script file must be given as command line argument!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize lua
|
||||||
|
lua_State *L = lua_open();
|
||||||
|
|
||||||
|
// load the lua libraries
|
||||||
|
luaL_openlibs(L);
|
||||||
|
|
||||||
|
// register local functions
|
||||||
|
lua_register_funcs(L);
|
||||||
|
|
||||||
|
// load the configuration from "config.lua"
|
||||||
|
if(luaL_dofile(L, "config.lua")) {
|
||||||
|
lua_showerror(L, "luaL_dofile(config.lua) failed.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getglobal(L, "WS2801_HOST");
|
||||||
|
if(!lua_isstring(L, -1)) return 2;
|
||||||
|
const char *host = lua_tostring(L, -1);
|
||||||
|
|
||||||
|
lua_getglobal(L, "WS2801_PORT");
|
||||||
|
if(!lua_isnumber(L, -1)) return 2;
|
||||||
|
unsigned short port = lua_tointeger(L, -1);
|
||||||
|
|
||||||
|
lua_getglobal(L, "GAMMA");
|
||||||
|
if(!lua_isnumber(L, -1)) return 2;
|
||||||
|
double gamma = lua_tonumber(L, -1);
|
||||||
|
|
||||||
|
lua_getglobal(L, "NUM_MODULES");
|
||||||
|
if(!lua_isnumber(L, -1)) return 2;
|
||||||
|
int num_modules = lua_tointeger(L, -1);
|
||||||
|
|
||||||
|
lua_getglobal(L, "CENTER_MODULE");
|
||||||
|
if(!lua_isnumber(L, -1)) return 2;
|
||||||
|
int center_module = lua_tointeger(L, -1);
|
||||||
|
|
||||||
|
// allocate arrays
|
||||||
|
red = malloc(num_modules * sizeof(double));
|
||||||
|
green = malloc(num_modules * sizeof(double));
|
||||||
|
blue = malloc(num_modules * sizeof(double));
|
||||||
|
|
||||||
|
// load and initialize the script
|
||||||
|
if(luaL_loadfile(L, argv[1])) {
|
||||||
|
lua_showerror(L, "luaL_loadfile(cmdline_argument) failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// priming call: read the lua file to make functions known
|
||||||
|
if(lua_pcall(L, 0, 0, 0)) {
|
||||||
|
lua_showerror(L, "lua_pcall failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the init function
|
||||||
|
lua_getglobal(L, "init");
|
||||||
|
lua_pushnumber(L, num_modules);
|
||||||
|
lua_pushnumber(L, center_module);
|
||||||
|
if(lua_pcall(L, 2, 1, 0)) {
|
||||||
|
lua_showerror(L, "lua_pcall(init) failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fadeStep = lua_tointeger(L, -1);
|
||||||
|
useFading = fadeStep > 0;
|
||||||
|
if(useFading) {
|
||||||
|
ws2801_set_fadestep(fadeStep);
|
||||||
|
printf("Fading enabled with fadestep %i.\n", fadeStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize the WS2801 library
|
||||||
|
printf("Connecting to %s:%i\n", host, port);
|
||||||
|
ws2801_init(host, port);
|
||||||
|
|
||||||
// create semaphores
|
// create semaphores
|
||||||
sem_init(&fftSemaphore, 0, 1);
|
sem_init(&fftSemaphore, 0, 1);
|
||||||
|
@ -178,68 +216,41 @@ int main(int argc, char **argv) {
|
||||||
// run the fft thread
|
// run the fft thread
|
||||||
pthread_create(&fftThread, NULL, fft_thread, NULL);
|
pthread_create(&fftThread, NULL, fft_thread, NULL);
|
||||||
|
|
||||||
ws2801_init(HOST, PORT);
|
|
||||||
|
|
||||||
while(running) {
|
while(running) {
|
||||||
for(i = COLORBUF_SIZE-1; i >= 0; i--) {
|
|
||||||
int pos = CENTER_POS + i;
|
|
||||||
if(pos < COLORBUF_SIZE-1) {
|
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
colorBuf[pos][j] = colorBuf[pos - 1][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = CENTER_POS - i;
|
|
||||||
if(pos >= 0) {
|
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
colorBuf[pos][j] = colorBuf[pos + 1][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(active) {
|
if(active) {
|
||||||
sem_wait(&fftSemaphore);
|
// call the periodic() function from LUA
|
||||||
curRedEnergy = redEnergy;
|
lua_getglobal(L, "periodic");
|
||||||
curGreenEnergy = greenEnergy;
|
if(lua_pcall(L, 0, 3, 0)) { // no arguments, 3 return values
|
||||||
curBlueEnergy = blueEnergy;
|
lua_showerror(L, "lua_pcall(periodic) failed.");
|
||||||
sem_post(&fftSemaphore);
|
|
||||||
|
|
||||||
maxRedEnergy *= COLOR_MAX_REDUCTION_FACTOR;
|
|
||||||
if(curRedEnergy > maxRedEnergy) {
|
|
||||||
maxRedEnergy = curRedEnergy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
maxGreenEnergy *= COLOR_MAX_REDUCTION_FACTOR;
|
// read the return values (reverse order, as lua uses a stack)
|
||||||
if(curGreenEnergy > maxGreenEnergy) {
|
lua_readdoublearray(L, blue, num_modules);
|
||||||
maxGreenEnergy = curGreenEnergy;
|
lua_readdoublearray(L, green, num_modules);
|
||||||
}
|
lua_readdoublearray(L, red, num_modules);
|
||||||
|
|
||||||
maxBlueEnergy *= COLOR_MAX_REDUCTION_FACTOR;
|
if(useFading) {
|
||||||
if(curBlueEnergy > maxBlueEnergy) {
|
for(i = 0; i < num_modules; i++) {
|
||||||
maxBlueEnergy = curBlueEnergy;
|
ws2801_fade_color(i,
|
||||||
}
|
255 * gamma_correct(red[i], gamma),
|
||||||
|
255 * gamma_correct(green[i], gamma),
|
||||||
colorBuf[CENTER_POS][0] = 255 * gamma_correct(curRedEnergy / maxRedEnergy);
|
255 * gamma_correct(blue[i], gamma));
|
||||||
colorBuf[CENTER_POS][1] = 255 * gamma_correct(curGreenEnergy / maxGreenEnergy);
|
|
||||||
colorBuf[CENTER_POS][2] = 255 * gamma_correct(curBlueEnergy / maxBlueEnergy);
|
|
||||||
|
|
||||||
/*
|
|
||||||
show_status(curRedEnergy, maxRedEnergy, curGreenEnergy, maxGreenEnergy,
|
|
||||||
curBlueEnergy, maxBlueEnergy);
|
|
||||||
*/
|
|
||||||
|
|
||||||
for(i = 0; i < NUM_MODULES; i++) {
|
|
||||||
ws2801_set_color(i,
|
|
||||||
weighted_avg(colorBuf, 0, 2 * i + 1),
|
|
||||||
weighted_avg(colorBuf, 1, 2 * i + 1),
|
|
||||||
weighted_avg(colorBuf, 2, 2 * i + 1));
|
|
||||||
}
|
}
|
||||||
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) {
|
if(lastUpdateTime < nextFrame - 1) {
|
||||||
printf("Idle for 1 second -> stopping updates.\n");
|
printf("Idle for 1 second -> stopping updates.\n");
|
||||||
|
|
||||||
for(i = 0; i < NUM_MODULES; i++) {
|
for(i = 0; i < num_modules; i++) {
|
||||||
ws2801_fade_color(i, 20, 20, 20);
|
ws2801_fade_color(i, 20, 20, 20);
|
||||||
}
|
}
|
||||||
ws2801_commit();
|
ws2801_commit();
|
||||||
|
@ -257,7 +268,14 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
ws2801_shutdown();
|
ws2801_shutdown();
|
||||||
|
|
||||||
|
// free arrays
|
||||||
|
free(red);
|
||||||
|
free(green);
|
||||||
|
free(blue);
|
||||||
|
|
||||||
pthread_join(fftThread, NULL);
|
pthread_join(fftThread, NULL);
|
||||||
|
|
||||||
|
lua_close(L);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
99
pulsecircle.lua
Normal file
99
pulsecircle.lua
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
COOLDOWN_FACTOR = 0.9998
|
||||||
|
FADE_FACTOR = 0.985
|
||||||
|
|
||||||
|
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 periodic()
|
||||||
|
local redEnergy = get_energy_in_band(0, 400);
|
||||||
|
local greenEnergy = get_energy_in_band(400, 4000);
|
||||||
|
local blueEnergy = get_energy_in_band(4000, 22000);
|
||||||
|
local centerIndex = 2 * center_module + 1;
|
||||||
|
|
||||||
|
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
|
||||||
|
if redEnergy > maxRedEnergy then
|
||||||
|
maxRedEnergy = redEnergy
|
||||||
|
end
|
||||||
|
|
||||||
|
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
|
||||||
|
if greenEnergy > maxGreenEnergy then
|
||||||
|
maxGreenEnergy = greenEnergy
|
||||||
|
end
|
||||||
|
|
||||||
|
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
|
||||||
|
if blueEnergy > maxBlueEnergy then
|
||||||
|
maxBlueEnergy = blueEnergy
|
||||||
|
end
|
||||||
|
|
||||||
|
-- move the color buffers on by one
|
||||||
|
for i = num_modules-1,1,-1 do
|
||||||
|
tmpRed[i+1] = FADE_FACTOR * tmpRed[i]
|
||||||
|
tmpGreen[i+1] = FADE_FACTOR * tmpGreen[i]
|
||||||
|
tmpBlue[i+1] = FADE_FACTOR * tmpBlue[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set the new value for the center module
|
||||||
|
newRed = redEnergy / maxRedEnergy
|
||||||
|
if newRed > tmpRed[num_modules] then
|
||||||
|
tmpRed[1] = newRed
|
||||||
|
else
|
||||||
|
tmpRed[1] = tmpRed[num_modules]
|
||||||
|
end
|
||||||
|
|
||||||
|
newGreen = greenEnergy / maxGreenEnergy
|
||||||
|
if newGreen > tmpGreen[num_modules] then
|
||||||
|
tmpGreen[1] = newGreen
|
||||||
|
else
|
||||||
|
tmpGreen[1] = tmpGreen[num_modules]
|
||||||
|
end
|
||||||
|
|
||||||
|
newBlue = blueEnergy / maxBlueEnergy
|
||||||
|
if newBlue > tmpBlue[num_modules] then
|
||||||
|
tmpBlue[1] = newBlue
|
||||||
|
else
|
||||||
|
tmpBlue[1] = tmpBlue[num_modules]
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1,num_modules do
|
||||||
|
red[i] = tmpRed[i]
|
||||||
|
green[i] = tmpGreen[i]
|
||||||
|
blue[i] = tmpBlue[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,nmod do
|
||||||
|
tmpRed[i] = 0
|
||||||
|
tmpGreen[i] = 0
|
||||||
|
tmpBlue[i] = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- don't use fading
|
||||||
|
return 0
|
||||||
|
end
|
93
pulsetunnel.lua
Normal file
93
pulsetunnel.lua
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
COOLDOWN_FACTOR = 0.9998
|
||||||
|
|
||||||
|
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 weighted_avg(array, centerIndex)
|
||||||
|
return 0.2 * array[centerIndex - 1] +
|
||||||
|
0.6 * array[centerIndex] +
|
||||||
|
0.2 * array[centerIndex + 1]
|
||||||
|
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 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 / maxRedEnergy
|
||||||
|
tmpGreen[centerIndex] = greenEnergy / maxGreenEnergy
|
||||||
|
tmpBlue[centerIndex] = blueEnergy / maxBlueEnergy
|
||||||
|
|
||||||
|
for i = 1,num_modules do
|
||||||
|
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
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
arecord -c 1 -f s16 -r 22050 | ./rtfft
|
arecord -c 1 -f s16 -r 44100 | ./musiclight2 $*
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#dd if=/tmp/mpd.fifo bs=1024 | ./musiclight2
|
#dd if=/tmp/mpd.fifo bs=1024 | ./musiclight2
|
||||||
./musiclight2 < /tmp/mpd.fifo
|
./musiclight2 $* < /tmp/mpd.fifo
|
||||||
|
|
|
@ -2,15 +2,18 @@
|
||||||
|
|
||||||
#parec -d "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" --channels=1 --format=s16 | mbuffer -R 88200 | ./musiclight2
|
#parec -d "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" --channels=1 --format=s16 | mbuffer -R 88200 | ./musiclight2
|
||||||
|
|
||||||
case $1 in
|
MODE="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
mic)
|
mic)
|
||||||
#mikro
|
#mikro
|
||||||
parec -d "alsa_input.pci-0000_00_1b.0.analog-stereo" --raw --rate=44100 --channels=1 --format=s16 | ./musiclight2
|
parec -d "alsa_input.pci-0000_00_1b.0.analog-stereo" --raw --rate=44100 --channels=1 --format=s16 | ./musiclight2 $*
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
# soundkarte
|
# soundkarte
|
||||||
parec -d "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" --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
|
esac
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
nc -l -p 12345 | ./musiclight2
|
nc -l -p 12345 | ./musiclight2 $*
|
||||||
|
|
97
vumeter.lua
Normal file
97
vumeter.lua
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
COOLDOWN_FACTOR = 0.9998
|
||||||
|
FACTOR = 0.033
|
||||||
|
|
||||||
|
num_modules = 20
|
||||||
|
center_module = 10
|
||||||
|
|
||||||
|
-- maximum energy values for each band
|
||||||
|
maxRedEnergy = 1
|
||||||
|
maxGreenEnergy = 1
|
||||||
|
maxBlueEnergy = 1
|
||||||
|
maxRMS = 1
|
||||||
|
|
||||||
|
-- output color buffers
|
||||||
|
red = {}
|
||||||
|
green = {}
|
||||||
|
blue = {}
|
||||||
|
|
||||||
|
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 rms = get_rms();
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
maxRMS = maxRMS * COOLDOWN_FACTOR
|
||||||
|
if rms > maxRMS then
|
||||||
|
maxRMS = rms
|
||||||
|
end
|
||||||
|
|
||||||
|
local brightness = rms / maxRMS
|
||||||
|
|
||||||
|
for i = 1,num_modules do
|
||||||
|
if i <= center_module and
|
||||||
|
center_module - i < center_module * redEnergy / maxRedEnergy or
|
||||||
|
i > center_module and
|
||||||
|
i - (center_module + 1) < (num_modules-center_module) * redEnergy / maxRedEnergy
|
||||||
|
then
|
||||||
|
redTarget = brightness
|
||||||
|
else
|
||||||
|
redTarget = 0
|
||||||
|
end
|
||||||
|
red[i] = (1 - FACTOR) * red[i] + FACTOR * redTarget;
|
||||||
|
|
||||||
|
if i <= center_module and
|
||||||
|
center_module - i < center_module * greenEnergy / maxGreenEnergy or
|
||||||
|
i > center_module and
|
||||||
|
i - (center_module + 1) < (num_modules-center_module) * greenEnergy / maxGreenEnergy
|
||||||
|
then
|
||||||
|
greenTarget = brightness
|
||||||
|
else
|
||||||
|
greenTarget = 0
|
||||||
|
end
|
||||||
|
green[i] = (1 - FACTOR) * green[i] + FACTOR * greenTarget;
|
||||||
|
|
||||||
|
if i <= center_module and
|
||||||
|
center_module - i < center_module * blueEnergy / maxBlueEnergy or
|
||||||
|
i > center_module and
|
||||||
|
i - (center_module + 1) < (num_modules-center_module) * blueEnergy / maxBlueEnergy
|
||||||
|
then
|
||||||
|
blueTarget = brightness
|
||||||
|
else
|
||||||
|
blueTarget = 0
|
||||||
|
end
|
||||||
|
blue[i] = (1 - FACTOR) * blue[i] + FACTOR * blueTarget;
|
||||||
|
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
|
||||||
|
|
||||||
|
-- fadestep (0 = no fading)
|
||||||
|
return 0
|
||||||
|
end
|
2
ws2801.c
2
ws2801.c
|
@ -32,7 +32,7 @@ struct WS2801Packet packetQueue[50];
|
||||||
int queueIndex = 0;
|
int queueIndex = 0;
|
||||||
|
|
||||||
// creates the socket needed for steering the LED strip
|
// creates the socket needed for steering the LED strip
|
||||||
int ws2801_init(char *host, unsigned short port) {
|
int ws2801_init(const char *host, unsigned short port) {
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
struct addrinfo *result;
|
struct addrinfo *result;
|
||||||
char portstr[6];
|
char portstr[6];
|
||||||
|
|
2
ws2801.h
2
ws2801.h
|
@ -10,7 +10,7 @@
|
||||||
#ifndef WS2801_H
|
#ifndef WS2801_H
|
||||||
#define WS2801_H
|
#define WS2801_H
|
||||||
|
|
||||||
int ws2801_init(char *host, unsigned short port);
|
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_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_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_add_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
|
Loading…
Reference in a new issue