Sound2Light auf RGB(W)-LED-Leisten
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.c 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * vim: sw=2 ts=2 expandtab
  3. *
  4. * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
  5. * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
  6. * do whatever you want with this stuff. If we meet some day, and you think
  7. * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
  8. */
  9. #include <pthread.h>
  10. #include <semaphore.h>
  11. #include <stdio.h>
  12. #include <math.h>
  13. #include <string.h>
  14. #include <stdint.h>
  15. #include <malloc.h>
  16. #include <lua.h>
  17. #include <lualib.h>
  18. #include <lauxlib.h>
  19. #include "lua_utils.h"
  20. #include "lua_wrappers.h"
  21. #include "fft.h"
  22. #include "utils.h"
  23. #include "ws2801.h"
  24. #include "config.h"
  25. // Frames per second
  26. #define FPS ((double)BUFFER_PARTS * SAMPLE_RATE / BLOCK_LEN)
  27. // Number of new samples put into the buffer each frame
  28. #define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS)
  29. double fft[BLOCK_LEN];
  30. sample signal[BLOCK_LEN];
  31. double rms;
  32. double lastUpdateTime = 0;
  33. sem_t fftSemaphore;
  34. int running = 1;
  35. void* fft_thread(void *param) {
  36. sample buffer[BLOCK_LEN];
  37. sample block[BLOCK_LEN];
  38. double fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
  39. double tmpFFT[BLOCK_LEN];
  40. double tmpRMS;
  41. double nextFrame = get_hires_time() + 0.05;
  42. double curTime;
  43. int i;
  44. init_fft();
  45. while(running) {
  46. // shift the buffer left
  47. memmove(buffer, buffer + READ_SAMPLES,
  48. (BLOCK_LEN - READ_SAMPLES) * sizeof(sample));
  49. size_t ret = fread(buffer + (BLOCK_LEN - READ_SAMPLES),
  50. sizeof(sample), READ_SAMPLES, stdin);
  51. if(ret != READ_SAMPLES) {
  52. break;
  53. }
  54. memcpy(block, buffer, BLOCK_LEN * sizeof(sample));
  55. apply_hanning(block);
  56. fft_transform(block, fftOutReal, fftOutImag);
  57. complex_to_absolute(fftOutReal, fftOutImag, tmpFFT);
  58. tmpRMS = 0;
  59. for(i = 0; i < BLOCK_LEN; i++) {
  60. tmpRMS += buffer[i]*buffer[i];
  61. }
  62. tmpRMS = sqrt(tmpRMS/BLOCK_LEN);
  63. // --- SAFE SECTION ---
  64. sem_wait(&fftSemaphore);
  65. memcpy(fft, tmpFFT, sizeof(fft));
  66. memcpy(signal, buffer, sizeof(signal));
  67. rms = tmpRMS;
  68. curTime = get_hires_time();
  69. lastUpdateTime = curTime;
  70. sem_post(&fftSemaphore);
  71. // --- END SAFE SECTION ---
  72. if(curTime > nextFrame + 0.05) {
  73. printf("Frame too late! Skipping.\n");
  74. nextFrame = -1;
  75. }
  76. if(curTime < nextFrame - 0.05) {
  77. printf("Frame too early.\n");
  78. nextFrame = -1;
  79. }
  80. if(nextFrame < 0) {
  81. printf("Frame time reset.\n");
  82. nextFrame = curTime;
  83. }
  84. nextFrame += 1.000/FPS;
  85. sleep_until(nextFrame);
  86. }
  87. return NULL;
  88. }
  89. double gamma_correct(double d, double gamma) {
  90. return pow(d, gamma);
  91. }
  92. int main(int argc, char **argv) {
  93. double nextFrame = get_hires_time() + LED_INTERVAL;
  94. int i;
  95. pthread_t fftThread;
  96. int active = 1;
  97. double *red;
  98. double *green;
  99. double *blue;
  100. int useFading, fadeStep;
  101. if(argc < 2) {
  102. fprintf(stderr, "LUA script file must be given as command line argument!\n");
  103. return 1;
  104. }
  105. // initialize lua
  106. lua_State *L = lua_open();
  107. // load the lua libraries
  108. luaL_openlibs(L);
  109. // register local functions
  110. lua_register_funcs(L);
  111. // load the configuration from "config.lua"
  112. if(luaL_dofile(L, "config.lua")) {
  113. lua_showerror(L, "luaL_dofile(config.lua) failed.");
  114. return 1;
  115. }
  116. lua_getglobal(L, "WS2801_HOST");
  117. if(!lua_isstring(L, -1)) return 2;
  118. const char *host = lua_tostring(L, -1);
  119. lua_getglobal(L, "WS2801_PORT");
  120. if(!lua_isnumber(L, -1)) return 2;
  121. unsigned short port = lua_tointeger(L, -1);
  122. lua_getglobal(L, "GAMMA");
  123. if(!lua_isnumber(L, -1)) return 2;
  124. double gamma = lua_tonumber(L, -1);
  125. lua_getglobal(L, "NUM_MODULES");
  126. if(!lua_isnumber(L, -1)) return 2;
  127. int num_modules = lua_tointeger(L, -1);
  128. lua_getglobal(L, "CENTER_MODULE");
  129. if(!lua_isnumber(L, -1)) return 2;
  130. int center_module = lua_tointeger(L, -1);
  131. // allocate arrays
  132. red = malloc(num_modules * sizeof(double));
  133. green = malloc(num_modules * sizeof(double));
  134. blue = malloc(num_modules * sizeof(double));
  135. // load and initialize the script
  136. if(luaL_loadfile(L, argv[1])) {
  137. lua_showerror(L, "luaL_loadfile(cmdline_argument) failed.");
  138. }
  139. // priming call: read the lua file to make functions known
  140. if(lua_pcall(L, 0, 0, 0)) {
  141. lua_showerror(L, "lua_pcall failed.");
  142. }
  143. // call the init function
  144. lua_getglobal(L, "init");
  145. lua_pushnumber(L, num_modules);
  146. lua_pushnumber(L, center_module);
  147. if(lua_pcall(L, 2, 1, 0)) {
  148. lua_showerror(L, "lua_pcall(init) failed.");
  149. }
  150. fadeStep = lua_tointeger(L, -1);
  151. useFading = fadeStep > 0;
  152. if(useFading) {
  153. ws2801_set_fadestep(fadeStep);
  154. printf("Fading enabled with fadestep %i.\n", fadeStep);
  155. }
  156. // initialize the WS2801 library
  157. printf("Connecting to %s:%i\n", host, port);
  158. ws2801_init(host, port);
  159. // create semaphores
  160. sem_init(&fftSemaphore, 0, 1);
  161. // run the fft thread
  162. pthread_create(&fftThread, NULL, fft_thread, NULL);
  163. while(running) {
  164. if(active) {
  165. // call the periodic() function from LUA
  166. lua_getglobal(L, "periodic");
  167. if(lua_pcall(L, 0, 3, 0)) { // no arguments, 3 return values
  168. lua_showerror(L, "lua_pcall(periodic) failed.");
  169. }
  170. // read the return values (reverse order, as lua uses a stack)
  171. lua_readdoublearray(L, blue, num_modules);
  172. lua_readdoublearray(L, green, num_modules);
  173. lua_readdoublearray(L, red, num_modules);
  174. if(useFading) {
  175. for(i = 0; i < num_modules; i++) {
  176. ws2801_fade_color(i,
  177. 255 * gamma_correct(red[i], gamma),
  178. 255 * gamma_correct(green[i], gamma),
  179. 255 * gamma_correct(blue[i], gamma));
  180. }
  181. ws2801_commit();
  182. } else {
  183. for(i = 0; i < num_modules; i++) {
  184. ws2801_set_color(i,
  185. 255 * gamma_correct(red[i], gamma),
  186. 255 * gamma_correct(green[i], gamma),
  187. 255 * gamma_correct(blue[i], gamma));
  188. }
  189. ws2801_commit();
  190. }
  191. if(lastUpdateTime < nextFrame - 1) {
  192. printf("Idle for 1 second -> stopping updates.\n");
  193. for(i = 0; i < num_modules; i++) {
  194. ws2801_fade_color(i, 20, 20, 20);
  195. }
  196. ws2801_commit();
  197. active = 0;
  198. }
  199. } else if(lastUpdateTime > nextFrame - 1) {
  200. printf("Resuming updates.\n");
  201. active = 1;
  202. }
  203. nextFrame += LED_INTERVAL;
  204. sleep_until(nextFrame);
  205. }
  206. ws2801_shutdown();
  207. // free arrays
  208. free(red);
  209. free(green);
  210. free(blue);
  211. pthread_join(fftThread, NULL);
  212. lua_close(L);
  213. return 0;
  214. }