Dreamachine 0.1
Being an old hippy, I’ve always wanted my own Dreamachine, the trance-induction device designed by William S. Burroughs’ compatriot, Bryon Gysin. Being a nerd, I’ve never been satisfied with the idea of a simple rotating flicker, but have felt that a more appropriate instrument for my own purposes would need to be… well, just more.
And now, with the ready availability of programmable LED strips, I’ve finally built my first version (which now wraps my cubicle at work) and am working out the details of the more sophisticated model to be installed in my meditation room at home.
The alpha model, code for which is shown below, is a simple strip of RGB LEDs hooked up to an Arduino. The code allows me to specify different waveforms, rates of change, and maximum values for each color channel, and push them down the strip in waves.
An Arduino is slow enough that actually ‘drawing’ colors across the strip would probably be pretty tedious, so all I really do is calculate the next value of each channel, assign it to the first LED, and then shift the whole thing forward one step. Holding the strip in memory – which you have to do for anything remotely interesting – turns out to blow the low memory of the Arduino pretty easily, so I couldn’t use a normal array processing routine to perform the shift… instead, I use C’s memmove, which performs the shift “in place” as it were.
The waveform I need to work on a bit more is the RAND, which needs some first-order smoothing and a slightly more sophisticated ‘colorizer’ than just the threshold.
I’ve gathered circular LEDs and illuminated rotary encoders to build the final version, which will allow me to control all the relevant parameters through a pretty little hardware interface. In the meantime, here’s the desktop model’s direct-control code:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
#include "LPD8806.h" #include "SPI.h" // Simple test for 160 (5 meters) of LPD8806-based RGB LED strip /*****************************************************************************/ // Number of RGB LEDs in strand: int nLEDs = 160; // Chose 2 pins for output; can be any valid output pins: int dataPin = 2; int clockPin = 3; // First parameter is the number of LEDs in the strand. The LED strips // are 32 LEDs per meter but you can extend or cut the strip. Next two // parameters are SPI data and clock pins: LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin); // You can optionally use hardware SPI for faster writes, just leave out // the data and clock pin parameters. But this does limit use to very // specific pins on the Arduino. For "classic" Arduinos (Uno, Duemilanove, // etc.), data = pin 11, clock = pin 13. For Arduino Mega, data = pin 51, // clock = pin 52. For 32u4 Breakout Board+ and Teensy, data = pin B2, // clock = pin B1. For Leonardo, this can ONLY be done on the ICSP pins. //LPD8806 strip = LPD8806(nLEDs); uint32_t q[159]; /* color array = {waveform, initial value, inc rate, max val} */ #define WFORM 0 #define WVAL 1 #define RATE 2 #define MAXVAL 3 #define TRI 0 #define SAWUP 1 #define SAWDN 2 #define RAND 3 float r[] = {TRI,0,.3,64}; float g[] = {TRI,0,.2,16}; float b[] = {TRI,0,.5,32}; void stepwave(float*); void setup() { Serial.begin(9600); randomSeed(analogRead(0)); int i; // Start up the LED strip strip.begin(); // Update the strip, to start they are all 'off' strip.show(); for(i=0; i<strip.numPixels(); i++){ q[i] = strip.Color(0,0,0); } pushQ(); } void loop() { stepwave(r); stepwave(g); stepwave(b); q[0] = strip.Color(int(r[WVAL]),int(g[WVAL]),int(b[WVAL])); pushQ(); shiftQ(); } void stepwave(float* ca){ long randNumber; switch(int(ca[WFORM])){ case TRI: ca[WVAL] += ca[RATE]; if(ca[WVAL] > ca[MAXVAL]){ ca[WVAL] = ca[MAXVAL]; ca[RATE] = 0 - ca[RATE]; } else if(ca[WVAL] < 0){ ca[WVAL] = 0; ca[RATE] = 0 - ca[RATE]; } break; case SAWUP: ca[WVAL] += ca[RATE]; if(ca[WVAL] > ca[MAXVAL]){ ca[WVAL] = 0; } break; case SAWDN: ca[WVAL] -= ca[RATE]; if(ca[WVAL] < 0){ ca[WVAL] = ca[MAXVAL]; } break; case RAND: randNumber = random(10); if (randNumber > 4){ ca[WVAL] += ca[RATE]; } else { ca[WVAL] -= ca[RATE]; } if(ca[WVAL] < 0){ ca[WVAL] = 0; } else if(ca[WVAL] > ca[MAXVAL]){ ca[WVAL] = ca[MAXVAL]; } } } void pushQ(){ int i; for(i=0; i<strip.numPixels(); i++){ strip.setPixelColor(i,q[i]); } strip.show(); } void shiftQ(){ memmove(&q[1], &q[0], sizeof(q) - sizeof(*q)); } |



