diff --git a/config.h b/config.h index 8dad959..736f8f7 100644 --- a/config.h +++ b/config.h @@ -16,13 +16,13 @@ // configuration variables for musiclight2 // networking -#define HOST "musiclight0.wiese.icmp.camp" +#define HOST "192.168.42.1" #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 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 diff --git a/config.lua b/config.lua index 26b9c5a..1c0f459 100644 --- a/config.lua +++ b/config.lua @@ -1,7 +1,8 @@ -WS2801_HOST = "10.42.6.183" +WS2801_HOST = "192.168.42.1" WS2801_PORT = 2703 NUM_MODULES = 16 +NUM_STRIPS = 8 CENTER_MODULE = 8 GAMMA = 2.0 diff --git a/flame.lua b/flame.lua index dfb3bc2..d245c89 100644 --- a/flame.lua +++ b/flame.lua @@ -157,25 +157,35 @@ function periodic() end -- make colors more exciting + remove the first (flickering) mass - for i = 1,num_modules do - red[i] = limit(OVERDRIVE * r_tmp[i+1]^EXPONENT) - green[i] = limit(OVERDRIVE * g_tmp[i+1]^EXPONENT) - blue[i] = limit(OVERDRIVE * b_tmp[i+1]^EXPONENT) - white[i] = limit(OVERDRIVE * w_tmp[i+1]^W_EXPONENT) + for m = 1,num_modules do + rval = limit(OVERDRIVE * r_tmp[m+1]^EXPONENT) + gval = limit(OVERDRIVE * g_tmp[m+1]^EXPONENT) + bval = limit(OVERDRIVE * b_tmp[m+1]^EXPONENT) + wval = limit(OVERDRIVE * w_tmp[m+1]^W_EXPONENT) + + for s = 1,num_strip do + i = idx(s, m) + + red[i] = rval + green[i] = gval + blue[i] = bval + white[i] = wval + end end -- return the 4 color arrays return red, green, blue, white end -function init(nmod, cmod) +function init(nstrip, nmod, cmod) + num_strip = nstrip num_modules = nmod center_module = nmod --cmod num_masses = nmod+1 --math.floor(nmod/2) excitement_pos = 1 - for i = 1,nmod do + for i = 1,(nmod*nstrip) do red[i] = 0 green[i] = 0 blue[i] = 0 diff --git a/lua_wrappers.c b/lua_wrappers.c index 004ad86..c788548 100644 --- a/lua_wrappers.c +++ b/lua_wrappers.c @@ -15,6 +15,7 @@ #include #include "fft.h" +#include "utils.h" #include "config.h" @@ -66,9 +67,24 @@ static int l_get_rms(lua_State *L) { return 1; // number of return values } +// calculate the position in the output arrays from strip and module index +static int l_idx(lua_State *L) { + luaL_checktype(L, 1, LUA_TNUMBER); + int strip = lua_tointeger(L, 1) - 1; // -1 because Lua counts from 1 + + luaL_checktype(L, 2, LUA_TNUMBER); + int module = lua_tointeger(L, 2) - 1; // -1 because Lua counts from 1 + + lua_pushnumber(L, idx(strip, module) + 1); // +1 because Lua counts from 1 + + return 1; // number of return values +} + void lua_register_funcs(lua_State *L) { 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); + + lua_register(L, "idx", l_idx); } diff --git a/main.c b/main.c index 50f3bdb..f22e8f1 100644 --- a/main.c +++ b/main.c @@ -36,11 +36,8 @@ // Number of new samples put into the buffer each frame #define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS) -#define NUM_SK6812 8 - value_type fft[BLOCK_LEN]; value_type rms; -value_type redEnergy, greenEnergy, blueEnergy; value_type lastUpdateTime = 0; sample signal[BLOCK_LEN]; @@ -49,6 +46,9 @@ sem_t fftSemaphore; struct sk6812_ctx sk6812; +int num_modules; +int num_strips; + int running = 1; void* fft_thread(void *param) { @@ -61,22 +61,22 @@ void* fft_thread(void *param) { double nextFrame = get_hires_time() + 0.05; double curTime; - int i; + int i; - init_fft(); + init_fft(); - while(running) { - // shift the buffer left - memmove(buffer, buffer + READ_SAMPLES, - (BLOCK_LEN - READ_SAMPLES) * sizeof(sample)); + while(running) { + // shift the buffer left + memmove(buffer, buffer + READ_SAMPLES, + (BLOCK_LEN - READ_SAMPLES) * sizeof(sample)); - size_t ret = fread(buffer + (BLOCK_LEN - READ_SAMPLES), - sizeof(sample), READ_SAMPLES, stdin); - if(ret != READ_SAMPLES) { - break; - } + size_t ret = fread(buffer + (BLOCK_LEN - READ_SAMPLES), + sizeof(sample), READ_SAMPLES, stdin); + if(ret != READ_SAMPLES) { + break; + } - memcpy(block, buffer, BLOCK_LEN * sizeof(sample)); + memcpy(block, buffer, BLOCK_LEN * sizeof(sample)); tmpRMS = 0; for(i = 0; i < BLOCK_LEN; i++) { @@ -88,9 +88,9 @@ void* fft_thread(void *param) { continue; } - apply_hanning(block); - fft_transform(block, fftOutReal, fftOutImag); - complex_to_absolute(fftOutReal, fftOutImag, tmpFFT); + apply_hanning(block); + fft_transform(block, fftOutReal, fftOutImag); + complex_to_absolute(fftOutReal, fftOutImag, tmpFFT); // --- SAFE SECTION --- sem_wait(&fftSemaphore); @@ -99,32 +99,32 @@ void* fft_thread(void *param) { memcpy(signal, buffer, sizeof(signal)); rms = tmpRMS; - curTime = get_hires_time(); + curTime = get_hires_time(); lastUpdateTime = curTime; - sem_post(&fftSemaphore); + sem_post(&fftSemaphore); // --- END SAFE SECTION --- - if(curTime > nextFrame + 0.05) { - printf("Frame too late! Skipping.\n"); - nextFrame = -1; - } + if(curTime > nextFrame + 0.05) { + printf("Frame too late! Skipping.\n"); + nextFrame = -1; + } - if(curTime < nextFrame - 0.05) { - printf("Frame too early.\n"); - nextFrame = -1; - } + if(curTime < nextFrame - 0.05) { + printf("Frame too early.\n"); + nextFrame = -1; + } - if(nextFrame < 0) { - printf("Frame time reset.\n"); - nextFrame = curTime; - } + if(nextFrame < 0) { + printf("Frame time reset.\n"); + nextFrame = curTime; + } - nextFrame += 1.000/FPS; - //sleep_until(nextFrame); - } + nextFrame += 1.000/FPS; + //sleep_until(nextFrame); + } - return NULL; + return NULL; } value_type gamma_correct(value_type d, value_type gamma) { @@ -134,8 +134,8 @@ value_type gamma_correct(value_type d, value_type gamma) { int main(int argc, char **argv) { double nextFrame = get_hires_time() + LED_INTERVAL; - int i; - pthread_t fftThread; + int i; + pthread_t fftThread; int active = 1; //int frame = 0; @@ -181,7 +181,11 @@ int main(int argc, char **argv) { lua_getglobal(L, "NUM_MODULES"); if(!lua_isnumber(L, -1)) return 2; - int num_modules = lua_tointeger(L, -1); + num_modules = lua_tointeger(L, -1); + + lua_getglobal(L, "NUM_STRIPS"); + if(!lua_isnumber(L, -1)) return 2; + num_strips = lua_tointeger(L, -1); lua_getglobal(L, "CENTER_MODULE"); if(!lua_isnumber(L, -1)) return 2; @@ -198,10 +202,10 @@ int main(int argc, char **argv) { 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)); + red = malloc(num_strips * num_modules * sizeof(double)); + green = malloc(num_strips * num_modules * sizeof(double)); + blue = malloc(num_strips * num_modules * sizeof(double)); + white = malloc(num_strips * num_modules * sizeof(double)); // load and initialize the script if(luaL_loadfile(L, argv[1])) { @@ -215,9 +219,10 @@ int main(int argc, char **argv) { // call the init function lua_getglobal(L, "init"); + lua_pushnumber(L, num_strips); lua_pushnumber(L, num_modules); lua_pushnumber(L, center_module); - if(lua_pcall(L, 2, 1, 0)) { + if(lua_pcall(L, 3, 1, 0)) { lua_showerror(L, "lua_pcall(init) failed."); } @@ -232,13 +237,13 @@ int main(int argc, char **argv) { printf("Connecting to %s:%i\n", host, port); sk6812_init(&sk6812, host, port); - // create semaphores - sem_init(&fftSemaphore, 0, 1); + // create semaphores + sem_init(&fftSemaphore, 0, 1); - // run the fft thread - pthread_create(&fftThread, NULL, fft_thread, NULL); + // run the fft thread + pthread_create(&fftThread, NULL, fft_thread, NULL); - while(running) { + while(running) { if(active) { // call the periodic() function from LUA lua_getglobal(L, "periodic"); @@ -247,27 +252,29 @@ int main(int argc, char **argv) { } // 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); + lua_readdoublearray(L, white, num_strips*num_modules); + lua_readdoublearray(L, blue, num_strips*num_modules); + lua_readdoublearray(L, green, num_strips*num_modules); + lua_readdoublearray(L, red, num_strips*num_modules); - for(int s = 0; s < NUM_SK6812; s++) { + for(int s = 0; s < num_strips; s++) { if(useFading) { for(i = 0; i < num_modules; i++) { + int lidx = idx(s, i); sk6812_fade_color(&sk6812, s, 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(red[lidx], gamma), + 255 * gamma_correct(green[lidx], gamma), + 255 * gamma_correct(blue[lidx], gamma), + 255 * gamma_correct(white[lidx], gamma)); } } else { for(i = 0; i < num_modules; i++) { + int lidx = idx(s, i); sk6812_set_color(&sk6812, s, i, - 255 * gamma_correct(red[i], gamma), - 255 * gamma_correct(green[i], gamma), - 255 * gamma_correct(blue[i], gamma), - 255 * gamma_correct(white[i], gamma)); + 255 * gamma_correct(red[lidx], gamma), + 255 * gamma_correct(green[lidx], gamma), + 255 * gamma_correct(blue[lidx], gamma), + 255 * gamma_correct(white[lidx], gamma)); } } } @@ -278,7 +285,7 @@ int main(int argc, char **argv) { printf("Idle for 1 second -> stopping updates.\n"); for(i = 0; i < num_modules; i++) { - for(int s = 0; s < NUM_SK6812; s++) { + for(int s = 0; s < num_strips; s++) { sk6812_fade_color(&sk6812, s, i, 0, 0, 0, 20); } } @@ -294,21 +301,19 @@ int main(int argc, char **argv) { nextFrame += LED_INTERVAL; sleep_until(nextFrame); - } - - for(int i = 0; i < NUM_SK6812; i++) { - sk6812_shutdown(&sk6812); } + sk6812_shutdown(&sk6812); + // free arrays free(red); free(green); free(blue); free(white); - pthread_join(fftThread, NULL); + pthread_join(fftThread, NULL); lua_close(L); - return 0; + return 0; } diff --git a/old_scripts/README.txt b/old_scripts/README.txt new file mode 100644 index 0000000..e001716 --- /dev/null +++ b/old_scripts/README.txt @@ -0,0 +1,2 @@ +The scripts in this directory are no longer compatible with the current API and +are preserved just for their algorithms. diff --git a/old_scripts/flame.lua b/old_scripts/flame.lua new file mode 100644 index 0000000..dfb3bc2 --- /dev/null +++ b/old_scripts/flame.lua @@ -0,0 +1,206 @@ +COOLDOWN_FACTOR = 0.9998 +OVERDRIVE = 1.70 +EXPONENT = 1.5 +W_EXPONENT = 2.2 + +M = 10.0 -- mass +D = 1 -- spring strength +DAMPING = {} -- filled in init() + +num_modules = 16 +center_module = 16 + +num_masses = math.floor(num_modules/2) +excitement_pos = 1 + +-- maximum energy values for each band +maxRedEnergy = 1 +maxGreenEnergy = 1 +maxBlueEnergy = 1 +maxWhiteEnergy = 1 + +-- spring-mass-grid values +pos_r = {} +pos_g = {} +pos_b = {} +pos_w = {} + +vel_r = {} +vel_g = {} +vel_b = {} +vel_w = {} + +acc_r = {} +acc_g = {} +acc_b = {} +acc_w = {} + +-- output color buffers +red = {} +green = {} +blue = {} +white = {} + +r_tmp = {} +g_tmp = {} +b_tmp = {} +w_tmp = {} + +function limit(val) + if val > 1 then + return 1 + elseif val < 0 then + return 0 + else + return val + end +end + +function periodic() + local redEnergy = get_energy_in_band(0, 400); + local greenEnergy = get_energy_in_band(400, 4000); + local blueEnergy = get_energy_in_band(4000, 12000); + local whiteEnergy = get_energy_in_band(12000, 22000); + local centerIndex = 2 * center_module + 1; + + --print(maxRedEnergy .. "\t" .. maxGreenEnergy .. "\t" .. maxBlueEnergy .. "\t" .. maxWhiteEnergy) + + maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR + if redEnergy > maxRedEnergy then + maxRedEnergy = redEnergy + end + + maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR + if greenEnergy > maxGreenEnergy then + maxGreenEnergy = greenEnergy + end + + maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR + if blueEnergy > maxBlueEnergy then + maxBlueEnergy = blueEnergy + end + + maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR + if whiteEnergy > maxWhiteEnergy then + maxWhiteEnergy = whiteEnergy + end + + -- update the spring-mass string + + -- the outside masses are special, as they are auto-returned to 0 position + -- { spring-mass pendulum } { friction } + --acc_r[1] = (-pos_r[1] + (pos_r[2] - pos_r[1])) * D / M + --acc_g[1] = (-pos_g[1] + (pos_g[2] - pos_g[1])) * D / M + --acc_b[1] = (-pos_b[1] + (pos_b[2] - pos_b[1])) * D / M + --acc_w[1] = (-pos_w[1] + (pos_w[2] - pos_w[1])) * D / M + + acc_r[num_masses] = (-pos_r[num_masses] + (pos_r[num_masses-1] - pos_r[num_masses])) * D / M + acc_g[num_masses] = (-pos_g[num_masses] + (pos_g[num_masses-1] - pos_g[num_masses])) * D / M + acc_b[num_masses] = (-pos_b[num_masses] + (pos_b[num_masses-1] - pos_b[num_masses])) * D / M + acc_w[num_masses] = (-pos_w[num_masses] + (pos_w[num_masses-1] - pos_w[num_masses])) * D / M + + -- inside masses are only influenced by their neighbors + for i = 2,num_masses-1 do + acc_r[i] = (pos_r[i-1] + pos_r[i+1] - 2 * pos_r[i]) * D / M + acc_g[i] = (pos_g[i-1] + pos_g[i+1] - 2 * pos_g[i]) * D / M + acc_b[i] = (pos_b[i-1] + pos_b[i+1] - 2 * pos_b[i]) * D / M + acc_w[i] = (pos_w[i-1] + pos_w[i+1] - 2 * pos_w[i]) * D / M + end + + -- update velocity and position + for i = 1,num_masses do + vel_r[i] = DAMPING[i] * (vel_r[i] + acc_r[i]) + vel_g[i] = DAMPING[i] * (vel_g[i] + acc_g[i]) + vel_b[i] = DAMPING[i] * (vel_b[i] + acc_b[i]) + vel_w[i] = DAMPING[i] * (vel_w[i] + acc_w[i]) + + pos_r[i] = pos_r[i] + vel_r[i] + pos_g[i] = pos_g[i] + vel_g[i] + pos_b[i] = pos_b[i] + vel_b[i] + pos_w[i] = pos_w[i] + vel_w[i] + end + + -- set the new position for the center module + newRed = redEnergy / maxRedEnergy + pos_r[excitement_pos] = newRed + vel_r[excitement_pos] = 0 + acc_r[excitement_pos] = 0 + + newGreen = greenEnergy / maxGreenEnergy + pos_g[excitement_pos] = newGreen + vel_g[excitement_pos] = 0 + acc_g[excitement_pos] = 0 + + newBlue = blueEnergy / maxBlueEnergy + pos_b[excitement_pos] = newBlue + vel_b[excitement_pos] = 0 + acc_b[excitement_pos] = 0 + + newWhite = whiteEnergy / maxWhiteEnergy + pos_w[excitement_pos] = newWhite + vel_w[excitement_pos] = 0 + acc_w[excitement_pos] = 0 + + -- map to LED modules + for i = 1,num_masses do + r_tmp[i] = pos_r[i] + g_tmp[i] = pos_g[i] + b_tmp[i] = pos_b[i] + w_tmp[i] = pos_w[i] + + --r_tmp[num_modules-i+1] = pos_r[i] + --g_tmp[num_modules-i+1] = pos_g[i] + --b_tmp[num_modules-i+1] = pos_b[i] + --w_tmp[num_modules-i+1] = pos_w[i] + + --print(i, pos_r[i]) + end + + -- make colors more exciting + remove the first (flickering) mass + for i = 1,num_modules do + red[i] = limit(OVERDRIVE * r_tmp[i+1]^EXPONENT) + green[i] = limit(OVERDRIVE * g_tmp[i+1]^EXPONENT) + blue[i] = limit(OVERDRIVE * b_tmp[i+1]^EXPONENT) + white[i] = limit(OVERDRIVE * w_tmp[i+1]^W_EXPONENT) + end + + -- return the 4 color arrays + return red, green, blue, white +end + +function init(nmod, cmod) + num_modules = nmod + center_module = nmod --cmod + + num_masses = nmod+1 --math.floor(nmod/2) + excitement_pos = 1 + + for i = 1,nmod do + red[i] = 0 + green[i] = 0 + blue[i] = 0 + white[i] = 0 + end + + for i = 1,num_masses do + pos_r[i] = 0 + pos_g[i] = 0 + pos_b[i] = 0 + pos_w[i] = 0 + + vel_r[i] = 0 + vel_g[i] = 0 + vel_b[i] = 0 + vel_w[i] = 0 + + acc_r[i] = 0 + acc_g[i] = 0 + acc_b[i] = 0 + acc_w[i] = 0 + + DAMPING[i] = 1 - 0.15 * math.abs((i - excitement_pos) / num_masses)^2 + end + + -- don't use fading + return 0 +end diff --git a/flame_diffspeed.lua b/old_scripts/flame_diffspeed.lua similarity index 100% rename from flame_diffspeed.lua rename to old_scripts/flame_diffspeed.lua diff --git a/pulsar.lua b/old_scripts/pulsar.lua similarity index 100% rename from pulsar.lua rename to old_scripts/pulsar.lua diff --git a/pulsecircle.lua b/old_scripts/pulsecircle.lua similarity index 100% rename from pulsecircle.lua rename to old_scripts/pulsecircle.lua diff --git a/pulsecircle_ultrafast.lua b/old_scripts/pulsecircle_ultrafast.lua similarity index 100% rename from pulsecircle_ultrafast.lua rename to old_scripts/pulsecircle_ultrafast.lua diff --git a/pulsetunnel.lua b/old_scripts/pulsetunnel.lua similarity index 100% rename from pulsetunnel.lua rename to old_scripts/pulsetunnel.lua diff --git a/pulsetunnel_commonmax.lua b/old_scripts/pulsetunnel_commonmax.lua similarity index 100% rename from pulsetunnel_commonmax.lua rename to old_scripts/pulsetunnel_commonmax.lua diff --git a/pulsetunnel_fast.lua b/old_scripts/pulsetunnel_fast.lua similarity index 100% rename from pulsetunnel_fast.lua rename to old_scripts/pulsetunnel_fast.lua diff --git a/vumeter.lua b/old_scripts/vumeter.lua similarity index 100% rename from vumeter.lua rename to old_scripts/vumeter.lua diff --git a/run_mpd.sh b/run_mpd.sh index 246cdae..53788bc 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/musiclight.fifo diff --git a/utils.c b/utils.c index ecfcca8..0c33aed 100644 --- a/utils.c +++ b/utils.c @@ -15,6 +15,8 @@ #include "utils.h" +extern int num_modules; + double get_hires_time(void) { struct timespec clk; clock_gettime(CLOCK_REALTIME, &clk); @@ -41,3 +43,7 @@ void sleep_until(double hires_time) { } while(ret == EINTR); } +int idx(int strip, int module) +{ + return strip * num_modules + module; +} diff --git a/utils.h b/utils.h index cba7fd3..cb47b82 100644 --- a/utils.h +++ b/utils.h @@ -14,5 +14,6 @@ double get_hires_time(void); void fsleep(double d); void sleep_until(double hires_time); +int idx(int strip, int module); #endif // UTILS_H