From d4a2e7ef4ccb2b2ff4bfeb52c192c035cb44da15 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sat, 28 Jul 2012 01:30:20 +0200 Subject: [PATCH 1/6] Added lua scripting capabilities - basic configuration is now done via a lua script - all the animation is generated by a lua script (see pulsetunnel.lua and vumeter.lua for examples) - basic calculations (FFT, RMS) are done in C and accessible on demand from the lua scripts --- Makefile | 11 ++- config.h | 7 -- config.lua | 7 ++ lua_utils.c | 73 +++++++++++++++ lua_utils.h | 20 +++++ lua_wrappers.c | 73 +++++++++++++++ lua_wrappers.h | 21 +++++ main.c | 232 ++++++++++++++++++++++++++---------------------- pulsetunnel.lua | 70 +++++++++++++++ run_alsa.sh | 2 +- run_mpd.sh | 2 +- run_pa.sh | 4 +- run_remote.sh | 2 +- vumeter.lua | 85 ++++++++++++++++++ ws2801.c | 2 +- ws2801.h | 2 +- 16 files changed, 487 insertions(+), 126 deletions(-) create mode 100644 config.lua create mode 100644 lua_utils.c create mode 100644 lua_utils.h create mode 100644 lua_wrappers.c create mode 100644 lua_wrappers.h create mode 100644 pulsetunnel.lua create mode 100644 vumeter.lua diff --git a/Makefile b/Makefile index 7535ab0..7e8251c 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ +LUA_CFLAGS=$(shell pkg-config --cflags lua) +LUA_LIBS=$(shell pkg-config --libs lua) + CC=gcc -CFLAGS+=-O3 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -D_XOPEN_SOURCE -LIBS=-lm -lpthread -lrt +CFLAGS+=-O2 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -D_XOPEN_SOURCE $(LUA_CFLAGS) +LIBS=-lm -lpthread -lrt $(LUA_LIBS) TARGET=musiclight2 -SOURCE=main.c fft.c utils.c ws2801.c -DEPS=config.h fft.h utils.h ws2801.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)) diff --git a/config.h b/config.h index 4d2103b..3de59bf 100644 --- a/config.h +++ b/config.h @@ -30,9 +30,6 @@ // update rate for the led strip (in seconds) #define LED_INTERVAL 0.03 -// number of modules in LED strip -#define NUM_MODULES 20 - // frequency ranges for the base colors #define RED_MIN_FREQ 0 #define RED_MAX_FREQ 400 @@ -43,10 +40,6 @@ #define COLOR_MAX_REDUCTION_FACTOR 0.9998 -#define CENTER_MODULE 10 - -#define GAMMA 2.0 - // sample data types typedef int16_t sample; typedef int64_t sample_sum; diff --git a/config.lua b/config.lua new file mode 100644 index 0000000..bb223d5 --- /dev/null +++ b/config.lua @@ -0,0 +1,7 @@ +WS2801_HOST = "192.168.23.222" +WS2801_PORT = 2703 + +NUM_MODULES = 20 +CENTER_MODULE = 10 + +GAMMA = 2.0 diff --git a/lua_utils.c b/lua_utils.c new file mode 100644 index 0000000..b715a8c --- /dev/null +++ b/lua_utils.c @@ -0,0 +1,73 @@ +/* + * vim: sw=2 ts=2 expandtab + * + * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"): + * 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 +#include +#include + +#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 (%u) is out of C array range (%u)!\n", k, len); + } else { + numbers[k-1] = v; + } + } + + lua_pop(L, 1); +} diff --git a/lua_utils.h b/lua_utils.h new file mode 100644 index 0000000..ce60603 --- /dev/null +++ b/lua_utils.h @@ -0,0 +1,20 @@ +/* + * vim: sw=2 ts=2 expandtab + * + * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"): + * 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 diff --git a/lua_wrappers.c b/lua_wrappers.c new file mode 100644 index 0000000..d366e64 --- /dev/null +++ b/lua_wrappers.c @@ -0,0 +1,73 @@ +/* + * vim: sw=2 ts=2 expandtab + * + * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"): + * 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 + +#include +#include +#include + +#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); +} diff --git a/lua_wrappers.h b/lua_wrappers.h new file mode 100644 index 0000000..28da0eb --- /dev/null +++ b/lua_wrappers.h @@ -0,0 +1,21 @@ +/* + * vim: sw=2 ts=2 expandtab + * + * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"): + * 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 diff --git a/main.c b/main.c index e0e2c44..5166168 100644 --- a/main.c +++ b/main.c @@ -14,6 +14,14 @@ #include #include #include +#include + +#include +#include +#include + +#include "lua_utils.h" +#include "lua_wrappers.h" #include "fft.h" #include "utils.h" @@ -27,12 +35,9 @@ // Number of new samples put into the buffer each frame #define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS) -#define COLORBUF_SIZE (2*(NUM_MODULES+1)) -#define CENTER_POS (2*CENTER_MODULE) - double fft[BLOCK_LEN]; +sample signal[BLOCK_LEN]; double rms; -double redEnergy, greenEnergy, blueEnergy; double lastUpdateTime = 0; sem_t fftSemaphore; @@ -72,7 +77,7 @@ void* fft_thread(void *param) { tmpRMS = 0; for(i = 0; i < BLOCK_LEN; i++) { - tmpRMS += block[i]*block[i]; + tmpRMS += buffer[i]*buffer[i]; } tmpRMS = sqrt(tmpRMS/BLOCK_LEN); @@ -80,10 +85,8 @@ void* fft_thread(void *param) { sem_wait(&fftSemaphore); memcpy(fft, tmpFFT, sizeof(fft)); + memcpy(signal, buffer, sizeof(signal)); 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(); lastUpdateTime = curTime; @@ -113,64 +116,97 @@ void* fft_thread(void *param) { return NULL; } -double gamma_correct(double d) { - return pow(d, GAMMA); -} - -void text_bar(double fill) { - int fillCnt = 10 * fill; - int i; - - for(i = 0; i < fillCnt; i++) { - printf("|"); - } - - for(; i < 10; i++) { - printf("-"); - } -} - -double 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(double curRed, double maxRed, double curGreen, double maxGreen, double curBlue, double 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); +double gamma_correct(double d, double gamma) { + return pow(d, gamma); } int main(int argc, char **argv) { double nextFrame = get_hires_time() + LED_INTERVAL; - int i, j; + int i; pthread_t fftThread; int active = 1; - uint8_t colorBuf[COLORBUF_SIZE][3]; + double *red; + double *green; + double *blue; - double curRedEnergy, curGreenEnergy, curBlueEnergy; - double maxRedEnergy = 1, maxGreenEnergy = 1, maxBlueEnergy = 1; + int useFading, fadeStep; - 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 sem_init(&fftSemaphore, 0, 1); @@ -178,68 +214,41 @@ int main(int argc, char **argv) { // run the fft thread pthread_create(&fftThread, NULL, fft_thread, NULL); - ws2801_init(HOST, PORT); - 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) { - sem_wait(&fftSemaphore); - curRedEnergy = redEnergy; - curGreenEnergy = greenEnergy; - curBlueEnergy = blueEnergy; - sem_post(&fftSemaphore); - - maxRedEnergy *= COLOR_MAX_REDUCTION_FACTOR; - if(curRedEnergy > maxRedEnergy) { - maxRedEnergy = curRedEnergy; + // call the periodic() function from LUA + lua_getglobal(L, "periodic"); + if(lua_pcall(L, 0, 3, 0)) { // no arguments, 3 return values + lua_showerror(L, "lua_pcall(periodic) failed."); } - maxGreenEnergy *= COLOR_MAX_REDUCTION_FACTOR; - if(curGreenEnergy > maxGreenEnergy) { - maxGreenEnergy = curGreenEnergy; + // read the return values (reverse order, as lua uses a stack) + lua_readdoublearray(L, blue, num_modules); + lua_readdoublearray(L, green, num_modules); + lua_readdoublearray(L, red, num_modules); + + 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(); } - maxBlueEnergy *= COLOR_MAX_REDUCTION_FACTOR; - if(curBlueEnergy > maxBlueEnergy) { - maxBlueEnergy = curBlueEnergy; - } - - colorBuf[CENTER_POS][0] = 255 * gamma_correct(curRedEnergy / maxRedEnergy); - 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(); - if(lastUpdateTime < nextFrame - 1) { 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_commit(); @@ -257,7 +266,14 @@ int main(int argc, char **argv) { ws2801_shutdown(); + // free arrays + free(red); + free(green); + free(blue); + pthread_join(fftThread, NULL); + lua_close(L); + return 0; } diff --git a/pulsetunnel.lua b/pulsetunnel.lua new file mode 100644 index 0000000..b2b1ccd --- /dev/null +++ b/pulsetunnel.lua @@ -0,0 +1,70 @@ +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 = {} + +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); + + 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,center_module,1 do + red[i-1] = red[i] + green[i-1] = green[i] + blue[i-1] = blue[i] + end + + for i = num_modules-1,center_module,-1 do + red[i+1] = red[i] + green[i+1] = green[i] + blue[i+1] = blue[i] + end + + -- set the new value for the center module + red[center_module] = redEnergy / maxRedEnergy + green[center_module] = greenEnergy / maxGreenEnergy + blue[center_module] = blueEnergy / maxBlueEnergy + + -- 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 + + -- don't use fading + return 0 +end diff --git a/run_alsa.sh b/run_alsa.sh index e8fee4e..660f12d 100755 --- a/run_alsa.sh +++ b/run_alsa.sh @@ -1,3 +1,3 @@ #!/bin/sh -arecord -c 1 -f s16 -r 22050 | ./rtfft +arecord -c 1 -f s16 -r 22050 | ./musiclight2 $* diff --git a/run_mpd.sh b/run_mpd.sh index d63ebd7..246cdae 100755 --- a/run_mpd.sh +++ b/run_mpd.sh @@ -1,4 +1,4 @@ #!/bin/sh #dd if=/tmp/mpd.fifo bs=1024 | ./musiclight2 -./musiclight2 < /tmp/mpd.fifo +./musiclight2 $* < /tmp/mpd.fifo diff --git a/run_pa.sh b/run_pa.sh index 1120439..de5990c 100755 --- a/run_pa.sh +++ b/run_pa.sh @@ -5,12 +5,12 @@ case $1 in mic) #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 - 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 diff --git a/run_remote.sh b/run_remote.sh index e5204cc..cbc98bc 100755 --- a/run_remote.sh +++ b/run_remote.sh @@ -1,3 +1,3 @@ #!/bin/sh -nc -l -p 12345 | ./musiclight2 +nc -l -p 12345 | ./musiclight2 $* diff --git a/vumeter.lua b/vumeter.lua new file mode 100644 index 0000000..f368c2d --- /dev/null +++ b/vumeter.lua @@ -0,0 +1,85 @@ +COOLDOWN_FACTOR = 0.9998 +FACTOR = 0.2 + +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 <= num_modules * redEnergy / maxRedEnergy then + redTarget = brightness + else + redTarget = 0 + end + red[i] = (1 - FACTOR) * red[i] + FACTOR * redTarget; + + if i <= num_modules * greenEnergy / maxGreenEnergy then + greenTarget = brightness + else + greenTarget = 0 + end + green[i] = (1 - FACTOR) * green[i] + FACTOR * greenTarget; + + if i <= num_modules * 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 diff --git a/ws2801.c b/ws2801.c index a0026ab..03c548a 100644 --- a/ws2801.c +++ b/ws2801.c @@ -32,7 +32,7 @@ struct WS2801Packet packetQueue[50]; int queueIndex = 0; // 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 *result; char portstr[6]; diff --git a/ws2801.h b/ws2801.h index cb310e9..24ef5c2 100644 --- a/ws2801.h +++ b/ws2801.h @@ -10,7 +10,7 @@ #ifndef 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_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); From c15d815da9e62e06a1383d4c535e2cb28b4ad69c Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 29 Jul 2012 22:28:41 +0200 Subject: [PATCH 2/6] Exact reimplementation of "old" C algo in LUA --- pulsetunnel.lua | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/pulsetunnel.lua b/pulsetunnel.lua index b2b1ccd..a8e1440 100644 --- a/pulsetunnel.lua +++ b/pulsetunnel.lua @@ -13,10 +13,21 @@ 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; maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR if redEnergy > maxRedEnergy then @@ -34,22 +45,28 @@ function periodic() end -- move the color buffers on by one in each direction - for i = 2,center_module,1 do - red[i-1] = red[i] - green[i-1] = green[i] - blue[i-1] = blue[i] + for i = 2,centerIndex,1 do + tmpRed[i-1] = tmpRed[i] + tmpGreen[i-1] = tmpGreen[i] + tmpBlue[i-1] = tmpBlue[i] end - for i = num_modules-1,center_module,-1 do - red[i+1] = red[i] - green[i+1] = green[i] - blue[i+1] = blue[i] + 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 - red[center_module] = redEnergy / maxRedEnergy - green[center_module] = greenEnergy / maxGreenEnergy - blue[center_module] = blueEnergy / maxBlueEnergy + 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 @@ -65,6 +82,12 @@ function init(nmod, cmod) 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 From bac8df287c8fb29a3bd8088e8cedd4e88389d408 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 29 Jul 2012 23:45:14 +0200 Subject: [PATCH 3/6] Make VU meter symmetrical to center module --- vumeter.lua | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/vumeter.lua b/vumeter.lua index f368c2d..97b9147 100644 --- a/vumeter.lua +++ b/vumeter.lua @@ -1,5 +1,5 @@ COOLDOWN_FACTOR = 0.9998 -FACTOR = 0.2 +FACTOR = 0.033 num_modules = 20 center_module = 10 @@ -44,21 +44,33 @@ function periodic() local brightness = rms / maxRMS for i = 1,num_modules do - if i <= num_modules * redEnergy / maxRedEnergy then + 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 <= num_modules * greenEnergy / maxGreenEnergy then + 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 <= num_modules * blueEnergy / maxBlueEnergy then + 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 From 6a127ea4979122caf48d5743ab3696e6dd59cc67 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 29 Jul 2012 23:46:03 +0200 Subject: [PATCH 4/6] Center of pulsetunnel is now between 2 modules The LED strip has an even number of modules, so this change makes the animation completely symmetrical. --- pulsetunnel.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pulsetunnel.lua b/pulsetunnel.lua index a8e1440..3f629e2 100644 --- a/pulsetunnel.lua +++ b/pulsetunnel.lua @@ -27,7 +27,7 @@ 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; + local centerIndex = 2 * center_module + 1; maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR if redEnergy > maxRedEnergy then From 751ef5f24df2bc9ece5530c929737dcf16a65595 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Wed, 8 Aug 2012 22:59:43 +0200 Subject: [PATCH 5/6] [lua] Added pulsecircle script --- pulsecircle.lua | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 pulsecircle.lua diff --git a/pulsecircle.lua b/pulsecircle.lua new file mode 100644 index 0000000..58b0fbe --- /dev/null +++ b/pulsecircle.lua @@ -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 From cc276ffc7e95a1dad74a7519b9017a7476ab7fa5 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Wed, 8 Aug 2012 23:01:00 +0200 Subject: [PATCH 6/6] [run-scripts] Fixed some bugs --- run_alsa.sh | 2 +- run_pa.sh | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/run_alsa.sh b/run_alsa.sh index 660f12d..338eba8 100755 --- a/run_alsa.sh +++ b/run_alsa.sh @@ -1,3 +1,3 @@ #!/bin/sh -arecord -c 1 -f s16 -r 22050 | ./musiclight2 $* +arecord -c 1 -f s16 -r 44100 | ./musiclight2 $* diff --git a/run_pa.sh b/run_pa.sh index de5990c..2617d7b 100755 --- a/run_pa.sh +++ b/run_pa.sh @@ -2,7 +2,10 @@ #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) #mikro parec -d "alsa_input.pci-0000_00_1b.0.analog-stereo" --raw --rate=44100 --channels=1 --format=s16 | ./musiclight2 $*